diff --git a/definitions/checks/check_hotfix_installed.rb b/definitions/checks/check_hotfix_installed.rb index 58c21c3d3..ef5c7ac90 100644 --- a/definitions/checks/check_hotfix_installed.rb +++ b/definitions/checks/check_hotfix_installed.rb @@ -4,8 +4,7 @@ class Checks::CheckHotfixInstalled < ForemanMaintain::Check description 'Check to verify if any hotfix installed on system' tags :pre_upgrade preparation_steps do - [Checks::Repositories::CheckNonRhRepository.new, - Procedures::Packages::Install.new(:packages => %w[yum-utils])] + [Checks::Repositories::CheckNonRhRepository.new] end confine do @@ -45,7 +44,7 @@ def modified_files(package) def installed_packages packages = [] - IO.popen(['repoquery', '-a', '--installed', '--qf', query_format]) do |io| + IO.popen(['dnf', 'repoquery', '-a', '--installed', '--qf', query_format]) do |io| io.each do |line| repo, pkg = line.chomp.split next if repo.nil? || pkg.nil? diff --git a/definitions/checks/package_manager/yum/validate_yum_config.rb b/definitions/checks/package_manager/dnf/validate_dnf_config.rb similarity index 58% rename from definitions/checks/package_manager/yum/validate_yum_config.rb rename to definitions/checks/package_manager/dnf/validate_dnf_config.rb index e20b154ef..c7321dd81 100644 --- a/definitions/checks/package_manager/yum/validate_yum_config.rb +++ b/definitions/checks/package_manager/dnf/validate_dnf_config.rb @@ -1,9 +1,9 @@ module Checks::PackageManager - module Yum - class ValidateYumConfig < ForemanMaintain::Check + module Dnf + class ValidateDnfConfig < ForemanMaintain::Check metadata do - label :validate_yum_config - description 'Check to validate yum configuration before upgrade' + label :validate_dnf_config + description 'Check to validate dnf configuration before upgrade' tags :pre_upgrade end @@ -17,30 +17,32 @@ def run private + # rubocop:disable Metrics/LineLength def failure_message(final_result) verb_string = final_result[:matched_keys].length > 1 ? 'are' : 'is' - "#{final_result[:matched_keys].join(',')} #{verb_string} set in /etc/yum.conf as below:"\ + "#{final_result[:matched_keys].join(',')} #{verb_string} set in /etc/dnf/dnf.conf as below:"\ "\n#{final_result[:grep_output]}"\ - "\nUnset this configuration as it is risky while yum update or upgrade!" + "\nUnset this configuration as it is risky while dnf update or upgrade!" end + # rubocop:enable Metrics/LineLength def verify_config_options result = {} - combined_regex = yum_config_options.values.join('|') + combined_regex = dnf_config_options.values.join('|') result[:grep_output] = execute_grep_cmd(combined_regex) - result[:matched_keys] = yum_config_options.keys.select do |key| + result[:matched_keys] = dnf_config_options.keys.select do |key| result[:grep_output].include?(key) end result end def execute_grep_cmd(regex_string) - execute_with_status("grep -iE '#{regex_string}' /etc/yum.conf")[1] + execute_with_status("grep -iE '#{regex_string}' /etc/dnf/dnf.conf")[1] end - def yum_config_options - @yum_config_options ||= { + def dnf_config_options + @dnf_config_options ||= { 'exclude' => '^exclude\s*=\s*\S+.*$', } end diff --git a/definitions/checks/repositories/check_upstream_repository.rb b/definitions/checks/repositories/check_upstream_repository.rb index 59ad3f5b1..1a4e28ce8 100644 --- a/definitions/checks/repositories/check_upstream_repository.rb +++ b/definitions/checks/repositories/check_upstream_repository.rb @@ -6,8 +6,7 @@ class Checks::CheckUpstreamRepository < ForemanMaintain::Check description 'Check if any upstream repositories are enabled on system' tags :pre_upgrade preparation_steps do - [Checks::Repositories::CheckNonRhRepository.new, - Procedures::Packages::Install.new(:packages => %w[yum-utils])] + [Checks::Repositories::CheckNonRhRepository.new] end confine do feature(:instance).downstream diff --git a/definitions/procedures/packages/installer_confirmation.rb b/definitions/procedures/packages/installer_confirmation.rb index 9796da075..b6957a67e 100644 --- a/definitions/procedures/packages/installer_confirmation.rb +++ b/definitions/procedures/packages/installer_confirmation.rb @@ -6,7 +6,7 @@ class InstallerConfirmation < ForemanMaintain::Procedure def run question = "\nWARNING: This script runs #{feature(:installer).installer_command} " \ - "after the yum execution \n" \ + "after the dnf execution \n" \ "to ensure the #{feature(:instance).product_name} " \ "is in a consistent state.\n" \ "As a result some of your services may be restarted. \n\n" \ diff --git a/definitions/procedures/packages/update.rb b/definitions/procedures/packages/update.rb index 23ecca813..8e7531507 100644 --- a/definitions/procedures/packages/update.rb +++ b/definitions/procedures/packages/update.rb @@ -6,13 +6,13 @@ class Update < ForemanMaintain::Procedure param :force, 'Do not skip if package is installed', :flag => true, :default => false param :warn_on_errors, 'Do not interrupt scenario on failure', :flag => true, :default => false - param :yum_options, 'Extra yum options if any', :array => true, :default => [] + param :dnf_options, 'Extra dnf options if any', :array => true, :default => [] end def run assumeyes_val = @assumeyes.nil? ? assumeyes? : @assumeyes package_manager.clean_cache(:assumeyes => assumeyes_val) - opts = { :assumeyes => assumeyes_val, :yum_options => @yum_options } + opts = { :assumeyes => assumeyes_val, :dnf_options => @dnf_options } packages_action(:update, @packages, opts) rescue ForemanMaintain::Error::ExecutionError => e if @warn_on_errors @@ -27,7 +27,7 @@ def necessary? end def description - if @yum_options.include?('--downloadonly') + if @dnf_options.include?('--downloadonly') "Download package(s) #{@packages.join(', ')}" else "Update package(s) #{@packages.join(', ')}" diff --git a/definitions/scenarios/self_upgrade.rb b/definitions/scenarios/self_upgrade.rb index 889a736ef..84cf770aa 100644 --- a/definitions/scenarios/self_upgrade.rb +++ b/definitions/scenarios/self_upgrade.rb @@ -67,13 +67,11 @@ class SelfUpgrade < SelfUpgradeBase def downstream_self_upgrade(pkgs_to_update) ForemanMaintain.enable_maintenance_module - if check_min_version('foreman', '2.5') || check_min_version('foreman-proxy', '2.5') - yum_options = req_repos_to_update_pkgs.map do |id| - "--enablerepo=#{id}" - end - add_step(Procedures::Packages::Update.new(packages: pkgs_to_update, assumeyes: true, - yum_options: yum_options)) + dnf_options = req_repos_to_update_pkgs.map do |id| + "--enablerepo=#{id}" end + add_step(Procedures::Packages::Update.new(packages: pkgs_to_update, assumeyes: true, + dnf_options: dnf_options)) end def upstream_self_upgrade(pkgs_to_update) diff --git a/definitions/scenarios/upgrade_to_capsule_6_15.rb b/definitions/scenarios/upgrade_to_capsule_6_15.rb index e3590bcdf..3eeabc9e6 100644 --- a/definitions/scenarios/upgrade_to_capsule_6_15.rb +++ b/definitions/scenarios/upgrade_to_capsule_6_15.rb @@ -58,7 +58,7 @@ def compose modules_to_enable = ["satellite-capsule:#{el_short_name}"] add_step(Procedures::Packages::EnableModules.new(:module_names => modules_to_enable)) add_step(Procedures::Packages::Update.new(:assumeyes => true, - :yum_options => ['--downloadonly'])) + :dnf_options => ['--downloadonly'])) add_step(Procedures::Service::Stop.new) add_step(Procedures::Packages::Update.new(:assumeyes => true)) add_step_with_context(Procedures::Installer::Upgrade) diff --git a/definitions/scenarios/upgrade_to_capsule_6_15_z.rb b/definitions/scenarios/upgrade_to_capsule_6_15_z.rb index 5a3ea6277..98b60555d 100644 --- a/definitions/scenarios/upgrade_to_capsule_6_15_z.rb +++ b/definitions/scenarios/upgrade_to_capsule_6_15_z.rb @@ -58,7 +58,7 @@ def compose modules_to_enable = ["satellite-capsule:#{el_short_name}"] add_step(Procedures::Packages::EnableModules.new(:module_names => modules_to_enable)) add_step(Procedures::Packages::Update.new(:assumeyes => true, - :yum_options => ['--downloadonly'])) + :dnf_options => ['--downloadonly'])) add_step(Procedures::Service::Stop.new) add_step(Procedures::Packages::Update.new(:assumeyes => true)) add_step_with_context(Procedures::Installer::Upgrade) diff --git a/definitions/scenarios/upgrade_to_katello_nightly.rb b/definitions/scenarios/upgrade_to_katello_nightly.rb index fabad6b8e..fa3ca65ca 100644 --- a/definitions/scenarios/upgrade_to_katello_nightly.rb +++ b/definitions/scenarios/upgrade_to_katello_nightly.rb @@ -55,7 +55,7 @@ def compose modules_to_enable = ["katello:#{el_short_name}", "pulpcore:#{el_short_name}"] add_step(Procedures::Packages::EnableModules.new(:module_names => modules_to_enable)) add_step(Procedures::Packages::Update.new(:assumeyes => true, - :yum_options => ['--downloadonly'])) + :dnf_options => ['--downloadonly'])) add_step(Procedures::Service::Stop.new) add_step(Procedures::Packages::Update.new(:assumeyes => true)) add_step_with_context(Procedures::Installer::Upgrade) diff --git a/definitions/scenarios/upgrade_to_satellite_6_15.rb b/definitions/scenarios/upgrade_to_satellite_6_15.rb index b62f1aa0c..ab05b5e62 100644 --- a/definitions/scenarios/upgrade_to_satellite_6_15.rb +++ b/definitions/scenarios/upgrade_to_satellite_6_15.rb @@ -59,7 +59,7 @@ def compose modules_to_enable = ["satellite:#{el_short_name}"] add_step(Procedures::Packages::EnableModules.new(:module_names => modules_to_enable)) add_step(Procedures::Packages::Update.new(:assumeyes => true, - :yum_options => ['--downloadonly'])) + :dnf_options => ['--downloadonly'])) add_step(Procedures::Service::Stop.new) add_step(Procedures::Packages::Update.new(:assumeyes => true)) add_step_with_context(Procedures::Installer::Upgrade) diff --git a/definitions/scenarios/upgrade_to_satellite_6_15_z.rb b/definitions/scenarios/upgrade_to_satellite_6_15_z.rb index 932c26899..4f6cbc8b8 100644 --- a/definitions/scenarios/upgrade_to_satellite_6_15_z.rb +++ b/definitions/scenarios/upgrade_to_satellite_6_15_z.rb @@ -58,7 +58,7 @@ def compose modules_to_enable = ["satellite:#{el_short_name}"] add_step(Procedures::Packages::EnableModules.new(:module_names => modules_to_enable)) add_step(Procedures::Packages::Update.new(:assumeyes => true, - :yum_options => ['--downloadonly'])) + :dnf_options => ['--downloadonly'])) add_step(Procedures::Service::Stop.new) add_step(Procedures::Packages::Update.new(:assumeyes => true)) add_step_with_context(Procedures::Installer::Upgrade) diff --git a/extras/foreman_protector/foreman-protector.conf b/extras/foreman_protector/foreman-protector.conf index 5c0664215..4cb8b3454 100644 --- a/extras/foreman_protector/foreman-protector.conf +++ b/extras/foreman_protector/foreman-protector.conf @@ -1,3 +1,3 @@ [main] enabled = 0 -whitelist = /etc/yum/pluginconf.d/foreman-protector.whitelist +whitelist = /etc/dnf/plugins/foreman-protector.whitelist diff --git a/extras/foreman_protector/yum/foreman-protector.py b/extras/foreman_protector/yum/foreman-protector.py deleted file mode 100644 index 3871853ba..000000000 --- a/extras/foreman_protector/yum/foreman-protector.py +++ /dev/null @@ -1,86 +0,0 @@ -from yum.plugins import PluginYumExit -from yum.plugins import TYPE_CORE -from rpmUtils.miscutils import splitFilename -from yum.packageSack import packagesNewestByName - -import urlgrabber -import urlgrabber.grabber - -import os -import fnmatch -import tempfile -import time - -requires_api_version = '2.1' -plugin_type = (TYPE_CORE,) - -_package_whitelist = set() -fileurl = None - -def _load_whitelist(): - try: - if fileurl: - llfile = urlgrabber.urlopen(fileurl) - for line in llfile.readlines(): - if line.startswith('#') or line.strip() == '': - continue - _package_whitelist.add(line.rstrip().lower()) - llfile.close() - except urlgrabber.grabber.URLGrabError as e: - raise PluginYumExit('Unable to read Foreman protector"s configuration: %s' % e) - -def _add_obsoletes(conduit): - if _package_whitelist: - # If anything obsoletes something that we have whitelisted ... then - # whitelist that too. - for (pkgtup, instTup) in conduit._base.up.getObsoletesTuples(): - if instTup[0] not in _package_whitelist: - continue - _package_whitelist.add(pkgtup[0].lower()) - -def _get_updates(base): - updates = {} - - for p in base.pkgSack.returnNewestByName(): - if p.name in _package_whitelist: - # This one is whitelisted, skip - continue - updates[p.name] = p - - return updates - -def config_hook(conduit): - global fileurl - - fileurl = conduit.confString('main', 'whitelist') - -def _add_package_whitelist_excluders(conduit): - if hasattr(conduit, 'registerPackageName'): - conduit.registerPackageName("yum-plugin-foreman-protector") - ape = conduit._base.pkgSack.addPackageExcluder - exid = 'foreman-protector.W.' - ape(None, exid + str(1), 'mark.washed') - ape(None, exid + str(2), 'wash.name.in', _package_whitelist) - ape(None, exid + str(3), 'exclude.marked') - -def exclude_hook(conduit): - conduit.info(3, 'Reading Foreman protector configuration') - - _load_whitelist() - _add_obsoletes(conduit) - - total = len(_get_updates(conduit._base)) - conduit.info(3, '*** Excluded total: %s' % total) - if total: - if total > 1: - suffix = 's' - else: - suffix = '' - conduit.info(1, '\n' - 'WARNING: Excluding %d package%s due to foreman-protector. \n' - 'Use foreman-maintain packages install/update \n' - 'to safely install packages without restrictions.\n' - 'Use foreman-maintain upgrade run for full upgrade.\n' - % (total, suffix)) - - _add_package_whitelist_excluders(conduit) diff --git a/lib/foreman_maintain/concerns/system_helpers.rb b/lib/foreman_maintain/concerns/system_helpers.rb index cd99125fe..24ee38e51 100644 --- a/lib/foreman_maintain/concerns/system_helpers.rb +++ b/lib/foreman_maintain/concerns/system_helpers.rb @@ -100,13 +100,13 @@ def server? end def packages_action(action, packages, options = {}) - options.validate_options!(:assumeyes, :yum_options) + options.validate_options!(:assumeyes, :dnf_options) case action when :install package_manager.install(packages, :assumeyes => options[:assumeyes]) when :update package_manager.update(packages, :assumeyes => options[:assumeyes], - :yum_options => options[:yum_options]) + :dnf_options => options[:dnf_options]) when :remove package_manager.remove(packages, :assumeyes => options[:assumeyes]) else diff --git a/lib/foreman_maintain/package_manager.rb b/lib/foreman_maintain/package_manager.rb index ff0462567..b1929bea6 100644 --- a/lib/foreman_maintain/package_manager.rb +++ b/lib/foreman_maintain/package_manager.rb @@ -1,5 +1,4 @@ require 'foreman_maintain/package_manager/base' -require 'foreman_maintain/package_manager/yum' require 'foreman_maintain/package_manager/dnf' require 'foreman_maintain/package_manager/apt' diff --git a/lib/foreman_maintain/package_manager/dnf.rb b/lib/foreman_maintain/package_manager/dnf.rb index c6ae92e99..889a5841a 100644 --- a/lib/foreman_maintain/package_manager/dnf.rb +++ b/lib/foreman_maintain/package_manager/dnf.rb @@ -1,14 +1,100 @@ module ForemanMaintain::PackageManager - class Dnf < Yum - def clean_cache(assumeyes: false) - dnf_action('clean', 'all', :assumeyes => assumeyes) - super + class Dnf < Base + PROTECTOR_CONFIG_FILE = '/etc/dnf/plugins/foreman-protector.conf'.freeze + PROTECTOR_WHITELIST_FILE = '/etc/dnf/plugins/foreman-protector.whitelist'.freeze + + def self.parse_envra(envra) + # envra format: 0:foreman-1.20.1.10-1.el7sat.noarch + parsed = envra.match(/\d*:?(?.*)-[^-]+-[^-]+\.[^.]+/) + parsed ? Hash[parsed.names.map(&:to_sym).zip(parsed.captures)].merge(:envra => envra) : nil + end + + def lock_versions + enable_protector + end + + def unlock_versions + disable_protector + end + + def versions_locked? + !!(protector_config =~ /^\s*enabled\s*=\s*1/) && + protector_whitelist_file_nonzero? + end + + def protector_whitelist_file_nonzero? + File.exist?(PROTECTOR_WHITELIST_FILE) && + !File.zero?(PROTECTOR_WHITELIST_FILE) end def version_locking_supported? true end + def installed?(packages) + packages_list = [packages].flatten(1).map { |pkg| "'#{pkg}'" }.join(' ') + sys.execute?(%(rpm -q #{packages_list})) + end + + def find_installed_package(name, queryformat = '') + rpm_cmd = "rpm -q '#{name}'" + unless queryformat.empty? + rpm_cmd += " --qf '#{queryformat}'" + end + status, result = sys.execute_with_status(rpm_cmd, interactive: false) + if status == 0 + result + end + end + + def install(packages, assumeyes: false) + dnf_action('install', packages, assumeyes: assumeyes) + end + + def reinstall(packages, assumeyes: false) + dnf_action('reinstall', packages, assumeyes: assumeyes) + end + + def remove(packages, assumeyes: false) + dnf_action('remove', packages, assumeyes: assumeyes) + end + + def update(packages = [], assumeyes: false, dnf_options: []) + dnf_action('update', packages, assumeyes: assumeyes, dnf_options: dnf_options) + end + + def check_update(packages: nil, with_status: false) + dnf_action( + 'check-update', + packages, + assumeyes: true, + valid_exit_statuses: [0, 100], + with_status: with_status + ) + end + + def update_available?(package) + cmd_output = dnf_action('check-update -q', package, with_status: true, assumeyes: false) + cmd_output[0] == 100 + end + + def files_not_owned_by_package(directory) + find_cmd = "find #{directory} -exec /bin/sh -c 'rpm -qf {} &> /dev/null || echo {}' \\;" + sys.execute(find_cmd).split("\n") + end + + def list_installed_packages(queryformat = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n') + # The queryformat should only include valid tag(s) as per `rpm --querytags` list. + # If any special formatting is required with querytag then it should be provided with tag i.e, + # "--%{VENDOR}" + # The queryformat string must end with '\n' + sys.execute!("rpm -qa --qf '#{queryformat}'").split("\n") + end + + def clean_cache(assumeyes: false) + dnf_action('clean', 'all', :assumeyes => assumeyes) + end + def module_enabled?(name) _status, result = info(name) result.match?(/Stream.+\[e\].+/) @@ -29,18 +115,59 @@ def info(name) private - def dnf_action(action, packages, with_status: false, assumeyes: false) + # rubocop:disable Metrics/LineLength, Metrics/ParameterLists + def dnf_action(action, packages, with_status: false, assumeyes: false, dnf_options: [], valid_exit_statuses: [0]) packages = [packages].flatten(1) - yum_options = [] - yum_options << '-y' if assumeyes + + dnf_options << '-y' if assumeyes + dnf_options << '--disableplugin=foreman-protector' + + command = ['dnf', dnf_options.join(' '), action] + + command.push(packages.join(' ')) unless packages.empty? + command = command.join(' ') + if with_status - sys.execute_with_status("dnf #{yum_options.join(' ')} #{action} #{packages.join(' ')}", - :interactive => !assumeyes) + sys.execute_with_status( + command, + :interactive => !assumeyes + ) else - sys.execute!("dnf #{yum_options.join(' ')} #{action} #{packages.join(' ')}", - :interactive => !assumeyes) + sys.execute!( + command, + :interactive => !assumeyes, + :valid_exit_statuses => valid_exit_statuses + ) + end + end + # rubocop:enable Metrics/LineLength, Metrics/ParameterLists + def protector_config + File.exist?(protector_config_file) ? File.read(protector_config_file) : '' + end + + def protector_config_file + PROTECTOR_CONFIG_FILE + end + + def enable_protector + setup_protector(true) + end + + def disable_protector + setup_protector(false) + end + + def setup_protector(enabled) + config = protector_config + config += "\n" unless config[-1] == "\n" + enabled_re = /^\s*enabled\s*=.*$/ + if enabled_re.match(config) + config = config.gsub(enabled_re, "enabled = #{enabled ? '1' : '0'}") + else + config += "enabled = #{enabled ? '1' : '0'}\n" end + File.open(protector_config_file, 'w') { |file| file.puts config } end end end diff --git a/lib/foreman_maintain/package_manager/yum.rb b/lib/foreman_maintain/package_manager/yum.rb deleted file mode 100644 index 54af1fa1c..000000000 --- a/lib/foreman_maintain/package_manager/yum.rb +++ /dev/null @@ -1,142 +0,0 @@ -module ForemanMaintain::PackageManager - class Yum < Base - PROTECTOR_CONFIG_FILE = '/etc/yum/pluginconf.d/foreman-protector.conf'.freeze - PROTECTOR_WHITELIST_FILE = '/etc/yum/pluginconf.d/foreman-protector.whitelist'.freeze - - def self.parse_envra(envra) - # envra format: 0:foreman-1.20.1.10-1.el7sat.noarch - parsed = envra.match(/\d*:?(?.*)-[^-]+-[^-]+\.[^.]+/) - parsed ? Hash[parsed.names.map(&:to_sym).zip(parsed.captures)].merge(:envra => envra) : nil - end - - def lock_versions - enable_protector - end - - def unlock_versions - disable_protector - end - - def versions_locked? - !!(protector_config =~ /^\s*enabled\s*=\s*1/) && - protector_whitelist_file_nonzero? - end - - def protector_whitelist_file_nonzero? - File.exist?(PROTECTOR_WHITELIST_FILE) && - !File.zero?(PROTECTOR_WHITELIST_FILE) - end - - def version_locking_supported? - true - end - - def installed?(packages) - packages_list = [packages].flatten(1).map { |pkg| "'#{pkg}'" }.join(' ') - sys.execute?(%(rpm -q #{packages_list})) - end - - def find_installed_package(name, queryformat = '') - rpm_cmd = "rpm -q '#{name}'" - unless queryformat.empty? - rpm_cmd += " --qf '#{queryformat}'" - end - status, result = sys.execute_with_status(rpm_cmd) - if status == 0 - result - end - end - - def install(packages, assumeyes: false) - yum_action('install', packages, :assumeyes => assumeyes) - end - - def reinstall(packages, assumeyes: false) - yum_action('reinstall', packages, :assumeyes => assumeyes) - end - - def remove(packages, assumeyes: false) - yum_action('remove', packages, :assumeyes => assumeyes) - end - - def update(packages = [], assumeyes: false, yum_options: []) - yum_action('update', packages, :assumeyes => assumeyes, :yum_options => yum_options) - end - - def clean_cache(assumeyes: false) - yum_action('clean', 'all', :assumeyes => assumeyes) - end - - def check_update(packages: nil, with_status: false) - yum_action('check-update', packages, :assumeyes => true, :valid_exit_statuses => [0, 100], - :with_status => with_status) - end - - def update_available?(package) - cmd_output = yum_action('check-update -q', package, :with_status => true, :assumeyes => false) - cmd_output[0] == 100 - end - - def files_not_owned_by_package(directory) - find_cmd = "find #{directory} -exec /bin/sh -c 'rpm -qf {} &> /dev/null || echo {}' \\;" - sys.execute(find_cmd).split("\n") - end - - def list_installed_packages(queryformat = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n') - # The queryformat should only include valid tag(s) as per `rpm --querytags` list. - # If any special formatting is required with querytag then it should be provided with tag i.e, - # "--%{VENDOR}" - # The queryformat string must end with '\n' - sys.execute!("rpm -qa --qf '#{queryformat}'").split("\n") - end - - private - - def protector_config - File.exist?(protector_config_file) ? File.read(protector_config_file) : '' - end - - def protector_config_file - PROTECTOR_CONFIG_FILE - end - - def enable_protector - setup_protector(true) - end - - def disable_protector - setup_protector(false) - end - - def setup_protector(enabled) - config = protector_config - config += "\n" unless config[-1] == "\n" - enabled_re = /^\s*enabled\s*=.*$/ - if enabled_re.match(config) - config = config.gsub(enabled_re, "enabled = #{enabled ? '1' : '0'}") - else - config += "enabled = #{enabled ? '1' : '0'}\n" - end - File.open(protector_config_file, 'w') { |file| file.puts config } - end - - def yum_action(action, packages, options) - with_status = options.fetch(:with_status, false) - assumeyes = options.fetch(:assumeyes, false) - valid_exit_statuses = options.fetch(:valid_exit_statuses, [0]) - yum_options = options.fetch(:yum_options, []) - packages = [packages].flatten(1) - yum_options << '-y' if assumeyes - yum_options << '--disableplugin=foreman-protector' - yum_options_s = yum_options.empty? ? '' : ' ' + yum_options.join(' ') - packages_s = packages.empty? ? '' : ' ' + packages.join(' ') - if with_status - sys.execute_with_status("yum#{yum_options_s} #{action}#{packages_s}", - :interactive => !assumeyes) - else - sys.execute!("yum#{yum_options_s} #{action}#{packages_s}", - :interactive => !assumeyes, :valid_exit_statuses => valid_exit_statuses) - end - end - end -end diff --git a/lib/foreman_maintain/repository_manager/el.rb b/lib/foreman_maintain/repository_manager/el.rb index 7ea84572b..45b4073f6 100644 --- a/lib/foreman_maintain/repository_manager/el.rb +++ b/lib/foreman_maintain/repository_manager/el.rb @@ -72,8 +72,8 @@ def hash_of_repoids_urls(repos, regex) entry.split(':', 2).last.strip end] - # The EL7 yum repolist output includes extra info in the output, - # as example + # repolist output includes extra info in the output + # # rhel-7-server-rpms/7Server/x86_64 # rhel-server-rhscl-7-rpms/7Server/x86_64 # This trims anything after first '/' to get correct repo label diff --git a/test/data/package_manager/yum/foreman-protector.conf.erb b/test/data/package_manager/dnf/foreman-protector.conf.erb similarity index 100% rename from test/data/package_manager/yum/foreman-protector.conf.erb rename to test/data/package_manager/dnf/foreman-protector.conf.erb diff --git a/test/definitions/procedures/update_package_test.rb b/test/definitions/procedures/update_package_test.rb index fc6693b4f..809cafbfe 100644 --- a/test/definitions/procedures/update_package_test.rb +++ b/test/definitions/procedures/update_package_test.rb @@ -7,16 +7,16 @@ ForemanMaintain.stubs(:el?).returns(true) procedure = Procedures::Packages::Update.new procedure.expects(:packages_action).with(:update, [], - { :assumeyes => false, :yum_options => [] }) + { :assumeyes => false, :dnf_options => [] }) result = run_procedure(procedure) assert result.success? end it 'updates all packages with --downloadonly' do ForemanMaintain.stubs(:el?).returns(true) - procedure = Procedures::Packages::Update.new(:yum_options => ['--downloadonly']) + procedure = Procedures::Packages::Update.new(:dnf_options => ['--downloadonly']) procedure.expects(:packages_action).with(:update, [], - { :assumeyes => false, :yum_options => ["--downloadonly"] }) + { :assumeyes => false, :dnf_options => ["--downloadonly"] }) result = run_procedure(procedure) assert result.success? end diff --git a/test/lib/package_manager/dnf_test.rb b/test/lib/package_manager/dnf_test.rb index 3b32ad5eb..d2b5cb068 100644 --- a/test/lib/package_manager/dnf_test.rb +++ b/test/lib/package_manager/dnf_test.rb @@ -4,46 +4,219 @@ module ForemanMaintain describe PackageManager::Dnf do - def expect_execute_with_status(command, response: [0, '']) + def expect_execute_with_status(command, response: [0, ''], interactive: true) ForemanMaintain::Utils::SystemHelpers. expects(:execute_with_status). - with(command, :interactive => false). + with(command, :interactive => interactive). returns(response) end - def expect_execute!(command, response: true) + def expect_execute!(command, response: true, interactive: true) ForemanMaintain::Utils::SystemHelpers. expects(:execute!). - with(command, :interactive => false). + with(command, :interactive => interactive, :valid_exit_statuses => [0]). returns(response) end + def expect_execute?(command, response: true) + ForemanMaintain::Utils::SystemHelpers. + expects(:execute?). + with(command). + returns(response) + end + + def with_lock_config(protector_enabled: false) + template = ERB.new(File.read(File.join(config_dir, 'foreman-protector.conf.erb'))) + Tempfile.open('test_foreman-protector.conf') do |tmp| + tmp.write(template.result(binding)) + tmp.rewind + yield(tmp) + end + end + subject { PackageManager::Dnf.new } + let(:config_dir) { File.expand_path('test/data/package_manager/dnf') } let(:enabled_module) { 'Stream : el8 [e] [a]' } let(:disabled_module) { 'Stream : el8' } let(:non_existent_module) { 'Unable to resolve argument satellit' } + describe 'lock_versions' do + it 'locks unlocked versions' do + with_lock_config(:protector_enabled => false) do |lock_conf| + subject.stubs(:protector_config_file).returns(lock_conf.path) + subject.stubs(:protector_whitelist_file_nonzero?).returns(true) + lock_conf.rewind + subject.lock_versions + lock_conf.rewind + _(subject.versions_locked?).must_equal true + end + end + + it 'does nothing on locked versions' do + with_lock_config(:protector_enabled => true) do |lock_conf| + subject.stubs(:protector_config_file).returns(lock_conf.path) + subject.stubs(:protector_whitelist_file_nonzero?).returns(true) + lock_conf.rewind + subject.lock_versions + lock_conf.rewind + _(subject.versions_locked?).must_equal true + end + end + end + + describe 'unlock_versions' do + it 'unlocks locked versions' do + with_lock_config(:protector_enabled => true) do |lock_conf| + subject.stubs(:protector_config_file).returns(lock_conf.path) + lock_conf.rewind + subject.unlock_versions + lock_conf.rewind + _(subject.versions_locked?).must_equal false + end + end + + it 'does nothing on unlocked versions' do + with_lock_config(:protector_enabled => false) do |lock_conf| + subject.stubs(:protector_config_file).returns(lock_conf.path) + lock_conf.rewind + subject.unlock_versions + lock_conf.rewind + _(subject.versions_locked?).must_equal false + end + end + end + + describe 'versions_locked?' do + it 'checks if packages were locked by lock_versions' do + with_lock_config(:protector_enabled => true) do |lock_conf| + subject.stubs(:protector_config_file).returns(lock_conf.path) + subject.stubs(:protector_whitelist_file_nonzero?).returns(true) + _(subject.versions_locked?).must_equal true + end + end + + it 'checks if packages were not locked by lock_versions' do + with_lock_config(:protector_enabled => false) do |lock_conf| + subject.stubs(:protector_config_file).returns(lock_conf.path) + lock_conf.rewind + _(subject.versions_locked?).must_equal false + end + end + end + + describe 'install' do + it 'invokes dnf to install single package' do + expect_execute!('dnf --disableplugin=foreman-protector install package') + subject.install('package') + end + + it 'invokes dnf to install list of packages' do + expect_execute!('dnf --disableplugin=foreman-protector install package1 package2') + subject.install(%w[package1 package2], :assumeyes => false) + end + + it 'invokes dnf to install package with yes enforced' do + expect_execute!('dnf -y --disableplugin=foreman-protector install package', + :interactive => false) + subject.install('package', :assumeyes => true) + end + end + + describe 'update' do + it 'invokes dnf to update single package' do + expect_execute!('dnf --disableplugin=foreman-protector update package') + subject.update('package') + end + + it 'invokes dnf to update list of packages' do + expect_execute!('dnf --disableplugin=foreman-protector update package1 package2') + subject.update(%w[package1 package2]) + end + + it 'invokes dnf to update package with yes enforced' do + expect_execute!('dnf -y --disableplugin=foreman-protector update package', + :interactive => false) + subject.update('package', :assumeyes => true) + end + + it 'invokes dnf to update all packages' do + expect_execute!('dnf --disableplugin=foreman-protector update') + subject.update + end + end + + describe 'clean_cache' do + it 'invokes dnf to clean cache' do + expect_execute!( + 'dnf -y --disableplugin=foreman-protector clean all', + :interactive => false + ) + subject.clean_cache(:assumeyes => true) + end + end + + describe 'installed?' do + it 'returns true if all packages listed are installed' do + expect_execute?("rpm -q 'package1' 'package2'") + + _(subject.installed?(%w[package1 package2])).must_equal true + end + + it 'returns false if any of the packages is not installed' do + expect_execute?("rpm -q 'missing' 'package'", :response => false) + _(subject.installed?(%w[missing package])).must_equal false + end + + it 'handles single package too' do + expect_execute?("rpm -q 'package'") + _(subject.installed?('package')).must_equal true + end + end + + describe 'find_installed_package' do + it 'invokes rpm to lookup the package and returns the pacakge' do + expect_execute_with_status( + "rpm -q 'package'", + :response => [0, 'package-3.4.3-161.el7.noarch'], + :interactive => false + ) + _(subject.find_installed_package('package')).must_equal 'package-3.4.3-161.el7.noarch' + end + + it 'invokes rpm to lookup the package and returns nil if not found' do + expect_execute_with_status( + "rpm -q 'package'", + :response => [1, 'package package is not insalled'], + :interactive => false + ) + assert_nil subject.find_installed_package('package') + end + end + describe 'module_enabled?' do it 'checks if a module is enabled' do expect_execute_with_status( - 'dnf -y module info test-module:el8', - :response => [0, enabled_module] + 'dnf -y --disableplugin=foreman-protector module info test-module:el8', + :response => [0, enabled_module], + :interactive => false ) assert subject.module_enabled?('test-module:el8') end it 'returns false if module does not exist' do expect_execute_with_status( - 'dnf -y module info test-module:el8', - :response => [1, non_existent_module] + 'dnf -y --disableplugin=foreman-protector module info test-module:el8', + :response => [1, non_existent_module], + :interactive => false ) refute subject.module_enabled?('test-module:el8') end it 'returns false if module exists but is not enabled' do expect_execute_with_status( - 'dnf -y module info test-module:el8', - :response => [0, disabled_module] + 'dnf -y --disableplugin=foreman-protector module info test-module:el8', + :response => [0, disabled_module], + :interactive => false ) refute subject.module_enabled?('test-module:el8') end @@ -51,14 +224,20 @@ def expect_execute!(command, response: true) describe 'enable_module' do it 'enables a module by name' do - expect_execute!('dnf -y module enable test-module:el8') + expect_execute!( + 'dnf -y --disableplugin=foreman-protector module enable test-module:el8', + :interactive => false + ) assert subject.enable_module('test-module:el8') end end describe 'module_exists?' do it 'check if a module exists' do - expect_execute_with_status('dnf -y module info test-module:el8') + expect_execute_with_status( + 'dnf -y --disableplugin=foreman-protector module info test-module:el8', + :interactive => false + ) assert subject.module_exists?('test-module:el8') end end diff --git a/test/lib/package_manager/yum_test.rb b/test/lib/package_manager/yum_test.rb deleted file mode 100644 index 94b1a8ac5..000000000 --- a/test/lib/package_manager/yum_test.rb +++ /dev/null @@ -1,193 +0,0 @@ -require 'test_helper' -require 'tempfile' -require 'foreman_maintain/package_manager' - -module ForemanMaintain - describe PackageManager::Yum do - def expect_sys_execute_with_status(command, - response: []) - - ForemanMaintain::Utils::SystemHelpers.expects(:execute_with_status). - with(command).returns(response) - end - - def expect_sys_execute!(command, - interactive: true, - valid_exit_statuses: [0], - response: 'OK') - - ForemanMaintain::Utils::SystemHelpers.expects(:execute!). - with( - command, - interactive: interactive, - valid_exit_statuses: valid_exit_statuses - ).returns(response) - end - - def expect_sys_execute?(command, response: true) - ForemanMaintain::Utils::SystemHelpers. - expects(:execute?). - with(command). - returns(response) - end - - def with_lock_config(protector_enabled: false) - template = ERB.new(File.read(File.join(config_dir, 'foreman-protector.conf.erb'))) - Tempfile.open('test_foreman-protector.conf') do |tmp| - tmp.write(template.result(binding)) - tmp.rewind - yield(tmp) - end - end - - subject { PackageManager::Yum.new } - let(:config_dir) { File.expand_path('test/data/package_manager/yum') } - - describe 'lock_versions' do - it 'locks unlocked versions' do - with_lock_config(:protector_enabled => false) do |lock_conf| - subject.stubs(:protector_config_file).returns(lock_conf.path) - subject.stubs(:protector_whitelist_file_nonzero?).returns(true) - lock_conf.rewind - subject.lock_versions - lock_conf.rewind - _(subject.versions_locked?).must_equal true - end - end - - it 'does nothing on locked versions' do - with_lock_config(:protector_enabled => true) do |lock_conf| - subject.stubs(:protector_config_file).returns(lock_conf.path) - subject.stubs(:protector_whitelist_file_nonzero?).returns(true) - lock_conf.rewind - subject.lock_versions - lock_conf.rewind - _(subject.versions_locked?).must_equal true - end - end - end - - describe 'unlock_versions' do - it 'unlocks locked versions' do - with_lock_config(:protector_enabled => true) do |lock_conf| - subject.stubs(:protector_config_file).returns(lock_conf.path) - lock_conf.rewind - subject.unlock_versions - lock_conf.rewind - _(subject.versions_locked?).must_equal false - end - end - - it 'does nothing on unlocked versions' do - with_lock_config(:protector_enabled => false) do |lock_conf| - subject.stubs(:protector_config_file).returns(lock_conf.path) - lock_conf.rewind - subject.unlock_versions - lock_conf.rewind - _(subject.versions_locked?).must_equal false - end - end - end - - describe 'versions_locked?' do - it 'checks if packages were locked by lock_versions' do - with_lock_config(:protector_enabled => true) do |lock_conf| - subject.stubs(:protector_config_file).returns(lock_conf.path) - subject.stubs(:protector_whitelist_file_nonzero?).returns(true) - _(subject.versions_locked?).must_equal true - end - end - - it 'checks if packages were not locked by lock_versions' do - with_lock_config(:protector_enabled => false) do |lock_conf| - subject.stubs(:protector_config_file).returns(lock_conf.path) - lock_conf.rewind - _(subject.versions_locked?).must_equal false - end - end - end - - describe 'install' do - it 'invokes yum to install single package' do - expect_sys_execute!('yum --disableplugin=foreman-protector install package') - subject.install('package') - end - - it 'invokes yum to install list of packages' do - expect_sys_execute!('yum --disableplugin=foreman-protector install package1 package2') - subject.install(%w[package1 package2], :assumeyes => false) - end - - it 'invokes yum to install package with yes enforced' do - expect_sys_execute!('yum -y --disableplugin=foreman-protector install package', - :interactive => false) - subject.install('package', :assumeyes => true) - end - end - - describe 'update' do - it 'invokes yum to update single package' do - expect_sys_execute!('yum --disableplugin=foreman-protector update package') - subject.update('package') - end - - it 'invokes yum to update list of packages' do - expect_sys_execute!('yum --disableplugin=foreman-protector update package1 package2') - subject.update(%w[package1 package2]) - end - - it 'invokes yum to update package with yes enforced' do - expect_sys_execute!('yum -y --disableplugin=foreman-protector update package', - :interactive => false) - subject.update('package', :assumeyes => true) - end - - it 'invokes yum to update all packages' do - expect_sys_execute!('yum --disableplugin=foreman-protector update') - subject.update - end - end - - describe 'clean_cache' do - it 'invokes yum to clean cache' do - expect_sys_execute!( - 'yum -y --disableplugin=foreman-protector clean all', - :interactive => false - ) - subject.clean_cache(:assumeyes => true) - end - end - - describe 'installed?' do - it 'returns true if all packages listed are installed' do - expect_sys_execute?("rpm -q 'package1' 'package2'") - - _(subject.installed?(%w[package1 package2])).must_equal true - end - - it 'returns false if any of the packages is not installed' do - expect_sys_execute?("rpm -q 'missing' 'package'", :response => false) - _(subject.installed?(%w[missing package])).must_equal false - end - - it 'handles single package too' do - expect_sys_execute?("rpm -q 'package'") - _(subject.installed?('package')).must_equal true - end - end - - describe 'find_installed_package' do - it 'invokes rpm to lookup the package and returns the pacakge' do - expect_sys_execute_with_status("rpm -q 'package'", - :response => [0, 'package-3.4.3-161.el7.noarch']) - _(subject.find_installed_package('package')).must_equal 'package-3.4.3-161.el7.noarch' - end - - it 'invokes rpm to lookup the package and returns nil if not found' do - expect_sys_execute_with_status("rpm -q 'package'", - :response => [1, 'package package is not insalled']) - assert_nil subject.find_installed_package('package') - end - end - end -end