summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Pelberg <toomas.pelberg@playtech.com>2010-10-20 09:37:08 +0300
committerToomas Pelberg <toomas.pelberg@playtech.com>2010-10-20 09:37:08 +0300
commitcb401f74de55b4eba0f647667872de4cb408d525 (patch)
treecb334d97b30aa5f8464539450f21abcc75c48932
parent04e3bf9aafa941b4e4488488b3af303c60664363 (diff)
downloadchef-cb401f74de55b4eba0f647667872de4cb408d525.tar.gz
Handle problem2 in http://tickets.opscode.com/browse/CHEF-1439, no need to recurse the provided by if already installed
-rw-r--r--chef/lib/chef/provider/package/apt.rb67
-rw-r--r--chef/spec/unit/provider/package/apt_spec.rb174
2 files changed, 147 insertions, 94 deletions
diff --git a/chef/lib/chef/provider/package/apt.rb b/chef/lib/chef/provider/package/apt.rb
index ae43e76550..14cf2bbb06 100644
--- a/chef/lib/chef/provider/package/apt.rb
+++ b/chef/lib/chef/provider/package/apt.rb
@@ -24,45 +24,58 @@ class Chef
class Provider
class Package
class Apt < Chef::Provider::Package
+
+ include Chef::Mixin::ShellOut
+ attr_accessor :virtual
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
-
- Chef::Log.debug("Checking apt-cache policy for #{@new_resource.package_name}")
- status = popen4("apt-cache policy #{@new_resource.package_name}") do |pid, stdin, stdout, stderr|
- stdout.each do |line|
- case line
- when /^\s{2}Installed: (.+)$/
- installed_version = $1
- if installed_version == '(none)'
- Chef::Log.debug("Current version is nil")
- @current_resource.version(nil)
- else
- Chef::Log.debug("Current version is #{installed_version}")
- @current_resource.version(installed_version)
- end
- when /^\s{2}Candidate: (.+)$/
- Chef::Log.debug("Current version is #{$1}")
- @candidate_version = $1
+ check_package_state(@new_resource.package_name)
+ @current_resource
+ end
+
+ def check_package_state(package)
+ Chef::Log.debug("Checking package status for #{package}")
+ installed = false
+ depends = false
+
+ shell_out!("aptitude show #{package}").stdout.each_line do |line|
+ case line
+ when /^State: installed/
+ installed = true
+ when /^Version: (.*)/
+ @candidate_version = $1
+ if installed
+ @current_resource.version($1)
+ else
+ @current_resource.version(nil)
end
+ when /Depends: (.*)$/
+ depends = $1
+ when /Provided by: ([\w\d\-\.]*)/
+ next if installed
+ virtual_provider = $1
+ virtual_provider = depends if depends
+ Chef::Log.debug("Virtual package provided by #{virtual_provider}")
+ @virtual = true
+ installed = check_package_state(virtual_provider)
+ @candidate_version = virtual_provider
end
end
- unless status.exitstatus == 0
- raise Chef::Exceptions::Package, "apt-cache failed - #{status.inspect}!"
- end
-
- if @candidate_version == "(none)"
+ if @candidate_version.nil?
raise Chef::Exceptions::Package, "apt does not have a version of package #{@new_resource.package_name}"
end
-
- @current_resource
+
+ return installed
end
def install_package(name, version)
+ package_name = "#{name}=#{version}"
+ package_name = "#{name} #{@candidate_version}" if @virtual
run_command_with_systems_locale(
- :command => "apt-get -q -y#{expand_options(@new_resource.options)} install #{name}=#{version}",
+ :command => "apt-get -q -y#{expand_options(@new_resource.options)} install #{package_name}",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
@@ -74,8 +87,10 @@ class Chef
end
def remove_package(name, version)
+ package_name = "#{name}"
+ package_name = "#{name} #{@candidate_version}" if @virtual
run_command_with_systems_locale(
- :command => "apt-get -q -y#{expand_options(@new_resource.options)} remove #{@new_resource.package_name}",
+ :command => "apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
diff --git a/chef/spec/unit/provider/package/apt_spec.rb b/chef/spec/unit/provider/package/apt_spec.rb
index 55b183d1da..c47c40be87 100644
--- a/chef/spec/unit/provider/package/apt_spec.rb
+++ b/chef/spec/unit/provider/package/apt_spec.rb
@@ -23,93 +23,131 @@ describe Chef::Provider::Package::Apt do
@node = Chef::Node.new
@node.cookbook_collection = {}
@run_context = Chef::RunContext.new(@node, {})
- @new_resource = Chef::Resource::Package.new("emacs", @run_context)
- @current_resource = Chef::Resource::Package.new("emacs", @run_context)
+ @new_resource = Chef::Resource::Package.new("irssi", @run_context)
+ @current_resource = Chef::Resource::Package.new("irssi", @run_context)
@status = mock("Status", :exitstatus => 0)
@provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context)
Chef::Resource::Package.stub!(:new).and_return(@current_resource)
@provider.stub!(:popen4).and_return(@status)
@stdin = mock("STDIN", :null_object => true)
- @stdout = mock("STDOUT", :null_object => true)
- @stdout.stub!(:each).and_yield("emacs:").
- and_yield(" Installed: (none)").
- and_yield(" Candidate: 0.1.1").
- and_yield(" Version Table:")
+ @stdout =<<-PKG_STATUS
+Package: irssi
+State: not installed
+Version: 0.8.12-7
+PKG_STATUS
@stderr = mock("STDERR", :null_object => true)
@pid = mock("PID", :null_object => true)
+ @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0)
end
describe "when loading current resource" do
it "should create a current resource with the name of the new_resource" do
+ @provider.should_receive(:shell_out!).and_return(@shell_out)
Chef::Resource::Package.should_receive(:new).and_return(@current_resource)
@provider.load_current_resource
end
it "should set the current resources package name to the new resources package name" do
+ @provider.should_receive(:shell_out!).and_return(@shell_out)
@current_resource.should_receive(:package_name).with(@new_resource.package_name)
@provider.load_current_resource
end
- it "should run apt-cache policy with the package name" do
- @provider.should_receive(:popen4).with("apt-cache policy #{@new_resource.package_name}").and_return(@status)
+ it "should run aptitude show with the package name" do
+ @provider.should_receive(:shell_out!).with("aptitude show #{@new_resource.package_name}").and_return(@shell_out)
@provider.load_current_resource
end
- it "should read stdout on apt-cache policy" do
- @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
- @stdout.should_receive(:each).and_return(true)
- @provider.load_current_resource
- end
-
- it "should set the installed version to nil on the current resource if apt-cache policy installed version is (none)" do
- @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ it "should set the installed version to nil on the current resource if package state is not installed" do
+ @provider.should_receive(:shell_out!).and_return(@shell_out)
@current_resource.should_receive(:version).with(nil).and_return(true)
@provider.load_current_resource
end
- it "should set the installed version if apt-cache policy has one" do
- @stdout.stub!(:each).and_yield("emacs:").
- and_yield(" Installed: 0.1.1").
- and_yield(" Candidate: 0.1.1").
- and_yield(" Version Table:")
- @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
- @current_resource.should_receive(:version).with("0.1.1").and_return(true)
+ it "should set the installed version if package has one" do
+ @stdout.replace(<<-INSTALLED)
+Package: sudo
+State: installed
+Automatically installed: no
+Version: 1.7.2p1-1ubuntu5
+Priority: important
+Section: admin
+Maintainer: Ubuntu Core Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+Uncompressed Size: 602k
+Depends: libc6 (>= 2.8), libpam0g (>= 0.99.7.1), libpam-modules
+Conflicts: sudo-ldap
+Replaces: sudo-ldap
+Provided by: sudo-ldap
+Description: Provide limited super user privileges to specific users
+Sudo is a program designed to allow a sysadmin to give limited root privileges
+to users and log root activity. The basic philosophy is to give as few
+privileges as possible but still allow people to get their work done.
+INSTALLED
+ @provider.should_receive(:shell_out!).and_return(@shell_out)
@provider.load_current_resource
+ @current_resource.version.should == "1.7.2p1-1ubuntu5"
+ @provider.candidate_version.should eql("1.7.2p1-1ubuntu5")
end
- it "should set the candidate version if apt-cache policy has one" do
- @stdout.stub!(:each).and_yield("emacs:").
- and_yield(" Installed: 0.1.1").
- and_yield(" Candidate: 10").
- and_yield(" Version Table:")
- @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
- @provider.load_current_resource
- @provider.candidate_version.should eql("10")
- end
-
- it "should raise an exception if apt-cache policy fails" do
- @status.should_receive(:exitstatus).and_return(1)
+ it "should raise an exception if aptitude show does not return a candidate version" do
+ @stdout.replace("E: Unable to locate package magic")
+ @provider.should_receive(:shell_out!).and_return(@shell_out)
lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package)
end
- it "should not raise an exception if apt-cache policy succeeds" do
- @status.should_receive(:exitstatus).and_return(0)
- lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::Package)
+ it "should return the current resouce" do
+ @provider.should_receive(:shell_out!).and_return(@shell_out)
+ @provider.load_current_resource.should eql(@current_resource)
end
- it "should raise an exception if apt-cache policy does not return a candidate version" do
- @stdout.stub!(:each).and_yield("emacs:").
- and_yield(" Installed: 0.1.1").
- and_yield(" Candidate: (none)").
- and_yield(" Version Table:")
- @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
- lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package)
+ it "should set candidate version to new package name if virtual package" do
+ @new_resource.package_name("libmysqlclient-dev")
+ virtual_package_out=<<-VPKG_STDOUT
+"No current or candidate version found for libmysqlclient-dev").
+Package: libmysqlclient-dev
+State: not a real package
+Provided by: libmysqlclient15-dev
+VPKG_STDOUT
+ virtual_package = mock(:stdout => virtual_package_out,:exitstatus => 0)
+ @provider.should_receive(:shell_out!).with("aptitude show libmysqlclient-dev").and_return(virtual_package)
+ real_package_out=mock("STDOUT", :null_object => true)
+ real_package_out =<<-REALPKG_STDOUT
+Package: libmysqlclient15-dev
+State: not installed
+Version: 5.0.51a-24+lenny4
+REALPKG_STDOUT
+ real_package = mock(:stdout => real_package_out,:exitstatus => 0)
+ @provider.should_receive(:shell_out!).with("aptitude show libmysqlclient15-dev").and_return(real_package)
+ @provider.load_current_resource
+ @provider.candidate_version.should eql("libmysqlclient15-dev")
end
- it "should return the current resouce" do
- @provider.load_current_resource.should eql(@current_resource)
+ it "should set candidate version to the depends package name if multiple virtual package providers" do
+ @new_resource.package_name("mysql-client")
+ virtual_package_out=<<-VPKG_STDOUT
+Package: mysql-client
+State: not installed
+Version: 5.1.41-3ubuntu12.6
+Depends: mysql-client-5.1
+Provided by: mysql-cluster-client-5.1, mysql-client-5.1
+Description: MySQL database client (metapackage depending on the latest version)
+VPKG_STDOUT
+ virtual_package = mock(:stdout => virtual_package_out,:exitstatus => 0)
+ @provider.should_receive(:shell_out!).with("aptitude show mysql-client").and_return(virtual_package)
+ real_package_out=<<-REALPKG_STDOUT
+Package: mysql-client-5.1
+State: not installed
+Version: Version: 5.1.41-3ubuntu12.6
+Conflicts: mysql-client (< 5.1.41-3ubuntu12.6), mysql-client-5.0
+Replaces: mysql-client (< 5.1.41-3ubuntu12.6), mysql-client-5.0
+Provides: mysql-client, mysql-client-4.1, virtual-mysql-client
+REALPKG_STDOUT
+ real_package = mock(:stdout => real_package_out,:exitstatus => 0)
+ @provider.should_receive(:shell_out!).with("aptitude show mysql-client-5.1").and_return(real_package)
+ @provider.load_current_resource
+ @provider.candidate_version.should eql("mysql-client-5.1")
end
end
@@ -118,32 +156,32 @@ describe Chef::Provider::Package::Apt do
it "should run apt-get install with the package name and version" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "apt-get -q -y install emacs=1.0",
+ :command => "apt-get -q -y install irssi=0.8.12-7",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
})
- @provider.install_package("emacs", "1.0")
+ @provider.install_package("irssi", "0.8.12-7")
end
it "should run apt-get install with the package name and version and options if specified" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "apt-get -q -y --force-yes install emacs=1.0",
+ :command => "apt-get -q -y --force-yes install irssi=0.8.12-7",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
})
@new_resource.stub!(:options).and_return("--force-yes")
- @provider.install_package("emacs", "1.0")
+ @provider.install_package("irssi", "0.8.12-7")
end
end
describe Chef::Provider::Package::Apt, "upgrade_package" do
it "should run install_package with the name and version" do
- @provider.should_receive(:install_package).with("emacs", "1.0")
- @provider.upgrade_package("emacs", "1.0")
+ @provider.should_receive(:install_package).with("irssi", "0.8.12-7")
+ @provider.upgrade_package("irssi", "0.8.12-7")
end
end
@@ -151,24 +189,24 @@ describe Chef::Provider::Package::Apt do
it "should run apt-get remove with the package name" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "apt-get -q -y remove emacs",
+ :command => "apt-get -q -y remove irssi",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
})
- @provider.remove_package("emacs", "1.0")
+ @provider.remove_package("irssi", "0.8.12-7")
end
it "should run apt-get remove with the package name and options if specified" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "apt-get -q -y --force-yes remove emacs",
+ :command => "apt-get -q -y --force-yes remove irssi",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
})
@new_resource.stub!(:options).and_return("--force-yes")
- @provider.remove_package("emacs", "1.0")
+ @provider.remove_package("irssi", "0.8.12-7")
end
end
@@ -176,52 +214,52 @@ describe Chef::Provider::Package::Apt do
it "should run apt-get purge with the package name" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "apt-get -q -y purge emacs",
+ :command => "apt-get -q -y purge irssi",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
})
- @provider.purge_package("emacs", "1.0")
+ @provider.purge_package("irssi", "0.8.12-7")
end
it "should run apt-get purge with the package name and options if specified" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "apt-get -q -y --force-yes purge emacs",
+ :command => "apt-get -q -y --force-yes purge irssi",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
})
@new_resource.stub!(:options).and_return("--force-yes")
- @provider.purge_package("emacs", "1.0")
+ @provider.purge_package("irssi", "0.8.12-7")
end
end
describe "when preseeding a package" do
before(:each) do
- @provider.stub!(:get_preseed_file).and_return("/tmp/emacs-10.seed")
+ @provider.stub!(:get_preseed_file).and_return("/tmp/irssi-0.8.12-7.seed")
@provider.stub!(:run_command_with_systems_locale).and_return(true)
end
it "should get the full path to the preseed response file" do
- @provider.should_receive(:get_preseed_file).with("emacs", "10").and_return("/tmp/emacs-10.seed")
- @provider.preseed_package("emacs", "10")
+ @provider.should_receive(:get_preseed_file).with("irssi", "0.8.12-7").and_return("/tmp/irssi-0.8.12-7.seed")
+ @provider.preseed_package("irssi", "0.8.12-7")
end
it "should run debconf-set-selections on the preseed file if it has changed" do
@provider.should_receive(:run_command_with_systems_locale).with({
- :command => "debconf-set-selections /tmp/emacs-10.seed",
+ :command => "debconf-set-selections /tmp/irssi-0.8.12-7.seed",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
}).and_return(true)
- @provider.preseed_package("emacs", "10")
+ @provider.preseed_package("irssi", "0.8.12-7")
end
it "should not run debconf-set-selections if the preseed file has not changed" do
@provider.stub!(:get_preseed_file).and_return(false)
@provider.should_not_receive(:run_command_with_systems_locale)
- @provider.preseed_package("emacs", "10")
+ @provider.preseed_package("irssi", "0.8.12-7")
end
end
end