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

Private Class Methods

op(property) click to toggle source
   # File lib/puppet/provider/nameservice.rb
97 def op(property)
98   @ops[property.name] || ("-#{property.name}")
99 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
104 def autogen(field)
105   field = field.intern
106   id_generators = {:user => :uid, :group => :gid}
107   if id_generators[@resource.class.name] == field
108     return self.class.autogen_id(field, @resource.class.name)
109   else
110     value = self.class.autogen_default(field)
111     if value
112       return value
113     elsif respond_to?("autogen_#{field}")
114       return send("autogen_#{field}")
115     else
116       return nil
117     end
118   end
119 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
288 def comments_insync?(current, should)
289   # we're only doing comparison here so don't mutate the string
290   desired = should[0].to_s.dup
291   current == desired.force_encoding(current.encoding)
292 end
create() click to toggle source
    # File lib/puppet/provider/nameservice.rb
151 def create
152   if exists?
153     info _("already exists")
154     # The object already exists
155     return nil
156   end
157 
158   begin
159     sensitive = has_sensitive_data?
160     execute(self.addcmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
161     if feature?(:manages_password_age) && (cmd = passcmd)
162       execute(cmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
163     end
164   rescue Puppet::ExecutionFailure => detail
165     raise Puppet::Error, _("Could not create %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
166   end
167 end
delete() click to toggle source
    # File lib/puppet/provider/nameservice.rb
169 def delete
170   unless exists?
171     info _("already absent")
172     # the object already doesn't exist
173     return nil
174   end
175 
176   begin
177     execute(self.deletecmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment})
178   rescue Puppet::ExecutionFailure => detail
179     raise Puppet::Error, _("Could not delete %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
180   end
181 end
ensure() click to toggle source
    # File lib/puppet/provider/nameservice.rb
183 def ensure
184   if exists?
185     :present
186   else
187     :absent
188   end
189 end
exists?() click to toggle source

Does our object exist?

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

Retrieve a specific value by name.

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

Retrieve what we can about our object

    # File lib/puppet/provider/nameservice.rb
220 def getinfo(refresh)
221   if @objectinfo.nil? or refresh == true
222     @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
223     begin
224       @objectinfo = Puppet::Etc.send(@etcmethod, @canonical_name)
225     rescue ArgumentError
226       @objectinfo = nil
227     end
228   end
229 
230   # Now convert our Etc struct into a hash.
231   @objectinfo ? info2hash(@objectinfo) : nil
232 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
236 def groups
237   Puppet::Util::POSIX.groups_of(@resource[:name]).join(',')
238 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
275 def has_sensitive_data?(property = nil)
276   false
277 end
info2hash(info) click to toggle source

Convert the Etc struct into a hash.

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