class Puppet::Provider::NameService

This is the parent class of all NSS classes. They're very different in their backend, but they're pretty similar on the front-end. This class provides a way for them all to be as similar as possible.

Public Class Methods

autogen_default(param) click to toggle source
   # File lib/puppet/provider/nameservice.rb
 8 def autogen_default(param)
 9   defined?(@autogen_defaults) ? @autogen_defaults[param.intern] : nil
10 end
autogen_defaults(hash) click to toggle source
   # File lib/puppet/provider/nameservice.rb
12 def autogen_defaults(hash)
13   @autogen_defaults ||= {}
14   hash.each do |param, value|
15     @autogen_defaults[param.intern] = value
16   end
17 end
autogen_id(field, resource_type) click to toggle source

Autogenerate either a uid or a gid. This is not very flexible: we can only generate one field type per class, and get kind of confused if asked for both.

    # File lib/puppet/provider/nameservice.rb
123 def self.autogen_id(field, resource_type)
124   # Figure out what sort of value we want to generate.
125   case resource_type
126   when :user;   database = :passwd;  method = :uid
127   when :group;  database = :group;   method = :gid
128   else
129     #TRANSLATORS "autogen_id()" is a method name and should not be translated
130     raise Puppet::DevError, _("autogen_id() does not support auto generation of id for resource type %{resource_type}") % { resource_type: resource_type }
131   end
132 
133   # Initialize from the data set, if needed.
134   unless @prevauto
135     # Sadly, Etc doesn't return an enumerator, it just invokes the block
136     # given, or returns the first record from the database.  There is no
137     # other, more convenient enumerator for these, so we fake one with this
138     # loop.  Thanks, Ruby, for your awesome abstractions. --daniel 2012-03-23
139     highest = []
140     Puppet::Etc.send(database) {|entry| highest << entry.send(method) }
141     highest = highest.reject {|x| x > 65000 }.max
142 
143     @prevauto = highest || 1000
144   end
145 
146   # ...and finally increment and return the next value.
147   @prevauto += 1
148 end
initvars() click to toggle source
Calls superclass method Puppet::Provider::initvars
   # File lib/puppet/provider/nameservice.rb
19 def initvars
20   @checks = {}
21   @options = {}
22   super
23 end
instances() click to toggle source
   # File lib/puppet/provider/nameservice.rb
25 def instances
26   objects = []
27   begin
28     method = Puppet::Etc.method(:"get#{section}ent")
29     while ent = method.call #rubocop:disable Lint/AssignmentInCondition
30       objects << new(:name => ent.name, :canonical_name => ent.canonical_name, :ensure => :present)
31     end
32   ensure
33     Puppet::Etc.send("end#{section}ent")
34   end
35   objects
36 end
new(resource) click to toggle source
Calls superclass method Puppet::Provider::new
    # File lib/puppet/provider/nameservice.rb
250 def initialize(resource)
251   super
252   @custom_environment = {}
253   @objectinfo = nil
254   if resource.is_a?(Hash) && !resource[:canonical_name].nil?
255     @canonical_name = resource[:canonical_name]
256   else
257     @canonical_name = resource[:name]
258   end
259 end
option(name, option) click to toggle source
   # File lib/puppet/provider/nameservice.rb
38 def option(name, option)
39   name = name.intern if name.is_a? String
40   (defined?(@options) and @options.include? name and @options[name].include? option) ? @options[name][option] : nil
41 end
options(name, hash) click to toggle source
   # File lib/puppet/provider/nameservice.rb
43 def options(name, hash)
44   unless resource_type.valid_parameter?(name)
45     raise Puppet::DevError, _("%{name} is not a valid attribute for %{resource_type}") % { name: name, resource_type: resource_type.name }
46   end
47   @options ||= {}
48   @options[name] ||= {}
49 
50   # Set options individually, so we can call the options method
51   # multiple times.
52   hash.each do |param, value|
53     @options[name][param] = value
54   end
55 end
resource_type=(resource_type) click to toggle source
Calls superclass method
   # File lib/puppet/provider/nameservice.rb
57 def resource_type=(resource_type)
58   super
59   @resource_type.validproperties.each do |prop|
60     next if prop == :ensure
61     define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
62     define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
63   end
64 end
section() click to toggle source

This is annoying, but there really aren't that many options, and this is built into Ruby.

   # File lib/puppet/provider/nameservice.rb
68 def section
69   unless resource_type
70     raise Puppet::DevError,
71       "Cannot determine Etc section without a resource type"
72   end
73 
74   if @resource_type.name == :group
75     "gr"
76   else
77     "pw"
78   end
79 end
validate(name, value) click to toggle source
   # File lib/puppet/provider/nameservice.rb
81 def validate(name, value)
82   name = name.intern if name.is_a? String
83   if @checks.include? name
84     block = @checks[name][:block]
85     raise ArgumentError, _("Invalid value %{value}: %{error}") % { value: value, error: @checks[name][:error] } unless block.call(value)
86   end
87 end
verify(name, error, &block) click to toggle source
   # File lib/puppet/provider/nameservice.rb
89 def verify(name, error, &block)
90   name = name.intern if name.is_a? String
91   @checks[name] = {:error => error, :block => block}
92 end

Private Class Methods

op(property) click to toggle source
   # File lib/puppet/provider/nameservice.rb
96 def op(property)
97   @ops[property.name] || ("-#{property.name}")
98 end

