Common code for AIX providers. This class implements basic structure for AIX resources.
Hector Rivas Gandara <keymon@gmail.com>
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
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
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
# 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
# File lib/puppet/provider/aixobject.rb, line 387 def initialize(resource) super @objectinfo = nil @objectosinfo = nil end
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
# 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 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 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
# File lib/puppet/provider/aixobject.rb, line 26 def deletecmd raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}" end
*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
Check that the user exists
# File lib/puppet/provider/aixobject.rb, line 282 def exists? !!getinfo(true) # !! => converts to bool end
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
Retrieve a specific value by name.
# File lib/puppet/provider/aixobject.rb, line 358 def get(param) (hash = getinfo(false)) ? hash[param] : nil end
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
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
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
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 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
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
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
# 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 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 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
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 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
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