summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md42
-rw-r--r--Dockerfile2
-rw-r--r--Gemfile.lock10
-rw-r--r--VERSION2
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--lib/chef/provider/package.rb39
-rw-r--r--lib/chef/provider/package/apt.rb7
-rw-r--r--lib/chef/provider/package/chocolatey.rb11
-rw-r--r--lib/chef/provider/package/dnf.rb4
-rw-r--r--lib/chef/provider/package/dnf/dnf_helper.py10
-rw-r--r--lib/chef/provider/package/dnf/python_helper.rb15
-rw-r--r--lib/chef/provider/package/rpm.rb5
-rw-r--r--lib/chef/provider/package/windows.rb15
-rw-r--r--lib/chef/provider/package/yum.rb24
-rw-r--r--lib/chef/provider/zypper_repository.rb112
-rw-r--r--lib/chef/resource/zypper_repository.rb1
-rw-r--r--lib/chef/version.rb2
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb5
-rw-r--r--spec/unit/provider/zypper_repository_spec.rb124
-rw-r--r--spec/unit/resource/zypper_repository_spec.rb20
20 files changed, 380 insertions, 72 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f0e6f4c5e..6d20d63ebd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,34 +1,40 @@
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
-<!-- latest_release 13.5.6 -->
-## [v13.5.6](https://github.com/chef/chef/tree/v13.5.6) (2017-09-29)
+<!-- latest_release 13.5.8 -->
+## [v13.5.8](https://github.com/chef/chef/tree/v13.5.8) (2017-10-03)
#### Merged Pull Requests
-- Bump InSpec to v1.40.0 [#6460](https://github.com/chef/chef/pull/6460) ([adamleff](https://github.com/adamleff))
+- Fixes to package upgrade behaviour [#6428](https://github.com/chef/chef/pull/6428) ([jonlives](https://github.com/jonlives))
<!-- latest_release -->
-<!-- release_rollup since=12.21.14 -->
-### Changes since 12.21.14 release
+<!-- release_rollup since=13.5.3 -->
+### Changes since 13.5.3 release
#### Merged Pull Requests
-- Bump InSpec to v1.40.0 [#6460](https://github.com/chef/chef/pull/6460) ([adamleff](https://github.com/adamleff)) <!-- 13.5.6 -->
-- Force encoding to UTF_8 in chef-shell to prevent failures [#6447](https://github.com/chef/chef/pull/6447) ([tas50](https://github.com/tas50)) <!-- 13.5.5 -->
+- Fixes to package upgrade behaviour [#6428](https://github.com/chef/chef/pull/6428) ([jonlives](https://github.com/jonlives)) <!-- 13.5.8 -->
+- Import the zypper GPG key before templating the repo [#6410](https://github.com/chef/chef/pull/6410) ([tas50](https://github.com/tas50)) <!-- 13.5.7 -->
- only warn about skipping sync once [#6454](https://github.com/chef/chef/pull/6454) ([Happycoil](https://github.com/Happycoil)) <!-- 13.5.4 -->
-- Replace which apt-get check with simple debian check in apt resources [#6409](https://github.com/chef/chef/pull/6409) ([tas50](https://github.com/tas50)) <!-- 13.4.25 -->
-- Quiet the output of the zypper refresh and add force [#6408](https://github.com/chef/chef/pull/6408) ([tas50](https://github.com/tas50)) <!-- 13.4.26 -->
-- Remove unused requires in yum_repository [#6413](https://github.com/chef/chef/pull/6413) ([tas50](https://github.com/tas50)) <!-- 13.4.27 -->
-- Open apt resources up to prevent breaking change [#6417](https://github.com/chef/chef/pull/6417) ([tas50](https://github.com/tas50)) <!-- 13.4.28 -->
-- Don&#39;t catch SIGCHLD from dnf_helper.py [#6416](https://github.com/chef/chef/pull/6416) ([nemith](https://github.com/nemith)) <!-- 13.4.29 -->
-- Add throttle and metalink options to yum_repository [#6431](https://github.com/chef/chef/pull/6431) ([tas50](https://github.com/tas50)) <!-- 13.4.31 -->
-- Fix Knife search ID only option to actually filter result set [#6438](https://github.com/chef/chef/pull/6438) ([dimsh99](https://github.com/dimsh99)) <!-- 13.4.32 -->
-- Update dependencies to pull in InSpec v1.39.1 [#6440](https://github.com/chef/chef/pull/6440) ([adamleff](https://github.com/adamleff)) <!-- 13.4.34 -->
-- Only accept MM/DD/YYYY for windows_task start_day [#6434](https://github.com/chef/chef/pull/6434) ([jaym](https://github.com/jaym)) <!-- 13.4.35 -->
-- fix password property is sensitive for mount resource [#6442](https://github.com/chef/chef/pull/6442) ([dimsh99](https://github.com/dimsh99)) <!-- 13.4.36 -->
+- Force encoding to UTF_8 in chef-shell to prevent failures [#6447](https://github.com/chef/chef/pull/6447) ([tas50](https://github.com/tas50)) <!-- 13.5.5 -->
+- Bump InSpec to v1.40.0 [#6460](https://github.com/chef/chef/pull/6460) ([adamleff](https://github.com/adamleff)) <!-- 13.5.6 -->
<!-- release_rollup -->
<!-- latest_stable_release -->
-## [v12.21.14](https://github.com/chef/chef/tree/v12.21.14) (2017-09-27)
+## [v13.5.3](https://github.com/chef/chef/tree/v13.5.3) (2017-10-03)
+
+#### Merged Pull Requests
+- fix password property is sensitive for mount resource [#6442](https://github.com/chef/chef/pull/6442) ([dimsh99](https://github.com/dimsh99))
+- Only accept MM/DD/YYYY for windows_task start_day [#6434](https://github.com/chef/chef/pull/6434) ([jaym](https://github.com/jaym))
+- Update dependencies to pull in InSpec v1.39.1 [#6440](https://github.com/chef/chef/pull/6440) ([adamleff](https://github.com/adamleff))
+- Fix Knife search ID only option to actually filter result set [#6438](https://github.com/chef/chef/pull/6438) ([dimsh99](https://github.com/dimsh99))
+- Add throttle and metalink options to yum_repository [#6431](https://github.com/chef/chef/pull/6431) ([tas50](https://github.com/tas50))
+- Don&#39;t catch SIGCHLD from dnf_helper.py [#6416](https://github.com/chef/chef/pull/6416) ([nemith](https://github.com/nemith))
+- Open apt resources up to prevent breaking change [#6417](https://github.com/chef/chef/pull/6417) ([tas50](https://github.com/tas50))
+- Remove unused requires in yum_repository [#6413](https://github.com/chef/chef/pull/6413) ([tas50](https://github.com/tas50))
+- Quiet the output of the zypper refresh and add force [#6408](https://github.com/chef/chef/pull/6408) ([tas50](https://github.com/tas50))
+- Replace which apt-get check with simple debian check in apt resources [#6409](https://github.com/chef/chef/pull/6409) ([tas50](https://github.com/tas50))
<!-- latest_stable_release -->
+## [v12.21.14](https://github.com/chef/chef/tree/v12.21.14) (2017-09-27)
+
## [v13.4.24](https://github.com/chef/chef/tree/v13.4.24) (2017-09-14)
#### Merged Pull Requests
diff --git a/Dockerfile b/Dockerfile
index 51e1669a26..25e6b5ff0b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,7 +2,7 @@ FROM busybox
MAINTAINER Chef Software, Inc. <docker@chef.io>
ARG CHANNEL=stable
-ARG VERSION=12.21.14
+ARG VERSION=13.5.3
RUN wget "http://packages.chef.io/files/${CHANNEL}/chef/${VERSION}/el/5/chef-${VERSION}-1.el5.x86_64.rpm" -O /tmp/chef-client.rpm && \
rpm2cpio /tmp/chef-client.rpm | cpio -idmv && \
diff --git a/Gemfile.lock b/Gemfile.lock
index ee88c25abc..6b60b069d9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -17,10 +17,10 @@ GIT
PATH
remote: .
specs:
- chef (13.5.6)
+ chef (13.5.8)
addressable
bundler (>= 1.10)
- chef-config (= 13.5.6)
+ chef-config (= 13.5.8)
chef-zero (>= 13.0)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
@@ -47,10 +47,10 @@ PATH
specinfra (~> 2.10)
syslog-logger (~> 1.6)
uuidtools (~> 2.1.5)
- chef (13.5.6-universal-mingw32)
+ chef (13.5.8-universal-mingw32)
addressable
bundler (>= 1.10)
- chef-config (= 13.5.6)
+ chef-config (= 13.5.8)
chef-zero (>= 13.0)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
@@ -92,7 +92,7 @@ PATH
PATH
remote: chef-config
specs:
- chef-config (13.5.6)
+ chef-config (13.5.8)
addressable
fuzzyurl
mixlib-config (~> 2.0)
diff --git a/VERSION b/VERSION
index c50c58133e..3c437d6e8f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-13.5.6 \ No newline at end of file
+13.5.8 \ No newline at end of file
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index f144a36c63..b5e461f962 100644
--- a/chef-config/lib/chef-config/version.rb
+++ b/chef-config/lib/chef-config/version.rb
@@ -21,7 +21,7 @@
module ChefConfig
CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__)
- VERSION = "13.5.6"
+ VERSION = "13.5.8"
end
#
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index 4810728524..95d16dd666 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -323,10 +323,38 @@ class Chef
#
# Note that most likely we need a spaceship operator on versions that subclasses can implement
# and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`.
+
+ # This method performs a strict equality check between two strings representing version numbers
#
+ # This function will eventually be deprecated in favour of the below version_equals function.
+
def target_version_already_installed?(current_version, target_version)
- return false unless current_version && target_version
- current_version == target_version
+ version_equals?(current_version, target_version)
+ end
+
+ # Note that most likely we need a spaceship operator on versions that subclasses can implement
+ # and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`.
+
+ # This method performs a strict equality check between two strings representing version numbers
+ #
+ def version_equals?(v1, v2)
+ return false unless v1 && v2
+ v1 == v2
+ end
+
+ # This function compares two version numbers and returns 'spaceship operator' style results, ie:
+ # if v1 < v2 then return -1
+ # if v1 = v2 then return 0
+ # if v1 > v2 then return 1
+ # if v1 and v2 are not comparable then return nil
+ #
+ # By default, this function will use Gem::Version comparison. Subclasses can reimplement this method
+ # for package-management system specific versions.
+ def version_compare(v1, v2)
+ gem_v1 = Gem::Version.new(v1)
+ gem_v2 = Gem::Version.new(v2)
+
+ gem_v1 <=> gem_v2
end
# Check the current_version against the new_resource.version, possibly using fuzzy
@@ -439,16 +467,19 @@ class Chef
each_package do |package_name, new_version, current_version, candidate_version|
case action
when :upgrade
- if target_version_already_installed?(current_version, new_version)
+ if version_equals?(current_version, new_version)
# this is an odd use case
Chef::Log.debug("#{new_resource} #{package_name} #{new_version} is already installed -- you are equality pinning with an :upgrade action, this may be deprecated in the future")
target_version_array.push(nil)
- elsif target_version_already_installed?(current_version, candidate_version)
+ elsif version_equals?(current_version, candidate_version)
Chef::Log.debug("#{new_resource} #{package_name} #{candidate_version} is already installed")
target_version_array.push(nil)
elsif candidate_version.nil?
Chef::Log.debug("#{new_resource} #{package_name} has no candidate_version to upgrade to")
target_version_array.push(nil)
+ elsif version_compare(current_version, candidate_version) == 1 && !new_resource.allow_downgrade
+ Chef::Log.debug("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{candidate_version}. Skipping...)")
+ target_version_array.push(nil)
else
Chef::Log.debug("#{new_resource} #{package_name} is out of date, will upgrade to #{candidate_version}")
target_version_array.push(candidate_version)
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index 3f8c34f50c..da86016621 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -127,6 +127,13 @@ class Chef
private
+ def version_compare(v1, v2)
+ gem_v1 = v1.gsub(/[_+]/, "+" => "-", "_" => "-") unless v1.nil?
+ gem_v2 = v2.gsub(/[_+]/, "+" => "-", "_" => "-") unless v2.nil?
+
+ Gem::Version.new(gem_v1) <=> Gem::Version.new(gem_v2)
+ 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.
diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb
index a1ec4504a0..c832116377 100644
--- a/lib/chef/provider/package/chocolatey.rb
+++ b/lib/chef/provider/package/chocolatey.rb
@@ -141,6 +141,17 @@ EOS
private
+ def version_compare(v1, v2)
+ if v1 == "latest" || v2 == "latest"
+ return 0
+ end
+
+ gem_v1 = Gem::Version.new(v1)
+ gem_v2 = Gem::Version.new(v2)
+
+ gem_v1 <=> gem_v2
+ end
+
# Magic to find where chocolatey is installed in the system, and to
# return the full path of choco.exe
#
diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb
index 31279e8312..a602a9b768 100644
--- a/lib/chef/provider/package/dnf.rb
+++ b/lib/chef/provider/package/dnf.rb
@@ -126,6 +126,10 @@ class Chef
end
end
+ def version_compare(v1, v2)
+ python_helper.compare_versions(v1, v2)
+ end
+
# @returns Array<Version>
def available_version(index)
@available_version ||= []
diff --git a/lib/chef/provider/package/dnf/dnf_helper.py b/lib/chef/provider/package/dnf/dnf_helper.py
index eb4d238f65..501d6fceee 100644
--- a/lib/chef/provider/package/dnf/dnf_helper.py
+++ b/lib/chef/provider/package/dnf/dnf_helper.py
@@ -26,6 +26,14 @@ def flushcache():
pass
get_sack().load_system_repo(build_cache=True)
+def versioncompare(versions):
+ sack = get_sack()
+ if (versions[0] is None) or (versions[1] is None):
+ sys.stdout.write('0\n')
+ else:
+ evr_comparison = sack.evr_cmp(versions[0], versions[1])
+ sys.stdout.write('{}\n'.format(evr_comparison))
+
def query(command):
sack = get_sack()
@@ -86,5 +94,7 @@ while 1:
query(command)
elif command['action'] == "flushcache":
flushcache()
+ elif command['action'] == "versioncompare":
+ versioncompare(command['versions'])
else:
raise RuntimeError("bad command")
diff --git a/lib/chef/provider/package/dnf/python_helper.rb b/lib/chef/provider/package/dnf/python_helper.rb
index 04f0298861..1801caa1c1 100644
--- a/lib/chef/provider/package/dnf/python_helper.rb
+++ b/lib/chef/provider/package/dnf/python_helper.rb
@@ -61,6 +61,15 @@ class Chef
start if stdin.nil?
end
+ def compare_versions(version1, version2)
+ with_helper do
+ json = build_version_query("versioncompare", [version1, version2])
+ Chef::Log.debug "sending '#{json}' to python helper"
+ stdin.syswrite json + "\n"
+ stdout.sysread(4096).chomp.to_i
+ end
+ end
+
# @returns Array<Version>
def query(action, provides, version = nil, arch = nil)
with_helper do
@@ -109,6 +118,12 @@ class Chef
FFI_Yajl::Encoder.encode(hash)
end
+ def build_version_query(action, versions)
+ hash = { "action" => action }
+ hash["versions"] = versions
+ FFI_Yajl::Encoder.encode(hash)
+ end
+
def parse_response(output)
array = output.split.map { |x| x == "nil" ? nil : x }
array.each_slice(3).map { |x| Version.new(*x) }.first
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index 7ec24f8c24..07617c814e 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -18,6 +18,7 @@
require "chef/provider/package"
require "chef/resource/package"
require "chef/mixin/get_source_from_package"
+require "chef/provider/package/yum/rpm_utils"
class Chef
class Provider
@@ -109,6 +110,10 @@ class Chef
private
+ def version_compare(v1, v2)
+ Chef::Provider::Package::Yum::RPMVersion.parse(v1) <=> Chef::Provider::Package::Yum::RPMVersion.parse(v2)
+ end
+
def uri_scheme?(str)
scheme = URI.split(str).first
return false unless scheme
diff --git a/lib/chef/provider/package/windows.rb b/lib/chef/provider/package/windows.rb
index ca9d1e813a..bade7f27a3 100644
--- a/lib/chef/provider/package/windows.rb
+++ b/lib/chef/provider/package/windows.rb
@@ -165,6 +165,10 @@ class Chef
#
# @return [Boolean] true if new_version is equal to or included in current_version
def target_version_already_installed?(current_version, new_version)
+ version_equals?(current_version, new_version)
+ end
+
+ def version_equals?(current_version, new_version)
Chef::Log.debug("Checking if #{new_resource} version '#{new_version}' is already installed. #{current_version} is currently installed")
if current_version.is_a?(Array)
current_version.include?(new_version)
@@ -179,6 +183,17 @@ class Chef
private
+ def version_compare(v1, v2)
+ if v1 == "latest" || v2 == "latest"
+ return 0
+ end
+
+ gem_v1 = Gem::Version.new(v1)
+ gem_v2 = Gem::Version.new(v2)
+
+ gem_v1 <=> gem_v2
+ end
+
def uninstall_registry_entries
@uninstall_registry_entries ||= Chef::Provider::Package::Windows::RegistryUninstallEntry.find_entries(new_resource.package_name)
end
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index d87e421409..7129104224 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -156,26 +156,6 @@ class Chef
yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} versionlock delete #{unlock_str}")
end
- # Keep upgrades from trying to install an older candidate version. Can happen when a new
- # version is installed then removed from a repository, now the older available version
- # shows up as a viable install candidate.
- #
- # Can be done in upgrade_package but an upgraded from->to log message slips out
- #
- # Hacky - better overall solution? Custom compare in Package provider?
- def action_upgrade
- # Could be uninstalled or have no candidate
- if current_resource.version.nil? || !candidate_version_array.any?
- super
- elsif candidate_version_array.zip(current_version_array).any? do |c, i|
- RPMVersion.parse(c) > RPMVersion.parse(i)
- end
- super
- else
- Chef::Log.debug("#{new_resource} is at the latest version - nothing to do")
- end
- end
-
private
#
@@ -190,6 +170,10 @@ class Chef
end
end
+ def version_compare(v1, v2)
+ RPMVersion.parse(v1) <=> RPMVersion.parse(v2)
+ end
+
# Enable or disable YumCache extra_repo_control
def manage_extra_repo_control
if new_resource.options
diff --git a/lib/chef/provider/zypper_repository.rb b/lib/chef/provider/zypper_repository.rb
index e6fd917d77..31cf8839b2 100644
--- a/lib/chef/provider/zypper_repository.rb
+++ b/lib/chef/provider/zypper_repository.rb
@@ -18,24 +18,25 @@
require "chef/resource"
require "chef/dsl/declare_resource"
-require "chef/mixin/which"
require "chef/provider/noop"
+require "chef/mixin/shell_out"
require "shellwords"
class Chef
class Provider
class ZypperRepository < Chef::Provider
-
- extend Chef::Mixin::Which
-
- provides :zypper_repository do
- which "zypper"
- end
+ provides :zypper_repository, platform_family: "suse"
def load_current_resource
end
action :create do
+ if new_resource.gpgautoimportkeys
+ install_gpg_key(new_resource.gpgkey)
+ else
+ Chef::Log.debug("'gpgautoimportkeys' property is set to false. Skipping key import.")
+ end
+
declare_resource(:template, "/etc/zypp/repos.d/#{escaped_repo_name}.repo") do
if template_available?(new_resource.source)
source new_resource.source
@@ -51,14 +52,14 @@ class Chef
end
action :delete do
- declare_resource(:execute, "zypper removerepo #{escaped_repo_name}") do
- only_if "zypper lr #{escaped_repo_name}"
+ declare_resource(:execute, "zypper --quiet --non-interactive removerepo #{escaped_repo_name}") do
+ only_if "zypper --quiet lr #{escaped_repo_name}"
end
end
action :refresh do
- declare_resource(:execute, "zypper#{' --gpg-auto-import-keys' if new_resource.gpgautoimportkeys} --quiet --no-confirm refresh --force #{escaped_repo_name}") do
- only_if "zypper lr #{escaped_repo_name}"
+ declare_resource(:execute, "zypper --quiet --non-interactive refresh --force #{escaped_repo_name}") do
+ only_if "zypper --quiet lr #{escaped_repo_name}"
end
end
@@ -66,14 +67,101 @@ class Chef
alias_method :action_remove, :action_delete
# zypper repos are allowed to have spaces in the names
+ # @return [String] escaped repo string
def escaped_repo_name
Shellwords.escape(new_resource.repo_name)
end
+ # return the specified cookbook name or the cookbook containing the
+ # resource.
+ #
+ # @return [String] name of the cookbook
+ def cookbook_name
+ new_resource.cookbook || new_resource.cookbook_name
+ end
+
+ # determine if a template file is available in the current run
+ # @param [String] path the path to the template file
+ #
+ # @return [Boolean] template file exists or doesn't
def template_available?(path)
- !path.nil? && run_context.has_template_in_cookbook?(new_resource.cookbook_name, path)
+ !path.nil? && run_context.has_template_in_cookbook?(cookbook_name, path)
+ end
+
+ # determine if a cookbook file is available in the run
+ # @param [String] path the path to the template file
+ #
+ # @return [Boolean] cookbook file exists or doesn't
+ def has_cookbook_file?(fn)
+ run_context.has_cookbook_file_in_cookbook?(cookbook_name, fn)
+ end
+
+ # Given the provided key URI determine what kind of chef resource we need
+ # to fetch the key
+ # @param [String] uri the uri of the gpg key (local path or http URL)
+ #
+ # @raise [Chef::Exceptions::FileNotFound] Key isn't remote or found in the current run
+ #
+ # @return [Symbol] :remote_file or :cookbook_file
+ def key_type(uri)
+ if uri.start_with?("http")
+ Chef::Log.debug("Will use :remote_file resource to cache the gpg key locally")
+ :remote_file
+ elsif has_cookbook_file?(uri)
+ Chef::Log.debug("Will use :cookbook_file resource to cache the gpg key locally")
+ :cookbook_file
+ else
+ raise Chef::Exceptions::FileNotFound, "Cannot determine location of gpgkey. Must start with 'http' or be a file managed by Chef."
+ end
end
+ # is the provided key already installed
+ # @param [String] key_path the path to the key on the local filesystem
+ #
+ # @return [boolean] is the key already known by rpm
+ def key_installed?(key_path)
+ so = shell_out("rpm -qa gpg-pubkey*")
+ # expected output & match: http://rubular.com/r/RdF7EcXEtb
+ status = /gpg-pubkey-#{key_fingerprint(key_path)}/.match(so.stdout)
+ Chef::Log.debug("GPG key at #{key_path} is known by rpm? #{status ? "true" : "false"}")
+ status
+ end
+
+ # extract the gpg key fingerprint from a local file
+ # @param [String] key_path the path to the key on the local filesystem
+ #
+ # @return [String] the fingerprint of the key
+ def key_fingerprint(key_path)
+ so = shell_out!("gpg --with-fingerprint #{key_path}")
+ # expected output and match: http://rubular.com/r/BpfMjxySQM
+ fingerprint = /pub\s*\S*\/(\S*)/.match(so.stdout)[1].downcase
+ Chef::Log.debug("GPG fingerprint of key at #{key_path} is #{fingerprint}")
+ fingerprint
+ end
+
+ # install the provided gpg key
+ # @param [String] uri the uri of the local or remote gpg key
+ def install_gpg_key(uri)
+ unless uri
+ Chef::Log.debug("'gpgkey' property not provided or set to nil. Skipping key import.")
+ return
+ end
+
+ cached_keyfile = ::File.join(Chef::Config[:file_cache_path], uri.split("/")[-1])
+
+ declare_resource(key_type(new_resource.gpgkey), cached_keyfile) do
+ source uri
+ mode "0644"
+ sensitive new_resource.sensitive
+ action :create
+ end
+
+ declare_resource(:execute, "import gpg key from #{new_resource.gpgkey}") do
+ command "/bin/rpm --import #{cached_keyfile}"
+ not_if { key_installed?(cached_keyfile) }
+ action :run
+ end
+ end
end
end
end
diff --git a/lib/chef/resource/zypper_repository.rb b/lib/chef/resource/zypper_repository.rb
index 69a96b42cf..88b6fd9336 100644
--- a/lib/chef/resource/zypper_repository.rb
+++ b/lib/chef/resource/zypper_repository.rb
@@ -39,6 +39,7 @@ class Chef
property :mode, default: "0644"
property :refresh_cache, [true, false], default: true
property :source, String, regex: /.*/
+ property :cookbook, String
property :gpgautoimportkeys, [true, false], default: true
default_action :create
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 63fd85c63c..01139015cf 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -23,7 +23,7 @@ require "chef/version_string"
class Chef
CHEF_ROOT = File.expand_path("../..", __FILE__)
- VERSION = Chef::VersionString.new("13.5.6")
+ VERSION = Chef::VersionString.new("13.5.8")
end
#
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index 856f8d460c..ac2b511ca9 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -383,6 +383,11 @@ describe Chef::Provider::Package::Rubygems do
provider.load_current_resource
expect(provider.target_version_already_installed?(provider.current_resource.version, new_resource.version)).to be_falsey
end
+
+ it "version_equals? should return false so that we can search for candidates" do
+ provider.load_current_resource
+ expect(provider.version_equals?(provider.current_resource.version, new_resource.version)).to be_falsey
+ end
end
describe "when new_resource version is an rspec version" do
diff --git a/spec/unit/provider/zypper_repository_spec.rb b/spec/unit/provider/zypper_repository_spec.rb
new file mode 100644
index 0000000000..a366a33e86
--- /dev/null
+++ b/spec/unit/provider/zypper_repository_spec.rb
@@ -0,0 +1,124 @@
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: 2017, 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"
+
+# Output of the command:
+# => rpm -qa gpg-pubkey*
+RPM_KEYS = <<-EOF
+gpg-pubkey-307e3d54-4be01a65
+gpg-pubkey-3dbdc284-53674dd4
+EOF
+
+# Output of the command:
+# => gpg --with-fingerprint [FILE]
+GPG_FINGER = <<-EOF
+pub 2048R/3DBDC284 2011-08-19 [expires: 2024-06-14]
+ Key fingerprint = 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62
+uid nginx signing key <signing-key@nginx.com>
+EOF
+
+describe Chef::Provider::ZypperRepository do
+ let(:new_resource) { Chef::Resource::ZypperRepository.new("Nginx Repository") }
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::ZypperRepository.new(new_resource, run_context)
+ end
+
+ let(:rpm_key_finger) do
+ double("shell_out_with_systems_locale", stdout: RPM_KEYS, exitstatus: 0, error?: false)
+ end
+
+ let(:gpg_finger) do
+ double("shell_out_with_systems_locale", stdout: GPG_FINGER, exitstatus: 0, error?: false)
+ end
+
+ it "responds to load_current_resource" do
+ expect(provider).to respond_to(:load_current_resource)
+ end
+
+ describe "#action_create" do
+ it "skips key import if gpgautoimportkeys is false" do
+ new_resource.gpgautoimportkeys(false)
+ expect(provider).to receive(:declare_resource)
+ expect(Chef::Log).to receive(:debug)
+ provider.run_action(:create)
+ end
+ end
+
+ describe "#escaped_repo_name" do
+ it "returns an escaped repo name" do
+ expect(provider.escaped_repo_name).to eq('Nginx\\ Repository')
+ end
+ end
+
+ describe "#cookbook_name" do
+ it "returns 'test' when the cookbook property is set" do
+ new_resource.cookbook("test")
+ expect(provider.cookbook_name).to eq("test")
+ end
+ end
+
+ describe "#key_type" do
+ it "returns :remote_file with an http URL" do
+ expect(provider.key_type("https://www.chef.io/key")).to eq(:remote_file)
+ end
+
+ it "returns :cookbook_file with a chef managed file" do
+ expect(provider).to receive(:has_cookbook_file?).and_return(true)
+ expect(provider.key_type("/foo/nginx.key")).to eq(:cookbook_file)
+ end
+
+ it "throws exception if an unknown file specified" do
+ expect(provider).to receive(:has_cookbook_file?).and_return(false)
+ expect { provider.key_type("/foo/nginx.key") }.to raise_error(Chef::Exceptions::FileNotFound)
+ end
+ end
+
+ describe "#key_installed?" do
+ before do
+ expect(provider).to receive(:shell_out).with("rpm -qa gpg-pubkey*").and_return(rpm_key_finger)
+ end
+
+ it "returns true if the key is installed" do
+ expect(provider).to receive(:key_fingerprint).and_return("3dbdc284")
+ expect(provider.key_installed?("/foo/nginx.key")).to be_truthy
+ end
+
+ it "returns false if the key is not installed" do
+ expect(provider).to receive(:key_fingerprint).and_return("BOGUS")
+ expect(provider.key_installed?("/foo/nginx.key")).to be_falsey
+ end
+ end
+
+ describe "#key_fingerprint" do
+ it "returns the key's fingerprint" do
+ expect(provider).to receive(:shell_out!).with("gpg --with-fingerprint /foo/nginx.key").and_return(gpg_finger)
+ expect(provider.key_fingerprint("/foo/nginx.key")).to eq("3dbdc284")
+ end
+ end
+
+ describe "#install_gpg_key" do
+ it "skips installing the key if a nil value for key is passed" do
+ expect(Chef::Log).to receive(:debug)
+ provider.install_gpg_key(nil)
+ end
+ end
+end
diff --git a/spec/unit/resource/zypper_repository_spec.rb b/spec/unit/resource/zypper_repository_spec.rb
index 16951d071c..de08b183a5 100644
--- a/spec/unit/resource/zypper_repository_spec.rb
+++ b/spec/unit/resource/zypper_repository_spec.rb
@@ -46,20 +46,22 @@ describe Chef::Resource::ZypperRepository do
expect { resource.action :delete }.to raise_error(ArgumentError)
end
- it "should resolve to a Noop class when zypper is not found" do
- expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(false)
+ it "resolves to a Noop class when on non-linux OS" do
+ node.automatic[:os] = "windows"
+ node.automatic[:platform_family] = "windows"
expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
end
- it "should resolve to a ZypperRepository class when zypper is found" do
- expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(true)
- expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository)
+ it "resolves to a Noop class when on non-suse linux" do
+ node.automatic[:os] = "linux"
+ node.automatic[:platform_family] = "debian"
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
end
- end
- context "on windows", :windows_only do
- it "should resolve to a NoOp provider" do
- expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
+ it "resolves to a ZypperRepository class when on a suse platform_family" do
+ node.automatic[:os] = "linux"
+ node.automatic[:platform_family] = "suse"
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository)
end
end
end