Class: Puppet::Provider::NameService

Inherits:
Puppet::Provider show all
Defined in:
lib/puppet/provider/nameservice.rb,
lib/puppet/provider/nameservice/pw.rb,
lib/puppet/provider/nameservice/objectadd.rb

Overview

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.

API:

  • public

Direct Known Subclasses

DirectoryService, ObjectAdd

Defined Under Namespace

Classes: DirectoryService, ObjectAdd, PW

Constant Summary

Constants inherited from Puppet::Provider

Confine

Constants included from Util

Util::AbsolutePathPosix, Util::AbsolutePathWindows, Util::DEFAULT_POSIX_MODE, Util::DEFAULT_WINDOWS_MODE

Constants included from Util::POSIX

Util::POSIX::LOCALE_ENV_VARS, Util::POSIX::USER_ENV_VARS

Constants included from Util::SymbolicFileMode

Util::SymbolicFileMode::SetGIDBit, Util::SymbolicFileMode::SetUIDBit, Util::SymbolicFileMode::StickyBit, Util::SymbolicFileMode::SymbolicMode, Util::SymbolicFileMode::SymbolicSpecialToBit

Constants included from Util::Docs

Util::Docs::HEADER_LEVELS

Instance Attribute Summary

Attributes inherited from Puppet::Provider

#model, #resource

Attributes included from Util::Docs

#doc, #nodoc

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Puppet::Provider

#<=>, #clear, #command, command, commands, declared_feature?, default?, default_match, defaultfor, execfail, #execfail, execpipe, #execpipe, execute, #execute, fact_match, feature_match, #flush, has_command, make_command_methods, mk_resource_methods, #name, optional_commands, post_resource_eval, prefetch, specificity, supports_parameter?, #to_s

Methods included from Util::Logging

#clear_deprecation_warnings, #deprecation_warning, #format_exception, #get_deprecation_offender, #log_and_raise, #log_deprecations_to_file, #log_exception, #puppet_deprecation_warning, #send_log

Methods included from Util

absolute_path?, activerecord_version, benchmark, binread, chuser, classproxy, deterministic_rand, execfail, execpipe, execute, exit_on_fail, logmethods, memory, path_to_uri, pretty_backtrace, proxy, replace_file, safe_posix_fork, symbolizehash, thinmark, uri_to_path, which, withenv, withumask

Methods included from Util::POSIX

#get_posix_field, #gid, #idfield, #methodbyid, #methodbyname, #search_posix_field, #uid

Methods included from Util::SymbolicFileMode

#normalize_symbolic_mode, #symbolic_mode_to_int, #valid_symbolic_mode?

Methods included from Util::Docs

#desc, #dochook, #doctable, #markdown_definitionlist, #markdown_header, #nodoc?, #pad, scrub

Methods included from Util::Warnings

clear_warnings, debug_once, notice_once, warnonce

Methods included from Confiner

#confine, #confine_collection, #suitable?

Methods included from Util::Errors

#adderrorcontext, #devfail, #error_context, #exceptwrap, #fail

Constructor Details

#initialize(resource) ⇒ NameService

Returns a new instance of NameService.

API:

  • public



275
276
277
278
279
# File 'lib/puppet/provider/nameservice.rb', line 275

def initialize(resource)
  super
  @custom_environment = {}
  @objectinfo = nil
end

Class Method Details

.autogen_default(param) ⇒ Object

API:

  • public



8
9
10
# File 'lib/puppet/provider/nameservice.rb', line 8

def autogen_default(param)
  defined?(@autogen_defaults) ? @autogen_defaults[param.intern] : nil
end

.autogen_defaults(hash) ⇒ Object

API:

  • public



12
13
14
15
16
17
# File 'lib/puppet/provider/nameservice.rb', line 12

def autogen_defaults(hash)
  @autogen_defaults ||= {}
  hash.each do |param, value|
    @autogen_defaults[param.intern] = value
  end
end

.autogen_id(field, resource_type) ⇒ Object

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.

API:

  • public



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
# File 'lib/puppet/provider/nameservice.rb', line 133

