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