summaryrefslogtreecommitdiff
path: root/lib/chef/provider/package/yum.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/provider/package/yum.rb')
-rw-r--r--lib/chef/provider/package/yum.rb168
1 files changed, 117 insertions, 51 deletions
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index 505f5fd6a3..405e4177ab 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -18,7 +18,7 @@
require 'chef/config'
require 'chef/provider/package'
-require 'chef/mixin/command'
+require 'chef/mixin/command' # handle_command_failures
require 'chef/mixin/shell_out'
require 'chef/resource/package'
require 'singleton'
@@ -976,14 +976,6 @@ class Chef
end
end
- def allow_downgrade
- if @new_resource.respond_to?("allow_downgrade")
- @new_resource.allow_downgrade
- else
- false
- end
- end
-
# Helpers
#
@@ -1018,7 +1010,7 @@ class Chef
if status.exitstatus > 0
command_output = "STDOUT: #{stdout}"
command_output << "STDERR: #{stderr}"
- handle_command_failures(status, command_output, {})
+ Chef::Mixin::Command.handle_command_failures(status, command_output, {})
end
end
@@ -1054,9 +1046,20 @@ class Chef
# 3) or a dependency, eg: "foo >= 1.1"
# Check if we have name or name+arch which has a priority over a dependency
- unless @yum.package_available?(@new_resource.package_name)
- # If they aren't in the installed packages they could be a dependency
- parse_dependency
+ package_name_array.each_with_index do |n, index|
+ unless @yum.package_available?(n)
+ # If they aren't in the installed packages they could be a dependency
+ dep = parse_dependency(n, new_version_array[index])
+ if dep
+ if @new_resource.package_name.is_a?(Array)
+ @new_resource.package_name(package_name_array - [n] + [dep.first])
+ @new_resource.version(new_version_array - [new_version_array[index]] + [dep.last]) if dep.last
+ else
+ @new_resource.package_name(dep.first)
+ @new_resource.version(dep.last) if dep.last
+ end
+ end
+ end
end
# Don't overwrite an existing arch
@@ -1090,10 +1093,18 @@ class Chef
Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
- installed_version = @yum.installed_version(@new_resource.package_name, arch)
- @current_resource.version(installed_version)
-
- @candidate_version = @yum.candidate_version(@new_resource.package_name, arch)
+ installed_version = []
+ @candidate_version = []
+ package_name_array.each do |pkg|
+ installed_version << @yum.installed_version(pkg, arch)
+ @candidate_version << @yum.candidate_version(pkg, arch)
+ end
+ if installed_version.size == 1
+ @current_resource.version(installed_version[0])
+ @candidate_version = @candidate_version[0]
+ else
+ @current_resource.version(installed_version)
+ end
Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " +
"#{@candidate_version || "(none)"}")
@@ -1101,43 +1112,77 @@ class Chef
@current_resource
end
- def install_package(name, version)
- if @new_resource.source
- yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
- else
- # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062
- if @yum.version_available?(name, version, arch)
+ def install_remote_package(name, version)
+ # Work around yum not exiting with an error if a package doesn't exist
+ # for CHEF-2062
+ all_avail = as_array(name).zip(as_array(version)).any? do |n, v|
+ @yum.version_available?(n, v, arch)
+ end
+ method = log_method = nil
+ methods = []
+ if all_avail
+ # More Yum fun:
+ #
+ # yum install of an old name+version will exit(1)
+ # yum install of an old name+version+arch will exit(0) for some reason
+ #
+ # Some packages can be installed multiple times like the kernel
+ as_array(name).zip(as_array(version)).each do |n, v|
method = "install"
log_method = "installing"
-
- # More Yum fun:
- #
- # yum install of an old name+version will exit(1)
- # yum install of an old name+version+arch will exit(0) for some reason
- #
- # Some packages can be installed multiple times like the kernel
- unless @yum.allow_multi_install.include?(name)
- if RPMVersion.parse(@current_resource.version) > RPMVersion.parse(version)
- # Unless they want this...
+ idx = package_name_array.index(n)
+ unless @yum.allow_multi_install.include?(n)
+ if RPMVersion.parse(current_version_array[idx]) > RPMVersion.parse(v)
+ # We allow downgrading only in the evenit of single-package
+ # rules where the user explicitly allowed it
if allow_downgrade
method = "downgrade"
log_method = "downgrading"
else
# we bail like yum when the package is older
- raise Chef::Exceptions::Package, "Installed package #{name}-#{@current_resource.version} is newer " +
- "than candidate package #{name}-#{version}"
+ raise Chef::Exceptions::Package, "Installed package #{n}-#{current_version_array[idx]} is newer " +
+ "than candidate package #{n}-#{v}"
end
end
end
+ # methods don't count for packages we won't be touching
+ next if RPMVersion.parse(current_version_array[idx]) == RPMVersion.parse(v)
+ methods << method
+ end
- repo = @yum.package_repository(name, version, arch)
- Chef::Log.info("#{@new_resource} #{log_method} #{name}-#{version}#{yum_arch} from #{repo} repository")
+ # We could split this up into two commands if we wanted to, but
+ # for now, just don't support this.
+ if methods.uniq.length > 1
+ raise Chef::Exceptions::Package, "Multipackage rule #{name} has a mix of upgrade and downgrade packages. Cannot proceed."
+ end
- yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}")
- else
- raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
- "and release? (version-release, e.g. 1.84-10.fc6)"
+ repos = []
+ pkg_string_bits = []
+ index = 0
+ as_array(name).zip(as_array(version)).each do |n, v|
+ s = ''
+ unless v == current_version_array[index]
+ s = "#{n}-#{v}#{yum_arch}"
+ repo = @yum.package_repository(n, v, arch)
+ repos << "#{s} from #{repo} repository"
+ pkg_string_bits << s
+ end
+ index += 1
end
+ pkg_string = pkg_string_bits.join(' ')
+ Chef::Log.info("#{@new_resource} #{log_method} #{repos.join(' ')}")
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{pkg_string}")
+ else
+ raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
+ "and release? (version-release, e.g. 1.84-10.fc6)"
+ end
+ end
+
+ def install_package(name, version)
+ if @new_resource.source
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
+ else
+ install_remote_package(name, version)
end
if flush_cache[:after]
@@ -1156,10 +1201,11 @@ class Chef
# 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.nil?
+ if @current_resource.version.nil? || !candidate_version_array.any?
super
- # Ensure the candidate is newer
- elsif RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version)
+ 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")
@@ -1172,10 +1218,13 @@ class Chef
def remove_package(name, version)
if version
- yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}")
+ remove_str = as_array(name).zip(as_array(version)).map do |x|
+ "#{x.join('-')}#{yum_arch}"
+ end.join(' ')
else
- yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}")
+ remove_str = as_array(name).map { |n| "#{n}#{yum_arch}" }.join(' ')
end
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{remove_str}")
if flush_cache[:after]
@yum.reload
@@ -1218,9 +1267,19 @@ class Chef
# matching them up with an actual package so the standard resource handling can apply.
#
# There is currently no support for filename matching.
- def parse_dependency
+ def parse_dependency(name,version)
# Transform the package_name into a requirement
- yum_require = RPMRequire.parse(@new_resource.package_name)
+
+ # If we are passed a version or a version constraint we have to assume it's a requirement first. If it can't be
+ # parsed only yum_require.name will be set and @new_resource.version will be left intact
+ if version
+ require_string = "#{name} #{version}"
+ else
+ # Transform the package_name into a requirement, might contain a version, could just be
+ # a match for virtual provides
+ require_string = name
+ end
+ yum_require = RPMRequire.parse(require_string)
# and gather all the packages that have a Provides feature satisfying the requirement.
# It could be multiple be we can only manage one
packages = @yum.packages_from_require(yum_require)
@@ -1238,8 +1297,11 @@ class Chef
unless packages.empty?
new_package_name = packages.first.name
- Chef::Log.debug("#{@new_resource} no package found for #{@new_resource.package_name} " +
- "but matched Provides for #{new_package_name}")
+ new_package_version = packages.first.version.to_s
+ debug_msg = "#{name}: Unable to match package '#{name}' but matched #{packages.size} "
+ debug_msg << packages.size == 1 ? "package" : "packages"
+ debug_msg << ", selected '#{new_package_name}' version '#{new_package_version}'"
+ Chef::Log.debug(debug_msg)
# Ensure it's not the same package under a different architecture
unique_names = []
@@ -1254,7 +1316,11 @@ class Chef
"specific version.")
end
- @new_resource.package_name(new_package_name)
+ if yum_require.version.to_s.nil?
+ new_package_version = nil
+ end
+
+ [new_package_name,new_package_version]
end
end