+1, but I don't know much about AIX. I'd like to make sure that we get some
solid AIX testing when this goes into a release candidate.
And I should also mention that the "%s"%x string syntax is on our list of
code smells, and will get converted to "#{x}" at some point in the near
future.
~Jesse
On Thu, Feb 4, 2010 at 2:07 PM, James Turnbull <[email protected]>wrote:
> From: Andrew Forgue <[email protected]>
>
> This patch adds support for the native AIX package manager.
>
> It allows installation from either the name of an lpp_source (if you
> have a NIM environment configured, or from a directory containing .bff
> files.
>
> Signed-off-by: Andrew Forgue <[email protected]>
> Signed-off-by: James Turnbull <[email protected]>
> ---
> lib/puppet/provider/package/aix.rb | 136
> ++++++++++++++++++++++++++++++++++++
> lib/puppet/provider/package/nim.rb | 37 ++++++++++
> spec/unit/provider/package/aix.rb | 66 +++++++++++++++++
> spec/unit/provider/package/nim.rb | 42 +++++++++++
> 4 files changed, 281 insertions(+), 0 deletions(-)
> create mode 100644 lib/puppet/provider/package/aix.rb
> create mode 100644 lib/puppet/provider/package/nim.rb
> create mode 100755 spec/unit/provider/package/aix.rb
> create mode 100755 spec/unit/provider/package/nim.rb
>
> diff --git a/lib/puppet/provider/package/aix.rb
> b/lib/puppet/provider/package/aix.rb
> new file mode 100644
> index 0000000..b6f23c0
> --- /dev/null
> +++ b/lib/puppet/provider/package/aix.rb
> @@ -0,0 +1,136 @@
> +require 'puppet/provider/package'
> +require 'puppet/util/package'
> +
> +Puppet::Type.type(:package).provide :aix, :parent =>
> Puppet::Provider::Package do
> + desc "Installation from AIX Software directory"
> +
> + # The commands we are using on an AIX box are installed standard
> + # (except nimclient) nimclient needs the bos.sysmgt.nim.client
> fileset.
> + commands :lslpp => "/usr/bin/lslpp",
> + :installp => "/usr/sbin/installp"
> +
> + # AIX supports versionable packages with and without a NIM server
> + has_feature :versionable
> +
> + confine :operatingsystem => [ :aix ]
> + defaultfor :operatingsystem => :aix
> +
> + attr_accessor :latest_info
> +
> + def self.srclistcmd(source)
> + return [ command(:installp), "-L", "-d", source ]
> + end
> +
> + def self.prefetch(packages)
> + if Process.euid != 0
> + raise Puppet::Error "The aix provider can only be used by
> root"
> + end
> +
> + return unless packages.detect { |name, package|
> package.should(:ensure) == :latest }
> +
> + sources = packages.collect { |name, package| package[:source]
> }.uniq
> +
> + updates = {}
> + sources.each do |source|
> + execute(self.srclistcmd(source)).each do |line|
> + if line =~ /^[^#][^:]*:([^:]*):([^:]*)/
> + current = {}
> + current[:name] = $1
> + current[:version] = $2
> + current[:source] = source
> +
> + if updates.key?(current[:name])
> + previous = updates[current[:name]]
> +
> + unless
> Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1
> + updates[ current[:name] ] = current
> + end
> +
> + else
> + updates[current[:name]] = current
> + end
> + end
> + end
> + end
> +
> + packages.each do |name, package|
> + if info = updates[package[:name]]
> + package.provider.latest_info = info[0]
> + end
> + end
> + end
> +
> + def uninstall
> + # Automatically process dependencies when installing/uninstalling
> + # with the -g option to installp.
> + installp "-gu", @resource[:name]
> + end
> +
> + def install(useversion = true)
> + unless source = @resource[:source]
> + self.fail "A directory is required which will be used to find
> packages"
> + end
> +
> + pkg = @resource[:name]
> +
> + if (! @resource.should(:ensure).is_a? Symbol) and useversion
> + pkg << " #[email protected](:ensure)}"
> + end
> +
> + installp "-acgwXY", "-d", source, pkg
> + end
> +
> + def self.pkglist(hash = {})
> + cmd = [command(:lslpp), "-qLc"]
> +
> + if name = hash[:pkgname]
> + cmd << name
> + end
> +
> + begin
> + list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect
> { |n,e|
> + { :name => n, :ensure => e, :provider => self.name }
> + }
> + rescue Puppet::ExecutionFailure => detail
> + if hash[:pkgname]
> + return nil
> + else
> + raise Puppet::Error, "Could not list installed Packages:
> %s" % detail
> + end
> + end
> +
> + if hash[:pkgname]
> + return list.shift
> + else
> + return list
> + end
> + end
> +
> + def self.instances
> + pkglist.collect do |hash|
> + new(hash)
> + end
> + end
> +
> + def latest
> + upd = latest_info
> +
> + unless upd.nil?
> + return "#{upd[:version]}"
> + else
> + if properties[:ensure] == :absent
> + raise Puppet::DevError, "Tried to get latest on a missing
> package"
> + end
> +
> + return properties[:ensure]
> + end
> + end
> +
> + def query
> + return self.class.pkglist(:pkgname => @resource[:name])
> + end
> +
> + def update
> + self.install(false)
> + end
> +end
> diff --git a/lib/puppet/provider/package/nim.rb
> b/lib/puppet/provider/package/nim.rb
> new file mode 100644
> index 0000000..18f2921
> --- /dev/null
> +++ b/lib/puppet/provider/package/nim.rb
> @@ -0,0 +1,37 @@
> +require 'puppet/provider/package'
> +require 'puppet/util/package'
> +
> +Puppet::Type.type(:package).provide :nim, :parent => :aix, :source => :aix
> do
> + desc "Installation from NIM LPP source"
> +
> + # The commands we are using on an AIX box are installed standard
> + # (except nimclient) nimclient needs the bos.sysmgt.nim.client
> fileset.
> + commands :nimclient => "/usr/sbin/nimclient"
> +
> + # If NIM has not been configured, /etc/niminfo will not be present.
> + # However, we have no way of knowing if the NIM server is not
> configured
> + # properly.
> + confine :exists => "/etc/niminfo"
> +
> + has_feature :versionable
> +
> + attr_accessor :latest_info
> +
> + def self.srclistcmd(source)
> + return [ command(:nimclient), "-o", "showres", "-a",
> "installp_flags=L", "-a", "resource=#{source}" ]
> + end
> +
> + def install(useversion = true)
> + unless source = @resource[:source]
> + self.fail "An LPP source location is required in 'source'"
> + end
> +
> + pkg = @resource[:name]
> +
> + if (! @resource.should(:ensure).is_a? Symbol) and useversion
> + pkg << " " << @resource.should(:ensure)
> + end
> +
> + nimclient "-o", "cust", "-a", "installp_flags=acgwXY", "-a",
> "lpp_source=#{source}", "-a", "filesets=#{pkg}"
> + end
> +end
> diff --git a/spec/unit/provider/package/aix.rb
> b/spec/unit/provider/package/aix.rb
> new file mode 100755
> index 0000000..691749d
> --- /dev/null
> +++ b/spec/unit/provider/package/aix.rb
> @@ -0,0 +1,66 @@
> +#!/usr/bin/env ruby
> +
> +require File.dirname(__FILE__) + '/../../../spec_helper'
> +
> +provider_class = Puppet::Type.type(:package).provider(:aix)
> +
> +describe provider_class do
> + before(:each) do
> + # Create a mock resource
> + @resource = stub 'resource'
> +
> + # A catch all; no parameters set
> + @resource.stubs(:[]).returns(nil)
> +
> + # But set name and source
> + @resource.stubs(:[]).with(:name).returns "mypackage"
> + @resource.stubs(:[]).with(:source).returns "mysource"
> + @resource.stubs(:[]).with(:ensure).returns :installed
> +
> + @provider = provider_class.new
> + @provider.resource = @resource
> + end
> +
> + [:install, :uninstall, :latest, :query, :update].each do |method|
> + it "should have a #{method} method" do
> + @provider.should respond_to(method)
> + end
> + end
> +
> + it "should uninstall a package" do
> + @provider.expects(:installp).with('-gu', 'mypackage')
> + @provider.uninstall
> + end
> +
> + describe "when installing" do
> + it "should install a package" do
> + @resource.stubs(:should).with(:ensure).returns(:installed)
> + @provider.expects(:installp).with('-acgwXY', '-d', 'mysource',
> 'mypackage')
> + @provider.install
> + end
> +
> + it "should install a specific package version" do
> + @resource.stubs(:should).with(:ensure).returns("1.2.3.4")
> + @provider.expects(:installp).with('-acgwXY', '-d', 'mysource',
> 'mypackage 1.2.3.4')
> + @provider.install
> + end
> + end
> +
> + describe "when finding the latest version" do
> + it "should return the current version when no later version is
> present" do
> + @provider.stubs(:latest_info).returns(nil)
> + @provider.stubs(:properties).returns( { :ensure => "1.2.3.4" }
> )
> + @provider.latest.should == "1.2.3.4"
> + end
> +
> + it "should return the latest version of a package" do
> + @provider.stubs(:latest_info).returns( { :version => "1.2.3.5"
> } )
> + @provider.latest.should == "1.2.3.5"
> + end
> + end
> +
> + it "update should install a package" do
> + @provider.expects(:install).with(false)
> + @provider.update
> + end
> +end
> diff --git a/spec/unit/provider/package/nim.rb
> b/spec/unit/provider/package/nim.rb
> new file mode 100755
> index 0000000..2018f65
> --- /dev/null
> +++ b/spec/unit/provider/package/nim.rb
> @@ -0,0 +1,42 @@
> +#!/usr/bin/env ruby
> +
> +require File.dirname(__FILE__) + '/../../../spec_helper'
> +
> +provider_class = Puppet::Type.type(:package).provider(:nim)
> +
> +describe provider_class do
> + before(:each) do
> + # Create a mock resource
> + @resource = stub 'resource'
> +
> + # A catch all; no parameters set
> + @resource.stubs(:[]).returns(nil)
> +
> + # But set name and source
> + @resource.stubs(:[]).with(:name).returns "mypackage"
> + @resource.stubs(:[]).with(:source).returns "mysource"
> + @resource.stubs(:[]).with(:ensure).returns :installed
> +
> + @provider = provider_class.new
> + @provider.resource = @resource
> + end
> +
> + it "should have an install method" do
> + @provider = provider_class.new
> + @provider.should respond_to(:install)
> + end
> +
> + describe "when installing" do
> + it "should install a package" do
> + @resource.stubs(:should).with(:ensure).returns(:installed)
> + @provider.expects(:nimclient).with("-o", "cust", "-a",
> "installp_flags=acgwXY", "-a", "lpp_source=mysource", "-a",
> "filesets='mypackage'")
> + @provider.install
> + end
> +
> + it "should install a versioned package" do
> + @resource.stubs(:should).with(:ensure).returns("1.2.3.4")
> + @provider.expects(:nimclient).with("-o", "cust", "-a",
> "installp_flags=acgwXY", "-a", "lpp_source=mysource", "-a",
> "filesets='mypackage 1.2.3.4'")
> + @provider.install
> + end
> + end
> + end
> --
> 1.6.6
>
> --
> You received this message because you are subscribed to the Google Groups
> "Puppet Developers" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected]<puppet-dev%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/puppet-dev?hl=en.
>
>
--
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en.