# 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_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

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

### 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

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

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

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

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

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

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 Instance Methods

op(property) click to toggle source

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