Public Instance Methods

autogen(field) click to toggle source

Autogenerate a value. Mostly used for uid/gid, but also used heavily with DirectoryServices

    # File lib/puppet/provider/nameservice.rb
103 def autogen(field)
104   field = field.intern
105   id_generators = {:user => :uid, :group => :gid}
106   if id_generators[@resource.class.name] == field
107     return self.class.autogen_id(field, @resource.class.name)
108   else
109     value = self.class.autogen_default(field)
110     if value
111       return value
112     elsif respond_to?("autogen_#{field}")
113       return send("autogen_#{field}")
114     else
115       return nil
116     end
117   end
118 end
comments_insync?(current, should) click to toggle source

From overriding Puppet::Property#insync? Ruby Etc::getpwnam < 2.1.0 always returns a struct with binary encoded string values, and >= 2.1.0 will return binary encoded strings for values incompatible with current locale charset, or Encoding.default_external if compatible. Compare a “should” value with encoding of “current” value, to avoid unnecessary property syncs and comparison of strings with different encodings. (PUP-6777)

return basic string comparison after re-encoding (same as Puppet::Property#property_matches)

    # File lib/puppet/provider/nameservice.rb
287 def comments_insync?(current, should)
288   # we're only doing comparison here so don't mutate the string
289   desired = should[0].to_s.dup
290   current == desired.force_encoding(current.encoding)
291 end
create() click to toggle source
    # File lib/puppet/provider/nameservice.rb
150 def create
151   if exists?
152     info _("already exists")
153     # The object already exists
154     return nil
155   end
156 
157   begin
158     sensitive = has_sensitive_data?
159     execute(self.addcmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
160     if feature?(:manages_password_age) && (cmd = passcmd)
161       execute(cmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
162     end
163   rescue Puppet::ExecutionFailure => detail
164     raise Puppet::Error, _("Could not create %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
165   end
166 end
delete() click to toggle source
    # File lib/puppet/provider/nameservice.rb
168 def delete
169   unless exists?
170     info _("already absent")
171     # the object already doesn't exist
172     return nil
173   end
174 
175   begin
176     execute(self.deletecmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment})
177   rescue Puppet::ExecutionFailure => detail
178     raise Puppet::Error, _("Could not delete %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
179   end
180 end
ensure() click to toggle source
    # File lib/puppet/provider/nameservice.rb
182 def ensure
183   if exists?
184     :present
185   else
186     :absent
187   end
188 end
exists?() click to toggle source

Does our object exist?

    # File lib/puppet/provider/nameservice.rb
191 def exists?
192   !!getinfo(true)
193 end
get(param) click to toggle source

Retrieve a specific value by name.

    # File lib/puppet/provider/nameservice.rb
196 def get(param)
197   (hash = getinfo(false)) ? unmunge(param, hash[param]) : nil
198 end
getinfo(refresh) click to toggle source

Retrieve what we can about our object

    # File lib/puppet/provider/nameservice.rb
219 def getinfo(refresh)
220   if @objectinfo.nil? or refresh == true
221     @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
222     begin
223       @objectinfo = Puppet::Etc.send(@etcmethod, @canonical_name)
224     rescue ArgumentError
225       @objectinfo = nil
226     end
227   end
228 
229   # Now convert our Etc struct into a hash.
230   @objectinfo ? info2hash(@objectinfo) : nil
231 end
groups() click to toggle source

The list of all groups the user is a member of. Different user mgmt systems will need to override this method.

    # File lib/puppet/provider/nameservice.rb
235 def groups
236   Puppet::Util::POSIX.groups_of(@resource[:name]).join(',')
237 end
has_sensitive_data?(property = nil) click to toggle source

Derived classes can override to declare sensitive data so a flag can be passed to execute

    # File lib/puppet/provider/nameservice.rb
274 def has_sensitive_data?(property = nil)
275   false
276 end
info2hash(info) click to toggle source

Convert the Etc struct into a hash.

    # File lib/puppet/provider/nameservice.rb
240 def info2hash(info)
241   hash = {}
242   self.class.resource_type.validproperties.each do |param|
243     method = posixmethod(param)
244     hash[param] = info.send(posixmethod(param)) if info.respond_to? method
245   end
246 
247   hash
248 end
munge(name, value) click to toggle source
    # File lib/puppet/provider/nameservice.rb
200 def munge(name, value)
201   block = self.class.option(name, :munge)
202   if block and block.is_a? Proc
203     block.call(value)
204   else
205     value
206   end
207 end
set(param, value) click to toggle source
    # File lib/puppet/provider/nameservice.rb
261 def set(param, value)
262   self.class.validate(param, value)
263   cmd = modifycmd(param, munge(param, value))
264   raise Puppet::DevError, _("Nameservice command must be an array") unless cmd.is_a?(Array)
265   sensitive = has_sensitive_data?(param)
266   begin
267     execute(cmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
268   rescue Puppet::ExecutionFailure => detail
269     raise Puppet::Error, _("Could not set %{param} on %{resource}[%{name}]: %{detail}") % { param: param, resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
270   end
271 end
unmunge(name, value) click to toggle source
    # File lib/puppet/provider/nameservice.rb
209 def unmunge(name, value)
210   block = self.class.option(name, :unmunge)
211   if block and block.is_a? Proc
212     block.call(value)
213   else
214     value
215   end
216 end