diff --git a/lib/puppet/provider/package/pkg.rb b/lib/puppet/provider/package/pkg.rb index 914010eb5..3c4414fd7 100644 --- a/lib/puppet/provider/package/pkg.rb +++ b/lib/puppet/provider/package/pkg.rb @@ -1,112 +1,112 @@ require 'puppet/provider/package' Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package do desc "OpenSolaris image packaging system. See pkg(5) for more information" commands :pkg => "/usr/bin/pkg" confine :operatingsystem => :solaris #defaultfor [:operatingsystem => :solaris, :kernelrelease => "5.11"] def self.instances packages = [] pkg(:list, '-H').each_line do |line| # now turn each returned line into a package object if hash = parse_line(line.chomp) packages << new(hash) end end packages end - self::REGEX = /^(\S+)(?:\s+\(.*?\))?\s+(\S+)(?:\s+(\S+))?\s+(\S+)$/ + self::REGEX = /^(\S+)(?:\s+\(.*?\))?\s+(\S+)\s+(\S+)?\s+(\S+)$/ self::FIELDS = [:name, :version, :status, :flags] def self.parse_line(line) hash = {} if match = self::REGEX.match(line) self::FIELDS.zip(match.captures) { |field,value| hash[field] = value } hash[:provider] = self.name # on solaris 11 we do not have a status field because the status # seems to be merged in the flags field. Simulate old behaviour on # solaris 11 flags = hash.delete(:flags) unless hash[:status] hash[:status] = case flags when /^i/ 'installed' when /^-/ 'known' else warning "unknown package state for #{hash[:name]}: #{flags}" 'unknown' end end if hash[:status] == "installed" hash[:ensure] = :present else hash[:ensure] = :absent end else warning "Failed to match 'pkg list' line #{line.inspect}" return nil end hash end # return the version of the package # TODO deal with multiple publishers def latest version = nil pkg(:list, "-Ha", @resource[:name]).each_line do |line| v = parse_line(line.chomp)[:status] case v when "known" return v when "installed" version = v else Puppet.warn "unknown package state for #{@resource[:name]}: #{v}" end end version end # install the package def install pkg :install, @resource[:name] end # uninstall the package def uninstall pkg :uninstall, '-r', @resource[:name] end # update the package to the latest version available def update self.install end # list a specific package def query begin output = pkg(:list, "-H", @resource[:name]) rescue Puppet::ExecutionFailure # pkg returns 1 if the package is not found. return {:ensure => :absent, :name => @resource[:name]} end hash = self.class.parse_line(output.chomp) || {:ensure => :absent, :name => @resource[:name]} hash end end diff --git a/spec/fixtures/unit/provider/package/pkg/solaris11 b/spec/fixtures/unit/provider/package/pkg/solaris11 index 2612e0885..e5bab71f2 100644 --- a/spec/fixtures/unit/provider/package/pkg/solaris11 +++ b/spec/fixtures/unit/provider/package/pkg/solaris11 @@ -1,13 +1,12 @@ compress/zip 3.0-0.175.0.0.0.2.537 i-- archiver/gnu-tar 1.26-0.175.0.0.0.2.537 i-- compress/bzip2 1.0.6-0.175.0.0.0.2.537 i-- compress/gzip 1.3.5-0.175.0.0.0.2.537 i-- compress/p7zip 9.20.1-0.175.0.0.0.2.537 i-- compress/unzip 6.0-0.175.0.0.0.2.537 i-- compress/zip 3.0-0.175.0.0.0.2.537 i-- x11/library/toolkit/libxaw7 1.0.9-0.175.0.0.0.0.1215 i-- x11/library/toolkit/libxt 1.0.9-0.175.0.0.0.0.1215 i-- shell/bash 4.1.9-0.175.0.0.0.2.537 i-- shell/zsh 4.3.12-0.175.0.0.0.2.537 i-- security/sudo 1.8.1.2-0.175.0.0.0.2.537 i-- -service/network/ntp 4.2.5.200-0.175.0.0.0.2.537 i-- diff --git a/spec/unit/provider/package/pkg_spec.rb b/spec/unit/provider/package/pkg_spec.rb index a1e193c27..71682df85 100755 --- a/spec/unit/provider/package/pkg_spec.rb +++ b/spec/unit/provider/package/pkg_spec.rb @@ -1,134 +1,133 @@ #!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:package).provider(:pkg) do before :each do @resource = Puppet::Resource.new(:package, 'dummy', :parameters => {:name => 'dummy', :ensure => :latest}) @provider = described_class.new(@resource) end def self.it_should_respond_to(*actions) actions.each do |action| it "should respond to :#{action}" do @provider.should respond_to(action) end end end it_should_respond_to :install, :uninstall, :update, :query, :latest it "should not be versionable" do described_class.should_not be_versionable end it "should use :install to update" do @provider.expects(:install) @provider.update end describe "when calling instances" do it "should correctly parse lines with preferred publisher" do described_class.expects(:pkg).with(:list,'-H').returns File.read(my_fixture('simple')) @instances = described_class.instances.map { |p| {:name => p.get(:name), :ensure => p.get(:ensure)} } @instances.size.should == 4 @instances[0].should == {:name => 'SUNPython', :ensure => :present} @instances[1].should == {:name => 'SUNWbind', :ensure => :present} @instances[2].should == {:name => 'SUNWdistro-license-copyright', :ensure => :present} @instances[3].should == {:name => 'SUNWfppd', :ensure => :present} end it "should correctly parse lines with non preferred publisher" do described_class.expects(:pkg).with(:list,'-H').returns File.read(my_fixture('publisher')) @instances = described_class.instances.map { |p| {:name => p.get(:name), :ensure => p.get(:ensure)} } @instances.size.should == 2 @instances[0].should == {:name => 'SUNWpcre', :ensure => :present} @instances[1].should == {:name => 'service/network/ssh', :ensure => :present} end it "should correctly parse lines on solaris 11" do described_class.expects(:pkg).with(:list, '-H').returns File.read(my_fixture('solaris11')) described_class.expects(:warning).never @instances = described_class.instances.map { |p| {:name => p.get(:name), :ensure => p.get(:ensure) }} - @instances.size.should == 13 + @instances.size.should == 12 @instances[0].should == {:name => 'compress/zip', :ensure => :present} @instances[1].should == {:name => 'archiver/gnu-tar', :ensure => :present} @instances[2].should == {:name => 'compress/bzip2', :ensure => :present} @instances[3].should == {:name => 'compress/gzip', :ensure => :present} @instances[4].should == {:name => 'compress/p7zip', :ensure => :present} @instances[5].should == {:name => 'compress/unzip', :ensure => :present} @instances[6].should == {:name => 'compress/zip', :ensure => :present} @instances[7].should == {:name => 'x11/library/toolkit/libxaw7', :ensure => :present} @instances[8].should == {:name => 'x11/library/toolkit/libxt', :ensure => :present} @instances[9].should == {:name => 'shell/bash', :ensure => :present} @instances[10].should == {:name => 'shell/zsh', :ensure => :present} @instances[11].should == {:name => 'security/sudo', :ensure => :present} - @instances[12].should == {:name => 'service/network/ntp', :ensure => :present} end it "should warn about incorrect lines" do fake_output = File.read(my_fixture('incomplete')) error_line = fake_output.lines[0] described_class.expects(:pkg).with(:list,'-H').returns fake_output described_class.expects(:warning).with "Failed to match 'pkg list' line #{error_line.inspect}" described_class.instances end it "should warn about unknown package status" do described_class.expects(:pkg).with(:list,'-H').returns File.read(my_fixture('unknown_status')) described_class.expects(:warning).with "unknown package state for compress/unzip: x--" described_class.instances end end describe "when query a package" do context "on solaris 10" do it "should find the package" do @provider.stubs(:pkg).with(:list,'-H','dummy').returns File.read(my_fixture('dummy_solaris10')) @provider.query.should == { :name => 'dummy', :ensure => :present, :version => '2.5.5-0.111', :status => "installed", :provider => :pkg, } end it "should return :absent when the package is not found" do # I dont know what the acutal error looks like, but according to type/pkg.rb we're just # reacting on the Exception anyways @provider.expects(:pkg).with(:list, "-H", "dummy").raises Puppet::ExecutionFailure, 'Not found' @provider.query.should == {:ensure => :absent, :name => "dummy"} end end context "on solaris 11" do it "should find the package" do @provider.stubs(:pkg).with(:list,'-H','dummy').returns File.read(my_fixture('dummy_solaris11')) @provider.query.should == { :name => 'dummy', :ensure => :present, :version => '1.0.6-0.175.0.0.0.2.537', :status => "installed", :provider => :pkg, } end it "should return :absent when the package is not found" do # I dont know what the acutal error looks like, but according to type/pkg.rb we're just # reacting on the Exception anyways @provider.expects(:pkg).with(:list, "-H", "dummy").raises Puppet::ExecutionFailure, 'Not found' @provider.query.should == {:ensure => :absent, :name => "dummy"} end end it "should return :absent when the packageline cannot be parsed" do @provider.stubs(:pkg).with(:list,'-H','dummy').returns File.read(my_fixture('incomplete')) @provider.query.should == { :name => 'dummy', :ensure => :absent } end end end