diff --git a/lib/puppet/provider/package/pkg.rb b/lib/puppet/provider/package/pkg.rb index 52fbec081..399a9df76 100644 --- a/lib/puppet/provider/package/pkg.rb +++ b/lib/puppet/provider/package/pkg.rb @@ -1,101 +1,96 @@ 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 = [] - cmd = "#{command(:pkg)} list -H" - execpipe(cmd) do |process| - hash = {} - + pkg(:list, '-H').each_line do |line| # now turn each returned line into a package object - process.each_line { |line| - if hash = parse_line(line) - packages << new(hash) - end - } + if hash = parse_line(line.chomp) + packages << new(hash) + end end packages end - self::REGEX = %r{^(\S+)\s+(\S+)\s+(\S+)\s+} + self::REGEX = /^(\S+)(?:\s+\(.*?\))?\s+(\S+)\s+(\S+)\s+\S+$/ self::FIELDS = [:name, :version, :status] 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 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]).split("\n").each do |line| - v = line.split[2] + 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) || {:ensure => :absent, :name => @resource[:name]} + hash = self.class.parse_line(output.chomp) || {:ensure => :absent, :name => @resource[:name]} hash end end diff --git a/spec/fixtures/unit/provider/package/pkg/dummy b/spec/fixtures/unit/provider/package/pkg/dummy new file mode 100644 index 000000000..2d56c39a6 --- /dev/null +++ b/spec/fixtures/unit/provider/package/pkg/dummy @@ -0,0 +1 @@ +dummy 2.5.5-0.111 installed ---- diff --git a/spec/fixtures/unit/provider/package/pkg/incomplete b/spec/fixtures/unit/provider/package/pkg/incomplete new file mode 100644 index 000000000..24a93d10a --- /dev/null +++ b/spec/fixtures/unit/provider/package/pkg/incomplete @@ -0,0 +1 @@ +dummy 2.5.5-0.111 installed ---- RANDOM_TRASH diff --git a/spec/fixtures/unit/provider/package/pkg/publisher b/spec/fixtures/unit/provider/package/pkg/publisher new file mode 100644 index 000000000..23be5b69f --- /dev/null +++ b/spec/fixtures/unit/provider/package/pkg/publisher @@ -0,0 +1,2 @@ +SUNWpcre (solaris) 8.8-0.111 installed ---- +service/network/ssh (solaris) 0.5.11-0.151.0.1 installed ----- diff --git a/spec/fixtures/unit/provider/package/pkg/simple b/spec/fixtures/unit/provider/package/pkg/simple new file mode 100644 index 000000000..80bb41389 --- /dev/null +++ b/spec/fixtures/unit/provider/package/pkg/simple @@ -0,0 +1,4 @@ +SUNPython 2.5.5-0.111 installed ---- +SUNWbind 9.3.6.1-0.111 installed ---- +SUNWdistro-license-copyright 0.5.11-0.111 installed ---- +SUNWfppd 0.2008.8.18-0.111 installed ---- diff --git a/spec/unit/provider/package/pkg_spec.rb b/spec/unit/provider/package/pkg_spec.rb index dd182c81e..f5cbc6ec5 100755 --- a/spec/unit/provider/package/pkg_spec.rb +++ b/spec/unit/provider/package/pkg_spec.rb @@ -1,63 +1,85 @@ #!/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 - it "should parse a line correctly" do - result = described_class.parse_line("dummy 1.0@1.0-1.0 installed ----") - result.should == {:name => "dummy", :version => "1.0@1.0-1.0", - :ensure => :present, :status => "installed", - :provider => :pkg} - 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| Hash.new(:name => p.get(:name), :ensure => p.get(:ensure)) } + @instances.size.should == 4 + @instances[0].should eql Hash.new(:name => 'SUNPython', :ensure => :present) + @instances[1].should eql Hash.new(:name => 'SUNWbind', :ensure => :present) + @instances[2].should eql Hash.new(:name => 'SUNWdistro-license-copyright', :ensure => :present) + @instances[3].should eql Hash.new(:name => 'SUNWfppd', :ensure => :present) + end - it "should fail to parse an incorrect line" do - result = described_class.parse_line("foo") - result.should be_nil - 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| Hash.new(:name => p.get(:name), :ensure => p.get(:ensure)) } + @instances.size.should == 2 + @instances[0].should eql Hash.new(:name => 'SUNWpcre', :ensure => :present) + @instances[1].should eql Hash.new(:name => 'service/network/ssh', :ensure => :present) + end - it "should fail to list a missing package" 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"} + 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 end - it "should fail to list a package when it can't parse the output line" do - @provider.expects(:pkg).with(:list, "-H", "dummy").returns "failed" - @provider.query.should == {:ensure => :absent, :name => "dummy"} - end + describe "when query a package" do + it "should find the package" do + @provider.stubs(:pkg).with(:list,'-H','dummy').returns File.read(my_fixture('dummy')) + @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 - it "should list package correctly" do - @provider.expects(:pkg).with(:list, "-H", "dummy").returns "dummy 1.0@1.0-1.0 installed ----" - @provider.query.should == { - :name => "dummy", - :version => "1.0@1.0-1.0", - :ensure => :present, - :status => "installed", - :provider => :pkg - } + 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