# class Puppet::Provider::AixObject

Common code for AIX providers. This class implements basic structure for AIX resources.

Author

  Hector Rivas Gandara <keymon@gmail.com>

### Attributes

attribute_mapping[RW]

### Public Class Methods

attribute_mapping_from() click to toggle source

Mapping from AIX attribute to Puppet property.

    # File lib/puppet/provider/aixobject.rb, line 55
    def self.attribute_mapping_from
      if ! @attribute_mapping_from
        @attribute_mapping_from = {}
        attribute_mapping.each { |elem|
          attribute_mapping_from[elem[:aix_attr]] = {
            :key => elem[:puppet_prop],
            :method => elem[:from]
          }
        }
      end
      @attribute_mapping_from
    end

attribute_mapping_to() click to toggle source

Mapping from Puppet property to AIX attribute.

    # File lib/puppet/provider/aixobject.rb, line 41
    def self.attribute_mapping_to
      if ! @attribute_mapping_to
        @attribute_mapping_to = {}
        attribute_mapping.each { |elem|
          attribute_mapping_to[elem[:puppet_prop]] = {
            :key => elem[:aix_attr],
            :method => elem[:to]
          }
        }
      end
      @attribute_mapping_to
    end

instances() click to toggle source

Return all existing instances

The method for returning a list of provider instances. Note that it returns providers, preferably with values already filled in, not resources.

    # File lib/puppet/provider/aixobject.rb, line 289
    def self.instances
      objects=[]
      self.list_all().each { |entry|
        objects << new(:name => entry, :ensure => :present)
      }
      objects
    end

mk_resource_methods() click to toggle source

    # File lib/puppet/provider/aixobject.rb, line 343
    def self.mk_resource_methods
      [resource_type.validproperties, resource_type.parameters].flatten.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

new(resource) click to toggle source
Calls superclass method Puppet::Provider.new

    # File lib/puppet/provider/aixobject.rb, line 387
    def initialize(resource)
      super
      @objectinfo = nil
      @objectosinfo = nil
    end

resource_type=(resource_type) click to toggle source

Define the needed getters and setters as soon as we know the resource type

Calls superclass method

    # File lib/puppet/provider/aixobject.rb, line 352
    def self.resource_type=(resource_type)
      super
      mk_resource_methods
    end

### Public Instance Methods

addcmd(extra_attrs = []) click to toggle source

    # File lib/puppet/provider/aixobject.rb, line 18
    def addcmd(extra_attrs = [])
      raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
    end

create() click to toggle source

Create a new instance of the resource

    # File lib/puppet/provider/aixobject.rb, line 310
    def create
      if exists?
        info "already exists"
        # The object already exists
        return nil
      end

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

delete() click to toggle source

Delete this instance of the resource

    # File lib/puppet/provider/aixobject.rb, line 325
    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

deletecmd() click to toggle source

    # File lib/puppet/provider/aixobject.rb, line 26
    def deletecmd
      raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
    end

ensure() click to toggle source

- *ensure*

      The basic state that the object should be in.  Valid values are
      `present`, `absent`, `role`.

    From ensurable: exists?, create, delete

    # File lib/puppet/provider/aixobject.rb, line 301
    def ensure
      if exists?
        :present
      else
        :absent
      end
    end

exists?() click to toggle source

Check that the user exists

    # File lib/puppet/provider/aixobject.rb, line 282
    def exists?
      !!getinfo(true) # !! => converts to bool
    end

flush() click to toggle source

Clear out the cached values.

    # File lib/puppet/provider/aixobject.rb, line 276
    def flush
      @property_hash.clear if @property_hash
      @objectinfo.clear if @objectinfo
    end

get(param) click to toggle source

Retrieve a specific value by name.

    # File lib/puppet/provider/aixobject.rb, line 358
    def get(param)
      (hash = getinfo(false)) ? hash[param] : nil
    end

get_arguments(key, value, mapping, objectinfo) click to toggle source

Gets the given command line argument for the given key and value, using the given mapping to translate key and value. All the objectinfo hash (@resource or @property_hash) is passed.

