[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, experimental, updated. debian/2.6.8-1-844-g7ec39d5
Hector Rivas Gandara
hrivas at caixagalicia.es
Tue May 10 08:03:30 UTC 2011
The following commit has been merged in the experimental branch:
commit 52f8dddf75e4611de4ea60cb29f4de3e11739226
Author: Hector Rivas Gandara <keymon at gmail.com>
Date: Mon Dec 27 11:20:26 2010 +0100
(#5432) Use AIX native commands to manage users and groups
Refactorized the aixobject.rb to allow new providers using commands with colon separated output.
diff --git a/lib/puppet/provider/aixobject.rb b/lib/puppet/provider/aixobject.rb
index 98ac13b..ae5180d 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 bcb81e1..0c3122b 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 ba95dbc..4a5c4ee 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")
--
Puppet packaging for Debian
More information about the Pkg-puppet-devel
mailing list