Repository: ansible/ansible

Issue:
meta: reset_connection not working
<!---
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
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
`meta` module's `reset_connection`

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
[vagrant@localhost infra-bootstrap]$ ansible --version
ansible 2.3.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.5 (default, Sep  5 2016, 02:30:38) [GCC 4.8.5 20150623 (Red Hat 4.8.5-9)]
```

##### CONFIGURATION
<!---
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.
-->
OEL7

##### SUMMARY
<!--- Explain the problem briefly -->
Using the `meta: reset_connection` instruction appears to be broken under very simple use case.

##### 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.
-->
Using a very simple playbook (below), the `meta: reset_connection` instruction stack traces (command below under `ACUAL RESULTS`)

<!--- Paste example playbooks or commands between quotes below -->
simple `test.yml`:
```yaml
---
- hosts: all
  tasks:
  - meta: reset_connection
```

inventory:
```
# Generated by Vagrant

node01
core ansible_connection=local

[core]
core

[development]
core
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The ssh connection to get reset successfully

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Ansible stack traces

<!--- Paste verbatim command output between quotes below -->
```
[vagrant@localhost infra-bootstrap]$ ansible-playbook --limit=core --inventory-file=/tmp/vagrant-ansible/inventory -vvv test.yml
Using /etc/ansible/ansible.cfg as config file
 [WARNING]: Found both group and host with same name: core


PLAYBOOK: test.yml ***************************************************************************************************************************************************
1 plays in test.yml

PLAY [all] ***********************************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************************
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/setup.py
<core> ESTABLISH LOCAL CONNECTION FOR USER: vagrant
<core> EXEC /bin/sh -c 'echo ~ && sleep 0'
<core> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807 `" && echo ansible-tmp-1492207079.55-247174731112807="` echo /home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807 `" ) && sleep 0'
<core> PUT /tmp/tmpbuhXwS TO /home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807/setup.py
<core> EXEC /bin/sh -c 'chmod u+x /home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807/ /home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807/setup.py && sleep 0'
<core> EXEC /bin/sh -c '/usr/bin/python /home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807/setup.py; rm -rf "/home/vagrant/.ansible/tmp/ansible-tmp-1492207079.55-247174731112807/" > /dev/null 2>&1 && sleep 0'
ok: [core]
META: ran handlers
ERROR! Unexpected Exception: 'NoneType' object has no attribute 'reset'
the full traceback was:

Traceback (most recent call last):
  File "/usr/bin/ansible-playbook", line 109, in <module>
    exit_code = cli.run()
  File "/usr/lib/python2.7/site-packages/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/usr/lib/python2.7/site-packages/ansible/executor/playbook_executor.py", line 153, in run
    result = self._tqm.run(play=play)
  File "/usr/lib/python2.7/site-packages/ansible/executor/task_queue_manager.py", line 284, in run
    play_return = strategy.run(iterator, play_context)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/strategy/linear.py", line 221, in run
    results.extend(self._execute_meta(task, play_context, iterator, host))
  File "/usr/lib/python2.7/site-packages/ansible/plugins/strategy/__init__.py", line 908, in _execute_meta
    connection.reset()
AttributeError: 'NoneType' object has no attribute 'reset'
```



Discussion:
@ansibot I can reproduce the issue.
If the robot can accept some command from someone to know if this is an issue can be reproduced...
Looks like this will fail if the config for 'transport = smart'. Using 'ssh' or 'paramiko' works.

Looks like there 'connection_loader.get' fails for 'smart' and ends up returning None and causing the error.
@alikins yes you are right.
I am also affected by this. The context is common with related issues. I try installing docker and then use it with the same account as used for connection.

There are three issues happening:
1. The connection of type "smart" is not converted to "ssh" in the meta
https://github.com/ansible/ansible/blob/v2.3.1.0-0.2.rc2/lib/ansible/plugins/strategy/__init__.py#L903
2. The connection parameters are not propagated
3. The ssh stop command is not checked for failure
https://github.com/ansible/ansible/blob/v2.3.1.0-0.2.rc2/lib/ansible/plugins/connection/ssh.py#L817

In the last one the result status and command output are discarded. The play should fail if the status is 
not 0 and the stdout/stderr should be reported as failure cause. I tested it with some additional log statements and it came clear that the target host and most likely port are not passed to the ssh command.



Resolving patch:
diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py
--- a/lib/ansible/plugins/connection/ssh.py
+++ b/lib/ansible/plugins/connection/ssh.py
@@ -894,9 +894,12 @@ def reset(self):
         cmd = map(to_bytes, self._build_command(self._play_context.ssh_executable, '-O', 'stop', self.host))
         controlpersist, controlpath = self._persistence_controls(cmd)
         if controlpersist:
+            display.vvv(u'sending stop: %s' % cmd)
             p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             stdout, stderr = p.communicate()
-            display.vvv(u'sending stop: %s' % cmd)
+            status_code = p.wait()
+            if status_code != 0:
+                raise AnsibleError("Cannot reset connection:\n%s" % stderr)
 
         self.close()
 


Test patch: