Fix 'yum skips updates' bug (#21113)

* Fix 'yum skips updates' bug

When the 'yum check-update' output is parsed, the regex used
to stitch wrapped lines together would fail on the first package.

It would fail because there is an empty line before the first
package, and this triggered the regex. To avoid a more complicated
regex, preprocess the check-update output to strip out any
empty lines.

The regex is also updated to include a group on the non whitespace
match to be used in the sub.

Add test cases based on info provided in the bug reports.

Fixes #20608
This commit is contained in:
Adrian Likins 2017-02-08 16:07:43 -05:00 committed by GitHub
commit e511326222
2 changed files with 227 additions and 16 deletions

View file

@ -844,6 +844,53 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos, in
return res
def run_check_update(module, yum_basecmd):
# run check-update to see if we have packages pending
rc, out, err = module.run_command(yum_basecmd + ['check-update'])
return rc, out, err
def parse_check_update(check_update_output):
updates = {}
# remove incorrect new lines in longer columns in output from yum check-update
# yum line wrapping can move the repo to the next line
#
# Meant to filter out sets of lines like:
# some_looooooooooooooooooooooooooooooooooooong_package_name 1:1.2.3-1.el7
# some-repo-label
#
# But it also needs to avoid catching lines like:
# Loading mirror speeds from cached hostfile
#
# ceph.x86_64 1:11.2.0-0.el7 ceph
# preprocess string and filter out empty lines so the regex below works
out = re.sub('\n[^\w]\W+(.*)', ' \1',
check_update_output)
available_updates = out.split('\n')
# build update dictionary
for line in available_updates:
line = line.split()
# ignore irrelevant lines
# '*' in line matches lines like mirror lists:
# * base: mirror.corbina.net
# len(line) != 3 could be junk or a continuation
#
# FIXME: what is the '.' not in line conditional for?
if '*' in line or len(line) != 3 or '.' not in line[0]:
continue
else:
pkg, version, repo = line
name, dist = pkg.rsplit('.', 1)
updates.update({name: {'version': version, 'dist': dist, 'repo': repo}})
return updates
def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos, installroot='/'):
res = {}
@ -862,26 +909,13 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos, in
if '*' in items:
update_all = True
# run check-update to see if we have packages pending
rc, out, err = module.run_command(yum_basecmd + ['check-update'])
rc, out, err = run_check_update(module, yum_basecmd)
if rc == 0 and update_all:
res['results'].append('Nothing to do here, all packages are up to date')
return res
elif rc == 100:
# remove incorrect new lines in longer columns in output from yum check-update
out=re.sub('\n\W+', ' ', out)
available_updates = out.split('\n')
# build update dictionary
for line in available_updates:
line = line.split()
# ignore irrelevant lines
# FIXME... revisit for something less kludgy
if '*' in line or len(line) != 3 or '.' not in line[0]:
continue
else:
pkg, version, repo = line
name, dist = pkg.rsplit('.', 1)
updates.update({name: {'version': version, 'dist': dist, 'repo': repo}})
updates = parse_check_update(out)
elif rc == 1:
res['msg'] = err
res['rc'] = rc
@ -920,6 +954,7 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos, in
nothing_to_do = False
break
# this contains the full NVR and spec could contain wildcards
# or virtual provides (like "python-*" or "smtp-daemon") while
# updates contains name only.