From ef7a75938a657792ba67d74e686371251b2709ad Mon Sep 17 00:00:00 2001
From: Toshio Kuratomi <toshio@fedoraproject.org>
Date: Mon, 15 Jun 2015 09:51:15 -0700
Subject: [PATCH] Further optimizations pointed out by @kustodian in #1516

* Only install yum-utils if needed (b/c we're going to use repoquery)
* Add a warning message explaining that why slower repoquery was used
  rather than yum API.
---
 packaging/os/yum.py | 86 ++++++++++++++++++++++++---------------------
 1 file changed, 45 insertions(+), 41 deletions(-)

diff --git a/packaging/os/yum.py b/packaging/os/yum.py
index 61fc9f53333..ece8b2407bd 100644
--- a/packaging/os/yum.py
+++ b/packaging/os/yum.py
@@ -165,12 +165,17 @@ def yum_base(conf_file=None):
         my.preconf.fn = conf_file
     return my
 
-def install_yum_utils(module):
+def ensure_yum_utils(module):
 
-    if not module.check_mode:    
+    repoquerybin = module.get_bin_path('repoquery', required=False)
+
+    if module.params['install_repoquery'] and not repoquerybin and not module.check_mode:
         yum_path = module.get_bin_path('yum')
         if yum_path:
-            rc, so, se = module.run_command('%s -y install yum-utils' % yum_path) 
+            rc, so, se = module.run_command('%s -y install yum-utils' % yum_path)
+        repoquerybin = module.get_bin_path('repoquery', required=False)
+
+    return repoquerybin
 
 def po_to_nevra(po):
 
@@ -313,7 +318,7 @@ def is_update(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=None, dis_r
         else:
             module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err))
             
-    return []
+    return set()
 
 def what_provides(module, repoq, req_spec, conf_file,  qf=def_qf, en_repos=None, dis_repos=None):
     if en_repos is None:
@@ -365,7 +370,7 @@ def what_provides(module, repoq, req_spec, conf_file,  qf=def_qf, en_repos=None,
         else:
             module.fail_json(msg='Error from repoquery: %s: %s' % (cmd, err + err2))
 
-    return []
+    return set()
 
 def transaction_exists(pkglist):
     """ 
@@ -626,8 +631,8 @@ 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(**res)
+
+    return res
 
 
 def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
@@ -681,8 +686,8 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
 
         if rc != 0:
             module.fail_json(**res)
-            
-    module.exit_json(**res)
+
+    return res
 
 def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
 
@@ -764,30 +769,15 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
         else:
             res['changed'] = True
 
-    module.exit_json(**res)
+    return res
 
 def ensure(module, state, pkgs, conf_file, enablerepo, disablerepo,
-           disable_gpg_check, exclude):
+           disable_gpg_check, exclude, repoq):
 
     yumbin = module.get_bin_path('yum')
     # need debug level 2 to get 'Nothing to do' for groupinstall.
     yum_basecmd = [yumbin, '-d', '2', '-y']
 
-    # If rhn-plugin is installed and no rhn-certificate is available on the
-    # system then users will see an error message using the yum API.  Use
-    # repoquery in those cases.
-
-    my = yum_base(conf_file)
-    # A sideeffect of accessing conf is that the configuration is
-    # loaded and plugins are discovered
-    my.conf
-
-    repoq = None
-    if 'rhnplugin' in my.plugins._plugins:
-        repoquery = module.get_bin_path('repoquery', required=False)
-        if repoquery:
-            repoq = [repoquery, '--show-duplicates', '--plugins', '--quiet']
-
     if conf_file and os.path.exists(conf_file):
         yum_basecmd += ['-c', conf_file]
         if repoq:
@@ -834,16 +824,19 @@ def ensure(module, state, pkgs, conf_file, enablerepo, disablerepo,
     if state in ['installed', 'present']:
         if disable_gpg_check:
             yum_basecmd.append('--nogpgcheck')
-        install(module, pkgs, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
+        res = install(module, pkgs, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
     elif state in ['removed', 'absent']:
-        remove(module, pkgs, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
+        res = remove(module, pkgs, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
     elif state == 'latest':
         if disable_gpg_check:
             yum_basecmd.append('--nogpgcheck')
-        latest(module, pkgs, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
+        res = latest(module, pkgs, repoq, yum_basecmd, conf_file, en_repos, dis_repos)
+    else:
+        # should be caught by AnsibleModule argument_spec
+        module.fail_json(msg="we should never get here unless this all
+                failed", changed=False, results='', errors='unepected state')
 
-    # should be caught by AnsibleModule argument_spec
-    return dict(changed=False, failed=True, results='', errors='unexpected state')
+    return res
 
 def main():
 
@@ -878,28 +871,39 @@ def main():
         supports_check_mode = True
     )
 
-    # this should not be needed, but exists as a failsafe
-    params = module.params
-    if params['install_repoquery'] and not repoquery and not module.check_mode:
-        install_yum_utils(module)
-
-    repoquerybin = module.get_bin_path('repoquery', required=False)
     if params['list']:
+        repoquerybin = ensure_yum_utils(module)
         if not repoquerybin:
             module.fail_json(msg="repoquery is required to use list= with this module. Please install the yum-utils package.")
         results = dict(results=list_stuff(module, repoquerybin, params['conf_file'], params['list']))
-        module.exit_json(**results)
 
     else:
+        # If rhn-plugin is installed and no rhn-certificate is available on
+        # the system then users will see an error message using the yum API.
+        # Use repoquery in those cases.
+
+        my = yum_base(conf_file)
+        # A sideeffect of accessing conf is that the configuration is
+        # loaded and plugins are discovered
+        my.conf
+        repoquery = None
+        if 'rhnplugin' in my.plugins._plugins:
+            repoquerybin = ensure_yum_utils(module)
+            if repoquerybin:
+                repoquery = [repoquerybin, '--show-duplicates', '--plugins', '--quiet']
+
         pkg = [ p.strip() for p in params['name']]
         exclude = params['exclude']
         state = params['state']
         enablerepo = params.get('enablerepo', '')
         disablerepo = params.get('disablerepo', '')
         disable_gpg_check = params['disable_gpg_check']
-        res = ensure(module, state, pkg, params['conf_file'], enablerepo,
-                     disablerepo, disable_gpg_check, exclude)
-        module.fail_json(msg="we should never get here unless this all failed", **res)
+        results = ensure(module, state, pkg, params['conf_file'], enablerepo,
+                     disablerepo, disable_gpg_check, exclude, repoquery)
+        if repoquery:
+            results['msg'] = '%s %s' % (results.get('msg',''), 'Warning: Due to potential bad behaviour with rhnplugin and certificates, used slower repoquery calls instead of Yum API.')
+
+    module.exit_json(**results)
 
 # import module snippets
 from ansible.module_utils.basic import *