summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/chef/provider/package/yum.rb51
-rw-r--r--lib/chef/provider/package/yum/python_helper.rb106
2 files changed, 120 insertions, 37 deletions
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index 121083ea46..07ed56aaf1 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -36,6 +36,7 @@ class Chef
allow_nils
use_multipackage_api
use_package_name_for_source
+ use_magic_version
provides :package, platform_family: "fedora_derived"
@@ -64,6 +65,16 @@ class Chef
current_resource
end
+ def load_after_resource
+ # force the installed version array to repopulate
+ @current_version = []
+ @after_resource = Chef::Resource::YumPackage.new(new_resource.name)
+ after_resource.package_name(new_resource.package_name)
+ after_resource.version(get_current_versions)
+
+ after_resource
+ end
+
def define_resource_requirements
requirements.assert(:install, :upgrade, :remove, :purge) do |a|
a.assertion { !new_resource.source || ::File.exist?(new_resource.source) }
@@ -80,9 +91,15 @@ class Chef
end
end
+ def magic_version_array
+ package_name_array.each_with_index.map do |pkg, i|
+ magical_version(i).version_with_arch
+ end
+ end
+
def get_current_versions
package_name_array.each_with_index.map do |pkg, i|
- installed_version(i).version_with_arch
+ current_version(i).version_with_arch
end
end
@@ -127,7 +144,7 @@ class Chef
alias upgrade_package install_package
def remove_package(names, versions)
- resolved_names = names.each_with_index.map { |name, i| installed_version(i).to_s unless name.nil? }
+ resolved_names = names.each_with_index.map { |name, i| magical_version(i).to_s unless name.nil? }
yum(options, "-y", "remove", resolved_names)
flushcache
end
@@ -157,10 +174,10 @@ class Chef
def resolved_package_lock_names(names)
names.each_with_index.map do |name, i|
unless name.nil?
- if installed_version(i).version.nil?
+ if magical_version(i).version.nil?
available_version(i).name
else
- installed_version(i).name
+ magical_version(i).name
end
end
end
@@ -226,15 +243,25 @@ class Chef
@available_version[index]
end
+ def magical_version(index)
+ @magical_version ||= []
+ @magical_version[index] ||= if new_resource.source
+ python_helper.package_query(:whatinstalled, available_version(index).name, version: safe_version_array[index], arch: safe_arch_array[index], options: options)
+ else
+ python_helper.package_query(:whatinstalled, package_name_array[index], version: safe_version_array[index], arch: safe_arch_array[index], options: options)
+ end
+ @magical_version[index]
+ end
+
# @return Array<Version>
- def installed_version(index)
- @installed_version ||= []
- @installed_version[index] ||= if new_resource.source
- python_helper.package_query(:whatinstalled, available_version(index).name, arch: safe_arch_array[index], options: options)
- else
- python_helper.package_query(:whatinstalled, package_name_array[index], arch: safe_arch_array[index], options: options)
- end
- @installed_version[index]
+ def current_version(index)
+ @current_version ||= []
+ @current_version[index] ||= if new_resource.source
+ python_helper.package_query(:whatinstalled, available_version(index).name, arch: safe_arch_array[index], options: options)
+ else
+ python_helper.package_query(:whatinstalled, package_name_array[index], arch: safe_arch_array[index], options: options)
+ end
+ @current_version[index]
end
def flushcache
diff --git a/lib/chef/provider/package/yum/python_helper.rb b/lib/chef/provider/package/yum/python_helper.rb
index db929ea88b..6ca5cf5183 100644
--- a/lib/chef/provider/package/yum/python_helper.rb
+++ b/lib/chef/provider/package/yum/python_helper.rb
@@ -115,10 +115,90 @@ class Chef
end
end
+ def is_arch?(arch)
+ # cspell:disable-next
+ arches = %w{alpha alphaev4 alphaev45 alphaev5 alphaev56 alphaev6 alphaev67 alphaev68 alphaev7 alphapca56 amd64 armv5tejl armv5tel armv6l armv7l athlon geode i386 i486 i586 i686 ia32e ia64 noarch ppc ppc64 ppc64iseries ppc64pseries s390 s390x sh3 sh4 sh4a sparc sparc64 sparc64v sparcv8 sparcv9 sparcv9v x86_64}
+ arches.include?(arch)
+ end
+
+ # We have a provides line with an epoch in it and yum cannot parse that, so we
+ # need to deconstruct the args. This doesn't support splats which is why we
+ # only do it for this particularly narrow use case.
+ #
+ # name-epoch:version
+ # name-epoch:version.arch
+ # name-epoch:version-release
+ # name-epoch:version-release.arch
+ #
+ # @api private
+ def deconstruct_args(provides)
+ raise "provides must have an epoch in the version to deconstruct" unless provides =~ /^(\S+)-(\d+):(\S+)/
+
+ name = $1
+ epoch = $2
+ other = $3
+ ret = { "provides" => name, "epoch" => epoch }
+ maybe_arch = other.rpartition(".").last
+ arch = if is_arch?(maybe_arch)
+ other.delete_suffix!(".#{maybe_arch}")
+ maybe_arch
+ end
+ ret.merge!({ "arch" => arch }) if arch
+ (version, _, release) = other.rpartition("-")
+ if version.empty?
+ ret.merge!({ "version" => release }) # yeah, rpartition is just weird
+ else
+ ret.merge!({ "version" => version, "release" => release })
+ end
+ end
+
+ # In the default case for the yum provider we now do terrible things with ruby
+ # to concatenate all the properties together to form a single string to feed to
+ # the python which favors using returnPackages/searchProvides over the
+ # searchNevra API. That means that these two different ways of constructing the
+ # resource are now perfectly identical:
+ #
+ # yum_package "zabbix-agent-4.0.15-1.fc31.x86_64"
+ #
+ # yum_package "zabbix-agent" do
+ # version "4.0.15-1.fc31"
+ # arch "x86_64"
+ # end
+ #
+ # This function handles turning the second form into the first form.
+ #
+ # In the case where the epoch is given in the version and we do not have any glob
+ # patterns that is handled by going the other way and calling deconstruct_args due
+ # to the yum libraries not supporting that calling pattern other than by searchNevra.
+ #
+ # NOTE: This is an ugly hack and should NOT be considered an endorsement of this approach
+ # towards any kind of features or bugfixes in the DNF provider. I'm doing this
+ # because YUM is sunsetting at this point and its very difficult to fight with the
+ # libraries on the python side of things.
+ #
+ # @api private
+ def combine_args(provides, version, arch)
+ provides = provides.dup
+ maybe_arch = provides.rpartition(".").last
+ if is_arch?(maybe_arch)
+ arch = maybe_arch
+ provides.delete_suffix!(".#{arch}")
+ end
+ provides = "#{provides}-#{version}" if version
+ provides = "#{provides}.#{arch}" if arch
+ # yum (on rhel7) can't handle an epoch in provides, but
+ # deconstructing the args can't handle dealing with globs
+ if provides =~ /-\d+:/ && provides !~ /[\*\?]/
+ deconstruct_args(provides)
+ else
+ { "provides" => provides }
+ end
+ end
+
# @return Array<Version>
# NB: "options" here is the yum_package options hash and is deliberately not **opts
def package_query(action, provides, version: nil, arch: nil, options: {})
- parameters = { "provides" => provides, "version" => version, "arch" => arch }
+ parameters = combine_args(provides, version, arch)
repo_opts = options_params(options || {})
parameters.merge!(repo_opts)
# XXX: for now we close the rpmdb before and after every query with an enablerepo/disablerepo to clean the helpers internal state
@@ -137,25 +217,6 @@ class Chef
private
- # i couldn't figure out how to decompose an evr on the python side, it seems reasonably
- # painless to do it in ruby (generally massaging nevras in the ruby side is HIGHLY
- # discouraged -- this is an "every rule has an exception" exception -- any additional
- # functionality should probably trigger moving this regexp logic into python)
- def add_version(hash, version)
- epoch = nil
- if version =~ /(\S+):(\S+)/
- epoch = $1
- version = $2
- end
- if version =~ /(\S+)-(\S+)/
- version = $1
- release = $2
- end
- hash["epoch"] = epoch unless epoch.nil?
- hash["release"] = release unless release.nil?
- hash["version"] = version
- end
-
def query(action, parameters)
with_helper do
json = build_query(action, parameters)
@@ -174,11 +235,6 @@ class Chef
hash[param_name] = param_value unless param_value.nil?
end
- # Special handling for certain action / param combos
- if %i{whatinstalled whatavailable}.include?(action)
- add_version(hash, parameters["version"]) unless parameters["version"].nil?
- end
-
FFI_Yajl::Encoder.encode(hash)
end