diff --git a/lib/ansible/modules/utilities/helper/meta.py b/lib/ansible/modules/utilities/helper/meta.py index a89bfc5d394..a8d3fd3c335 100644 --- a/lib/ansible/modules/utilities/helper/meta.py +++ b/lib/ansible/modules/utilities/helper/meta.py @@ -40,6 +40,7 @@ options: - "C(clear_facts) (added in 2.1) causes the gathered facts for the hosts specified in the play's list of hosts to be cleared, including the fact cache." - "C(clear_host_errors) (added in 2.1) clears the failed state (if any) from hosts specified in the play's list of hosts." - "C(end_play) (added in 2.2) causes the play to end without failing the host." + - "C(reset_connection) (added in 2.3) interrupts a persistent connection (i.e. ssh + control persist)" choices: ['noop', 'flush_handlers', 'refresh_inventory', 'clear_facts', 'clear_host_errors', 'end_play'] required: true default: null @@ -50,29 +51,32 @@ author: ''' EXAMPLES = ''' -# force all notified handlers to run at this point, not waiting for normal sync points - template: src: new.j2 dest: /etc/config.txt notify: myhandler -- meta: flush_handlers +- name: force all notified handlers to run at this point, not waiting for normal sync points + meta: flush_handlers -# reload inventory, useful with dynamic inventories when play makes changes to the existing hosts -- cloud_guest: # this is fake module +- name: reload inventory, useful with dynamic inventories when play makes changes to the existing hosts + cloud_guest: # this is fake module name: newhost state: present - - name: Refresh inventory to ensure new instaces exist in inventory meta: refresh_inventory - name: Clear gathered facts from all currently targeted hosts meta: clear_facts -# bring host back to play after failure -- copy: +- name: bring host back to play after failure + copy: src: file dest: /etc/file remote_user: imightnothavepermission - meta: clear_host_errors + +- user: name={{ansible_user}} groups=input +- name: reset ssh connection to allow user changes to affect 'current login user' + meta: reset_connection ''' diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index 7a26d158335..b62e9a08a9f 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -776,18 +776,16 @@ class Connection(ConnectionBase): display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self.host) self._file_transport_command(in_path, out_path, 'get') - def close(self): - # If we have a persistent ssh connection (ControlPersist), we can ask it - # to stop listening. Otherwise, there's nothing to do here. - - # TODO: reenable once winrm issues are fixed - # temporarily disabled as we are forced to currently close connections after every task because of winrm - # if self._connected and self._persistent: - # ssh_executable = self._play_context.ssh_executable - # cmd = self._build_command('ssh', '-O', 'stop', self.host) - # - # cmd = map(to_bytes, cmd) - # p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - # stdout, stderr = p.communicate() + def reset(self): + # If we have a persistent ssh connection (ControlPersist), we can ask it to stop listening. + cmd = map(to_bytes, self._build_command(self._play_context.ssh_executable, '-O', 'stop', self.host)) + controlpersist, controlpath = self._persistence_controls(cmd) + if controlpersist: + p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + display.vvv(u'sending stop: %s' % cmd) + self.close() + + def close(self): self._connected = False diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index 8b277638d65..9252b6c4474 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -902,8 +902,10 @@ class StrategyBase: if not host.name in self._tqm._unreachable_hosts: iterator._host_states[host.name].run_state = iterator.ITERATING_COMPLETE msg="ending play" - #elif meta_action == 'reset_connection': - # connection_info.connection.close() + elif meta_action == 'reset_connection': + connection = connection_loader.get(play_context.connection, play_context, '/dev/null') + connection.reset() + msg= 'reset connection' else: raise AnsibleError("invalid meta action requested: %s" % meta_action, obj=task._ds)