Repository: ansible/ansible

Issue:
urpmi: update_cache is broken
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
urpmi

##### ANSIBLE VERSION
```
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/mitya/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.13 (default, Dec 31 2017, 00:22:48) [GCC 5.4.0]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Mageia Linux 6

##### SUMMARY
In the `urpmi` module, `update_cache` is borked.
The `urpmi.update` executable resides in `/usr/sbin`, thus it should be invoked with full path. At the moment, it is called as is, causing "[Errno 2] No such file or directory".

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
---

- hosts: localhost

  tasks:

  - name: foo
    urpmi: package=foo update_cache=true
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
urpmi cache should be updated prior to the package installation

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
fatal: [localhost]: FAILED! => {"changed": false, "cmd": "urpmi.update -a -q", "failed": true, "msg": "[Errno 2] No such file or directory", "rc": 2}
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/packaging/os/urpmi.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/packaging/os/urpmi.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @pmakowski
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/packaging/os/urpmi.py b/lib/ansible/modules/packaging/os/urpmi.py
--- a/lib/ansible/modules/packaging/os/urpmi.py
+++ b/lib/ansible/modules/packaging/os/urpmi.py
@@ -22,10 +22,12 @@
   - Manages packages with I(urpmi) (such as for Mageia or Mandriva)
 version_added: "1.3.4"
 options:
-  pkg:
+  name:
     description:
-      - Name of package to install, upgrade or remove.
+      - A list of package names to install, upgrade or remove.
     required: yes
+    version_added: "2.6"
+    aliases: [ package, pkg ]
   state:
     description:
       - Indicates the desired package state.
@@ -82,20 +84,19 @@
     update_cache: yes
 '''
 
+
 import os
 import shlex
 import sys
 
 from ansible.module_utils.basic import AnsibleModule
 
-URPMI_PATH = '/usr/sbin/urpmi'
-URPME_PATH = '/usr/sbin/urpme'
-
 
 def query_package(module, name, root):
     # rpm -q returns 0 if the package is installed,
     # 1 if it is not installed
-    cmd = "rpm -q %s %s" % (name, root_option(root))
+    rpm_path = module.get_bin_path("rpm", True)
+    cmd = "%s -q %s %s" % (rpm_path, name, root_option(root))
     rc, stdout, stderr = module.run_command(cmd, check_rc=False)
     if rc == 0:
         return True
@@ -106,13 +107,16 @@ def query_package(module, name, root):
 def query_package_provides(module, name, root):
     # rpm -q returns 0 if the package is installed,
     # 1 if it is not installed
-    cmd = "rpm -q --provides %s %s" % (name, root_option(root))
+    rpm_path = module.get_bin_path("rpm", True)
+    cmd = "%s -q --whatprovides %s %s" % (rpm_path, name, root_option(root))
     rc, stdout, stderr = module.run_command(cmd, check_rc=False)
     return rc == 0
 
 
 def update_package_db(module):
-    cmd = "urpmi.update -a -q"
+
+    urpmiupdate_path = module.get_bin_path("urpmi.update", True)
+    cmd = "%s -a -q" % (urpmiupdate_path,)
     rc, stdout, stderr = module.run_command(cmd, check_rc=False)
     if rc != 0:
         module.fail_json(msg="could not update package db")
@@ -127,7 +131,8 @@ def remove_packages(module, packages, root):
         if not query_package(module, package, root):
             continue
 
-        cmd = "%s --auto %s %s" % (URPME_PATH, root_option(root), package)
+        urpme_path = module.get_bin_path("urpme", True)
+        cmd = "%s --auto %s %s" % (urpme_path, root_option(root), package)
         rc, stdout, stderr = module.run_command(cmd, check_rc=False)
 
         if rc != 0:
@@ -160,17 +165,20 @@ def install_packages(module, pkgspec, root, force=True, no_recommends=True):
         else:
             force_yes = ''
 
-        cmd = ("%s --auto %s --quiet %s %s %s" % (URPMI_PATH, force_yes, no_recommends_yes, root_option(root), packages))
+        urpmi_path = module.get_bin_path("urpmi", True)
+        cmd = ("%s --auto %s --quiet %s %s %s" % (urpmi_path, force_yes,
+                                                  no_recommends_yes,
+                                                  root_option(root),
+                                                  packages))
 
         rc, out, err = module.run_command(cmd)
 
-        installed = True
-        for packages in pkgspec:
+        for package in pkgspec:
             if not query_package_provides(module, package, root):
-                installed = False
+                module.fail_json(msg="'urpmi %s' failed: %s" % (package, err))
 
         # urpmi always have 0 for exit code if --force is used
-        if rc or not installed:
+        if rc:
             module.fail_json(msg="'urpmi %s' failed: %s" % (packages, err))
         else:
             module.exit_json(changed=True, msg="%s present(s)" % packages)
@@ -188,18 +196,16 @@ def root_option(root):
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            state=dict(type='str', default='installed', choices=['absent', 'installed', 'present', 'removed']),
+            state=dict(type='str', default='installed',
+                       choices=['absent', 'installed', 'present', 'removed']),
             update_cache=dict(type='bool', default=False, aliases=['update-cache']),
             force=dict(type='bool', default=True),
             no_recommends=dict(type='bool', default=True, aliases=['no-recommends']),
-            package=dict(type='str', required=True, aliases=['name', 'pkg']),
+            name=dict(type='list', required=True, aliases=['package', 'pkg']),
             root=dict(type='str', aliases=['installroot']),
         ),
     )
 
-    if not os.path.exists(URPMI_PATH):
-        module.fail_json(msg="cannot find urpmi, looking for %s" % (URPMI_PATH))
-
     p = module.params
 
     force_yes = p['force']
@@ -209,7 +215,7 @@ def main():
     if p['update_cache']:
         update_package_db(module)
 
-    packages = p['package'].split(',')
+    packages = p['package']
 
     if p['state'] in ['installed', 'present']:
         install_packages(module, packages, root, force_yes, no_recommends_yes)


Test patch: