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?
# File lib/chef/provider/package/yum.rb, line 1157 def action_upgrade # Could be uninstalled or have no candidate if @current_resource.version.nil? || candidate_version.nil? super # Ensure the candidate is newer elsif RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version) super else Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do") end end
# File lib/chef/provider/package/yum.rb, line 979 def allow_downgrade if @new_resource.respond_to?("allow_downgrade") @new_resource.allow_downgrade else false end end
Extra attributes
# File lib/chef/provider/package/yum.rb, line 963 def arch if @new_resource.respond_to?("arch") @new_resource.arch else nil end end
# File lib/chef/provider/package/yum.rb, line 971 def flush_cache if @new_resource.respond_to?("flush_cache") @new_resource.flush_cache else { :before => false, :after => false } end end
# File lib/chef/provider/package/yum.rb, line 1104 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) 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... 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}" end end end repo = @yum.package_repository(name, version, arch) Chef::Log.info("#{@new_resource} #{log_method} #{name}-#{version}#{yum_arch} from #{repo} repository") 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)" end end if flush_cache[:after] @yum.reload else @yum.reload_installed end end
Standard Provider methods for Parent
# File lib/chef/provider/package/yum.rb, line 1028 def load_current_resource if flush_cache[:before] @yum.reload end if @new_resource.options repo_control = [] @new_resource.options.split.each do |opt| if opt =~ %{--(enable|disable)repo=.+} repo_control << opt end end if repo_control.size > 0 @yum.enable_extra_repo_control(repo_control.join(" ")) else @yum.disable_extra_repo_control end else @yum.disable_extra_repo_control end # At this point package_name could be: # # 1) a package name, eg: "foo" # 2) a package name.arch, eg: "foo.i386" # 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 end # Don't overwrite an existing arch unless arch parse_arch end @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) if @new_resource.source unless ::File.exists?(@new_resource.source) raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" end Chef::Log.debug("#{@new_resource} checking rpm status") shell_out!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line| case line when /([\w\d_.-]+)\s([\w\d_.-]+)/ @current_resource.package_name($1) @new_resource.version($2) end end end if @new_resource.version new_resource = "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch}" else new_resource = "#{@new_resource.package_name}#{yum_arch}" end 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) Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " + "#{@candidate_version || "(none)"}") @current_resource end
# File lib/chef/provider/package/yum.rb, line 1187 def purge_package(name, version) remove_package(name, version) end
# File lib/chef/provider/package/yum.rb, line 1173 def remove_package(name, version) if version yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}") else yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}") end if flush_cache[:after] @yum.reload else @yum.reload_installed end end
# File lib/chef/provider/package/yum.rb, line 1169 def upgrade_package(name, version) install_package(name, version) end
Helpers
# File lib/chef/provider/package/yum.rb, line 990 def yum_arch arch ? ".#{arch}" : nil end
# File lib/chef/provider/package/yum.rb, line 994 def yum_command(command) status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]}) # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't # considered fatal - meaning the rpm is still successfully installed. These issue # cause yum to emit a non fatal warning but still exit(1). As there's currently no # way to suppress this behavior and an exit(1) will break a Chef run we make an # effort to trap these and re-run the same install command - it will either fail a # second time or succeed. # # A cleaner solution would have to be done in python and better hook into # yum/rpm to handle exceptions as we see fit. if status.exitstatus == 1 stdout.each_line do |l| # rpm-4.4.2.3 lib/psm.c line 2182 if l =~ %{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$} Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " + "so running install again to verify.") status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]}) break end end end if status.exitstatus > 0 command_output = "STDOUT: #{stdout}" command_output << "STDERR: #{stderr}" handle_command_failures(status, command_output, {}) end end
Generated with the Darkfish Rdoc Generator 2.