diff options
| author | Hector Rivas Gandara <keymon@gmail.com> | 2010-12-28 14:46:38 +0100 |
|---|---|---|
| committer | Hector Rivas Gandara <keymon@gmail.com> | 2011-01-10 08:44:39 +0100 |
| commit | aa8c09fbb0298adb48654a68778e46d9f68f9fb9 (patch) | |
| tree | c8570979b2641c141593b2fe5496565048a9a608 /lib/puppet | |
| parent | d65e094c05739324b14a921152092e080aa32b4e (diff) | |
| download | puppet-aa8c09fbb0298adb48654a68778e46d9f68f9fb9.tar.gz puppet-aa8c09fbb0298adb48654a68778e46d9f68f9fb9.tar.xz puppet-aa8c09fbb0298adb48654a68778e46d9f68f9fb9.zip | |
(#5432) Use AIX native commands to manage users and groups
Specific providers should be created for AIX to manage users and groups.
AIX bases the authentication management on a set of commands: mkuser, rmuser, chuser, lsuser, mkgroup, rmgroup, chgroup, lsg
This commit implements such providers.
The types where extended with:
- feature: :manages_aix_lam
- newparam(ia_load_module): authentication module to use in user and group AIX providers.
- newproperty("attributes"): AIX attributes that are not managed by puppet directely.
Notes::
- AIX users can have expiry date defined with minute granularity,
but puppet does not allow it. There is a ticket open for that (#5431)
- AIX maximum password age is in WEEKs, not days.
Squashed commit of the following:
commit dd9efff227f60dd7d11e33f754870f6344526097
Author: Hector Rivas Gandara <keymon@gmail.com>
Date: Tue Dec 28 14:42:35 2010 +0100
Added new property "attributes" in AIX group provider for AIX attributes
that are not managed by puppet directely.
commit cd23fff3a3a4963f12c0029d43db3c530a0e4fa3
Author: Hector Rivas Gandara <keymon@gmail.com>
Date: Tue Dec 28 14:33:50 2010 +0100
Converted file from Windows to Unix format
commit c6929e9b557802fe908469ca51339ce249242c94
Author: Hector Rivas Gandara <keymon@gmail.com>
Date: Tue Dec 28 14:32:29 2010 +0100
Added new property "attributes" in AIX user provider for AIX attributes
that are not managed by puppet directely.
commit d2814dc9d7730635a17a9bdbbc6ef9518f23b39d
Author: Hector Rivas Gandara <keymon@gmail.com>
Date: Tue Dec 28 12:48:07 2010 +0100
Added feature :ia_load_module and new parameter
(newparam) ia_load_module, to define authentication module to use
in user and group AIX providers.
commit 95a4e960a93c1b75a4a0053c07fa192bf552d63b
Author: Hector Rivas Gandara <keymon@gmail.com>
Date: Tue Dec 28 12:46:20 2010 +0100
Fixed typo in if sentence
Diffstat (limited to 'lib/puppet')
| -rwxr-xr-x | lib/puppet/provider/aixobject.rb | 23 | ||||
| -rwxr-xr-x | lib/puppet/provider/group/aix.rb | 88 | ||||
| -rwxr-xr-x | lib/puppet/provider/user/aix.rb | 650 | ||||
| -rwxr-xr-x | lib/puppet/type/group.rb | 36 | ||||
| -rwxr-xr-x | lib/puppet/type/user.rb | 37 |
5 files changed, 516 insertions, 318 deletions
diff --git a/lib/puppet/provider/aixobject.rb b/lib/puppet/provider/aixobject.rb index d98e36b18..dcb3bff78 100755 --- a/lib/puppet/provider/aixobject.rb +++ b/lib/puppet/provider/aixobject.rb @@ -193,7 +193,7 @@ class Puppet::Provider::AixObject < Puppet::Provider info "Empty key in string 'i'?" continue end - key = key_str.downcase.to_sym + key = key_str.to_sym properties = self.load_attribute(key, val, mapping, properties) end @@ -232,13 +232,13 @@ class Puppet::Provider::AixObject < Puppet::Provider # For the colon separated list it will: # 1. Get keys from first line. # 2. Parse next line. - def parse_command_output(output) + 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(':')) + self.parse_colon_list(lines[1], lines[0][1..-1].split(':'), mapping) else - self.parse_attr_list(lines[0]) + self.parse_attr_list(lines[0], mapping) end end @@ -247,7 +247,10 @@ class Puppet::Provider::AixObject < Puppet::Provider 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}" @@ -256,6 +259,15 @@ class Puppet::Provider::AixObject < Puppet::Provider @objectinfo end + # Retrieve what we can about our object, without translate the values. + def getosinfo(refresh = false) + if @objectosinfo .nil? or refresh == true + getinfo(refresh) + end + @objectosinfo + end + + # List all elements of given type. It works for colon separated commands and # list commands. def list_all @@ -369,7 +381,7 @@ class Puppet::Provider::AixObject < Puppet::Provider @property_hash[symbolize(param)] = value if getinfo().nil? - # This is weird... + # 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] @@ -377,7 +389,6 @@ class Puppet::Provider::AixObject < Puppet::Provider end #self.class.validate(param, value) - if cmd = modifycmd({param =>value}) begin execute(cmd) diff --git a/lib/puppet/provider/group/aix.rb b/lib/puppet/provider/group/aix.rb index 6ae16b529..ceb889840 100755 --- a/lib/puppet/provider/group/aix.rb +++ b/lib/puppet/provider/group/aix.rb @@ -9,17 +9,12 @@ require 'puppet/provider/aixobject' Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject do desc "Group management for AIX! Users are managed with mkgroup, rmgroup, lsgroup, chgroup" - # Constants - # Default extra attributes to add when element is created - # registry=compat: Needed if you are using LDAP by default. - @DEFAULT_EXTRA_ATTRS = [ "registry=compat", ] - - - # This will the the default provider for this platform + # This will the the default provider for this platform defaultfor :operatingsystem => :aix confine :operatingsystem => :aix # Provider features + has_features :manages_aix_lam has_features :manages_members # Commands that manage the element @@ -28,6 +23,11 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d commands :delete => "/usr/sbin/rmgroup" commands :modify => "/usr/bin/chgroup" + # Group attributes to ignore + def self.attribute_ignore + [] + end + # AIX attributes to properties mapping. # # Valid attributes to be managed by this provider. @@ -45,8 +45,20 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d #-------------- # Command lines + + def get_ia_module_args + if @resource[:ia_load_module] + ["-R", @resource[:ia_load_module].to_s] + else + [] + end + end + + def lscmd(value=@resource[:name]) - [self.class.command(:list), "-R", self.class.ia_module , value] + [self.class.command(:list)] + + self.get_ia_module_args + + [ value] end def lsallcmd() @@ -58,18 +70,40 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d # Puppet does not call to self.<parameter>= method if it does not exists. # # It gets an extra list of arguments to add to the user. - [self.class.command(:add), "-R", self.class.ia_module ]+ + [self.class.command(:add) ] + + self.get_ia_module_args + self.hash2args(@resource.to_hash) + extra_attrs + [@resource[:name]] end - def modifycmd(hash = property_hash) - [self.class.command(:modify), "-R", self.class.ia_module ]+ - self.hash2args(hash) + [@resource[:name]] + def modifycmd(hash = property_hash, translate=true) + if translate + args = self.hash2args(hash) + else + args = self.hash2args(hash, nil) + end + return nil if args.empty? + + [self.class.command(:modify)] + + self.get_ia_module_args + + args + [@resource[:name]] end def deletecmd - [self.class.command(:delete),"-R", self.class.ia_module, @resource[:name]] + [self.class.command(:delete)] + + self.get_ia_module_args + + [@resource[:name]] + end + + + def get_arguments(key, value, mapping, objectinfo) + # In the case of attributes, return a list of key=vlaue + if key == :attributes + raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \ + unless value and value.is_a? Hash + return value.select { |k,v| true }.map { |pair| pair.join("=") } + end + super(key, value, mapping, objectinfo) end # Force convert users it a list. @@ -77,4 +111,32 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d (value.is_a? String) ? value.split(',') : value end + def filter_attributes(hash) + # Return only not managed attributtes. + hash.select { + |k,v| !self.class.attribute_mapping_from.include?(k) and + !self.class.attribute_ignore.include?(k) + }.inject({}) { + |hash, array| hash[array[0]] = array[1]; hash + } + end + + def attributes + filter_attributes(getosinfo(refresh = false)) + end + + def attributes=(attr_hash) + #self.class.validate(param, value) + param = :attributes + cmd = modifycmd({param => filter_attributes(attr_hash)}, false) + if cmd + begin + execute(cmd) + rescue Puppet::ExecutionFailure => detail + raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}" + end + end + end + + end diff --git a/lib/puppet/provider/user/aix.rb b/lib/puppet/provider/user/aix.rb index 06dfd5240..c231da816 100755 --- a/lib/puppet/provider/user/aix.rb +++ b/lib/puppet/provider/user/aix.rb @@ -1,299 +1,351 @@ -#
-# User Puppet provider for AIX. It uses standar commands to manage users:
-# mkuser, rmuser, lsuser, chuser
-#
-# Notes:
-# - AIX users can have expiry date defined with minute granularity,
-# but puppet does not allow it. There is a ticket open for that (#5431)
-# - AIX maximum password age is in WEEKs, not days
-# - I force the compat IA module.
-#
-# See http://projects.puppetlabs.com/projects/puppet/wiki/Development_Provider_Development
-# for more information
-#
-# Author:: Hector Rivas Gandara <keymon@gmail.com>
-#
-# TODO::
-# - Add new AIX specific attributes, specilly registry and SYSTEM.
-#
-require 'puppet/provider/aixobject'
-require 'tempfile'
-require 'date'
-
-Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
- desc "User management for AIX! Users are managed with mkuser, rmuser, chuser, lsuser"
-
- # 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" ]
-
- # This will the the default provider for this platform
- defaultfor :operatingsystem => :aix
- confine :operatingsystem => :aix
-
- # Commands that manage the element
- 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
- 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|
- # value.is_a? String || value.is_a? Integer
- #end
- #
- #verify :groups, "Groups must be comma-separated" do |value|
- # value !~ /\s/
- #end
-
- # AIX attributes to properties mapping.
- #
- # Valid attributes to be managed by this provider.
- # 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
- self.attribute_mapping = [
- #:name => :name,
- {:aix_attr => :pgrp, :puppet_prop => :gid,
- :to => :gid_to_attr, :from => :gid_from_attr},
- {:aix_attr => :id, :puppet_prop => :uid},
- {:aix_attr => :groups, :puppet_prop => :groups},
- {:aix_attr => :home, :puppet_prop => :home},
- {:aix_attr => :shell, :puppet_prop => :shell},
- {:aix_attr => :expires, :puppet_prop => :expiry,
- :to => :expiry_to_attr, :from => :expiry_from_attr},
- {:aix_attr => :maxage, :puppet_prop => :password_max_age},
- {:aix_attr => :minage, :puppet_prop => :password_min_age},
- ]
-
- #--------------
- # Command lines
-
- 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.
- #
- # It gets an extra list of arguments to add to the user.
- [self.class.command(:add), "-R", self.class.ia_module ]+
- self.hash2args(@resource.to_hash) +
- extra_attrs + [@resource[:name]]
- end
-
- def modifycmd(hash = property_hash)
- [self.class.command(:modify), "-R", self.class.ia_module ]+
- self.hash2args(hash) + [@resource[:name]]
- end
-
- def deletecmd
- [self.class.command(:delete),"-R", self.class.ia_module, @resource[:name]]
- end
-
- #--------------
- # We overwrite the create function to change the password after creation.
- def create
- super
- # Reset the password if needed
- self.password = @resource[:password] if @resource[:password]
- end
-
-
- # Get the groupname from its id
- def self.groupname_by_id(gid)
- groupname=nil
- execute(lsgroupscmd("ALL")).each { |entry|
- attrs = self.parse_attr_list(entry, nil)
- if attrs and attrs.include? :id and gid == attrs[:id].to_i
- groupname = entry.split(" ")[0]
- end
- }
- groupname
- end
-
- # Get the groupname from its id
- def groupid_by_name(groupname)
- attrs = self.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 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
- else
- raise ArgumentError, "AIX group must be a valid existing group" unless groupid_by_name(value)
- groupname = value
- end
- groupname
- end
-
- # The user's primary group. Can be specified numerically or by name.
- def gid_to_attr(value)
- verify_group(value)
- end
-
- 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 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'
- if value.is_a? String and value!="0000-00-00"
- d = DateTime.parse(value, "%Y-%m-%d %H:%M")
- newdate = d.strftime("%m%d%H%M%y")
- end
- newdate
- end
-
- 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")
- #expiry_date = d.strftime("%Y-%m-%d")
- expiry_date = "20#{$5}-#{$1}-#{$2}"
- else
- Puppet.warn("Could not convert AIX expires date '#{value}' on #{@resource.class.name}[#{@resource.name}]") \
- unless value == '0'
- expiry_date = :absent
- end
- expiry_date
- end
-
- #--------------------------------
- # Getter and Setter
- # When the provider is initialized, create getter/setter methods for each
- # property our resource type supports.
- # If setter or getter already defined it will not be overwritten
-
- #- **password**
- # The user's password, in whatever encrypted format the local machine
- # requires. Be sure to enclose any value that includes a dollar sign ($)
- # in single quotes ('). Requires features manages_passwords.
- #
- # Retrieve the password parsing directly the /etc/security/passwd
- def password
- password = :absent
- user = @resource[:name]
- f = File.open("/etc/security/passwd", 'r')
- # Skip to the user
- f.each { |l| break if l =~ /^#{user}:\s*$/ }
- if ! f.eof?
- f.each { |l|
- # If there is a new user stanza, stop
- break if l =~ /^\S*:\s*$/
- # If the password= entry is found, return it
- if l =~ /^\s*password\s*=\s*(.*)$/
- password = $1; break;
- end
- }
- end
- f.close()
- return password
- end
-
- def password=(value)
- user = @resource[:name]
-
- # Puppet execute does not support strings as input, only files.
- tmpfile = Tempfile.new('puppet_#{user}_pw')
- tmpfile << "#{user}:#{value}\n"
- tmpfile.close()
-
- # Options '-e', '-c', use encrypted password and clear flags
- # Must receibe "user:enc_password" as input
- # command, arguments = {:failonfail => true, :combine => true}
- cmd = [self.class.command(:chpasswd),"-R", self.class.ia_module,
- '-e', '-c', user]
- begin
- execute(cmd, {:failonfail => true, :combine => true, :stdinfile => tmpfile.path })
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
- ensure
- tmpfile.delete()
- end
- end
-
- #- **comment**
- # A description of the user. Generally is a user's full name.
- #def comment=(value)
- #end
- #
- #def comment
- #end
- # UNSUPPORTED
- #- **profile_membership**
- # Whether specified roles should be treated as the only roles
- # of which the user is a member or whether they should merely
- # be treated as the minimum membership list. Valid values are
- # `inclusive`, `minimum`.
- # UNSUPPORTED
- #- **profiles**
- # The profiles the user has. Multiple profiles should be
- # specified as an array. Requires features manages_solaris_rbac.
- # UNSUPPORTED
- #- **project**
- # The name of the project associated with a user Requires features
- # manages_solaris_rbac.
- # UNSUPPORTED
- #- **role_membership**
- # Whether specified roles should be treated as the only roles
- # of which the user is a member or whether they should merely
- # be treated as the minimum membership list. Valid values are
- # `inclusive`, `minimum`.
- # UNSUPPORTED
- #- **roles**
- # The roles the user has. Multiple roles should be
- # specified as an array. Requires features manages_solaris_rbac.
- # UNSUPPORTED
- #- **key_membership**
- # Whether specified key value pairs should be treated as the only
- # attributes
- # of the user or whether they should merely
- # be treated as the minimum list. Valid values are `inclusive`,
- # `minimum`.
- # UNSUPPORTED
- #- **keys**
- # Specify user attributes in an array of keyvalue pairs Requires features
- # manages_solaris_rbac.
- # UNSUPPORTED
- #- **allowdupe**
- # Whether to allow duplicate UIDs. Valid values are `true`, `false`.
- # UNSUPPORTED
- #- **auths**
- # The auths the user has. Multiple auths should be
- # specified as an array. Requires features manages_solaris_rbac.
- # UNSUPPORTED
- #- **auth_membership**
- # Whether specified auths should be treated as the only auths
- # of which the user is a member or whether they should merely
- # be treated as the minimum membership list. Valid values are
- # `inclusive`, `minimum`.
- # UNSUPPORTED
-
-end
+# +# User Puppet provider for AIX. It uses standar commands to manage users: +# mkuser, rmuser, lsuser, chuser +# +# Notes: +# - AIX users can have expiry date defined with minute granularity, +# but puppet does not allow it. There is a ticket open for that (#5431) +# - AIX maximum password age is in WEEKs, not days +# - I force the compat IA module. +# +# See http://projects.puppetlabs.com/projects/puppet/wiki/Development_Provider_Development +# for more information +# +# Author:: Hector Rivas Gandara <keymon@gmail.com> +# +require 'puppet/provider/aixobject' +require 'tempfile' +require 'date' + +Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do + desc "User management for AIX! Users are managed with mkuser, rmuser, chuser, lsuser" + + # This will the the default provider for this platform + defaultfor :operatingsystem => :aix + confine :operatingsystem => :aix + + # Commands that manage the element + 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_aix_lam + 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| + # value.is_a? String || value.is_a? Integer + #end + # + #verify :groups, "Groups must be comma-separated" do |value| + # value !~ /\s/ + #end + + # User attributes to ignore + def self.attribute_ignore + [] + end + + # AIX attributes to properties mapping. + # + # Valid attributes to be managed by this provider. + # 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 + self.attribute_mapping = [ + #:name => :name, + {:aix_attr => :pgrp, :puppet_prop => :gid, + :to => :gid_to_attr, :from => :gid_from_attr}, + {:aix_attr => :id, :puppet_prop => :uid}, + {:aix_attr => :groups, :puppet_prop => :groups}, + {:aix_attr => :home, :puppet_prop => :home}, + {:aix_attr => :shell, :puppet_prop => :shell}, + {:aix_attr => :expires, :puppet_prop => :expiry, + :to => :expiry_to_attr, :from => :expiry_from_attr}, + {:aix_attr => :maxage, :puppet_prop => :password_max_age}, + {:aix_attr => :minage, :puppet_prop => :password_min_age}, + ] + + #-------------- + # Command lines + def get_ia_module_args + if @resource[:ia_load_module] + ["-R", @resource[:ia_load_module].to_s] + else + [] + end + end + + def lsgroupscmd(value=@resource[:name]) + [command(:lsgroup)] + + self.get_ia_module_args + + ["-a", "id", value] + end + + def lscmd(value=@resource[:name]) + [self.class.command(:list)] + self.get_ia_module_args + [ 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. + # + # It gets an extra list of arguments to add to the user. + [self.class.command(:add)] + self.get_ia_module_args + + self.hash2args(@resource.to_hash) + + extra_attrs + [@resource[:name]] + end + + # Get modify command + def modifycmd(hash = property_hash, translate=true) + if translate + args = self.hash2args(hash) + else + args = self.hash2args(hash, nil) + end + return nil if args.empty? + + [self.class.command(:modify)] + self.get_ia_module_args + + args + [@resource[:name]] + end + + def deletecmd + [self.class.command(:delete)] + self.get_ia_module_args + [@resource[:name]] + end + + #-------------- + # We overwrite the create function to change the password after creation. + def create + super + # Reset the password if needed + self.password = @resource[:password] if @resource[:password] + end + + + def get_arguments(key, value, mapping, objectinfo) + # In the case of attributes, return a list of key=vlaue + if key == :attributes + raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \ + unless value and value.is_a? Hash + return value.select { |k,v| true }.map { |pair| pair.join("=") } + end + super(key, value, mapping, objectinfo) + end + + # Get the groupname from its id + def self.groupname_by_id(gid) + groupname=nil + execute(lsgroupscmd("ALL")).each { |entry| + attrs = self.parse_attr_list(entry, nil) + if attrs and attrs.include? :id and gid == attrs[:id].to_i + groupname = entry.split(" ")[0] + end + } + groupname + end + + # Get the groupname from its id + def groupid_by_name(groupname) + attrs = self.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 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 + else + raise ArgumentError, "AIX group must be a valid existing group" unless groupid_by_name(value) + groupname = value + end + groupname + end + + # The user's primary group. Can be specified numerically or by name. + def gid_to_attr(value) + verify_group(value) + end + + 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 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' + if value.is_a? String and value!="0000-00-00" + d = DateTime.parse(value, "%Y-%m-%d %H:%M") + newdate = d.strftime("%m%d%H%M%y") + end + newdate + end + + 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") + #expiry_date = d.strftime("%Y-%m-%d") + expiry_date = "20#{$5}-#{$1}-#{$2}" + else + Puppet.warn("Could not convert AIX expires date '#{value}' on #{@resource.class.name}[#{@resource.name}]") \ + unless value == '0' + expiry_date = :absent + end + expiry_date + end + + #-------------------------------- + # Getter and Setter + # When the provider is initialized, create getter/setter methods for each + # property our resource type supports. + # If setter or getter already defined it will not be overwritten + + #- **password** + # The user's password, in whatever encrypted format the local machine + # requires. Be sure to enclose any value that includes a dollar sign ($) + # in single quotes ('). Requires features manages_passwords. + # + # Retrieve the password parsing directly the /etc/security/passwd + def password + password = :absent + user = @resource[:name] + f = File.open("/etc/security/passwd", 'r') + # Skip to the user + f.each { |l| break if l =~ /^#{user}:\s*$/ } + if ! f.eof? + f.each { |l| + # If there is a new user stanza, stop + break if l =~ /^\S*:\s*$/ + # If the password= entry is found, return it + if l =~ /^\s*password\s*=\s*(.*)$/ + password = $1; break; + end + } + end + f.close() + return password + end + + def password=(value) + user = @resource[:name] + + # Puppet execute does not support strings as input, only files. + tmpfile = Tempfile.new('puppet_#{user}_pw') + tmpfile << "#{user}:#{value}\n" + tmpfile.close() + + # Options '-e', '-c', use encrypted password and clear flags + # Must receibe "user:enc_password" as input + # command, arguments = {:failonfail => true, :combine => true} + cmd = [self.class.command(:chpasswd),"-R", self.class.ia_module, + '-e', '-c', user] + begin + execute(cmd, {:failonfail => true, :combine => true, :stdinfile => tmpfile.path }) + rescue Puppet::ExecutionFailure => detail + raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}" + ensure + tmpfile.delete() + end + end + + def filter_attributes(hash) + # Return only not managed attributtes. + hash.select { + |k,v| !self.class.attribute_mapping_from.include?(k) and + !self.class.attribute_ignore.include?(k) + }.inject({}) { + |hash, array| hash[array[0]] = array[1]; hash + } + end + + def attributes + filter_attributes(getosinfo(refresh = false)) + end + + def attributes=(attr_hash) + #self.class.validate(param, value) + param = :attributes + cmd = modifycmd({param => filter_attributes(attr_hash)}, false) + if cmd + begin + execute(cmd) + rescue Puppet::ExecutionFailure => detail + raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}" + end + end + end + + #- **comment** + # A description of the user. Generally is a user's full name. + #def comment=(value) + #end + # + #def comment + #end + # UNSUPPORTED + #- **profile_membership** + # Whether specified roles should be treated as the only roles + # of which the user is a member or whether they should merely + # be treated as the minimum membership list. Valid values are + # `inclusive`, `minimum`. + # UNSUPPORTED + #- **profiles** + # The profiles the user has. Multiple profiles should be + # specified as an array. Requires features manages_solaris_rbac. + # UNSUPPORTED + #- **project** + # The name of the project associated with a user Requires features + # manages_solaris_rbac. + # UNSUPPORTED + #- **role_membership** + # Whether specified roles should be treated as the only roles + # of which the user is a member or whether they should merely + # be treated as the minimum membership list. Valid values are + # `inclusive`, `minimum`. + # UNSUPPORTED + #- **roles** + # The roles the user has. Multiple roles should be + # specified as an array. Requires features manages_solaris_rbac. + # UNSUPPORTED + #- **key_membership** + # Whether specified key value pairs should be treated as the only + # attributes + # of the user or whether they should merely + # be treated as the minimum list. Valid values are `inclusive`, + # `minimum`. + # UNSUPPORTED + #- **keys** + # Specify user attributes in an array of keyvalue pairs Requires features + # manages_solaris_rbac. + # UNSUPPORTED + #- **allowdupe** + # Whether to allow duplicate UIDs. Valid values are `true`, `false`. + # UNSUPPORTED + #- **auths** + # The auths the user has. Multiple auths should be + # specified as an array. Requires features manages_solaris_rbac. + # UNSUPPORTED + #- **auth_membership** + # Whether specified auths should be treated as the only auths + # of which the user is a member or whether they should merely + # be treated as the minimum membership list. Valid values are + # `inclusive`, `minimum`. + # UNSUPPORTED + +end diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb index cde1cfd65..aa96bd9c3 100755 --- a/lib/puppet/type/group.rb +++ b/lib/puppet/type/group.rb @@ -15,6 +15,9 @@ module Puppet feature :manages_members, "For directories where membership is an attribute of groups not users." + feature :manages_aix_lam, + "The provider can manage AIX Loadable Authentication Module (LAM) system." + ensurable do desc "Create or remove the group." @@ -95,5 +98,38 @@ module Puppet defaultto false end + + newparam(:ia_load_module, :required_features => :manages_aix_lam) do + desc "The name of the I&A module to use to manage this user" + + defaultto "compat" + end + + newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do + desc "Specify group AIX attributes in an array of keyvalue pairs" + + def membership + :attribute_membership + end + + def delimiter + " " + end + + validate do |value| + raise ArgumentError, "Attributes value pairs must be seperated by an =" unless value.include?("=") + end + end + + newparam(:attribute_membership) do + desc "Whether specified attribute value pairs should be treated as the only attributes + of the user or whether they should merely + be treated as the minimum list." + + newvalues(:inclusive, :minimum) + + defaultto :minimum + end + end end diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index 761d5d71b..b2cafadc0 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -34,6 +34,9 @@ module Puppet feature :manages_expiry, "The provider can manage the expiry date for a user." + feature :manages_aix_lam, + "The provider can manage AIX Loadable Authentication Module (LAM) system." + newproperty(:ensure, :parent => Puppet::Property::Ensure) do newvalue(:present, :event => :user_created) do provider.create @@ -434,5 +437,39 @@ module Puppet newproperty(:project, :required_features => :manages_solaris_rbac) do desc "The name of the project associated with a user" end + + newparam(:ia_load_module, :required_features => :manages_aix_lam) do + desc "The name of the I&A module to use to manage this user" + + defaultto "compat" + end + + newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do + desc "Specify user AIX attributes in an array of keyvalue pairs" + + def membership + :attribute_membership + end + + def delimiter + " " + end + + validate do |value| + raise ArgumentError, "Attributes value pairs must be seperated by an =" unless value.include?("=") + end + end + + newparam(:attribute_membership) do + desc "Whether specified attribute value pairs should be treated as the only attributes + of the user or whether they should merely + be treated as the minimum list." + + newvalues(:inclusive, :minimum) + + defaultto :minimum + end + + end end |