This operation works with each property one by one, and default behaviour is return the arguments as key=value pairs. Subclasses must reimplement this if more complex operations/arguments are needed

    # File lib/puppet/provider/aixobject.rb, line 113
    def get_arguments(key, value, mapping, objectinfo)
      if mapping.nil?
        new_key = key
        new_value = value
      elsif mapping[key].nil?
        # is not present in mapping, ignore it.
        new_key = nil
        new_value = nil
      elsif mapping[key][:method].nil?
        new_key = mapping[key][:key]
        new_value = value
      elsif
        new_key = mapping[key][:key]
        new_value = method(mapping[key][:method]).call(value)
      end

      # convert it to string
      new_value = Array(new_value).join(',')

      if new_key
        return [ "#{new_key}=#{new_value}" ]
      else
        return []
      end
    end

getinfo(refresh = false) click to toggle source

Retrieve all the information of an existing resource. It will execute ‘lscmd’ command and parse the output, using the mapping ‘attribute_mapping_from’ to translate the keys and values.

    # File lib/puppet/provider/aixobject.rb, line 226
    def getinfo(refresh = false)
      if @objectinfo.nil? or refresh == true
        # Execute lsuser, split all attributes and add them to a dict.
        begin
          output = execute(self.lscmd)
          @objectinfo = self.parse_command_output(execute(self.lscmd))
          # All attributtes without translation
          @objectosinfo = self.parse_command_output(execute(self.lscmd), nil)
        rescue Puppet::ExecutionFailure => detail
          # Print error if needed. FIXME: Do not check the user here.
          Puppet.debug "aix.getinfo(): Could not find #{@resource.class.name} #{@resource.name}: #{detail}"
        end
      end
      @objectinfo
    end

getosinfo(refresh = false) click to toggle source

Like getinfo, but it will not use the mapping to translate the keys and values. It might be usefult to retrieve some raw information.

    # File lib/puppet/provider/aixobject.rb, line 244
    def getosinfo(refresh = false)
      if @objectosinfo .nil? or refresh == true
        getinfo(refresh)
      end
      @objectosinfo
    end

hash2args(hash, mapping=self.class.attribute_mapping_to) click to toggle source

Convert the provider properties (hash) to AIX command arguments (list of strings) This function will translate each value/key and generate the argument using the #get_arguments function.

    # File lib/puppet/provider/aixobject.rb, line 143
    def hash2args(hash, mapping=self.class.attribute_mapping_to)
      return "" unless hash
      arg_list = []
      hash.each {|key, val|
        arg_list += self.get_arguments(key, val, mapping, hash)
      }
      arg_list
    end

list_all() click to toggle source

List all elements of given type. It works for colon separated commands and list commands. It returns a list of names.

    # File lib/puppet/provider/aixobject.rb, line 255
    def list_all
      names = []
      begin
        output = execute(self.lsallcmd()).split('\n')
        (output.select{ |l| l != /^#/ }).each { |v|
          name = v.split(/[ :]/)
          names << name if not name.empty?
        }
      rescue Puppet::ExecutionFailure => detail
        # Print error if needed
        Puppet.debug "aix.list_all(): Could not get all resources of type #{@resource.class.name}: #{detail}"
      end
      names
    end

load_attribute(key, value, mapping, objectinfo) click to toggle source

Loads an AIX attribute (key=value) and stores it in the given hash with puppet semantics. It translates the pair using the given mapping.

This operation works with each property one by one, subclasses must reimplement this if more complex operations are needed

    # File lib/puppet/provider/aixobject.rb, line 89
    def load_attribute(key, value, mapping, objectinfo)
      if mapping.nil?
        objectinfo[key] = value
      elsif mapping[key].nil?
        # is not present in mapping, ignore it.
        true
      elsif mapping[key][:method].nil?
        objectinfo[mapping[key][:key]] = value
      elsif
        objectinfo[mapping[key][:key]] = method(mapping[key][:method]).call(value)
      end

      return objectinfo
    end

lscmd(value=@resource[:name]) click to toggle source

The real provider must implement these functions.

    # File lib/puppet/provider/aixobject.rb, line 10
    def lscmd(value=@resource[:name])
      raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
    end

modifycmd(attributes_hash) click to toggle source

    # File lib/puppet/provider/aixobject.rb, line 22
    def modifycmd(attributes_hash)
      raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}"
    end

