[dnf] Make "remove" filtering closer to dnf CLI (#73033)

Change:
- Internally, use dnf.subject.Subject#get_best_query for state: absent
- Add a bunch of tests for removing packages, given a bunch of different
  pkg specs (nv, nvr, nvra, wildcard, etc.)

Test Plan:
- New tests
- Local experiments with DNF API via PDB.

Tickets:
- Fixes #72809

Signed-off-by: Rick Elrod <rick@elrod.me>
This commit is contained in:
Rick Elrod 2021-01-07 11:32:06 -06:00 committed by GitHub
parent 77942acefc
commit 44ee04bd1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 15 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- "dnf - When ``state: absent``, package names are now matched similarly to how the ``dnf`` CLI matches them (https://github.com/ansible/ansible/issues/72809)."

View file

@ -1155,21 +1155,11 @@ class DnfModule(YumDnf):
response['results'].append(handled_remove_error)
continue
installed_pkg = list(map(str, installed.filter(name=pkg_spec).run()))
if installed_pkg:
candidate_pkg = self._packagename_dict(installed_pkg[0])
installed_pkg = installed.filter(name=candidate_pkg['name']).run()
else:
candidate_pkg = self._packagename_dict(pkg_spec)
installed_pkg = installed.filter(nevra=pkg_spec).run()
if installed_pkg:
installed_pkg = installed_pkg[0]
evr_cmp = self._compare_evr(
installed_pkg.epoch, installed_pkg.version, installed_pkg.release,
candidate_pkg['epoch'], candidate_pkg['version'], candidate_pkg['release'],
)
if evr_cmp == 0:
self.base.remove(pkg_spec)
installed_pkg = dnf.subject.Subject(pkg_spec).get_best_query(
sack=self.base.sack).installed().run()
for pkg in installed_pkg:
self.base.remove(str(pkg))
# Like the dnf CLI we want to allow recursive removal of dependent
# packages

View file

@ -772,3 +772,53 @@
that:
- wildcard_absent is successful
- wildcard_absent is not changed
- name: Test removing with various package specs
block:
- name: Ensure sos is installed
dnf:
name: sos
state: present
- name: Determine version of sos
command: rpm -q --queryformat=%{version} sos
register: sos_version_command
- name: Determine release of sos
command: rpm -q --queryformat=%{release} sos
register: sos_release_command
- name: Determine arch of sos
command: rpm -q --queryformat=%{arch} sos
register: sos_arch_command
- set_fact:
sos_version: "{{ sos_version_command.stdout | trim }}"
sos_release: "{{ sos_release_command.stdout | trim }}"
sos_arch: "{{ sos_arch_command.stdout | trim }}"
# We are just trying to remove the package by specifying its spec in a
# bunch of different ways. Each "item" here is a test (a name passed, to make
# sure it matches, with how we call Hawkey in the dnf module).
- include_tasks: test_sos_removal.yml
with_items:
- sos
- sos-{{ sos_version }}
- sos-{{ sos_version }}-{{ sos_release }}
- sos-{{ sos_version }}-{{ sos_release }}.{{ sos_arch }}
- sos-*-{{ sos_release }}
- sos-{{ sos_version[0] }}*
- sos-{{ sos_version[0] }}*-{{ sos_release }}
- sos-{{ sos_version[0] }}*{{ sos_arch }}
- name: Ensure deleting a non-existing package fails correctly
dnf:
name: a-non-existent-package
state: absent
ignore_errors: true
register: nonexisting
- assert:
that:
- nonexisting is success
- nonexisting.msg == 'Nothing to do'

View file

@ -0,0 +1,19 @@
# These are safe to just check in check_mode, because in the module, the
# logic to match packages will happen anyway. check_mode will just prevent
# the transaction from actually running once the matches are found.
- name: Remove {{ item }}
dnf:
name: "{{ item }}"
state: absent
check_mode: true
register: sos_rm
- debug:
var: sos_rm
- assert:
that:
- sos_rm is successful
- sos_rm is changed
- "'Removed: sos-{{ sos_version }}-{{ sos_release }}' in sos_rm.results[0]"
- sos_rm.results|length == 1