Repository: ansible/ansible-modules-extras

Issue:
rabbitmq_parameter fails when passing dynamically generated json
##### Issue Type:

“Bug Report”
##### Ansible Version:

ansible 1.8.2
  configured module search path = None

Tested also on ansible 1.9
ansible 1.9 (devel 8f06ba2bc1) last updated 2015/02/05 11:16:37 (GMT +200)
  lib/ansible/modules/core: (detached HEAD 600fc15b42) last updated 2015/02/05 11:16:50 (GMT +200)
  lib/ansible/modules/extras: (detached HEAD 77485f6c6a) last updated 2015/02/05 11:17:01 (GMT +200)
  v2/ansible/modules/core: (detached HEAD 600fc15b42) last updated 2015/02/05 11:17:13 (GMT +200)
  v2/ansible/modules/extras: (detached HEAD 77485f6c6a) last updated 2015/02/05 11:17:36 (GMT +200)
  configured module search path = None
##### Environment:

OS X 10.9.5 > Ubuntu 14.04
##### Summary:

Passing non-hardcoded json (through templating) to rabbitmq_parameter's "value" argument raises an exception. It works when hardcoding the json though.
##### Steps To Reproduce:

Here's an example playbook with one successful task (the first one), and two failing tasks (the next two) which both raise the same exception (see below). All of them are supposed to do the same thing.

```
- hosts: my-host
  tasks:
        - set_fact:
              upstream_list:
                    - upstream: "test"
                    - upstream: "test2"
              json_upstreams: '[{"upstream":"test1"},{"upstream":"test2"}]'

        - rabbitmq_parameter:
              component: federation-upstream-set
              name: test-upstream-set
              value: '[{"upstream":"test1"},{"upstream":"test2"}]'
           sudo: yes

        - rabbitmq_parameter:
              component: federation-upstream-set
              name: test-upstream-set
              value: '{{ json_upstreams }}'
           sudo: yes

        - rabbitmq_parameter:
              component: federation-upstream-set
              name: test-upstream-set
              value: '{{ upstream_list|to_json }}'
           sudo: yes
```
##### Expected Results:

Set a federation-upstream-set parameter to the default vhost.
##### Actual Results:

The two failing tasks raise the same exception. The output from ansible with -vvvv is as follows:

```
<my-host> ESTABLISH CONNECTION FOR USER: xxxx
<my-host> REMOTE_MODULE rabbitmq_parameter name=test-upstream-set component=federation-upstream-set vhost=/
<my-host> EXEC ssh -C -vvv -o ForwardAgent=yes -o ControlMaster=auto -o     ControlPersist=30m -o ControlPath="xxxx/.ansible/cp/ansible-ssh-%h-%p-%r" -o Port=22 -o     KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-k
eyex,hostbased,publickey -o PasswordAuthentication=no -o User=xxxx -o ConnectTimeout=10 my-    host /bin/sh -c 'sudo -k && sudo -H -S -p "[sudo via ansible, key=xxxxxx] password: " -u root /bin/sh -c         '"'"'echo SUDO-SUCCESS-xxxxxx; LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python'"'"''
failed: [my-host] => {"failed": true, "parsed": false}
SUDO-SUCCESS-xxxxxx
OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011
debug1: Reading configuration data /xxxxx/.ssh/config
debug1: Reading configuration data /etc/ssh_config
debug1: /etc/ssh_config line 20: Applying options for *
debug1: /etc/ssh_config line 102: Applying options for *
debug1: auto-mux: Trying existing master
debug2: fd 3 setting O_NONBLOCK
debug2: mux_client_hello_exchange: master version 4
debug3: mux_client_forwards: request forwardings: 0 local, 0 remote
debug3: mux_client_request_session: entering
debug3: mux_client_request_alive: entering
debug3: mux_client_request_alive: done pid = 58450
debug3: mux_client_request_session: session request sent
debug1: mux_client_request_session: master session id: 2
[sudo via ansible, key=xxxxx] password: Traceback (most recent call last):
  File "<stdin>", line 1717, in <module>
  File "<stdin>", line 142, in main
  File "<stdin>", line 104, in set
  File "<stdin>", line 88, in _exec
  File "<stdin>", line 1566, in run_command
  File "/usr/lib/python2.7/posixpath.py", line 261, in expanduser
    if not path.startswith('~'):
AttributeError: 'list' object has no attribute 'startswith'
debug3: mux_client_read_packet: read header failed: Broken pipe
debug2: Received exit status from master 1
```
##### Tentative solution:

From what I've seen while troubleshooting the issue, the problem comes from the rabbitmq_parameter module being passed a list to its "value" argument. It is then passed to AnsibleModule::run_command, which assumes it is a string and passes it through os.path.expanduser.
I've managed to correct this behavior by setting the value to `value if type(value) == str else json.dumps(value)`.
I can submit a more complete patch or pull request if this is indeed a bug and not an issue in my playbook.



Discussion:
[module: messaging/rabbitmq_parameter.py]

@axelcdv Thanks for submitting this bug report. Apologies for taking so long to triage it. Since this bug has been open for a while, we would appreciate if you can verify if you are still seeing the reported behavior in the latest version.

If you are seeing the reported behavior, just let us know and we will leave the bug open and notify the module maintainer.

If you are no longer seeing the reported behavior, please let us know and we will close the bug report.

I've got the same issue trying to setup shovel using rabbitmq_parameter with ansible version 1.9.3.

```
-  rabbitmq_parameter:
    component: shovel
    name: "{{item.src}}_duplication"
    value: '{ "src-uri": "amqp://", "src-queue": "{{item.src}}", "dest-uri": "amqp://", "dest-queue": "{{item.dest}}" }'
    state: present
  with_items: 
    - { src: 'aaa', dest: 'bbb' }
```

Output:

```
       <localhost> REMOTE_MODULE rabbitmq_parameter name=aaa_duplication component=shovel state=present
       <localhost> EXEC ['/bin/sh', '-c', 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832 && echo $HOME/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832']
       <localhost> PUT /tmp/tmpfDxoAw TO /home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter
       <localhost> EXEC ['/bin/sh', '-c', u'LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter; rm -rf /home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/ >/dev/null 2>&1']
       failed: [localhost] => (item={u'dest': u'bbb', u'src': u'aaa'}) => {"failed": true, "item": {"dest": "bbb", "src": "aaa"}, "parsed": false}
       Traceback (most recent call last):
         File "/home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter", line 1764, in <module>
           main()
         File "/home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter", line 145, in main
           rabbitmq_parameter.set()
         File "/home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter", line 104, in set
           self._exec(['set_parameter', '-p', self.vhost, self.component, self.name, self.value])
         File "/home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter", line 88, in _exec
           rc, out, err = self.module.run_command(cmd + args, check_rc=True)
         File "/home/vagrant/.ansible/tmp/ansible-tmp-1444649840.0-200891719251832/rabbitmq_parameter", line 1608, in run_command
           args = [ os.path.expandvars(os.path.expanduser(x)) for x in args ]
         File "/usr/lib/python2.7/posixpath.py", line 261, in expanduser
           if not path.startswith('~'):
       AttributeError: 'dict' object has no attribute 'startswith'
```


Resolving patch:
diff --git a/messaging/rabbitmq_parameter.py b/messaging/rabbitmq_parameter.py
--- a/messaging/rabbitmq_parameter.py
+++ b/messaging/rabbitmq_parameter.py
@@ -126,6 +126,8 @@ def main():
     component = module.params['component']
     name = module.params['name']
     value = module.params['value']
+    if not isinstance(value, str):
+        value = json.dumps(value)
     vhost = module.params['vhost']
     state = module.params['state']
     node = module.params['node']


Test patch: