+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.

Reply via email to