diff options
Diffstat (limited to 'lib/puppet')
| -rwxr-xr-x | lib/puppet/provider/aixobject.rb | 244 | ||||
| -rwxr-xr-x | lib/puppet/provider/group/aix.rb | 2 | ||||
| -rwxr-xr-x | lib/puppet/provider/user/aix.rb | 33 |
3 files changed, 201 insertions, 78 deletions
diff --git a/lib/puppet/provider/aixobject.rb b/lib/puppet/provider/aixobject.rb index 98ac13bdf..ae5180d5e 100755 --- a/lib/puppet/provider/aixobject.rb +++ b/lib/puppet/provider/aixobject.rb @@ -12,20 +12,13 @@ class Puppet::Provider::AixObject < Puppet::Provider # TODO:: add a type parameter to change this class << self attr_accessor :ia_module - end - - - # AIX attributes to properties mapping. Subclasses should rewrite them - # It is a list with of hash - # :aix_attr AIX command attribute name - # :puppet_prop Puppet propertie name - # :to Method to adapt puppet property to aix command value. Optional. - # :from Method to adapt aix command value to puppet property. Optional - class << self - attr_accessor :attribute_mapping + end + + # The real provider must implement these functions. + def lscmd(value=@resource[:name]) + raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}" end - # Provider must implement these functions. def lscmd(value=@resource[:name]) raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}" end @@ -42,7 +35,13 @@ class Puppet::Provider::AixObject < Puppet::Provider raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: #{detail}" end - # attribute_mapping class variable, + + # Valid attributes to be managed by this provider. + # It is a list of hashes + # :aix_attr AIX command attribute name + # :puppet_prop Puppet propertie name + # :to Optional. Method name that adapts puppet property to aix command value. + # :from Optional. Method to adapt aix command line value to puppet property. Optional class << self attr_accessor :attribute_mapping end @@ -70,12 +69,12 @@ class Puppet::Provider::AixObject < Puppet::Provider end @attribute_mapping_from 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 [key, value] - def self.translate_attr(key, value, mapping) + def translate_attr(key, value, mapping) return [key, value] unless mapping return nil unless mapping[key] @@ -86,18 +85,103 @@ class Puppet::Provider::AixObject < Puppet::Provider end [mapping[key][:key], new_value] end + + # Gets the given command line argument for the given key, value and mapping. + def get_arg(key, value, mapping) + arg = nil + if ret = self.translate_attr(key, val, mapping) + new_key = ret[0] + new_val = ret[1] + + # Arrays are separated by commas + if new_val.is_a? Array + value = new_val.join(",") + else + value = new_val.to_s + end + + # Get the needed argument + if mapping[key][:to_arg] + arg = method(mapping[key][:to_arg]).call(new_key, value) + else + arg = (new_key.to_s + "=" + value ) + end + end + return arg + end + - #----- - # Convert a pair key-value using the + # Reads and attribute. + # Here we implement the default behaviour. + # Subclasses must reimplement this. + 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 - # Parse AIX command attributes (string) and return provider hash + 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 + if new_val.is_a? Array + new_val = new_val.join(",") + else + new_val = new_val.to_s + end + + if new_key? + return [ "#{new_key}=#{new_value}" ] + else + return [] + end + end + + # Convert the provider properties to AIX command arguments (string) + # This function will translate each value/key and generate the argument. + # By default, arguments are created as aix_key=aix_value + 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 + + # Parse AIX command attributes in a format of space separated of key=value + # pairs: "uid=100 groups=a,b,c" + # It returns and return provider hash. + # # If a mapping is provided, the keys are translated as defined in the # mapping hash. Only values included in mapping will be added # NOTE: it will ignore the items not including '=' - def self.attr2hash(str, mapping=attribute_mapping_from) + def parse_attr_list(str, mapping=self.class.attribute_mapping_from) properties = {} attrs = [] - if !str or (attrs = str.split()[0..-1]).empty? + if !str or (attrs = str.split()).empty? return nil end @@ -109,40 +193,53 @@ class Puppet::Provider::AixObject < Puppet::Provider info "Empty key in string 'i'?" continue end - key = key_str.to_sym + key = key_str.downcase.to_sym - if ret = self.translate_attr(key, val, mapping) - new_key = ret[0] - new_val = ret[1] - - properties[new_key] = new_val - end + properties = self.load_attribute(key, val, mapping, properties) end } properties.empty? ? nil : properties end - # Convert the provider properties to AIX command attributes (string) - def self.hash2attr(hash, mapping=attribute_mapping_to) - return "" unless hash - attr_list = [] - hash.each {|key, val| - - if ret = self.translate_attr(key, val, mapping) - new_key = ret[0] - new_val = ret[1] - - # Arrays are separated by commas - if new_val.is_a? Array - value = new_val.join(",") - else - value = new_val.to_s - end - - attr_list << (new_key.to_s + "=" + value ) - end + # Parse AIX colon separated list of attributes, using given list of keys + # to name the 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. Only values included in mapping will be added + # NOTE: it will ignore the items not including '=' + 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) } - attr_list + properties.empty? ? nil : properties + + end + + # Default parsing function for colon separated list or attributte list + # (key=val pairs). 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. + def parse_command_output(output) + 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(':')) + else + self.parse_attr_list(lines[0]) + end end # Retrieve what we can about our object @@ -150,17 +247,33 @@ class Puppet::Provider::AixObject < Puppet::Provider if @objectinfo.nil? or refresh == true # Execute lsuser, split all attributes and add them to a dict. begin - attrs = execute(self.lscmd).split("\n")[0] - @objectinfo = self.class.attr2hash(attrs) + @objectinfo = self.parse_command_output(execute(self.lscmd)) rescue Puppet::ExecutionFailure => detail - # Print error if needed - Puppet.debug "aix.getinfo(): Could not find #{@resource.class.name} #{@resource.name}: #{detail}" \ - unless detail.to_s.include? "User \"#{@resource.name}\" does not exist." + # 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 + # List all elements of given type. It works for colon separated commands and + # list commands. + 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 + + #------------- # Provider API # ------------ @@ -168,7 +281,7 @@ class Puppet::Provider::AixObject < Puppet::Provider # Clear out the cached values. def flush @property_hash.clear if @property_hash - @object_info.clear if @object_info + @objectinfo.clear if @objectinfo end # Check that the user exists @@ -192,9 +305,9 @@ class Puppet::Provider::AixObject < Puppet::Provider # The method for returning a list of provider instances. Note that it returns # providers, preferably with values already filled in, not resources. def self.instances - objects = [] - execute(lscmd("ALL")).each { |entry| - objects << new(:name => entry.split(" ")[0], :ensure => :present) + objects=[] + self.list_all().each { |entry| + objects << new(:name => entry, :ensure => :present) } objects end @@ -254,17 +367,23 @@ class Puppet::Provider::AixObject < Puppet::Provider # Set a property. def set(param, value) @property_hash[symbolize(param)] = value - # If value does not change, do not update. + + 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) - 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}" + + 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. @@ -279,4 +398,3 @@ class Puppet::Provider::AixObject < Puppet::Provider end end -#end diff --git a/lib/puppet/provider/group/aix.rb b/lib/puppet/provider/group/aix.rb index bcb81e1c5..0c3122b86 100755 --- a/lib/puppet/provider/group/aix.rb +++ b/lib/puppet/provider/group/aix.rb @@ -69,7 +69,7 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d end # Force convert users it a list. - def self.users_from_attr(value) + def users_from_attr(value) (value.is_a? String) ? value.split(',') : value end diff --git a/lib/puppet/provider/user/aix.rb b/lib/puppet/provider/user/aix.rb index ba95dbc49..4a5c4ee79 100755 --- a/lib/puppet/provider/user/aix.rb +++ b/lib/puppet/provider/user/aix.rb @@ -26,23 +26,24 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do # Constants
# Default extra attributes to add when element is created
# registry=compat SYSTEM=compat: Needed if you are using LDAP by default.
- @DEFAULT_EXTRA_ATTRS = [ "registry=compat", " SYSTEM=compat" ]
+ @DEFAULT_EXTRA_ATTRS = [ "registry=compat", "SYSTEM=compat" ]
# This will the the default provider for this platform
defaultfor :operatingsystem => :aix
confine :operatingsystem => :aix
# Commands that manage the element
- commands :lsgroup => "/usr/sbin/lsgroup"
-
commands :list => "/usr/sbin/lsuser"
commands :add => "/usr/bin/mkuser"
commands :delete => "/usr/sbin/rmuser"
commands :modify => "/usr/bin/chuser"
+
+ commands :lsgroup => "/usr/sbin/lsgroup"
commands :chpasswd => "/bin/chpasswd"
# Provider features
- has_features :manages_homedir, :manages_passwords, :manages_expiry, :manages_password_age
+ has_features :manages_homedir, :manages_passwords
+ has_features :manages_expiry, :manages_password_age
# Attribute verification (TODO)
#verify :gid, "GID must be an string or int of a valid group" do |value|
@@ -78,14 +79,18 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do #--------------
# Command lines
- def self.lsgroupscmd(value=@resource[:name])
- [command(:lsgroup),"-R", ia_module, "-a", "id", value]
+ def lsgroupscmd(value=@resource[:name])
+ [command(:lsgroup),"-R", self.class.ia_module, "-a", "id", value]
end
def lscmd(value=@resource[:name])
[self.class.command(:list), "-R", self.class.ia_module , value]
end
+ def lsallcmd()
+ lscmd("ALL")
+ end
+
def addcmd(extra_attrs = [])
# Here we use the @resource.to_hash to get the list of provided parameters
# Puppet does not call to self.<parameter>= method if it does not exists.
@@ -118,7 +123,7 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do def self.groupname_by_id(gid)
groupname=nil
execute(lsgroupscmd("ALL")).each { |entry|
- attrs = attr2hash(entry, nil)
+ attrs = parse_attr_list(entry, nil)
if attrs and attrs.include? :id and gid == attrs[:id].to_i
groupname = entry.split(" ")[0]
end
@@ -127,13 +132,13 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do end
# Get the groupname from its id
- def self.groupid_by_name(groupname)
- attrs = attr2hash(execute(lsgroupscmd(groupname)).split("\n")[0], nil)
+ def groupid_by_name(groupname)
+ attrs = parse_attr_list(execute(lsgroupscmd(groupname)).split("\n")[0], nil)
attrs ? attrs[:id].to_i : nil
end
# Check that a group exists and is valid
- def self.verify_group(value)
+ def verify_group(value)
if value.is_a? Integer or value.is_a? Fixnum
groupname = self.groupname_by_id(value)
raise ArgumentError, "AIX group must be a valid existing group" unless groupname
@@ -145,17 +150,17 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do end
# The user's primary group. Can be specified numerically or by name.
- def self.gid_to_attr(value)
+ def gid_to_attr(value)
verify_group(value)
end
- def self.gid_from_attr(value)
+ def gid_from_attr(value)
groupid_by_name(value)
end
# The expiry date for this user. Must be provided in
# a zero padded YYYY-MM-DD HH:MM format
- def self.expiry_to_attr(value)
+ def expiry_to_attr(value)
# For chuser the expires parameter is a 10-character string in the MMDDhhmmyy format
# that is,"%m%d%H%M%y"
newdate = '0'
@@ -166,7 +171,7 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do newdate
end
- def self.expiry_from_attr(value)
+ def expiry_from_attr(value)
if value =~ /(..)(..)(..)(..)(..)/
#d= DateTime.parse("20#{$5}-#{$1}-#{$2} #{$3}:#{$4}")
#expiry_date = d.strftime("%Y-%m-%d %H:%M")
|
