diff --git a/lib/ansible/cli/scripts/ansible_connection_cli_stub.py b/lib/ansible/cli/scripts/ansible_connection_cli_stub.py index 20bfc6b3a8b..2505cbf2c46 100755 --- a/lib/ansible/cli/scripts/ansible_connection_cli_stub.py +++ b/lib/ansible/cli/scripts/ansible_connection_cli_stub.py @@ -71,10 +71,11 @@ class ConnectionProcess(object): The connection process wraps around a Connection object that manages the connection to a remote device that persists over the playbook ''' - def __init__(self, fd, play_context, socket_path, original_path, ansible_playbook_pid=None): + def __init__(self, fd, play_context, socket_path, original_path, task_uuid=None, ansible_playbook_pid=None): self.play_context = play_context self.socket_path = socket_path self.original_path = original_path + self._task_uuid = task_uuid self.fd = fd self.exception = None @@ -98,7 +99,7 @@ class ConnectionProcess(object): if self.play_context.private_key_file and self.play_context.private_key_file[0] not in '~/': self.play_context.private_key_file = os.path.join(self.original_path, self.play_context.private_key_file) self.connection = connection_loader.get(self.play_context.connection, self.play_context, '/dev/null', - ansible_playbook_pid=self._ansible_playbook_pid) + task_uuid=self._task_uuid, ansible_playbook_pid=self._ansible_playbook_pid) self.connection.set_options(var_options=variables) self.connection._socket_path = self.socket_path @@ -257,8 +258,8 @@ def main(): if rc == 0: ssh = connection_loader.get('ssh', class_only=True) ansible_playbook_pid = sys.argv[1] + task_uuid = sys.argv[2] cp = ssh._create_control_path(play_context.remote_addr, play_context.port, play_context.remote_user, play_context.connection, ansible_playbook_pid) - # create the persistent connection dir if need be and create the paths # which we will be using later tmp_path = unfrackpath(C.PERSISTENT_CONTROL_PATH_DIR) @@ -278,7 +279,7 @@ def main(): try: os.close(r) wfd = os.fdopen(w, 'w') - process = ConnectionProcess(wfd, play_context, socket_path, original_path, ansible_playbook_pid) + process = ConnectionProcess(wfd, play_context, socket_path, original_path, task_uuid, ansible_playbook_pid) process.start(variables) except Exception: messages.append(('error', traceback.format_exc())) @@ -305,7 +306,7 @@ def main(): pc_data = to_text(init_data) try: conn.update_play_context(pc_data) - conn.set_cli_prompt_context() + conn.update_cli_prompt_context(task_uuid) except Exception as exc: # Only network_cli has update_play context and set_cli_prompt_context, so missing this is # not fatal e.g. netconf diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 0516479adc2..73e0aeed22a 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -926,7 +926,7 @@ class TaskExecutor: display.vvvv('using connection plugin %s' % connection.transport, host=self._play_context.remote_addr) options = self._get_persistent_connection_options(connection, variables, templar) - socket_path = start_connection(self._play_context, options) + socket_path = start_connection(self._play_context, options, self._task._uuid) display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr) setattr(connection, '_socket_path', socket_path) @@ -1046,7 +1046,7 @@ class TaskExecutor: return handler -def start_connection(play_context, variables): +def start_connection(play_context, variables, task_uuid): ''' Starts the persistent connection ''' @@ -1078,7 +1078,7 @@ def start_connection(play_context, variables): python = sys.executable master, slave = pty.openpty() p = subprocess.Popen( - [python, ansible_connection, to_text(os.getppid())], + [python, ansible_connection, to_text(os.getppid()), to_text(task_uuid)], stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env ) os.close(slave) diff --git a/lib/ansible/plugins/action/aireos.py b/lib/ansible/plugins/action/aireos.py index 38e897ae00c..d10d6353f2a 100644 --- a/lib/ansible/plugins/action/aireos.py +++ b/lib/ansible/plugins/action/aireos.py @@ -57,7 +57,7 @@ class ActionModule(ActionNetworkModule): command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/aruba.py b/lib/ansible/plugins/action/aruba.py index 193fdac91f5..4763a5d257d 100644 --- a/lib/ansible/plugins/action/aruba.py +++ b/lib/ansible/plugins/action/aruba.py @@ -58,7 +58,7 @@ class ActionModule(ActionNetworkModule): command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/asa.py b/lib/ansible/plugins/action/asa.py index 2f9a939920d..b58d18e71f1 100644 --- a/lib/ansible/plugins/action/asa.py +++ b/lib/ansible/plugins/action/asa.py @@ -55,7 +55,7 @@ class ActionModule(ActionNetworkModule): pc.become_method = 'enable' display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/bigip.py b/lib/ansible/plugins/action/bigip.py index 6420212d731..0103d757f2e 100644 --- a/lib/ansible/plugins/action/bigip.py +++ b/lib/ansible/plugins/action/bigip.py @@ -69,7 +69,7 @@ class ActionModule(ActionNetworkModule): command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/bigiq.py b/lib/ansible/plugins/action/bigiq.py index 3b3553cf47a..8b4bd15fc51 100644 --- a/lib/ansible/plugins/action/bigiq.py +++ b/lib/ansible/plugins/action/bigiq.py @@ -66,7 +66,7 @@ class ActionModule(_ActionModule): command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/ce.py b/lib/ansible/plugins/action/ce.py index c5877d22d70..54093ac39c6 100644 --- a/lib/ansible/plugins/action/ce.py +++ b/lib/ansible/plugins/action/ce.py @@ -58,7 +58,7 @@ class ActionModule(ActionNetworkModule): if self._task.action in ['ce_netconf'] or self._task.action not in CLI_SUPPORTED_MODULES: pc.connection = 'netconf' display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/cnos.py b/lib/ansible/plugins/action/cnos.py index 064fb3a9439..5120b4ae91d 100644 --- a/lib/ansible/plugins/action/cnos.py +++ b/lib/ansible/plugins/action/cnos.py @@ -52,7 +52,7 @@ class ActionModule(ActionNetworkModule): pc.become_method = 'enable' display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/dellos10.py b/lib/ansible/plugins/action/dellos10.py index d3a8480b170..ec8423626ea 100644 --- a/lib/ansible/plugins/action/dellos10.py +++ b/lib/ansible/plugins/action/dellos10.py @@ -62,7 +62,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/dellos6.py b/lib/ansible/plugins/action/dellos6.py index 9efcb6493d5..98b4596dbd0 100644 --- a/lib/ansible/plugins/action/dellos6.py +++ b/lib/ansible/plugins/action/dellos6.py @@ -63,7 +63,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/dellos9.py b/lib/ansible/plugins/action/dellos9.py index 318f0d87892..7e79b3219e1 100644 --- a/lib/ansible/plugins/action/dellos9.py +++ b/lib/ansible/plugins/action/dellos9.py @@ -63,7 +63,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/enos.py b/lib/ansible/plugins/action/enos.py index 4eb650f6f4d..68da7bffa17 100644 --- a/lib/ansible/plugins/action/enos.py +++ b/lib/ansible/plugins/action/enos.py @@ -52,7 +52,7 @@ class ActionModule(ActionNetworkModule): pc.become_method = 'enable' display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/eos.py b/lib/ansible/plugins/action/eos.py index 9a4d41efae5..1019d4bbc4e 100644 --- a/lib/ansible/plugins/action/eos.py +++ b/lib/ansible/plugins/action/eos.py @@ -68,7 +68,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/action/ios.py b/lib/ansible/plugins/action/ios.py index 9d2a630559a..50ebc781426 100644 --- a/lib/ansible/plugins/action/ios.py +++ b/lib/ansible/plugins/action/ios.py @@ -59,7 +59,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/action/iosxr.py b/lib/ansible/plugins/action/iosxr.py index 61950309ca8..c9617cba313 100644 --- a/lib/ansible/plugins/action/iosxr.py +++ b/lib/ansible/plugins/action/iosxr.py @@ -58,7 +58,7 @@ class ActionModule(ActionNetworkModule): pc.password = provider['password'] or self._play_context.password display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/action/ironware.py b/lib/ansible/plugins/action/ironware.py index 0ef8898d2cf..a76ae74a405 100644 --- a/lib/ansible/plugins/action/ironware.py +++ b/lib/ansible/plugins/action/ironware.py @@ -58,7 +58,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/action/junos.py b/lib/ansible/plugins/action/junos.py index ee09f2060fb..385d4899c3e 100644 --- a/lib/ansible/plugins/action/junos.py +++ b/lib/ansible/plugins/action/junos.py @@ -63,7 +63,7 @@ class ActionModule(ActionNetworkModule): pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/action/net_base.py b/lib/ansible/plugins/action/net_base.py index 9a207f1efca..b6cee56deb3 100644 --- a/lib/ansible/plugins/action/net_base.py +++ b/lib/ansible/plugins/action/net_base.py @@ -133,7 +133,7 @@ class ActionModule(ActionBase): display.vvv('using connection plugin %s (was local)' % play_context.connection, play_context.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', - play_context, sys.stdin) + play_context, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': play_context.timeout}) diff --git a/lib/ansible/plugins/action/netconf.py b/lib/ansible/plugins/action/netconf.py index 54250212131..9c0510b4650 100644 --- a/lib/ansible/plugins/action/netconf.py +++ b/lib/ansible/plugins/action/netconf.py @@ -54,7 +54,7 @@ class ActionModule(ActionNetworkModule): pc.private_key_file = args.get('ssh_keyfile') or self._play_context.private_key_file display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) timeout = args.get('timeout') command_timeout = int(timeout) if timeout else connection.get_option('persistent_command_timeout') diff --git a/lib/ansible/plugins/action/nxos.py b/lib/ansible/plugins/action/nxos.py index 5d9763da83c..fb634b15586 100644 --- a/lib/ansible/plugins/action/nxos.py +++ b/lib/ansible/plugins/action/nxos.py @@ -101,7 +101,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/action/sros.py b/lib/ansible/plugins/action/sros.py index 3ee7f1c9c89..e7af522bb72 100644 --- a/lib/ansible/plugins/action/sros.py +++ b/lib/ansible/plugins/action/sros.py @@ -56,7 +56,7 @@ class ActionModule(ActionNetworkModule): command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() diff --git a/lib/ansible/plugins/action/vyos.py b/lib/ansible/plugins/action/vyos.py index e0083d98fe2..c7a8a732971 100644 --- a/lib/ansible/plugins/action/vyos.py +++ b/lib/ansible/plugins/action/vyos.py @@ -55,7 +55,7 @@ class ActionModule(ActionNetworkModule): pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') connection.set_options(direct={'persistent_command_timeout': command_timeout}) diff --git a/lib/ansible/plugins/connection/network_cli.py b/lib/ansible/plugins/connection/network_cli.py index c80c7084f8f..f5a07860067 100644 --- a/lib/ansible/plugins/connection/network_cli.py +++ b/lib/ansible/plugins/connection/network_cli.py @@ -319,6 +319,7 @@ class Connection(NetworkConnectionBase): self._terminal = None self.cliconf = None self._paramiko_conn = None + self._task_uuid = to_text(kwargs.get('task_uuid', '')) if self._play_context.verbosity > 3: logging.getLogger('paramiko').setLevel(logging.DEBUG) @@ -408,6 +409,12 @@ class Connection(NetworkConnectionBase): if hasattr(self, 'disable_response_logging'): self.disable_response_logging() + def update_cli_prompt_context(self, task_uuid): + # set cli prompt context at the start of new task run only + if self._task_uuid != task_uuid: + self.set_cli_prompt_context() + self._task_uuid = task_uuid + def _connect(self): ''' Connects to the remote device and starts the terminal diff --git a/lib/ansible/plugins/connection/persistent.py b/lib/ansible/plugins/connection/persistent.py index fc4f5a44d06..626d9dd433f 100644 --- a/lib/ansible/plugins/connection/persistent.py +++ b/lib/ansible/plugins/connection/persistent.py @@ -31,6 +31,7 @@ options: """ from ansible.executor.task_executor import start_connection from ansible.plugins.connection import ConnectionBase +from ansible.module_utils._text import to_text from ansible.module_utils.connection import Connection as SocketConnection from ansible.utils.display import Display @@ -43,6 +44,10 @@ class Connection(ConnectionBase): transport = 'persistent' has_pipelining = False + def __init__(self, play_context, new_stdin, *args, **kwargs): + super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs) + self._task_uuid = to_text(kwargs.get('task_uuid', '')) + def _connect(self): self._connected = True return self @@ -71,7 +76,7 @@ class Connection(ConnectionBase): """ display.vvvv('starting connection from persistent connection plugin', host=self._play_context.remote_addr) variables = {'ansible_command_timeout': self.get_option('persistent_command_timeout')} - socket_path = start_connection(self._play_context, variables) + socket_path = start_connection(self._play_context, variables, self._task_uuid) display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr) setattr(self, '_socket_path', socket_path) return socket_path diff --git a/test/integration/targets/junos_command/tests/cli/cli_commmand.yaml b/test/integration/targets/junos_command/tests/cli/cli_commmand.yaml index 012327adeff..64022023c1d 100644 --- a/test/integration/targets/junos_command/tests/cli/cli_commmand.yaml +++ b/test/integration/targets/junos_command/tests/cli/cli_commmand.yaml @@ -29,6 +29,36 @@ - assert: that: - "result.changed == false" + + - cli_command: + command: "{{item}}" + prompt: + - "New password" + - "Retype new password" + answer: + - "Test1234" + - "Test1234" + check_all: True + loop: + - "configure" + - "rollback" + - "set system login user ansible_test class operator authentication plain-text-password" + - "commit" + register: result + ignore_errors: True + + - assert: + that: + - "'failed' not in result" + + - junos_netconf: + register: result + ignore_errors: True + + - assert: + that: + - "result.failed == false" + when: ansible_connection == 'network_cli' - debug: msg="END cli/cli_command.yaml on connection={{ ansible_connection }}"