diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2016-05-03 10:24:15 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2016-05-03 11:16:10 -0700 |
commit | c564889f5fda607185ba7b7ceebeaa15888a97cd (patch) | |
tree | ecd579c9b45d0c38bf6bd8e5328f959850dcb37c | |
parent | 98ead2710216d29774c50a0d80fca050919a67a2 (diff) | |
download | chef-c564889f5fda607185ba7b7ceebeaa15888a97cd.tar.gz |
multipackage apt provider
-rw-r--r-- | lib/chef/provider/package.rb | 2 | ||||
-rw-r--r-- | lib/chef/provider/package/apt.rb | 63 | ||||
-rw-r--r-- | spec/unit/provider/package/apt_spec.rb | 54 | ||||
-rw-r--r-- | spec/unit/provider/package_spec.rb | 14 |
4 files changed, 73 insertions, 60 deletions
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index ca9b526920..73a5d36bab 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -558,7 +558,7 @@ class Chef # @param args [String] variable number of string arguments # @return [String] nicely concatenated string or empty string def a_to_s(*args) - args.reject { |i| i.nil? || i == "" }.join(" ") + args.flatten.reject { |i| i.nil? || i == "" }.join(" ") end end end diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb index ac730202b8..cfaac0addb 100644 --- a/lib/chef/provider/package/apt.rb +++ b/lib/chef/provider/package/apt.rb @@ -17,13 +17,13 @@ # require "chef/provider/package" -require "chef/mixin/command" -require "chef/resource/package" +require "chef/resource/apt_package" class Chef class Provider class Package class Apt < Chef::Provider::Package + use_multipackage_api provides :package, platform_family: "debian" provides :apt_package, os: "linux" @@ -37,24 +37,24 @@ class Chef end def load_current_resource - @current_resource = Chef::Resource::Package.new(@new_resource.name) - @current_resource.package_name(@new_resource.package_name) - check_all_packages_state(@new_resource.package_name) - @current_resource + @current_resource = Chef::Resource::AptPackage.new(new_resource.name) + current_resource.package_name(new_resource.package_name) + check_all_packages_state(new_resource.package_name) + current_resource end def define_resource_requirements super requirements.assert(:all_actions) do |a| - a.assertion { !@new_resource.source } + a.assertion { !new_resource.source } a.failure_message(Chef::Exceptions::Package, "apt package provider cannot handle source attribute. Use dpkg provider instead") end end def default_release_options # Use apt::Default-Release option only if provider supports it - "-o APT::Default-Release=#{@new_resource.default_release}" if @new_resource.respond_to?(:default_release) && @new_resource.default_release + "-o APT::Default-Release=#{new_resource.default_release}" if new_resource.respond_to?(:default_release) && new_resource.default_release end def check_package_state(pkg) @@ -63,15 +63,15 @@ class Chef installed_version = nil candidate_version = nil - shell_out_with_timeout!("apt-cache#{expand_options(default_release_options)} policy #{pkg}").stdout.each_line do |line| + run_noninteractive("apt-cache", default_release_options, "policy", pkg).stdout.each_line do |line| case line when /^\s{2}Installed: (.+)$/ installed_version = $1 if installed_version == "(none)" - Chef::Log.debug("#{@new_resource} current version is nil") + Chef::Log.debug("#{new_resource} current version is nil") installed_version = nil else - Chef::Log.debug("#{@new_resource} current version is #{installed_version}") + Chef::Log.debug("#{new_resource} current version is #{installed_version}") installed = true end when /^\s{2}Candidate: (.+)$/ @@ -79,7 +79,7 @@ class Chef if candidate_version == "(none)" # This may not be an appropriate assumption, but it shouldn't break anything that already worked -- btm is_virtual_package = true - showpkg = shell_out_with_timeout!("apt-cache showpkg #{pkg}").stdout + showpkg = run_noninteractive("apt-cache showpkg", pkg).stdout providers = Hash.new showpkg.rpartition(/Reverse Provides: ?#{$/}/)[2].each_line do |line| provider, version = line.split @@ -87,16 +87,16 @@ class Chef end # Check if the package providing this virtual package is installed num_providers = providers.length - raise Chef::Exceptions::Package, "#{@new_resource.package_name} has no candidate in the apt-cache" if num_providers == 0 + raise Chef::Exceptions::Package, "#{new_resource.package_name} has no candidate in the apt-cache" if num_providers == 0 # apt will only install a virtual package if there is a single providing package - raise Chef::Exceptions::Package, "#{@new_resource.package_name} is a virtual package provided by #{num_providers} packages, you must explicitly select one to install" if num_providers > 1 + raise Chef::Exceptions::Package, "#{new_resource.package_name} is a virtual package provided by #{num_providers} packages, you must explicitly select one to install" if num_providers > 1 # Check if the package providing this virtual package is installed - Chef::Log.info("#{@new_resource} is a virtual package, actually acting on package[#{providers.keys.first}]") + Chef::Log.info("#{new_resource} is a virtual package, actually acting on package[#{providers.keys.first}]") ret = check_package_state(providers.keys.first) installed = ret[:installed] installed_version = ret[:installed_version] else - Chef::Log.debug("#{@new_resource} candidate version is #{$1}") + Chef::Log.debug("#{new_resource} candidate version is #{$1}") end end end @@ -126,23 +126,21 @@ class Chef @candidate_version = [] final_installed_version = [] [package].flatten.each do |pkg| - @candidate_version << candidate_version[pkg] + candidate_version << candidate_version[pkg] final_installed_version << installed_version[pkg] end - @current_resource.version(final_installed_version) + current_resource.version(final_installed_version) else @candidate_version = candidate_version[package] - @current_resource.version(installed_version[package]) + current_resource.version(installed_version[package]) end end def install_package(name, version) - name_array = [ name ].flatten - version_array = [ version ].flatten - package_name = name_array.zip(version_array).map do |n, v| + package_name = name.zip(version).map do |n, v| is_virtual_package[n] ? n : "#{n}=#{v}" end.join(" ") - run_noninteractive("apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}") + run_noninteractive("apt-get -q -y", default_release_options, new_resource.options, "install", package_name) end def upgrade_package(name, version) @@ -150,24 +148,21 @@ class Chef end def remove_package(name, version) - package_name = [ name ].flatten.join(" ") - run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}") + run_noninteractive("apt-get -q -y", new_resource.options, "remove", name) end def purge_package(name, version) - package_name = [ name ].flatten.join(" ") - run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{package_name}") + run_noninteractive("apt-get -q -y", new_resource.options, "purge", name) end def preseed_package(preseed_file) - Chef::Log.info("#{@new_resource} pre-seeding package installation instructions") - run_noninteractive("debconf-set-selections #{preseed_file}") + Chef::Log.info("#{new_resource} pre-seeding package installation instructions") + run_noninteractive("debconf-set-selections", preseed_file) end def reconfig_package(name, version) - package_name = [ name ].flatten.join(" ") - Chef::Log.info("#{@new_resource} reconfiguring") - run_noninteractive("dpkg-reconfigure #{package_name}") + Chef::Log.info("#{new_resource} reconfiguring") + run_noninteractive("dpkg-reconfigure", name) end private @@ -175,8 +170,8 @@ class Chef # Runs command via shell_out with magic environment to disable # interactive prompts. Command is run with default localization rather # than forcing locale to "C", so command output may not be stable. - def run_noninteractive(command) - shell_out_with_timeout!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) + def run_noninteractive(*args) + shell_out_with_timeout!(a_to_s(*args), :env => { "DEBIAN_FRONTEND" => "noninteractive" }) end end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index b5f0646b79..3fd48e46e8 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -52,6 +52,7 @@ irssi: it "should create a current resource with the name of the new_resource" do expect(@provider).to receive(:shell_out!).with( "apt-cache policy #{@new_resource.package_name}", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(@shell_out) @provider.load_current_resource @@ -95,6 +96,7 @@ libmysqlclient15-dev: virtual_package = double(:stdout => virtual_package_out, :exitstatus => 0) expect(@provider).to receive(:shell_out!).with( "apt-cache policy libmysqlclient15-dev", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(virtual_package) showpkg_out = <<-SHOWPKG_STDOUT @@ -118,6 +120,7 @@ libmysqlclient-dev 5.1.41-3ubuntu12 showpkg = double(:stdout => showpkg_out, :exitstatus => 0) expect(@provider).to receive(:shell_out!).with( "apt-cache showpkg libmysqlclient15-dev", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(showpkg) real_package_out = <<-RPKG_STDOUT @@ -136,6 +139,7 @@ libmysqlclient-dev: real_package = double(:stdout => real_package_out, :exitstatus => 0) expect(@provider).to receive(:shell_out!).with( "apt-cache policy libmysqlclient-dev", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(real_package) @provider.load_current_resource @@ -152,6 +156,7 @@ mp3-decoder: virtual_package = double(:stdout => virtual_package_out, :exitstatus => 0) expect(@provider).to receive(:shell_out!).with( "apt-cache policy mp3-decoder", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(virtual_package) showpkg_out = <<-SHOWPKG_STDOUT @@ -178,6 +183,7 @@ mpg123 1.12.1-0ubuntu1 showpkg = double(:stdout => showpkg_out, :exitstatus => 0) expect(@provider).to receive(:shell_out!).with( "apt-cache showpkg mp3-decoder", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(showpkg) expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package) @@ -191,6 +197,7 @@ mpg123 1.12.1-0ubuntu1 allow(@new_resource).to receive(:provider).and_return(nil) expect(@provider).to receive(:shell_out!).with( "apt-cache -o APT::Default-Release=lenny-backports policy irssi", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ).and_return(@shell_out) @provider.load_current_resource @@ -200,11 +207,12 @@ mpg123 1.12.1-0ubuntu1 @new_resource.source "pluto" expect(@provider).to receive(:shell_out!).with( "apt-cache policy #{@new_resource.package_name}", + :env => { "DEBIAN_FRONTEND" => "noninteractive" } , :timeout => @timeout ).and_return(@shell_out) @provider.load_current_resource @provider.define_resource_requirements - expect(@provider).to receive(:shell_out!).with("apt-cache policy irssi", { :timeout => 900 }).and_return(@shell_out) + expect(@provider).to receive(:shell_out!).with("apt-cache policy irssi", { :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => 900 }).and_return(@shell_out) expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) end end @@ -219,20 +227,20 @@ mpg123 1.12.1-0ubuntu1 it "should run apt-get install with the package name and version" do expect(@provider).to receive(:shell_out!). with( "apt-get -q -y install irssi=0.8.12-7", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) - @provider.install_package("irssi", "0.8.12-7") + @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 expect(@provider).to receive(:shell_out!).with( "apt-get -q -y --force-yes install irssi=0.8.12-7", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) @new_resource.options("--force-yes") - @provider.install_package("irssi", "0.8.12-7") + @provider.install_package(["irssi"], ["0.8.12-7"]) end it "should run apt-get install with the package name and version and default_release if there is one and provider is explicitly defined" do @@ -244,19 +252,19 @@ mpg123 1.12.1-0ubuntu1 expect(@provider).to receive(:shell_out!).with( "apt-get -q -y -o APT::Default-Release=lenny-backports install irssi=0.8.12-7", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) - @provider.install_package("irssi", "0.8.12-7") + @provider.install_package(["irssi"], ["0.8.12-7"]) end end describe resource_klass, "upgrade_package" do it "should run install_package with the name and version" do - expect(@provider).to receive(:install_package).with("irssi", "0.8.12-7") - @provider.upgrade_package("irssi", "0.8.12-7") + expect(@provider).to receive(:install_package).with(["irssi"], ["0.8.12-7"]) + @provider.upgrade_package(["irssi"], ["0.8.12-7"]) end end @@ -265,21 +273,21 @@ mpg123 1.12.1-0ubuntu1 it "should run apt-get remove with the package name" do expect(@provider).to receive(:shell_out!).with( "apt-get -q -y remove irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) - @provider.remove_package("irssi", "0.8.12-7") + @provider.remove_package(["irssi"], ["0.8.12-7"]) end it "should run apt-get remove with the package name and options if specified" do expect(@provider).to receive(:shell_out!).with( "apt-get -q -y --force-yes remove irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) @new_resource.options("--force-yes") - @provider.remove_package("irssi", "0.8.12-7") + @provider.remove_package(["irssi"], ["0.8.12-7"]) end end @@ -288,21 +296,21 @@ mpg123 1.12.1-0ubuntu1 it "should run apt-get purge with the package name" do expect(@provider).to receive(:shell_out!).with( "apt-get -q -y purge irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) - @provider.purge_package("irssi", "0.8.12-7") + @provider.purge_package(["irssi"], ["0.8.12-7"]) end it "should run apt-get purge with the package name and options if specified" do expect(@provider).to receive(:shell_out!).with( "apt-get -q -y --force-yes purge irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) @new_resource.options("--force-yes") - @provider.purge_package("irssi", "0.8.12-7") + @provider.purge_package(["irssi"], ["0.8.12-7"]) end end @@ -316,7 +324,7 @@ mpg123 1.12.1-0ubuntu1 expect(@provider).to receive(:shell_out!).with( "debconf-set-selections /tmp/irssi-0.8.12-7.seed", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) @@ -326,7 +334,7 @@ mpg123 1.12.1-0ubuntu1 it "should run debconf-set-selections on the preseed file if it has changed" do expect(@provider).to receive(:shell_out!).with( "debconf-set-selections /tmp/irssi-0.8.12-7.seed", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) file = @provider.get_preseed_file("irssi", "0.8.12-7") @@ -347,7 +355,7 @@ mpg123 1.12.1-0ubuntu1 it "should run dpkg-reconfigure package" do expect(@provider).to receive(:shell_out!).with( "dpkg-reconfigure irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) @provider.reconfig_package("irssi", "0.8.12-7") @@ -359,10 +367,10 @@ mpg123 1.12.1-0ubuntu1 @provider.is_virtual_package["libmysqlclient-dev"] = true expect(@provider).to receive(:shell_out!).with( "apt-get -q -y install libmysqlclient-dev", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) - @provider.install_package("libmysqlclient-dev", "not_a_real_version") + @provider.install_package(["libmysqlclient-dev"], ["not_a_real_version"]) end end @@ -373,7 +381,7 @@ mpg123 1.12.1-0ubuntu1 @provider.is_virtual_package["irssi"] = false expect(@provider).to receive(:shell_out!).with( "apt-get -q -y install libmysqlclient-dev irssi=0.8.12-7", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, :timeout => @timeout ) @provider.install_package(["libmysqlclient-dev", "irssi"], ["not_a_real_version", "0.8.12-7"]) diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb index abf0322868..393b5f6853 100644 --- a/spec/unit/provider/package_spec.rb +++ b/spec/unit/provider/package_spec.rb @@ -458,8 +458,18 @@ describe "Subclass with use_multipackage_api" do expect(provider.use_multipackage_api?).to be true end - it "offers a_to_s to subclasses to convert an array of strings to a single string" do - expect(provider.send(:a_to_s, "a", nil, "b", "", "c", " ", "d e", "f-g")).to eq("a b c d e f-g") + context "#a_to_s utility for subclasses" do + it "converts varargs of strings to a single string" do + expect(provider.send(:a_to_s, "a", nil, "b", "", "c", " ", "d e", "f-g")).to eq("a b c d e f-g") + end + + it "converts an array of strings to a single string" do + expect(provider.send(:a_to_s, ["a", nil, "b", "", "c", " ", "d e", "f-g"])).to eq("a b c d e f-g") + end + + it "converts a mishmash of array args to a single string" do + expect(provider.send(:a_to_s, "a", [ nil, "b", "", [ "c" ] ], " ", [ "d e", "f-g" ])).to eq("a b c d e f-g") + end end it "when user passes string to package_name, passes arrays to install_package" do |