Repository: ansible/ansible-modules-extras

Issue:
rabbitmq_user module assumes there is at least one user on target system
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME

rabbitmq_user
##### ANSIBLE VERSION

"ansible 2.2.0 (devel fbec9ce58b) last updated 2016/05/04 13:07:35 (GMT +200)"
##### CONFIGURATION

<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
##### OS / ENVIRONMENT

```
zaz@blackjack:work/ansible-playbox <master*> $ cat ansible.cfg
[defaults]
inventory = hosts
roles_path = roles
host_key_checking = False

[ssh_connection]
scp_if_ssh = True
ssh_args = -o ForwardAgent=yes
pipelining = True
```
##### SUMMARY

Running rabbitmq_user on a system where there are no rabbitmq users (i.e. guest user has been removed) produces the following failure output:

```
fatal: [vogsphere-dev-broker.42.fr]: FAILED! => {"changed": false, "failed": true, "module_stderr": "", "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_A4Rnkc/ansible_module_rabbitmq_user.py\", line 302, in <module>\r\n    main()\r\n  File \"/tmp/ansible_A4Rnkc/ansible_module_rabbitmq_user.py\", line 295, in main\r\n    rabbitmq_user.set_permissions()\r\n  File \"/tmp/ansible_A4Rnkc/ansible_module_rabbitmq_user.py\", line 206, in set_permissions\r\n    for permission in self._permissions:\r\nTypeError: 'NoneType' object is not iterable\r\n", "msg": "MODULE FAILURE", "parsed": false}
```

Next run works, because the module adds the user before attempting to set permissions, but after reading the existing permissions into self._permissions
##### STEPS TO REPRODUCE

Tested on a Debian 8.3 target system, but I see no reason why it couldn't be reproduced elsewhere.

```
- hosts: REDACTED
  tasks:
    - name: update apt
      apt: update_cache=yes
    - name: install rabbitmq-server
      apt: name=rabbitmq-server state=latest
    - name: delete guest user
      rabbitmq_user: >
        user=guest state=absent
    - name: attempt to create a user
      rabbitmq_user: >
        user=demo
        password=randompassword
        vhost=/ configure_priv=".*" read_priv=".*" write_priv=".*" state=present
        tags=administrator
```
##### EXPECTED RESULTS

rabbitmq-server is installed
guest user is deleted
demo user is created
##### ACTUAL RESULTS

```
zaz@blackjack:work/ansible-playbox <master*> $ ansible-playbook a.yml

PLAY [REDACTED] **********************************************

TASK [setup] *******************************************************************
ok: [REDACTED]

TASK [update apt] **************************************************************
ok: [REDACTED]

TASK [install rabbitmq-server] *************************************************
ok: [REDACTED]

TASK [delete guest user] *******************************************************
ok: [REDACTED]

TASK [attempt to create a user] ************************************************
fatal: [REDACTED]: FAILED! => {"changed": false, "failed": true, "module_stderr": "", "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_szbjWf/ansible_module_rabbitmq_user.py\", line 302, in <module>\r\n    main()\r\n  File \"/tmp/ansible_szbjWf/ansible_module_rabbitmq_user.py\", line 295, in main\r\n    rabbitmq_user.set_permissions()\r\n  File \"/tmp/ansible_szbjWf/ansible_module_rabbitmq_user.py\", line 206, in set_permissions\r\n    for permission in self._permissions:\r\nTypeError: 'NoneType' object is not iterable\r\n", "msg": "MODULE FAILURE", "parsed": false}

NO MORE HOSTS LEFT *************************************************************
    to retry, use: --limit @a.retry

PLAY RECAP *********************************************************************
REDACTED : ok=4    changed=0    unreachable=0    failed=1
```
##### MORE DETAILS

The module appears to first read the current permissions of the system into an internal list (self._permissions) before attempting to update them to the requested permissions. However, since this list is actually initialized to None, on a system with no users, it stays None. When the module attempts to actually set the permissions, the call fails because it attempts to iterate on _permissions.

Easily fixed by setting self._permissions to [] instead of None in the __init__ of the module, will submit pull request shortly.



Discussion:

Resolving patch:
diff --git a/messaging/rabbitmq_user.py b/messaging/rabbitmq_user.py
--- a/messaging/rabbitmq_user.py
+++ b/messaging/rabbitmq_user.py
@@ -139,7 +139,7 @@ def __init__(self, module, username, password, tags, permissions,
         self.bulk_permissions = bulk_permissions
 
         self._tags = None
-        self._permissions = None
+        self._permissions = []
         self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
 
     def _exec(self, args, run_in_check_mode=False):


Test patch: