Fix dnf package matching (#75411) (#75417)

* Fix a bug with the dnf module not using all components of a package name when filtering to determine if it's installed

* changelog

* Simplify splitting on the last '.'

* Update lib/ansible/modules/dnf.py

(cherry picked from commit b541a148d5)
pull/75428/head
Sloane Hertel 3 years ago committed by GitHub
parent 0cf5666778
commit c1dd0caf2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
bugfixes:
- dnf module - Use all components of a package name to determine if it's installed (https://github.com/ansible/ansible/issues/75311).

@ -391,15 +391,7 @@ class DnfModule(YumDnf):
return result
def _packagename_dict(self, packagename):
"""
Return a dictionary of information for a package name string or None
if the package name doesn't contain at least all NVR elements
"""
if packagename[-4:] == '.rpm':
packagename = packagename[:-4]
def _split_package_arch(self, packagename):
# This list was auto generated on a Fedora 28 system with the following one-liner
# printf '[ '; for arch in $(ls /usr/lib/rpm/platform); do printf '"%s", ' ${arch%-linux}; done; printf ']\n'
redhat_rpm_arches = [
@ -414,15 +406,26 @@ class DnfModule(YumDnf):
"sparc", "sparcv8", "sparcv9", "sparcv9v", "x86_64"
]
rpm_arch_re = re.compile(r'(.*)\.(.*)')
name, delimiter, arch = packagename.rpartition('.')
if name and arch and arch in redhat_rpm_arches:
return name, arch
return packagename, None
def _packagename_dict(self, packagename):
"""
Return a dictionary of information for a package name string or None
if the package name doesn't contain at least all NVR elements
"""
if packagename[-4:] == '.rpm':
packagename = packagename[:-4]
rpm_nevr_re = re.compile(r'(\S+)-(?:(\d*):)?(.*)-(~?\w+[\w.+]*)')
try:
arch = None
rpm_arch_match = rpm_arch_re.match(packagename)
if rpm_arch_match:
nevr, arch = rpm_arch_match.groups()
if arch in redhat_rpm_arches:
packagename = nevr
nevr, arch = self._split_package_arch(packagename)
if arch:
packagename = nevr
rpm_nevr_match = rpm_nevr_re.match(packagename)
if rpm_nevr_match:
name, epoch, version, release = rpm_nevr_re.match(packagename).groups()
@ -682,7 +685,20 @@ class DnfModule(YumDnf):
def _is_installed(self, pkg):
installed = self.base.sack.query().installed()
if installed.filter(name=pkg):
package_spec = {}
name, arch = self._split_package_arch(pkg)
if arch:
package_spec['arch'] = arch
package_details = self._packagename_dict(pkg)
if package_details:
package_details['epoch'] = int(package_details['epoch'])
package_spec.update(package_details)
else:
package_spec['name'] = name
if installed.filter(**package_spec):
return True
else:
return False

@ -98,6 +98,19 @@
allow_downgrade: true
disable_gpg_check: true
- name: Verify toaster is not upgraded with state=installed
dnf:
name: "{{ item }}"
state: installed
register: installed
loop:
- toaster
- toaster.noarch
- toaster-1.2.3.4-1.el8.noarch
- assert:
that: "[0, 1, 2] | map('extract', installed.results, 'changed') == [False, False, False]"
- name: Ask for pending updates with bugfix=true and security=true
dnf:
name: '*'
@ -118,6 +131,21 @@
- '"Installed: oven-1.2.3.5-1.el8.noarch" in update_bugfix.results'
- '"Removed: oven-1.2.3.4-1.el8.noarch" in update_bugfix.results'
- name: Install old version of toaster again
dnf:
name: "{{ updateinfo_repo }}/toaster-1.2.3.4-1.el8.noarch.rpm"
allow_downgrade: true
disable_gpg_check: true
- name: Verify toaster is upgraded with state=latest
dnf:
name: toaster.noarch
state: latest
register: result
- assert:
that: result.changed
always:
- name: Remove installed packages
dnf:

Loading…
Cancel
Save