From 92615669c06ccf4b4ee264644d2968ad1568d7b1 Mon Sep 17 00:00:00 2001 From: queridiculo Date: Wed, 1 Jul 2015 17:14:55 -0400 Subject: [PATCH] yum: improved check_mode handling and package update flow. --- lib/ansible/modules/packaging/os/yum.py | 165 ++++++++++++++++-------- 1 file changed, 113 insertions(+), 52 deletions(-) diff --git a/lib/ansible/modules/packaging/os/yum.py b/lib/ansible/modules/packaging/os/yum.py index 80de14c8c87..41ee17d0bc2 100644 --- a/lib/ansible/modules/packaging/os/yum.py +++ b/lib/ansible/modules/packaging/os/yum.py @@ -224,7 +224,7 @@ def is_installed(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, di for rid in en_repos: my.repos.enableRepo(rid) - e,m,u = my.rpmdb.matchPackageNames([pkgspec]) + e, m, u = my.rpmdb.matchPackageNames([pkgspec]) pkgs = e + m if not pkgs: pkgs.extend(my.returnInstalledPackagesByDep(pkgspec)) @@ -236,16 +236,16 @@ def is_installed(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, di else: cmd = repoq + ["--disablerepo=*", "--pkgnarrow=installed", "--qf", qf, pkgspec] - rc,out,err = module.run_command(cmd) + rc, out, err = module.run_command(cmd) if not is_pkg: cmd = repoq + ["--disablerepo=*", "--pkgnarrow=installed", "--qf", qf, "--whatprovides", pkgspec] - rc2,out2,err2 = module.run_command(cmd) + rc2, out2, err2 = module.run_command(cmd) else: - rc2,out2,err2 = (0, '', '') + rc2, out2, err2 = (0, '', '') if rc == 0 and rc2 == 0: out += out2 - return [ p for p in out.split('\n') if p.strip() ] + return [p for p in out.split('\n') if p.strip()] else: module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err + err2)) @@ -553,7 +553,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): module.fail_json(msg="Failure downloading %s, %s" % (spec, e)) #groups :( - elif spec.startswith('@'): + elif spec.startswith('@'): # complete wild ass guess b/c it's a group pkg = spec @@ -620,7 +620,11 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): shutil.rmtree(tempdir) except Exception, e: module.fail_json(msg="Failure deleting temp directory %s, %s" % (tempdir, e)) - module.exit_json(changed=True) + + for p in pkgs: + # take note of which packages are getting installed + res['results'].append('%s will be installed' % p) + module.exit_json(changed=True, results=res['results']) changed = True @@ -688,7 +692,10 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): cmd = yum_basecmd + ["remove"] + pkgs if module.check_mode: - module.exit_json(changed=True) + # take note of which packages are getting removed + for p in pkgs: + res['results'].append('%s will be removed' % p) + module.exit_json(changed=True, results=res['results']) rc, out, err = module.run_command(cmd) @@ -723,47 +730,69 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): res['msg'] = '' res['changed'] = False res['rc'] = 0 - - for spec in items: - - pkg = None - basecmd = 'update' - cmd = '' - # groups, again - if spec.startswith('@'): - pkg = spec - - elif spec == '*': #update all - # use check-update to see if there is any need - rc,out,err = module.run_command(yum_basecmd + ['check-update']) - if rc == 100: - cmd = yum_basecmd + [basecmd] - else: - res['results'].append('All packages up to date') + pkgs = {} + pkgs['update'] = [] + pkgs['install'] = [] + updates = {} + update_all = False + cmd = None + + # determine if we're doing an update all + 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']) + if rc == 0 and update_all: + res['results'].append('Nothing to do here, all packages are up to date') + return res + elif rc == 100: + 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 - - # dep/pkgname - find it - else: - if is_installed(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos): - basecmd = 'update' else: - basecmd = 'install' + pkg, version, repo = line + name, dist = pkg.split('.') + updates.update({name: {'version': version, 'dist': dist, 'repo': repo}}) + elif rc == 1: + res['msg'] = err + res['rc'] = rc + module.fail_json(**res) + if update_all: + cmd = yum_basecmd + ['update'] + else: + for spec in items: + # some guess work involved with groups. update @ will install the group if missing + if spec.startswith('@'): + pkgs['update'].append(spec) + continue + # dep/pkgname - find it + else: + if is_installed(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos): + pkgs['update'].append(spec) + else: + pkgs['install'].append(spec) pkglist = what_provides(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos) + # FIXME..? may not be desirable to throw an exception here if a single package is missing if not pkglist: res['msg'] += "No Package matching '%s' found available, installed or updated" % spec module.fail_json(**res) - + nothing_to_do = True for this in pkglist: - if basecmd == 'install' and is_available(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos): + if spec in pkgs['install'] and is_available(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos): nothing_to_do = False break - - if basecmd == 'update' and is_update(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos): - nothing_to_do = False - break - + + if spec in pkgs['update'] and spec in updates.keys(): + nothing_to_do = False + if nothing_to_do: res['results'].append("All packages providing %s are up to date" % spec) continue @@ -775,26 +804,59 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): res['msg'] += "The following packages have pending transactions: %s" % ", ".join(conflicts) module.fail_json(**res) - pkg = spec - if not cmd: - cmd = yum_basecmd + [basecmd, pkg] + # list of package updates + if update_all: + will_update = updates.keys() + else: + will_update = [u for u in pkgs['update'] if u in updates.keys() or u.startswith('@')] - if module.check_mode: - return module.exit_json(changed=True) + # check_mode output + if module.check_mode: + for w in will_update: + if w.startswith('@'): + msg = '%s will be updated' % w + else: + msg = '%s will be updated with %s-%s.%s from %s' % (w, w, updates[w]['version'], updates[w]['dist'], updates[w]['repo']) + res['results'].append(msg) - rc, out, err = module.run_command(cmd) + for p in pkgs['install']: + res['results'].append('%s will be installed' % p) - res['rc'] += rc - res['results'].append(out) - res['msg'] += err + if len(will_update) > 0 or len(pkgs['install']) > 0: + res['changed'] = True - # FIXME if it is - update it and check to see if it applied - # check to see if there is no longer an update available for the pkgspec + return res - if rc: - res['failed'] = True + # run commands + if cmd: # update all + rc, out, err = module.run_command(cmd) + res['changed'] = True + else: + if len(pkgs['install']) > 0: # install missing + cmd = yum_basecmd + ['install'] + pkgs['install'] + rc, out, err = module.run_command(cmd) + res['changed'] = True else: + rc, out, err = [0, '', ''] + + if len(will_update) > 0: # update present + cmd = yum_basecmd + ['update'] + pkgs['update'] + rc2, out2, err2 = module.run_command(cmd) res['changed'] = True + else: + rc2, out2, err2 = [0, '', ''] + + if not update_all: + rc += rc2 + out += out2 + err += err2 + + res['rc'] += rc + res['msg'] += err + res['results'].append(out) + + if rc: + res['failed'] = True return res @@ -939,4 +1001,3 @@ from ansible.module_utils.basic import * from ansible.module_utils.urls import * if __name__ == '__main__': main() -