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

addcmd( _extra_attrs = [] ) click to toggle source
# File lib/puppet/provider/aixobject.rb, line 14
def addcmd( _extra_attrs = [] )
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement addcmd"
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}", detail.backtrace
  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}", detail.backtrace
  end
end
deletecmd() click to toggle source
# File lib/puppet/provider/aixobject.rb, line 22
def deletecmd
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement deletecmd"
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 109
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 223
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(output)
      # All attributtes without translation
      @objectosinfo = self.parse_command_output(output, 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 241
def getosinfo(refresh = false)
  if @objectosinfo.nil? or refresh == true
    getinfo(refresh)
  end
  @objectosinfo || Hash.new
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 139
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
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 85
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}: Base AixObject provider doesn't implement lscmd"
end
modifycmd( _attributes_hash = {} ) click to toggle source
# File lib/puppet/provider/aixobject.rb, line 18
def modifycmd( _attributes_hash = {} )
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement modifycmd"
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 a 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 157
def parse_attr_list(str, mapping=self.class.attribute_mapping_from)
  properties = {}
  attrs = []
  if str.nil? 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.nil? or key_str.empty?
        info "Empty key in string 'i'?"
        continue
      end
      key_str.strip!
      key = key_str.to_sym
      val.strip! if val

      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 191
def parse_colon_list(str, key_list, mapping=self.class.attribute_mapping_from)
  properties = {}
  attrs = []
  if str.nil? 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 210
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}", detail.backtrace
    end
  end

  # Refresh de info.
  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 68
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

Public Class Methods

attribute_mapping_from() click to toggle source

Mapping from AIX attribute to Puppet property.

# File lib/puppet/provider/aixobject.rb, line 51
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 37
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=[]
  list_all.each { |entry|
    objects << new(:name => entry, :ensure => :present)
  }
  objects
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 252
def self.list_all
  names = []
  begin
    output = execute([self.command(:list), 'ALL'])

    output = output.split("\n").select{ |line| line != /^#/ }

    output.each do |line|
      name = line.split(/[ :]/)[0]
      names << name if not name.empty?
    end
  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
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
# 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

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