def self.autogen_id(field, resource_type)
  # Figure out what sort of value we want to generate.
  case resource_type
  when :user;   database = :passwd;  method = :uid
  when :group;  database = :group;   method = :gid
  else
    raise Puppet::DevError, "Invalid resource name #{resource}"
  end

  # Initialize from the data set, if needed.
  unless @prevauto
    # Sadly, Etc doesn't return an enumerator, it just invokes the block
    # given, or returns the first record from the database.  There is no
    # other, more convenient enumerator for these, so we fake one with this
    # loop.  Thanks, Ruby, for your awesome abstractions. --daniel 2012-03-23
    highest = []
    Etc.send(database) {|entry| highest << entry.send(method) }
    highest = highest.reject {|x| x > 65000 }.max

    @prevauto = highest || 1000
  end

  # ...and finally increment and return the next value.
  @prevauto += 1
end

.initvarsObject

API:

  • public



19
20
21
22
23
# File 'lib/puppet/provider/nameservice.rb', line 19

def initvars
  @checks = {}
  @options = {}
  super
end

.instancesObject

API:

  • public



25
26
27
28
29
30
31
32
# File 'lib/puppet/provider/nameservice.rb', line 25

def instances
  objects = []
  listbyname do |name|
    objects << new(:name => name, :ensure => :present)
  end

  objects
end

.listbynameObject

List everything out by name. Abstracted a bit so that it works for both users and groups.

API:

  • public



53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/puppet/provider/nameservice.rb', line 53

def listbyname
  names = []
  Etc.send("set#{section()}ent")
  begin
    while ent = Etc.send("get#{section()}ent")
      names << ent.name
      yield ent.name if block_given?
    end
  ensure
    Etc.send("end#{section()}ent")
  end

  names
end

.option(name, option) ⇒ Object

API:

  • public



34
35
36
37
# File 'lib/puppet/provider/nameservice.rb', line 34

def option(name, option)
  name = name.intern if name.is_a? String
  (defined?(@options) and @options.include? name and @options[name].include? option) ? @options[name][option] : nil
end

.options(name, hash) ⇒ Object

Raises:

API:

  • public



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/puppet/provider/nameservice.rb', line 39

def options(name, hash)
  raise Puppet::DevError, "#{name} is not a valid attribute for #{resource_type.name}" unless resource_type.valid_parameter?(name)
  @options ||= {}
  @options[name] ||= {}

  # Set options individually, so we can call the options method
  # multiple times.
  hash.each do |param, value|
    @options[name][param] = value
  end
end

.resource_type=(resource_type) ⇒ Object

API:

  • public



68
69
70
71
72
73
74
75
# File 'lib/puppet/provider/nameservice.rb', line 68

def resource_type=(resource_type)
  super
  @resource_type.validproperties.each do |prop|
    next if prop == :ensure
    define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
    define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
  end
end

.sectionObject

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

API:

  • public



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/puppet/provider/nameservice.rb', line 79

def section
  unless resource_type
    raise Puppet::DevError,
      "Cannot determine Etc section without a resource type"
  end

  if @resource_type.name == :group
    "gr"
  else
    "pw"
  end
end

.validate(name, value) ⇒ Object

API:

  • public



92
93
94
95
96
97
98
# File 'lib/puppet/provider/nameservice.rb', line 92

def validate(name, value)
  name = name.intern if name.is_a? String
  if @checks.include? name
    block = @checks[name][:block]
    raise ArgumentError, "Invalid value #{value}: #{@checks[name][:error]}" unless block.call(value)
  end
end

.verify(name, error, &block) ⇒ Object

API:

  • public



100
101
102
103
# File 'lib/puppet/provider/nameservice.rb', line 100

def verify(name, error, &block)
  name = name.intern if name.is_a? String
  @checks[name] = {:error => error, :block => block}
end

Instance Method Details

#autogen(field) ⇒ Object

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

API:

  • public



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/puppet/provider/nameservice.rb', line 114

def autogen(field)
  field = field.intern
  id_generators = {:user => :uid, :group => :gid}
  if id_generators[@resource.class.name] == field
    return self.class.autogen_id(field, @resource.class.name)
  else
    if value = self.class.autogen_default(field)
      return value
    elsif respond_to?("autogen_#{field}")
      return send("autogen_#{field}")
    else
      return nil
    end
  end
end

#createObject

API:

  • public



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/puppet/provider/nameservice.rb', line 159

def create
  if exists?
    info "already exists"
    # The object already exists
    return nil
  end

  begin
    execute(self.addcmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment})
    if feature?(:manages_password_age) && (cmd = passcmd)
      execute(cmd)
    end
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
  end
end

#deleteObject

API:

  • public



176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/puppet/provider/nameservice.rb', line 176

def delete
  unless exists?
    info "already absent"
    # the object already doesn't exist
    return nil
  end

  begin
    execute(self.deletecmd)
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, "Could not delete #{@resource.class.name} #{@resource.name}: #{detail}", detail.backtrace
  end
end

#ensureObject

API:

  • public



190
191
192
193
194
195
196
# File 'lib/puppet/provider/nameservice.rb', line 190

def ensure
  if exists?
    :present
  else
    :absent
  end
end

#exists?Boolean

Does our object exist?

Returns:

API:

  • public



199
200
201
# File 'lib/puppet/provider/nameservice.rb', line 199

def exists?
  !!getinfo(true)
end

#get(param) ⇒ Object

Retrieve a specific value by name.

API:

  • public



204
205
206
# File 'lib/puppet/provider/nameservice.rb', line 204

def get(param)
  (hash = getinfo(false)) ? unmunge(param, hash[param]) : nil
end

#getinfo(refresh) ⇒ Object

Retrieve what we can about our object

API:

  • public



225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/puppet/provider/nameservice.rb', line 225

def getinfo(refresh)
  if @objectinfo.nil? or refresh == true
    @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
    begin
      @objectinfo = Etc.send(@etcmethod, @resource[:name])
    rescue ArgumentError
      @objectinfo = nil
    end
  end

  # Now convert our Etc struct into a hash.
  @objectinfo ? info2hash(@objectinfo) : nil
end

#groupsObject

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

API:

  • public



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/puppet/provider/nameservice.rb', line 241

def groups
  groups = []

  # Reset our group list
  Etc.setgrent

  user = @resource[:name]

  # Now iterate across all of the groups, adding each one our
  # user is a member of
  while group = Etc.getgrent
    members = group.mem

    groups << group.name if members.include? user
  end

  # We have to close the file, so each listing is a separate
  # reading of the file.
  Etc.endgrent

  groups.join(",")
end

#info2hash(info) ⇒ Object

Convert the Etc struct into a hash.

API:

  • public



265
266
267
268
269
270
271
272
273
# File 'lib/puppet/provider/nameservice.rb', line 265

def info2hash(info)
  hash = {}
  self.class.resource_type.validproperties.each do |param|
    method = posixmethod(param)
    hash[param] = info.send(posixmethod(param)) if info.respond_to? method
  end

  hash
end

#munge(name, value) ⇒ Object

API:

  • public



208
209
210
211
212
213
214
# File 'lib/puppet/provider/nameservice.rb', line 208

def munge(name, value)
  if block = self.class.option(name, :munge) and block.is_a? Proc
    block.call(value)
  else
    value
  end
end

#set(param, value) ⇒ Object

Raises:

API:

  • public



281
282
283
284
285
286
287
288
289
290
# File 'lib/puppet/provider/nameservice.rb', line 281

def set(param, value)
  self.class.validate(param, value)
  cmd = modifycmd(param, munge(param, value))
  raise Puppet::DevError, "Nameservice command must be an array" unless cmd.is_a?(Array)
  begin
    execute(cmd)
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
  end
end

#unmunge(name, value) ⇒ Object

API:

  • public



216
217
218
219
220
221
222
# File 'lib/puppet/provider/nameservice.rb', line 216

def unmunge(name, value)
  if block = self.class.option(name, :unmunge) and block.is_a? Proc
    block.call(value)
  else
    value
  end
end