diff options
-rw-r--r-- | lib/chef/provider/package/apt.rb | 28 | ||||
-rw-r--r-- | spec/functional/resource/apt_package_spec.rb | 2 | ||||
-rw-r--r-- | spec/unit/provider/package/apt_spec.rb | 98 |
3 files changed, 110 insertions, 18 deletions
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb index dbacaedb07..6f2f645ead 100644 --- a/lib/chef/provider/package/apt.rb +++ b/lib/chef/provider/package/apt.rb @@ -176,6 +176,7 @@ class Chef def resolve_package_versions(pkg) current_version = nil candidate_version = nil + all_versions = [] run_noninteractive("apt-cache", default_release_options, "policy", pkg).stdout.each_line do |line| case line when /^\s{2}Installed: (.+)$/ @@ -184,9 +185,34 @@ class Chef when /^\s{2}Candidate: (.+)$/ candidate_version = ( $1 != "(none)" ) ? $1 : nil logger.trace("#{new_resource} candidate version for #{pkg} is #{$1}") + when /\s+(?:\*\*\* )?(\S+) \d+/ + all_versions << $1 end end - [ current_version, candidate_version ] + # This is a bit ugly... really this whole provider needs + # to be rewritten to use target_version_array and friends, but + # for now this gets us moving + idx = package_name_array.index(pkg) + chosen_version = + if idx + user_ver = new_version_array[idx] + if user_ver + if all_versions.include?(user_ver) + user_ver + else + logger.debug("User specified a version that's not available") + nil + end + else + # user didn't specify a version, use candidate + candidate_version + end + else + # this probably means we're redirected from a virtual + # package, so... just go with candidate version + candidate_version + end + [ current_version, chosen_version ] end def resolve_virtual_package_name(pkg) diff --git a/spec/functional/resource/apt_package_spec.rb b/spec/functional/resource/apt_package_spec.rb index 9f10e27731..8e888ce54a 100644 --- a/spec/functional/resource/apt_package_spec.rb +++ b/spec/functional/resource/apt_package_spec.rb @@ -186,7 +186,7 @@ describe Chef::Resource::AptPackage, metadata do it "raises a reasonable error for action :install" do expect do package_resource.run_action(:install) - end.to raise_error(Mixlib::ShellOut::ShellCommandFailed) + end.to raise_error(Chef::Exceptions::Package) end end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 2ff1f0fddc..45d6d16229 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -48,6 +48,21 @@ describe Chef::Provider::Package::Apt do @timeout = 900 end + def ubuntu1804downgrade_stubs + so = instance_double(Mixlib::ShellOut, stdout: "apt 1.6~beta1 (amd64)\notherstuff\n") + so2 = instance_double(Mixlib::ShellOut, error?: false) + allow(@provider).to receive(:shell_out).with("apt-get --version").and_return(so) + allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.6~beta1", "gt", "1.1.0").and_return(so2) + end + + def ubuntu1404downgrade_stubs + so = instance_double(Mixlib::ShellOut, stdout: "apt 1.0.1ubuntu2 for amd64 compiled on Dec 8 2016 16:23:38\notherstuff\n") + so2 = instance_double(Mixlib::ShellOut, error?: true) + allow(@provider).to receive(:shell_out).with("apt-get --version").and_return(so) + allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.0.1ubuntu2", "gt", "1.1.0").and_return(so2) + allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.0.1ubuntu2", "eq", "1.1.0").and_return(so2) + end + describe "when loading current resource" do it "should create a current resource with the name of the new_resource" do @@ -237,6 +252,72 @@ describe Chef::Provider::Package::Apt do ).and_return(@shell_out) expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) end + + it "downgrades when requested" do + ubuntu1804downgrade_stubs + so = instance_double(Mixlib::ShellOut, stdout: "apt 1.6~beta1 (amd64)\notherstuff\n") + so2 = instance_double(Mixlib::ShellOut, error?: false) + allow(@provider).to receive(:shell_out).with("apt-get --version").and_return(so) + allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.6~beta1", "gt", "1.1.0").and_return(so2) + + @new_resource.package_name("libmysqlclient-dev") + @new_resource.version("5.1.41-3ubuntu12.7") + real_package_out = <<~RPKG_STDOUT + libmysqlclient-dev: + Installed: 5.1.41-3ubuntu12.10 + Candidate: 5.1.41-3ubuntu12.10 + Version table: + *** 5.1.41-3ubuntu12.10 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main packages + 100 /var/lib/dpkg/status + 5.1.41-3ubuntu12.7 0 + 500 http://security.ubuntu.com/ubuntu/ lucid-security/main packages + 5.1.41-3ubuntu12 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main packages + RPKG_STDOUT + real_package = double(stdout: real_package_out, exitstatus: 0) + expect(@provider).to receive(:shell_out_compacted!).with( + "apt-cache", "policy", "libmysqlclient-dev", + env: { "DEBIAN_FRONTEND" => "noninteractive" }, + timeout: @timeout + ).and_return(real_package) + expect(@provider).to receive(:shell_out_compacted!).with( + "apt-get", "-q", "-y", "--allow-downgrades", "-o", "Dpkg::Options::=--force-confdef", "-o", "Dpkg::Options::=--force-confold", "install", "libmysqlclient-dev=5.1.41-3ubuntu12.7", + env: { "DEBIAN_FRONTEND" => "noninteractive" }, + timeout: @timeout + ) + @provider.run_action(:install) + end + + it "raises an exception if bad version specified" do + @new_resource.package_name("libmysqlclient-dev") + @new_resource.version("non_existent") + real_package_out = <<~RPKG_STDOUT + libmysqlclient-dev: + Installed: 5.1.41-3ubuntu12.10 + Candidate: 5.1.41-3ubuntu12.10 + Version table: + *** 5.1.41-3ubuntu12.10 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main packages + 100 /var/lib/dpkg/status + 5.1.41-3ubuntu12.7 0 + 500 http://security.ubuntu.com/ubuntu/ lucid-security/main packages + 5.1.41-3ubuntu12 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main packages + RPKG_STDOUT + real_package = double(stdout: real_package_out, exitstatus: 0) + expect(@provider).to receive(:shell_out_compacted!).with( + "apt-cache", "policy", @new_resource.package_name, + env: { "DEBIAN_FRONTEND" => "noninteractive" } , + timeout: @timeout + ).and_return(real_package) + expect(@provider).to receive(:shell_out_compacted!).with( + "apt-cache", "showpkg", @new_resource.package_name, + env: { "DEBIAN_FRONTEND" => "noninteractive" } , + timeout: @timeout + ).and_return(real_package) + expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) + end end context "after loading the current resource" do @@ -257,21 +338,6 @@ describe Chef::Provider::Package::Apt do }) end - def ubuntu1804downgrade_stubs - so = instance_double(Mixlib::ShellOut, stdout: "apt 1.6~beta1 (amd64)\notherstuff\n") - so2 = instance_double(Mixlib::ShellOut, error?: false) - allow(@provider).to receive(:shell_out).with("apt-get --version").and_return(so) - allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.6~beta1", "gt", "1.1.0").and_return(so2) - end - - def ubuntu1404downgrade_stubs - so = instance_double(Mixlib::ShellOut, stdout: "apt 1.0.1ubuntu2 for amd64 compiled on Dec 8 2016 16:23:38\notherstuff\n") - so2 = instance_double(Mixlib::ShellOut, error?: true) - allow(@provider).to receive(:shell_out).with("apt-get --version").and_return(so) - allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.0.1ubuntu2", "gt", "1.1.0").and_return(so2) - allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.0.1ubuntu2", "eq", "1.1.0").and_return(so2) - end - describe "install_package" do before(:each) do ubuntu1804downgrade_stubs @@ -590,7 +656,7 @@ describe Chef::Provider::Package::Apt do end end - describe "#action_install" do + describe "#action_upgrade" do it "should run dpkg to compare versions if an existing version is installed" do allow(@provider).to receive(:get_current_versions).and_return("1.4.0") allow(@new_resource).to receive(:allow_downgrade).and_return(false) |