diff options
author | Kapil Chouhan <kapil.chouhan@msystechnologies.com> | 2019-03-19 16:47:26 +0530 |
---|---|---|
committer | Kapil Chouhan <kapil.chouhan@msystechnologies.com> | 2019-05-07 14:04:03 +0530 |
commit | 38c62c0c14794045154d886ffaf6f27778e659dd (patch) | |
tree | 0e563f420fce95ed1af6a7b21b187bc08e560647 | |
parent | 66c0fdeb65c19d267bd501550e60cd16d7bb4901 (diff) | |
download | chef-38c62c0c14794045154d886ffaf6f27778e659dd.tar.gz |
Move response_file and response_file_variables out of base package resource
Signed-off-by: Kapil Chouhan <kapil.chouhan@msystechnologies.com>
Fix for Move response_file and response_file_variables out of base package resource
Signed-off-by: Kapil Chouhan <kapil.chouhan@msystechnologies.com>
update require changes
Signed-off-by: Kapil Chouhan <kapil.chouhan@msystechnologies.com>
Updated require changes
Signed-off-by: Kapil Chouhan <kapil.chouhan@msystechnologies.com>
Fixed some unit test cases
Signed-off-by: Kapil Chouhan <kapil.chouhan@msystechnologies.com>
-rw-r--r-- | lib/chef/provider/package.rb | 91 | ||||
-rw-r--r-- | lib/chef/provider/package/apt.rb | 19 | ||||
-rw-r--r-- | lib/chef/provider/package/deb.rb | 131 | ||||
-rw-r--r-- | lib/chef/provider/package/dpkg.rb | 18 | ||||
-rw-r--r-- | lib/chef/resource/apt_package.rb | 8 | ||||
-rw-r--r-- | lib/chef/resource/dpkg_package.rb | 8 | ||||
-rw-r--r-- | lib/chef/resource/package.rb | 8 | ||||
-rw-r--r-- | spec/data/cookbooks/irssi/files/default/irssi.response | 2 | ||||
-rw-r--r-- | spec/data/cookbooks/wget/files/default/wget.response | 2 | ||||
-rw-r--r-- | spec/support/shared/unit/provider/package/package_shared.rb | 95 | ||||
-rw-r--r-- | spec/unit/cookbook_loader_spec.rb | 2 | ||||
-rw-r--r-- | spec/unit/provider/package/apt_spec.rb | 30 | ||||
-rw-r--r-- | spec/unit/provider/package/deb_spec.rb | 135 | ||||
-rw-r--r-- | spec/unit/provider/package/dpkg_spec.rb | 29 | ||||
-rw-r--r-- | spec/unit/provider/package_spec.rb | 168 | ||||
-rw-r--r-- | spec/unit/resource/apt_package_spec.rb | 10 | ||||
-rw-r--r-- | spec/unit/resource/dpkg_package_spec.rb | 10 | ||||
-rw-r--r-- | spec/unit/resource/package_spec.rb | 10 |
18 files changed, 467 insertions, 309 deletions
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index 44d7fed6f4..d0fb216604 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -88,14 +88,7 @@ class Chef return end - # @todo: move the preseed code out of the base class (and complete the fix for Array of preseeds? ugh...) - if new_resource.response_file - if preseed_file = get_preseed_file(package_names_for_targets, versions_for_targets) - converge_by("preseed package #{package_names_for_targets}") do - preseed_package(preseed_file) - end - end - end + prepare_for_installation converge_by(install_description) do multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version| @@ -194,31 +187,6 @@ class Chef end end - action :reconfig do - if current_resource.version.nil? - logger.trace("#{new_resource} is NOT installed - nothing to do") - return - end - - unless new_resource.response_file - logger.trace("#{new_resource} no response_file provided - nothing to do") - return - end - - if preseed_file = get_preseed_file(new_resource.package_name, current_resource.version) - converge_by("reconfigure package #{new_resource.package_name}") do - preseed_package(preseed_file) - multipackage_api_adapter(new_resource.package_name, current_resource.version) do |name, version| - reconfig_package(name, version) - - end - logger.info("#{new_resource} reconfigured") - end - else - logger.trace("#{new_resource} preseeding has not changed - nothing to do") - end - end - def action_lock packages_locked = if respond_to?(:packages_all_locked?, true) packages_all_locked?(Array(new_resource.package_name), Array(new_resource.version)) @@ -262,6 +230,10 @@ class Chef raise Chef::Exceptions::UnsupportedAction, "#{self} has no way to detect if package is locked" end + # Subclasses will override this to a method and provide a preseed file path + def prepare_for_installation + end + # @todo use composition rather than inheritance def multipackage_api_adapter(name, version) @@ -292,7 +264,7 @@ class Chef raise Chef::Exceptions::UnsupportedAction, "#{self} does not support pre-seeding package install/upgrade instructions" end - def reconfig_package(name, version) + def reconfig_package(name) raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :reconfig" ) end @@ -384,46 +356,6 @@ class Chef target_version_already_installed?(current_version, new_version) end - # @todo: extract apt/dpkg specific preseeding to a helper class - def get_preseed_file(name, version) - resource = preseed_resource(name, version) - resource.run_action(:create) - logger.trace("#{new_resource} fetched preseed file to #{resource.path}") - - if resource.updated_by_last_action? - resource.path - else - false - end - end - - # @todo: extract apt/dpkg specific preseeding to a helper class - def preseed_resource(name, version) - # A directory in our cache to store this cookbook's preseed files in - file_cache_dir = Chef::FileCache.create_cache_path("preseed/#{new_resource.cookbook_name}") - # The full path where the preseed file will be stored - cache_seed_to = "#{file_cache_dir}/#{name}-#{version}.seed" - - logger.trace("#{new_resource} fetching preseed file to #{cache_seed_to}") - - if template_available?(new_resource.response_file) - logger.trace("#{new_resource} fetching preseed file via Template") - remote_file = Chef::Resource::Template.new(cache_seed_to, run_context) - remote_file.variables(new_resource.response_file_variables) - elsif cookbook_file_available?(new_resource.response_file) - logger.trace("#{new_resource} fetching preseed file via cookbook_file") - remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context) - else - message = "No template or cookbook file found for response file #{new_resource.response_file}" - raise Chef::Exceptions::FileNotFound, message - end - - remote_file.cookbook_name = new_resource.cookbook_name - remote_file.source(new_resource.response_file) - remote_file.backup(false) - remote_file - end - # helper method used by subclasses # def as_array(thing) @@ -479,7 +411,6 @@ class Chef @target_version_array ||= begin target_version_array = [] - each_package do |package_name, new_version, current_version, candidate_version| case action when :upgrade @@ -657,16 +588,6 @@ class Chef end end - # @todo: extract apt/dpkg specific preseeding to a helper class - def template_available?(path) - run_context.has_template_in_cookbook?(new_resource.cookbook_name, path) - end - - # @todo: extract apt/dpkg specific preseeding to a helper class - def cookbook_file_available?(path) - run_context.has_cookbook_file_in_cookbook?(new_resource.cookbook_name, path) - end - def allow_downgrade if new_resource.respond_to?("allow_downgrade") new_resource.allow_downgrade diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb index dfc7e602dd..75c7935805 100644 --- a/lib/chef/provider/package/apt.rb +++ b/lib/chef/provider/package/apt.rb @@ -17,12 +17,14 @@ # require "chef/provider/package" +require "chef/provider/package/deb" require "chef/resource/apt_package" class Chef class Provider class Package class Apt < Chef::Provider::Package + include Chef::Provider::Package::Deb use_multipackage_api provides :package, platform_family: "debian" @@ -114,16 +116,6 @@ class Chef run_noninteractive("apt-get", "-q", "-y", options, "purge", package_name) end - def preseed_package(preseed_file) - logger.info("#{new_resource} pre-seeding package installation instructions") - run_noninteractive("debconf-set-selections", preseed_file) - end - - def reconfig_package(name, version) - logger.info("#{new_resource} reconfiguring") - run_noninteractive("dpkg-reconfigure", name) - end - def lock_package(name, version) run_noninteractive("apt-mark", options, "hold", name) end @@ -161,13 +153,6 @@ class Chef end end - # 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(*args) - shell_out!(*args, env: { "DEBIAN_FRONTEND" => "noninteractive" }) - end - def default_release_options # Use apt::Default-Release option only if provider supports it if new_resource.respond_to?(:default_release) && new_resource.default_release diff --git a/lib/chef/provider/package/deb.rb b/lib/chef/provider/package/deb.rb new file mode 100644 index 0000000000..439127e18a --- /dev/null +++ b/lib/chef/provider/package/deb.rb @@ -0,0 +1,131 @@ +# +# Author:: Kapil Chouhan (<kapil.chouhan@msystechnologies.com>) +# Copyright:: Copyright 2010-2019, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "chef/provider/package" + +class Chef + class Provider + class Package + module Deb + def self.included(base) + base.class_eval do + use_multipackage_api + + action :reconfig do + if current_resource.version.nil? + logger.trace("#{new_resource} is NOT installed - nothing to do") + return + end + + unless new_resource.response_file + logger.trace("#{new_resource} no response_file provided - nothing to do") + return + end + + if preseed_file = get_preseed_file(new_resource.package_name, current_resource.version) + converge_by("reconfigure package #{new_resource.package_name}") do + preseed_package(preseed_file) + multipackage_api_adapter(new_resource.package_name, current_resource.version) do |name, _version| + reconfig_package(name) + end + logger.info("#{new_resource} reconfigured") + end + else + logger.trace("#{new_resource} preseeding has not changed - nothing to do") + end + end + + # This method is used for getting preseed file + # it will return preseed file path or false if response_file is present + def prepare_for_installation + if new_resource.response_file && preseed_file = get_preseed_file(package_names_for_targets, versions_for_targets) + converge_by("preseed package #{package_names_for_targets}") do + preseed_package(preseed_file) + end + end + end + + def get_preseed_file(name, version) + resource = preseed_resource(name, version) + resource.run_action(:create) + logger.trace("#{new_resource} fetched preseed file to #{resource.path}") + + if resource.updated_by_last_action? + resource.path + else + false + end + end + + def preseed_resource(name, version) + # A directory in our cache to store this cookbook's preseed files in + file_cache_dir = Chef::FileCache.create_cache_path("preseed/#{new_resource.cookbook_name}") + # The full path where the preseed file will be stored + cache_seed_to = "#{file_cache_dir}/#{name}-#{version}.seed" + + logger.trace("#{new_resource} fetching preseed file to #{cache_seed_to}") + + if template_available?(new_resource.response_file) + logger.trace("#{new_resource} fetching preseed file via Template") + remote_file = Chef::Resource::Template.new(cache_seed_to, run_context) + remote_file.variables(new_resource.response_file_variables) + elsif cookbook_file_available?(new_resource.response_file) + logger.trace("#{new_resource} fetching preseed file via cookbook_file") + remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context) + else + message = "No template or cookbook file found for response file #{new_resource.response_file}" + raise Chef::Exceptions::FileNotFound, message + end + + remote_file.cookbook_name = new_resource.cookbook_name + remote_file.source(new_resource.response_file) + remote_file.backup(false) + remote_file + end + + def preseed_package(preseed_file) + logger.info("#{new_resource} pre-seeding package installation instructions") + run_noninteractive("debconf-set-selections", preseed_file) + end + + def reconfig_package(name) + logger.info("#{new_resource} reconfiguring") + run_noninteractive("dpkg-reconfigure", *name) + end + + # Runs command via shell_out with magic environment to disable + # interactive prompts. + def run_noninteractive(*command) + shell_out!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" }) + end + + private + + def template_available?(path) + run_context.has_template_in_cookbook?(new_resource.cookbook_name, path) + end + + def cookbook_file_available?(path) + run_context.has_cookbook_file_in_cookbook?(new_resource.cookbook_name, path) + end + end + end + end + end + end +end diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb index 38129c8931..25878797c1 100644 --- a/lib/chef/provider/package/dpkg.rb +++ b/lib/chef/provider/package/dpkg.rb @@ -17,12 +17,14 @@ # require "chef/provider/package" +require "chef/provider/package/deb" require "chef/resource/package" class Chef class Provider class Package class Dpkg < Chef::Provider::Package + include Chef::Provider::Package::Deb DPKG_REMOVED = /^Status: deinstall ok config-files/.freeze DPKG_INSTALLED = /^Status: install ok installed/.freeze DPKG_VERSION = /^Version: (.+)$/.freeze @@ -91,16 +93,6 @@ class Chef install_package(name, version) end - def preseed_package(preseed_file) - logger.info("#{new_resource} pre-seeding package installation instructions") - run_noninteractive("debconf-set-selections", *preseed_file) - end - - def reconfig_package(name, version) - logger.info("#{new_resource} reconfiguring") - run_noninteractive("dpkg-reconfigure", *name) - end - # Override the superclass check. Multiple sources are required here. def check_resource_semantics!; end @@ -149,12 +141,6 @@ class Chef end end - # Runs command via shell_out with magic environment to disable - # interactive prompts. - def run_noninteractive(*command) - shell_out!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" }) - end - # Returns true if all sources exist. Returns false if any do not, or if no # sources were specified. # diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb index e55d37fcc8..4ee636062d 100644 --- a/lib/chef/resource/apt_package.rb +++ b/lib/chef/resource/apt_package.rb @@ -35,6 +35,14 @@ class Chef description: "Overwrite existing configuration files with those supplied by the package, if prompted by APT.", default: false + property :response_file, String, + description: "The direct path to the file used to pre-seed a package.", + desired_state: false + + property :response_file_variables, Hash, + description: "A Hash of response file variables in the form of {'VARIABLE' => 'VALUE'}.", + default: lazy { Hash.new }, desired_state: false + end end end diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb index 742b291508..f5b9e5f14a 100644 --- a/lib/chef/resource/dpkg_package.rb +++ b/lib/chef/resource/dpkg_package.rb @@ -28,6 +28,14 @@ class Chef property :source, [ String, Array, nil ], description: "The path to a package in the local file system." + + property :response_file, String, + description: "The direct path to the file used to pre-seed a package.", + desired_state: false + + property :response_file_variables, Hash, + description: "A Hash of response file variables in the form of {'VARIABLE' => 'VALUE'}.", + default: lazy { Hash.new }, desired_state: false end end end diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb index 71f030244b..67b01402a7 100644 --- a/lib/chef/resource/package.rb +++ b/lib/chef/resource/package.rb @@ -52,14 +52,6 @@ class Chef description: "One (or more) additional command options that are passed to the command.", coerce: proc { |x| x.is_a?(String) ? x.shellsplit : x } - property :response_file, String, - description: "The direct path to the file used to pre-seed a package.", - desired_state: false - - property :response_file_variables, Hash, - description: "A Hash of response file variables in the form of {'VARIABLE' => 'VALUE'}.", - default: lazy { Hash.new }, desired_state: false - property :source, String, description: "The optional path to a package on the local file system.", desired_state: false diff --git a/spec/data/cookbooks/irssi/files/default/irssi.response b/spec/data/cookbooks/irssi/files/default/irssi.response new file mode 100644 index 0000000000..6b67a12758 --- /dev/null +++ b/spec/data/cookbooks/irssi/files/default/irssi.response @@ -0,0 +1,2 @@ +# Hi, I'm pretending to be the preseed file for installing the irssi on debian +# or Ubuntu diff --git a/spec/data/cookbooks/wget/files/default/wget.response b/spec/data/cookbooks/wget/files/default/wget.response new file mode 100644 index 0000000000..b5f22f4d10 --- /dev/null +++ b/spec/data/cookbooks/wget/files/default/wget.response @@ -0,0 +1,2 @@ +# Hi, I'm pretending to be the preseed file for installing the wget on debian +# or Ubuntu diff --git a/spec/support/shared/unit/provider/package/package_shared.rb b/spec/support/shared/unit/provider/package/package_shared.rb new file mode 100644 index 0000000000..7cd97f5e0c --- /dev/null +++ b/spec/support/shared/unit/provider/package/package_shared.rb @@ -0,0 +1,95 @@ +# +# Author:: Kapil Chouhan (<kapil.chouhan@msystechnologies.com>) +# Copyright:: Copyright 2010-2019, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +shared_examples_for "given a response file" do + let(:cookbook_repo) { File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) } + let(:cookbook_loader) do + Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo) + Chef::CookbookLoader.new(cookbook_repo) + end + let(:cookbook_collection) do + cookbook_loader.load_cookbooks + Chef::CookbookCollection.new(cookbook_loader) + end + let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) } + + describe "creating the cookbook file resource to fetch the response file" do + before do + expect(Chef::FileCache).to receive(:create_cache_path).with(path).and_return(tmp_path) + end + + it "sets the preseed resource's runcontext to its own run context" do + cookbook_collection + allow(Chef::FileCache).to receive(:create_cache_path).and_return(tmp_path) + expect(@provider.preseed_resource(package_name, package_version).run_context).not_to be_nil + expect(@provider.preseed_resource(package_name, package_version).run_context).to equal(@provider.run_context) + end + + it "should set the cookbook name of the remote file to the new resources cookbook name" do + expect(@provider.preseed_resource(package_name, package_version).cookbook_name).to eq(package_name) + end + + it "should set remote files source to the new resources response file" do + expect(@provider.preseed_resource(package_name, package_version).source).to eq(response) + end + + it "should never back up the cached response file" do + expect(@provider.preseed_resource(package_name, package_version).backup).to be_falsey + end + + it "sets the install path of the resource to $file_cache/$cookbook/$pkg_name-$pkg_version.seed" do + expect(@provider.preseed_resource(package_name, package_version).path).to eq(tmp_preseed_path) + end + end + + describe "when installing the preseed file to the cache location" do + let(:response_file_destination) { Dir.tmpdir + preseed_path } + let(:response_file_resource) do + response_file_resource = Chef::Resource::CookbookFile.new(response_file_destination, run_context) + response_file_resource.cookbook_name = package_name + response_file_resource.backup(false) + response_file_resource.source(response) + response_file_resource + end + + before do + expect(@provider).to receive(:preseed_resource).with(package_name, package_version).and_return(response_file_resource) + end + + after do + FileUtils.rm(response_file_destination) if ::File.exist?(response_file_destination) + end + + it "creates the preseed file in the cache" do + expect(response_file_resource).to receive(:run_action).with(:create) + @provider.get_preseed_file(package_name, package_version) + end + + it "returns the path to the response file if the response file was updated" do + expect(@provider.get_preseed_file(package_name, package_version)).to eq(response_file_destination) + end + + it "should return false if the response file has not been updated" do + response_file_resource.updated_by_last_action(false) + expect(response_file_resource).not_to be_updated_by_last_action + # don't let the response_file_resource set updated to true + expect(response_file_resource).to receive(:run_action).with(:create) + expect(@provider.get_preseed_file(package_name, package_version)).to be(false) + end + end +end diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb index ddb4f00f35..9180f13f33 100644 --- a/spec/unit/cookbook_loader_spec.rb +++ b/spec/unit/cookbook_loader_spec.rb @@ -101,7 +101,7 @@ describe Chef::CookbookLoader do cookbook_loader.each_key do |cookbook_name| seen << cookbook_name end - expect(seen).to eq %w{angrybash apache2 borken ignorken java name-mismatch openldap preseed supports-platform-constraints} + expect(seen).to eq %w{angrybash apache2 borken ignorken irssi java name-mismatch openldap preseed supports-platform-constraints wget} end end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 24bd642317..31b37f5094 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -24,10 +24,11 @@ describe Chef::Provider::Package::Apt do # XXX: sorry this is ugly and was done quickly to get 12.0.2 out, this file needs a rewrite to use # let blocks and shared examples + let(:node) { Chef::Node.new } + let(:events) { Chef::EventDispatch::Dispatcher.new } + before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) + @run_context = Chef::RunContext.new(node, {}, events) allow(@run_context).to receive(:logger).and_return(logger) @new_resource = Chef::Resource::AptPackage.new("irssi", @run_context) @@ -428,6 +429,27 @@ describe Chef::Provider::Package::Apt do end end + describe "when given a response file" do + it_behaves_like "given a response file" do + before do + @provider = Chef::Provider::Package::Apt.new(new_resource, run_context) + end + let(:new_resource) do + new_resource = Chef::Resource::AptPackage.new("irssi", run_context) + new_resource.response_file("irssi.response") + new_resource.cookbook_name = "irssi" + new_resource + end + let(:path) { "preseed/irssi" } + let(:tmp_path) { "/tmp/preseed/irssi" } + let(:package_name) { "irssi" } + let(:package_version) { "1.0.5-1" } + let(:response) { "irssi.response" } + let(:tmp_preseed_path) { "/tmp/preseed/irssi/irssi-1.0.5-1.seed" } + let(:preseed_path) { "/preseed--irssi--irssi-1.0.5-1.seed" } + end + end + describe "when preseeding a package" do before(:each) do allow(@provider).to receive(:get_preseed_file).and_return("/tmp/irssi-0.8.12-7.seed") @@ -472,7 +494,7 @@ describe Chef::Provider::Package::Apt do env: { "DEBIAN_FRONTEND" => "noninteractive" }, timeout: @timeout ) - @provider.reconfig_package("irssi", "0.8.12-7") + @provider.reconfig_package("irssi") end end diff --git a/spec/unit/provider/package/deb_spec.rb b/spec/unit/provider/package/deb_spec.rb new file mode 100644 index 0000000000..d67a79586f --- /dev/null +++ b/spec/unit/provider/package/deb_spec.rb @@ -0,0 +1,135 @@ +# +# Author:: Kapil Chouhan (<kapil.chouhan@msystechnologies.com>) +# Copyright:: Copyright 2010-2019, Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" + +describe Chef::Provider::Package::Deb do + let(:node) do + node = Chef::Node.new + node.automatic_attrs[:platform] = :just_testing + node.automatic_attrs[:platform_version] = :just_testing + node + end + let(:events) { Chef::EventDispatch::Dispatcher.new } + let(:logger) { double("Mixlib::Log::Child").as_null_object } + let(:run_context) { Chef::RunContext.new(node, {}, events) } + let(:new_resource) { Chef::Resource::AptPackage.new("emacs", run_context) } + let(:current_resource) { Chef::Resource::AptPackage.new("emacs", run_context) } + let(:candidate_version) { "1.0" } + let(:provider) do + provider = Chef::Provider::Package::Apt.new(new_resource, run_context) { include Chef::Provider::Package::Deb } + provider.current_resource = current_resource + provider.candidate_version = candidate_version + provider + end + + before do + allow(run_context).to receive(:logger).and_return(logger) + end + + describe "when reconfiguring the package" do + before(:each) do + allow(provider).to receive(:reconfig_package).and_return(true) + end + + context "when reconfigure the package" do + it "reconfigure the package and update the resource" do + allow(provider).to receive(:get_current_versions).and_return("1.0") + allow(new_resource).to receive(:response_file).and_return(true) + expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test") + allow(provider).to receive(:preseed_package).and_return(true) + allow(provider).to receive(:reconfig_package).and_return(true) + expect(logger).to receive(:info).with("apt_package[emacs] reconfigured") + expect(provider).to receive(:reconfig_package) + provider.run_action(:reconfig) + expect(new_resource).to be_updated + expect(new_resource).to be_updated_by_last_action + end + end + + context "when not reconfigure the package" do + it "does not reconfigure the package if the package is not installed" do + allow(provider).to receive(:get_current_versions).and_return(nil) + allow(provider.load_current_resource).to receive(:version).and_return(nil) + expect(logger).to receive(:trace).with("apt_package[emacs] is NOT installed - nothing to do") + expect(provider).not_to receive(:reconfig_package) + provider.run_action(:reconfig) + expect(new_resource).not_to be_updated_by_last_action + end + + it "does not reconfigure the package if no response_file is given" do + allow(provider).to receive(:get_current_versions).and_return("1.0") + allow(new_resource).to receive(:response_file).and_return(nil) + expect(logger).to receive(:trace).with("apt_package[emacs] no response_file provided - nothing to do") + expect(provider).not_to receive(:reconfig_package) + provider.run_action(:reconfig) + expect(new_resource).not_to be_updated_by_last_action + end + + it "does not reconfigure the package if the response_file has not changed" do + allow(provider).to receive(:get_current_versions).and_return("1.0") + allow(new_resource).to receive(:response_file).and_return(true) + expect(provider).to receive(:get_preseed_file).and_return(false) + allow(provider).to receive(:preseed_package).and_return(false) + expect(logger).to receive(:trace).with("apt_package[emacs] preseeding has not changed - nothing to do") + expect(provider).not_to receive(:reconfig_package) + provider.run_action(:reconfig) + expect(new_resource).not_to be_updated_by_last_action + end + end + end + + describe "Subclass with use_multipackage_api" do + class MyDebianPackageResource < Chef::Resource::Package + end + + class MyDebianPackageProvider < Chef::Provider::Package + include Chef::Provider::Package::Deb + use_multipackage_api + end + let(:node) { Chef::Node.new } + let(:events) { Chef::EventDispatch::Dispatcher.new } + let(:run_context) { Chef::RunContext.new(node, {}, events) } + let(:new_resource) { MyDebianPackageResource.new("installs the packages") } + let(:current_resource) { MyDebianPackageResource.new("installs the packages") } + let(:provider) do + provider = MyDebianPackageProvider.new(new_resource, run_context) + provider.current_resource = current_resource + provider + end + + it "has use_multipackage_api? methods on the class and instance" do + expect(MyDebianPackageProvider.use_multipackage_api?).to be true + expect(provider.use_multipackage_api?).to be true + end + + it "when user passes string to package_name, passes arrays to reconfig_package" do + new_resource.package_name "vim" + current_resource.package_name "vim" + current_resource.version [ "1.0" ] + allow(new_resource).to receive(:response_file).and_return(true) + allow(new_resource).to receive(:resource_name).and_return(:apt_package) + expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test") + allow(provider).to receive(:preseed_package).and_return(true) + allow(provider).to receive(:reconfig_package).and_return(true) + expect(provider).to receive(:reconfig_package).with([ "vim" ]).and_return(true) + provider.run_action(:reconfig) + expect(new_resource).to be_updated_by_last_action + end + end +end diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb index 9df19f0f1b..318b91c77e 100644 --- a/spec/unit/provider/package/dpkg_spec.rb +++ b/spec/unit/provider/package/dpkg_spec.rb @@ -53,7 +53,6 @@ describe Chef::Provider::Package::Dpkg do before(:each) do allow(provider).to receive(:shell_out_compacted!).with("dpkg-deb", "-W", source, timeout: 900).and_return(dpkg_deb_status) allow(provider).to receive(:shell_out_compacted!).with("dpkg", "-s", package, timeout: 900, returns: [0, 1]).and_return(double(stdout: "", exitstatus: 1)) - allow(::File).to receive(:exist?).with(source).and_return(true) end describe "#define_resource_requirements" do @@ -104,6 +103,9 @@ describe Chef::Provider::Package::Dpkg do end describe "when loading the current resource state" do + before(:each) do + allow(::File).to receive(:exist?).with(source).and_return(true) + end it "should create a current resource with the name of the new_resource" do provider.load_current_resource @@ -213,6 +215,10 @@ describe Chef::Provider::Package::Dpkg do end describe Chef::Provider::Package::Dpkg, "install and upgrade" do + before(:each) do + allow(::File).to receive(:exist?).with(source).and_return(true) + end + it "should run dpkg -i with the package source" do expect(provider).to receive(:run_noninteractive).with( "dpkg", "-i", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb" @@ -284,4 +290,25 @@ describe Chef::Provider::Package::Dpkg do provider.purge_package(["wget"], ["1.11.4-1ubuntu1"]) end end + + describe "when given a response file" do + it_behaves_like "given a response file" do + before do + @provider = Chef::Provider::Package::Dpkg.new(new_resource, run_context) + end + let(:new_resource) do + new_resource = Chef::Resource::DpkgPackage.new("wget", run_context) + new_resource.response_file("wget.response") + new_resource.cookbook_name = "wget" + new_resource + end + let(:path) { "preseed/wget" } + let(:tmp_path) { "/tmp/preseed/wget" } + let(:package_name) { "wget" } + let(:package_version) { "1.11.4" } + let(:response) { "wget.response" } + let(:tmp_preseed_path) { "/tmp/preseed/wget/wget-1.11.4.seed" } + let(:preseed_path) { "/preseed--wget--wget-1.11.4.seed" } + end + end end diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb index f085e09ce4..accd913ebe 100644 --- a/spec/unit/provider/package_spec.rb +++ b/spec/unit/provider/package_spec.rb @@ -61,24 +61,6 @@ describe Chef::Provider::Package do expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) end - it "should call preseed_package if a response_file is given" do - new_resource.response_file("foo") - expect(provider).to receive(:get_preseed_file).with( - new_resource.package_name, - provider.candidate_version - ).and_return("/var/cache/preseed-test") - - expect(provider).to receive(:preseed_package).with( - "/var/cache/preseed-test" - ).and_return(true) - provider.run_action(:install) - end - - it "should not call preseed_package if a response_file is not given" do - expect(provider).not_to receive(:preseed_package) - provider.run_action(:install) - end - it "should install the package at the candidate_version if it is not already installed" do expect(provider).to receive(:install_package).with( new_resource.package_name, @@ -281,53 +263,6 @@ describe Chef::Provider::Package do end - describe "when reconfiguring the package" do - before(:each) do - allow(provider).to receive(:reconfig_package).and_return(true) - end - - it "should info log, reconfigure the package and update the resource" do - allow(current_resource).to receive(:version).and_return("1.0") - allow(new_resource).to receive(:response_file).and_return(true) - expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test") - allow(provider).to receive(:preseed_package).and_return(true) - allow(provider).to receive(:reconfig_package).and_return(true) - expect(logger).to receive(:info).with("package[install emacs] reconfigured") - expect(provider).to receive(:reconfig_package) - provider.run_action(:reconfig) - expect(new_resource).to be_updated - expect(new_resource).to be_updated_by_last_action - end - - it "should debug log and not reconfigure the package if the package is not installed" do - allow(current_resource).to receive(:version).and_return(nil) - expect(logger).to receive(:trace).with("package[install emacs] is NOT installed - nothing to do") - expect(provider).not_to receive(:reconfig_package) - provider.run_action(:reconfig) - expect(new_resource).not_to be_updated_by_last_action - end - - it "should debug log and not reconfigure the package if no response_file is given" do - allow(current_resource).to receive(:version).and_return("1.0") - allow(new_resource).to receive(:response_file).and_return(nil) - expect(logger).to receive(:trace).with("package[install emacs] no response_file provided - nothing to do") - expect(provider).not_to receive(:reconfig_package) - provider.run_action(:reconfig) - expect(new_resource).not_to be_updated_by_last_action - end - - it "should debug log and not reconfigure the package if the response_file has not changed" do - allow(current_resource).to receive(:version).and_return("1.0") - allow(new_resource).to receive(:response_file).and_return(true) - expect(provider).to receive(:get_preseed_file).and_return(false) - allow(provider).to receive(:preseed_package).and_return(false) - expect(logger).to receive(:trace).with("package[install emacs] preseeding has not changed - nothing to do") - expect(provider).not_to receive(:reconfig_package) - provider.run_action(:reconfig) - expect(new_resource).not_to be_updated_by_last_action - end - end - describe "When locking the package" do before(:each) do allow(provider).to receive(:lock_package).with( @@ -421,7 +356,7 @@ describe Chef::Provider::Package do end it "should raise UnsupportedAction for reconfig" do - expect { provider.reconfig_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction) + expect { provider.reconfig_package("emacs") }.to raise_error(Chef::Exceptions::UnsupportedAction) end it "should raise UnsupportedAction for lock" do @@ -432,91 +367,6 @@ describe Chef::Provider::Package do expect { provider.unlock_package("emacs", nil) }.to raise_error(Chef::Exceptions::UnsupportedAction) end end - - describe "when given a response file" do - let(:cookbook_repo) { File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) } - let(:cookbook_loader) do - Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo) - Chef::CookbookLoader.new(cookbook_repo) - end - let(:cookbook_collection) do - cookbook_loader.load_cookbooks - Chef::CookbookCollection.new(cookbook_loader) - end - let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) } - let(:new_resource) do - new_resource = Chef::Resource::Package.new("emacs") - new_resource.response_file("java.response") - new_resource.cookbook_name = "java" - new_resource - end - - describe "creating the cookbook file resource to fetch the response file" do - before do - expect(Chef::FileCache).to receive(:create_cache_path).with("preseed/java").and_return("/tmp/preseed/java") - end - - it "sets the preseed resource's runcontext to its own run context" do - allow(Chef::FileCache).to receive(:create_cache_path).and_return("/tmp/preseed/java") - expect(provider.preseed_resource("java", "6").run_context).not_to be_nil - expect(provider.preseed_resource("java", "6").run_context).to equal(provider.run_context) - end - - it "should set the cookbook name of the remote file to the new resources cookbook name" do - expect(provider.preseed_resource("java", "6").cookbook_name).to eq("java") - end - - it "should set remote files source to the new resources response file" do - expect(provider.preseed_resource("java", "6").source).to eq("java.response") - end - - it "should never back up the cached response file" do - expect(provider.preseed_resource("java", "6").backup).to be_falsey - end - - it "sets the install path of the resource to $file_cache/$cookbook/$pkg_name-$pkg_version.seed" do - expect(provider.preseed_resource("java", "6").path).to eq("/tmp/preseed/java/java-6.seed") - end - end - - describe "when installing the preseed file to the cache location" do - let(:response_file_destination) { Dir.tmpdir + "/preseed--java--java-6.seed" } - let(:response_file_resource) do - response_file_resource = Chef::Resource::CookbookFile.new(response_file_destination, run_context) - response_file_resource.cookbook_name = "java" - response_file_resource.backup(false) - response_file_resource.source("java.response") - response_file_resource - end - - before do - expect(provider).to receive(:preseed_resource).with("java", "6").and_return(response_file_resource) - end - - after do - FileUtils.rm(response_file_destination) if ::File.exist?(response_file_destination) - end - - it "creates the preseed file in the cache" do - expect(response_file_resource).to receive(:run_action).with(:create) - provider.get_preseed_file("java", "6") - end - - it "returns the path to the response file if the response file was updated" do - expect(provider.get_preseed_file("java", "6")).to eq(response_file_destination) - end - - it "should return false if the response file has not been updated" do - response_file_resource.updated_by_last_action(false) - expect(response_file_resource).not_to be_updated_by_last_action - # don't let the response_file_resource set updated to true - expect(response_file_resource).to receive(:run_action).with(:create) - expect(provider.get_preseed_file("java", "6")).to be(false) - end - - end - - end end describe "Subclass with use_multipackage_api" do @@ -622,22 +472,6 @@ describe "Subclass with use_multipackage_api" do expect(new_resource).to be_updated_by_last_action expect(new_resource.version).to eql(nil) end - - it "when user passes string to package_name, passes arrays to reconfig_package" do - new_resource.package_name "vim" - current_resource.package_name "vim" - current_resource.version [ "1.0" ] - allow(new_resource).to receive(:response_file).and_return(true) - expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test") - allow(provider).to receive(:preseed_package).and_return(true) - allow(provider).to receive(:reconfig_package).and_return(true) - expect(provider).to receive(:reconfig_package).with( - [ "vim" ], - [ "1.0" ] - ).and_return(true) - provider.run_action(:reconfig) - expect(new_resource).to be_updated_by_last_action - end end describe "Chef::Provider::Package - Multi" do diff --git a/spec/unit/resource/apt_package_spec.rb b/spec/unit/resource/apt_package_spec.rb index 66fe05ef33..c39c768ae2 100644 --- a/spec/unit/resource/apt_package_spec.rb +++ b/spec/unit/resource/apt_package_spec.rb @@ -53,4 +53,14 @@ describe Chef::Resource::AptPackage, "initialize" do it "should preserve configuration files by default" do expect(resource.overwrite_config_files).to eql(false) end + + it "accepts a string for the response file" do + resource.response_file "something" + expect(resource.response_file).to eql("something") + end + + it "accepts a hash for response file template variables" do + resource.response_file_variables({ variables: true }) + expect(resource.response_file_variables).to eql({ variables: true }) + end end diff --git a/spec/unit/resource/dpkg_package_spec.rb b/spec/unit/resource/dpkg_package_spec.rb index ff32d7e413..562dbeef76 100644 --- a/spec/unit/resource/dpkg_package_spec.rb +++ b/spec/unit/resource/dpkg_package_spec.rb @@ -36,6 +36,16 @@ describe Chef::Resource::DpkgPackage, "initialize" do expect(resource.action).to eql([:install]) end + it "accepts a string for the response file" do + resource.response_file "something" + expect(resource.response_file).to eql("something") + end + + it "accepts a hash for response file template variables" do + resource.response_file_variables({ variables: true }) + expect(resource.response_file_variables).to eql({ variables: true }) + end + it "supports :install, :lock, :purge, :reconfig, :remove, :unlock, :upgrade actions" do expect { resource.action :install }.not_to raise_error expect { resource.action :lock }.not_to raise_error diff --git a/spec/unit/resource/package_spec.rb b/spec/unit/resource/package_spec.rb index b0e1304775..6e3d609e4b 100644 --- a/spec/unit/resource/package_spec.rb +++ b/spec/unit/resource/package_spec.rb @@ -50,16 +50,6 @@ describe Chef::Resource::Package do expect(resource.version).to eql("something") end - it "accepts a string for the response file" do - resource.response_file "something" - expect(resource.response_file).to eql("something") - end - - it "accepts a hash for response file template variables" do - resource.response_file_variables({ variables: true }) - expect(resource.response_file_variables).to eql({ variables: true }) - end - it "accepts a string for the source" do resource.source "something" expect(resource.source).to eql("something") |