summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/nameservice/netinfo.rb
blob: f03e67445e87b4e3cf8833ecf0bebffae52463ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# Manage NetInfo POSIX objects.  Probably only used on OS X, but I suppose
# it could be used elsewhere.

require 'puppet'
require 'puppet/provider/nameservice'

class Puppet::Provider::NameService
class NetInfo < Puppet::Provider::NameService
    class << self
        attr_writer :netinfodir
    end

    # We have to initialize manually because we're not using
    # classgen() here.
    initvars()

    commands :lookupd => "/usr/sbin/lookupd"

    # Attempt to flush the database, but this doesn't seem to work at all.
    def self.flush
        begin
            lookupd "-flushcache"
        rescue Puppet::ExecutionFailure
            # Don't throw an error; it's just a failed cache flush
            Puppet.err "Could not flush lookupd cache: %s" % output
        end
    end

    # Similar to posixmethod, what key do we use to get data?  Defaults
    # to being the object name.
    def self.netinfodir
        if defined? @netinfodir
            return @netinfodir
        else
            return @resource_type.name.to_s + "s"
        end
    end

    def self.finish
        case self.name
        when :uid:
            noautogen
        when :gid:
            noautogen
        end
    end
    
    def self.instances
        report(@resource_type.validproperties).collect do |hash|
            self.new(hash)
        end
    end
    
    # Convert a NetInfo line into a hash of data.
    def self.line2hash(line, params)
        values = line.split(/\t/)

        hash = {}
        params.zip(values).each do |param, value|
            next if value == '#NoValue#'
            hash[param] = if value =~ /^[-0-9]+$/
                Integer(value)
            else
                value
            end
        end
        hash
    end
    
    # What field the value is stored under.
    def self.netinfokey(name)
        name = symbolize(name)
        self.option(name, :key) || name
    end
    
    # Retrieve the data, yo.
    # FIXME This should retrieve as much information as possible,
    # rather than retrieving it one at a time.
    def self.report(*params)
        dir = self.netinfodir()
        cmd = [command(:nireport), "/", "/%s" % dir]
        
        params.flatten!

        # We require the name in order to know if we match.  There's no
        # way to just report on our individual object, we have to get the
        # whole list.
        params.unshift :name unless params.include? :name

        params.each do |param|
            if key = netinfokey(param)
                cmd << key.to_s
            else
                raise Puppet::DevError,
                    "Could not find netinfokey for property %s" %
                    self.class.name
            end
        end

        begin
            output = execute(cmd)
        rescue Puppet::ExecutionFailure => detail
            Puppet.err "Failed to call nireport: %s" % detail
            return nil
        end

        return output.split("\n").collect { |line|
            line2hash(line, params)
        }
    end
    
    # How to add an object.
    def addcmd
        creatorcmd("-create")
    end

    def creatorcmd(arg)
        cmd = [command(:niutil)]
        cmd << arg

        cmd << "/" << "/%s/%s" % [self.class.netinfodir(), @resource[:name]]
        return cmd
    end

    def deletecmd
        creatorcmd("-destroy")
    end
    
    def destroy
        delete()
    end

    def ensure=(arg)
        super

        # Because our stupid type can't create the whole thing at once,
        # we have to do this hackishness.  Yay.
        if arg == :present
            @resource.class.validproperties.each do |name|
                next if name == :ensure
                next unless val = @resource.should(name) || autogen(name)
                self.send(name.to_s + "=", val)
            end
        end
    end

    # Retrieve a specific value by name.
    def get(param)
        hash = getinfo(false)
        if hash
            return hash[param]
        else
            return :absent
        end
    end

    # Retrieve everything about this object at once, instead of separately.
    def getinfo(refresh = false)
        if refresh or (! defined? @infohash or ! @infohash)
            properties = [:name] + self.class.resource_type.validproperties
            properties.delete(:ensure) if properties.include? :ensure
            @infohash = single_report(*properties)
        end

        return @infohash
    end

    def modifycmd(param, value)
        cmd = [command(:niutil)]
        # if value.is_a?(Array)
        #     warning "Netinfo providers cannot currently handle multiple values"
        # end

        cmd << "-createprop" << "/" << "/%s/%s" % [self.class.netinfodir, @resource[:name]]

        value = [value] unless value.is_a?(Array)
        if key = netinfokey(param)
            cmd << key
            cmd += value
        else
            raise Puppet::DevError,
                "Could not find netinfokey for property %s" %
                self.class.name
        end
        cmd
    end

    # Determine the flag to pass to our command.
    def netinfokey(name)
        self.class.netinfokey(name)
    end
    
    # Get a report for a single resource, not the whole table
    def single_report(*properties)
        self.class.report(*properties).find do |hash| hash[:name] == self.name end
    end

    def setuserlist(group, list)
        cmd = [command(:niutil), "-createprop", "/", "/groups/%s" % group, "users", list.join(",")]
        begin
            output = execute(cmd)
        rescue Puppet::ExecutionFailure => detail
            raise Puppet::Error, "Failed to set user list on %s: %s" %
                [group, detail]
        end
    end
end
end

# $Id$