Repository: ansible/ansible

Issue:
expect fails with 'str' object has no attribute 'decode' for python3
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
expect module: modules/commands/expect.py

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 3.5.1 (default, Apr  2 2017, 11:46:56) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
```

##### CONFIGURATION
```
host_key_checking = False
```


##### OS / ENVIRONMENT
Running Python 3.5.3 on the targeted hosts (with pexpect==4.2.1) by modifiying the `ansible_python_interpreter` in the inventory file (`ansible_python_interpreter=/usr/local/bin/python3`)

##### SUMMARY
When running a play with the expect module and Python 3 installed on the targeted hosts, it fails with the following error:
```
fatal: [debian8]: FAILED! => {
    "changed": false,
    "failed": true,
    "module_stderr": "Shared connection to 192.168.33.111 closed.\r\n",
    "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_39h5lqrl/ansible_module_expect.py\", line 244, in <module>\r\n    main()\r\n  File \"/tmp/ansible_39h5lqrl/ansible_module_expect.py\", line 160, in main\r\n    events[key.decode()] = response\r\nAttributeError: 'str' object has no attribute 'decode'\r\n",
    "msg": "MODULE FAILURE",
    "rc": 0
}
```
This issue is pretty similar to #21668. Both seems to be related to the fact python3 has not `decode` for strings. The offending line is here: https://github.com/ansible/ansible/blob/2bf7297bf399d293b48371ee525872d2b4c02e97/lib/ansible/modules/commands/expect.py#L160

##### STEPS TO REPRODUCE
```yaml
---
- hosts: debian8
  tasks:
    - name: Test Script
      expect:
        command: test.sh
        responses:
          enter one: 'one'
          enter two: 'two'
```
test.sh:
```bash
#!/usr/bin/env bash
read -p "enter one: " one
echo $one
read -p "enter two: " two
echo $two
```

##### EXPECTED RESULTS
Module executed by providing the given responses.

##### ACTUAL RESULTS
```
Using module file /usr/local/lib/python3.5/site-packages/ansible/modules/commands/expect.py
<192.168.33.111> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.111> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile="/Users/elmhaidara/dev/vms/debian8/.vagrant/machines/debian8/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=10 -o ControlPath=/Users/elmhaidara/.ansible/cp/db944c059a 192.168.33.111 '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
<192.168.33.111> (0, b'/home/vagrant\n', b'')
<192.168.33.111> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.111> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile="/Users/elmhaidara/dev/vms/debian8/.vagrant/machines/debian8/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=10 -o ControlPath=/Users/elmhaidara/.ansible/cp/db944c059a 192.168.33.111 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339 `" && echo ansible-tmp-1493766691.040637-147158662762339="` echo /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339 `" ) && sleep 0'"'"''
<192.168.33.111> (0, b'ansible-tmp-1493766691.040637-147158662762339=/home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339\n', b'')
<192.168.33.111> PUT /var/folders/3g/c_w63l892b34bhhy6m0vgl2r0000gn/T/tmp16lswu1n TO /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339/expect.py
<192.168.33.111> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile="/Users/elmhaidara/dev/vms/debian8/.vagrant/machines/debian8/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=10 -o ControlPath=/Users/elmhaidara/.ansible/cp/db944c059a '[192.168.33.111]'
<192.168.33.111> (0, b'sftp> put /var/folders/3g/c_w63l892b34bhhy6m0vgl2r0000gn/T/tmp16lswu1n /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339/expect.py\n', b'')
<192.168.33.111> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.111> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile="/Users/elmhaidara/dev/vms/debian8/.vagrant/machines/debian8/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=10 -o ControlPath=/Users/elmhaidara/.ansible/cp/db944c059a 192.168.33.111 '/bin/sh -c '"'"'chmod u+x /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339/ /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339/expect.py && sleep 0'"'"''
<192.168.33.111> (0, b'', b'')
<192.168.33.111> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.111> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile="/Users/elmhaidara/dev/vms/debian8/.vagrant/machines/debian8/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=10 -o ControlPath=/Users/elmhaidara/.ansible/cp/db944c059a -tt 192.168.33.111 '/bin/sh -c '"'"'/usr/local/bin/python3 /home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339/expect.py; rm -rf "/home/vagrant/.ansible/tmp/ansible-tmp-1493766691.040637-147158662762339/" > /dev/null 2>&1 && sleep 0'"'"''
<192.168.33.111> (0, b'Traceback (most recent call last):\r\n  File "/tmp/ansible_39h5lqrl/ansible_module_expect.py", line 244, in <module>\r\n    main()\r\n  File "/tmp/ansible_39h5lqrl/ansible_module_expect.py", line 160, in main\r\n    events[key.decode()] = response\r\nAttributeError: \'str\' object has no attribute \'decode\'\r\n', b'Shared connection to 192.168.33.111 closed.\r\n')
fatal: [debian8]: FAILED! => {
    "changed": false,
    "failed": true,
    "module_stderr": "Shared connection to 192.168.33.111 closed.\r\n",
    "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_39h5lqrl/ansible_module_expect.py\", line 244, in <module>\r\n    main()\r\n  File \"/tmp/ansible_39h5lqrl/ansible_module_expect.py\", line 160, in main\r\n    events[key.decode()] = response\r\nAttributeError: 'str' object has no attribute 'decode'\r\n",
    "msg": "MODULE FAILURE",
    "rc": 0
}
```



Discussion:
cc @sivel
[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/commands/expect.py b/lib/ansible/modules/commands/expect.py
--- a/lib/ansible/modules/commands/expect.py
+++ b/lib/ansible/modules/commands/expect.py
@@ -157,7 +157,7 @@ def main():
         else:
             response = u'%s\n' % to_text(value).rstrip(u'\n')
 
-        events[key.decode()] = response
+        events[to_text(key)] = response
 
     if args.strip() == '':
         module.fail_json(rc=256, msg="no command given")


Test patch: