diff --git a/changelogs/fragments/62809-dnf-wildcard-absent-failure.yml b/changelogs/fragments/62809-dnf-wildcard-absent-failure.yml new file mode 100644 index 0000000000..a2a3db4746 --- /dev/null +++ b/changelogs/fragments/62809-dnf-wildcard-absent-failure.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - dnf - Properly handle idempotent transactions with package name wildcard globs (https://github.com/ansible/ansible/issues/62809) diff --git a/lib/ansible/modules/packaging/os/dnf.py b/lib/ansible/modules/packaging/os/dnf.py index 55f569bc06..2a4e2c9080 100644 --- a/lib/ansible/modules/packaging/os/dnf.py +++ b/lib/ansible/modules/packaging/os/dnf.py @@ -334,16 +334,29 @@ class DnfModule(YumDnf): # https://github.com/ansible/ansible/issues/57189 return True - def _sanitize_dnf_error_msg(self, spec, error): + def _sanitize_dnf_error_msg_install(self, spec, error): """ For unhandled dnf.exceptions.Error scenarios, there are certain error - messages we want to filter. Do that here. + messages we want to filter in an install scenario. Do that here. """ if to_text("no package matched") in to_text(error): return "No package {0} available.".format(spec) return error + def _sanitize_dnf_error_msg_remove(self, spec, error): + """ + For unhandled dnf.exceptions.Error scenarios, there are certain error + messages we want to ignore in a removal scenario as known benign + failures. Do that here. + """ + if 'no package matched' in to_native(error): + return (False, "{0} is not installed".format(spec)) + + # Return value is tuple of: + # ("Is this actually a failure?", "Error Message") + return (True, error) + def _package_dict(self, package): """Return a dictionary of information for the package.""" # NOTE: This no longer contains the 'dnfstate' field because it is @@ -991,7 +1004,7 @@ class DnfModule(YumDnf): install_result = self._mark_package_install(pkg_spec) if install_result['failed']: failure_response['msg'] += install_result['msg'] - failure_response['failures'].append(self._sanitize_dnf_error_msg(pkg_spec, install_result['failure'])) + failure_response['failures'].append(self._sanitize_dnf_error_msg_install(pkg_spec, install_result['failure'])) else: response['results'].append(install_result['msg']) @@ -1051,7 +1064,7 @@ class DnfModule(YumDnf): install_result = self._mark_package_install(pkg_spec, upgrade=True) if install_result['failed']: failure_response['msg'] += install_result['msg'] - failure_response['failures'].append(self._sanitize_dnf_error_msg(pkg_spec, install_result['failure'])) + failure_response['failures'].append(self._sanitize_dnf_error_msg_install(pkg_spec, install_result['failure'])) else: response['results'].append(install_result['msg']) @@ -1104,7 +1117,11 @@ class DnfModule(YumDnf): try: self.base.remove(pkg_spec) except dnf.exceptions.MarkingError as e: - failure_response['failures'].append('{0} - {1}'.format(pkg_spec, to_native(e))) + is_failure, handled_remove_error = self._sanitize_dnf_error_msg_remove(pkg_spec, to_native(e)) + if is_failure: + failure_response['failures'].append('{0} - {1}'.format(pkg_spec, to_native(e))) + else: + response['results'].append(handled_remove_error) continue installed_pkg = list(map(str, installed.filter(name=pkg_spec).run())) diff --git a/test/integration/targets/yum/tasks/yum.yml b/test/integration/targets/yum/tasks/yum.yml index 800fe91289..bf70882ed0 100644 --- a/test/integration/targets/yum/tasks/yum.yml +++ b/test/integration/targets/yum/tasks/yum.yml @@ -693,6 +693,40 @@ yum_version: "{%- if item.yumstate == 'installed' -%}{{ item.version }}{%- else -%}{{ yum_version }}{%- endif -%}" with_items: "{{ yum_version.results }}" +- name: Ensure double uninstall of wildcard globs works + block: + - name: "Install lohit-*-fonts" + yum: + name: "lohit-*-fonts" + state: present + + - name: "Remove lohit-*-fonts (1st time)" + yum: + name: "lohit-*-fonts" + state: absent + register: remove_lohit_fonts_1 + + - name: "Verify lohit-*-fonts (1st time)" + assert: + that: + - "remove_lohit_fonts_1 is changed" + - "'msg' in remove_lohit_fonts_1" + - "'results' in remove_lohit_fonts_1" + + - name: "Remove lohit-*-fonts (2nd time)" + yum: + name: "lohit-*-fonts" + state: absent + register: remove_lohit_fonts_2 + + - name: "Verify lohit-*-fonts (2nd time)" + assert: + that: + - "remove_lohit_fonts_2 is not changed" + - "'msg' in remove_lohit_fonts_2" + - "'results' in remove_lohit_fonts_2" + - "'lohit-*-fonts is not installed' in remove_lohit_fonts_2['results']" + - block: - name: uninstall bc yum: name=bc state=removed