parse_attr_list(str, mapping=self.class.attribute_mapping_from) click to toggle source

Parse AIX command attributes from the output of an AIX command, that which format is a list of space separated of key=value pairs: “uid=100 groups=a,b,c”. It returns an hash.

If a mapping is provided, the keys are translated as defined in the mapping hash. And only values included in mapping will be added

NOTE: it will ignore the items not including ‘=’

    # File lib/puppet/provider/aixobject.rb, line 161
    def parse_attr_list(str, mapping=self.class.attribute_mapping_from)
      properties = {}
      attrs = []
      if !str or (attrs = str.split()).empty?
        return nil
      end

      attrs.each { |i|
        if i.include? "=" # Ignore if it does not include '='
          (key_str, val) = i.split('=')
          # Check the key
          if !key_str or key_str.empty?
            info "Empty key in string 'i'?"
            continue
          end
          key = key_str.to_sym

          properties = self.load_attribute(key, val, mapping, properties)
        end
      }
      properties.empty? ? nil : properties
    end

parse_colon_list(str, key_list, mapping=self.class.attribute_mapping_from) click to toggle source

Parse AIX command output in a colon separated list of attributes, This function is useful to parse the output of commands like lsfs -c:

    #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
    /:/dev/hd4:jfs2::bootfs:557056:rw:yes:no
    /home:/dev/hd1:jfs2:::2129920:rw:yes:no
    /usr:/dev/hd2:jfs2::bootfs:9797632:rw:yes:no

If a mapping is provided, the keys are translated as defined in the mapping hash. And only values included in mapping will be added

    # File lib/puppet/provider/aixobject.rb, line 193
    def parse_colon_list(str, key_list, mapping=self.class.attribute_mapping_from)
      properties = {}
      attrs = []
      if !str or (attrs = str.split(':')).empty?
        return nil
      end

      attrs.each { |val|
        key = key_list.shift.downcase.to_sym
        properties = self.load_attribute(key, val, mapping, properties)
      }
      properties.empty? ? nil : properties

    end

parse_command_output(output, mapping=self.class.attribute_mapping_from) click to toggle source

Default parsing function for AIX commands. It will choose the method depending of the first line. For the colon separated list it will:

    1. Get keys from first line.
    2. Parse next line.

    # File lib/puppet/provider/aixobject.rb, line 213
    def parse_command_output(output, mapping=self.class.attribute_mapping_from)
      lines = output.split("\n")
      # if it begins with #something:... is a colon separated list.
      if lines[0] =~ /^#.*:/
        self.parse_colon_list(lines[1], lines[0][1..-1].split(':'), mapping)
      else
        self.parse_attr_list(lines[0], mapping)
      end
    end

set(param, value) click to toggle source

Set a property.

    # File lib/puppet/provider/aixobject.rb, line 363
    def set(param, value)
      @property_hash[param.intern] = value

      if getinfo().nil?
        # This is weird...
        raise Puppet::Error, "Trying to update parameter '#{param}' to '#{value}' for a resource that does not exists #{@resource.class.name} #{@resource.name}: #{detail}"
      end
      if value == getinfo()[param.to_sym]
        return
      end

      #self.class.validate(param, value)
      if cmd = modifycmd({param =>value})
        begin
          execute(cmd)
        rescue Puppet::ExecutionFailure  => detail
          raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
        end
      end

      # Refresh de info.
      hash = getinfo(true)
    end

translate_attr(key, value, mapping) click to toggle source

This functions translates a key and value using the given mapping. Mapping can be nil (no translation) or a hash with this format {:key => new_key, :method => translate_method} It returns a list with the pair [key, value]

    # File lib/puppet/provider/aixobject.rb, line 72
    def translate_attr(key, value, mapping)
      return [key, value] unless mapping
      return nil unless mapping[key]

      if mapping[key][:method]
        new_value = method(mapping[key][:method]).call(value)
      else
        new_value = value
      end
      [mapping[key][:key], new_value]
    end