class 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, line 8
def autogen_default(param)
  defined?(@autogen_defaults) ? @autogen_defaults[param.intern] : nil
end
autogen_defaults(hash) click to toggle source
# 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) 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, 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
initvars() click to toggle source
Calls superclass method Puppet::Provider.initvars
# File lib/puppet/provider/nameservice.rb, line 19
def initvars
  @checks = {}
  super
end
instances() click to toggle source
# File lib/puppet/provider/nameservice.rb, line 24
def instances
  objects = []
  listbyname do |name|
    objects << new(:name => name, :ensure => :present)
  end

  objects
end
listbyname() { |name| ... } click to toggle source

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

# File lib/puppet/provider/nameservice.rb, line 52
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
new(resource) click to toggle source
Calls superclass method Puppet::Provider.new
# File lib/puppet/provider/nameservice.rb, line 259
def initialize(resource)
  super

  @objectinfo = nil
end
option(name, option) click to toggle source
# File lib/puppet/provider/nameservice.rb, line 33
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) click to toggle source
# File lib/puppet/provider/nameservice.rb, line 38
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) click to toggle source
Calls superclass method
# File lib/puppet/provider/nameservice.rb, line 67
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
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, line 78
def section
  unless defined?(@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) click to toggle source
# 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) click to toggle source
# 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

Private Class Methods

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

Public Instance Methods

autogen(field) click to toggle source

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

# 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
create() click to toggle source
# 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)
    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}"
  end
end
delete() click to toggle source
# 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}"
  end
end
ensure() click to toggle source
# File lib/puppet/provider/nameservice.rb, line 190
def ensure
  if exists?
    :present
  else
    :absent
  end
end
exists?() click to toggle source

Does our object exist?

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

Retrieve a specific value by name.

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

Retrieve what we can about our object

# File lib/puppet/provider/nameservice.rb, line 209
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 => detail
      @objectinfo = nil
    end
  end

  # Now convert our Etc struct into a hash.
  @objectinfo ? info2hash(@objectinfo) : nil
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, line 225
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) click to toggle source

Convert the Etc struct into a hash.

# File lib/puppet/provider/nameservice.rb, line 249
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
set(param, value) click to toggle source
# File lib/puppet/provider/nameservice.rb, line 265
def set(param, value)
  self.class.validate(param, value)
  cmd = modifycmd(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}"
  end
end