yum also parse obsolete package output (#45365)

* yum also parse obsolete package output

This is a rebase of the patch originally proposed in
https://github.com/ansible/ansible/pull/40001 by machacekondra

Fixes #39978

Signed-off-by: Adam Miller <admiller@redhat.com>

* properly parse the obsoletes, provide a new output entry, add changelog

Signed-off-by: Adam Miller <admiller@redhat.com>

* make pep8 happy

Signed-off-by: Adam Miller <admiller@redhat.com>

* remove q debugging output

Signed-off-by: Adam Miller <admiller@redhat.com>
(cherry picked from commit 091fb1dc3f)
This commit is contained in:
Adam Miller 2018-11-06 15:07:50 -06:00 committed by Toshio Kuratomi
parent 7f29557016
commit 4156d01c01
3 changed files with 51 additions and 19 deletions

View file

@ -0,0 +1,3 @@
---
minor_changes:
- "yum - when checking for updates, now properly include Obsoletes (both old and new) package data in the module JSON output, fixes https://github.com/ansible/ansible/issues/39978"

View file

@ -1094,6 +1094,7 @@ class YumModule(YumDnf):
@staticmethod
def parse_check_update(check_update_output):
updates = {}
obsoletes = {}
# remove incorrect new lines in longer columns in output from yum check-update
# yum line wrapping can move the repo to the next line
@ -1118,17 +1119,24 @@ class YumModule(YumDnf):
# ignore irrelevant lines
# '*' in line matches lines like mirror lists:
# * base: mirror.corbina.net
# len(line) != 3 could be junk or a continuation
# len(line) != 3 or 6 could be junk or a continuation
# len(line) = 6 is package obsoletes
#
# FIXME: what is the '.' not in line conditional for?
if '*' in line or len(line) != 3 or '.' not in line[0]:
if '*' in line or len(line) not in [3, 6] or '.' not in line[0]:
continue
else:
pkg, version, repo = line
pkg, version, repo = line[0], line[1], line[2]
name, dist = pkg.rsplit('.', 1)
updates.update({name: {'version': version, 'dist': dist, 'repo': repo}})
return updates
if len(line) == 6:
obsolete_pkg, obsolete_version, obsolete_repo = line[3], line[4], line[5]
obsolete_name, obsolete_dist = obsolete_pkg.rsplit('.', 1)
obsoletes.update({obsolete_name: {'version': obsolete_version, 'dist': obsolete_dist, 'repo': obsolete_repo}})
return updates, obsoletes
def latest(self, items, repoq):
@ -1141,6 +1149,7 @@ class YumModule(YumDnf):
pkgs['update'] = []
pkgs['install'] = []
updates = {}
obsoletes = {}
update_all = False
cmd = None
@ -1154,7 +1163,7 @@ class YumModule(YumDnf):
res['results'].append('Nothing to do here, all packages are up to date')
return res
elif rc == 100:
updates = self.parse_check_update(out)
updates, obsoletes = self.parse_check_update(out)
elif rc == 1:
res['msg'] = err
res['rc'] = rc
@ -1286,6 +1295,9 @@ class YumModule(YumDnf):
if will_update or pkgs['install']:
res['changed'] = True
if obsoletes:
res['obsoletes'] = obsoletes
return res
# run commands
@ -1310,6 +1322,9 @@ class YumModule(YumDnf):
if rc:
res['failed'] = True
if obsoletes:
res['obsoletes'] = obsoletes
return res
def ensure(self, repoq):

View file

@ -127,9 +127,19 @@ glibc.x86_64 2.17-157.el7_3.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
unwrapped_output_rhel7_obsoletes = unwrapped_output_rhel7 + wrapped_output_rhel7_obsoletes_postfix
unwrapped_output_rhel7_expected_pkgs = ["NetworkManager-openvpn", "NetworkManager-openvpn-gnome", "cabal-install",
"cgit", "python34-libs", "python34-test", "python34-tkinter",
"python34-tools", "qgit", "rdiff-backup", "stoken-libs", "xlockmore"]
unwrapped_output_rhel7_expected_new_obsoletes_pkgs = [
"ddashboard", "python-bugzilla", "python2-futures", "python2-pip",
"python2-pyxdg", "python2-simplejson"
]
unwrapped_output_rhel7_expected_old_obsoletes_pkgs = [
"developerdashboard", "python-bugzilla-develdashboardfixes",
"python-futures", "python-pip", "pyxdg", "python-simplejson"
]
unwrapped_output_rhel7_expected_updated_pkgs = [
"NetworkManager-openvpn", "NetworkManager-openvpn-gnome", "cabal-install",
"cgit", "python34-libs", "python34-test", "python34-tkinter",
"python34-tools", "qgit", "rdiff-backup", "stoken-libs", "xlockmore"
]
class TestYumUpdateCheckParse(unittest.TestCase):
@ -141,34 +151,34 @@ class TestYumUpdateCheckParse(unittest.TestCase):
self.assertIsInstance(result, dict)
def test_empty_output(self):
res = YumModule.parse_check_update("")
res, obs = YumModule.parse_check_update("")
expected_pkgs = []
self._assert_expected(expected_pkgs, res)
def test_longname(self):
res = YumModule.parse_check_update(longname)
res, obs = YumModule.parse_check_update(longname)
expected_pkgs = ['xxxxxxxxxxxxxxxxxxxxxxxxxx', 'glibc']
self._assert_expected(expected_pkgs, res)
def test_plugin_load_error(self):
res = YumModule.parse_check_update(yum_plugin_load_error)
res, obs = YumModule.parse_check_update(yum_plugin_load_error)
expected_pkgs = []
self._assert_expected(expected_pkgs, res)
def test_wrapped_output_1(self):
res = YumModule.parse_check_update(wrapped_output_1)
res, obs = YumModule.parse_check_update(wrapped_output_1)
expected_pkgs = ["vms-agent"]
self._assert_expected(expected_pkgs, res)
def test_wrapped_output_2(self):
res = YumModule.parse_check_update(wrapped_output_2)
res, obs = YumModule.parse_check_update(wrapped_output_2)
expected_pkgs = ["empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty-empty",
"libtiff"]
self._assert_expected(expected_pkgs, res)
def test_wrapped_output_3(self):
res = YumModule.parse_check_update(wrapped_output_3)
res, obs = YumModule.parse_check_update(wrapped_output_3)
expected_pkgs = ["ceph", "ceph-base", "ceph-common", "ceph-mds",
"ceph-mon", "ceph-osd", "ceph-selinux", "libcephfs1",
"librados2", "libradosstriper1", "librbd1", "librgw2",
@ -176,16 +186,20 @@ class TestYumUpdateCheckParse(unittest.TestCase):
self._assert_expected(expected_pkgs, res)
def test_wrapped_output_4(self):
res = YumModule.parse_check_update(wrapped_output_4)
res, obs = YumModule.parse_check_update(wrapped_output_4)
expected_pkgs = ["ipxe-roms-qemu", "quota", "quota-nls", "rdma", "screen",
"sos", "sssd-client"]
self._assert_expected(expected_pkgs, res)
def test_wrapped_output_rhel7(self):
res = YumModule.parse_check_update(unwrapped_output_rhel7)
self._assert_expected(unwrapped_output_rhel7_expected_pkgs, res)
res, obs = YumModule.parse_check_update(unwrapped_output_rhel7)
self._assert_expected(unwrapped_output_rhel7_expected_updated_pkgs, res)
def test_wrapped_output_rhel7_obsoletes(self):
res = YumModule.parse_check_update(unwrapped_output_rhel7_obsoletes)
self._assert_expected(unwrapped_output_rhel7_expected_pkgs, res)
res, obs = YumModule.parse_check_update(unwrapped_output_rhel7_obsoletes)
self._assert_expected(
unwrapped_output_rhel7_expected_updated_pkgs + unwrapped_output_rhel7_expected_new_obsoletes_pkgs,
res
)
self._assert_expected(unwrapped_output_rhel7_expected_old_obsoletes_pkgs, obs)