diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index be9fedfb5dc..007cb32a33f 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -2918,3 +2918,7 @@ class AnsibleModule(object): def get_module_path(): return os.path.dirname(os.path.realpath(__file__)) + + +def get_timestamp(): + return datetime.datetime.now().replace(microsecond=0).isoformat() diff --git a/lib/ansible/module_utils/network/nxos/nxos.py b/lib/ansible/module_utils/network/nxos/nxos.py index 987e9cf0d0e..7684328bf91 100644 --- a/lib/ansible/module_utils/network/nxos/nxos.py +++ b/lib/ansible/module_utils/network/nxos/nxos.py @@ -33,7 +33,7 @@ import json import re from ansible.module_utils._text import to_text -from ansible.module_utils.basic import env_fallback, return_values +from ansible.module_utils.basic import env_fallback, return_values, get_timestamp from ansible.module_utils.network.common.utils import to_list, ComplexList from ansible.module_utils.connection import Connection, ConnectionError from ansible.module_utils.common._collections_compat import Mapping @@ -154,13 +154,13 @@ class Cli: self._device_configs[cmd] = cfg return cfg - def run_commands(self, commands, check_rc=True): + def run_commands(self, commands, check_rc=True, return_timestamps=False): """Run list of commands on remote device and return results """ connection = self._get_connection() try: - out = connection.run_commands(commands, check_rc) + out, timestamps = connection.run_commands(commands, check_rc) if check_rc == 'retry_json': capabilities = self.get_capabilities() network_api = capabilities.get('network_api') @@ -170,8 +170,11 @@ class Cli: if ('Invalid command at' in resp or 'Ambiguous command at' in resp) and 'json' in resp: if commands[index]['output'] == 'json': commands[index]['output'] = 'text' - out = connection.run_commands(commands, check_rc) - return out + out, timestamps = connection.run_commands(commands, check_rc) + if return_timestamps: + return out, timestamps + else: + return out except ConnectionError as exc: self._module.fail_json(msg=to_text(exc)) @@ -339,6 +342,7 @@ class LocalNxapi: headers = {'Content-Type': 'application/json'} result = list() + timestamps = list() timeout = self._module.params['timeout'] use_proxy = self._module.params['provider']['use_proxy'] @@ -346,6 +350,7 @@ class LocalNxapi: if self._nxapi_auth: headers['Cookie'] = self._nxapi_auth + timestamp = get_timestamp() response, headers = fetch_url( self._module, self._url, data=req, headers=headers, timeout=timeout, method='POST', use_proxy=use_proxy @@ -373,12 +378,13 @@ class LocalNxapi: self._error(output=output, **item) elif 'body' in item: result.append(item['body']) + timestamps.append(timestamp) # else: # error in command but since check_status is disabled # silently drop it. # result.append(item['msg']) - return result + return result, timestamps def get_config(self, flags=None): """Retrieves the current config from the device or cache @@ -392,17 +398,18 @@ class LocalNxapi: try: return self._device_configs[cmd] except KeyError: - out = self.send_request(cmd) + out, out_timestamps = self.send_request(cmd) cfg = str(out[0]).strip() self._device_configs[cmd] = cfg return cfg - def run_commands(self, commands, check_rc=True): + def run_commands(self, commands, check_rc=True, return_timestamps=False): """Run list of commands on remote device and return results """ output = None queue = list() responses = list() + timestamps = list() def _send(commands, output): return self.send_request(commands, output, check_status=check_rc) @@ -413,16 +420,23 @@ class LocalNxapi: item['output'] = 'json' if all((output == 'json', item['output'] == 'text')) or all((output == 'text', item['output'] == 'json')): - responses.extend(_send(queue, output)) + out, out_timestamps = _send(queue, output) + responses.extend(out) + timestamps.extend(out_timestamps) queue = list() output = item['output'] or 'json' queue.append(item['command']) if queue: - responses.extend(_send(queue, output)) + out, out_timestamps = _send(queue, output) + responses.extend(out) + timestamps.extend(out_timestamps) - return responses + if return_timestamps: + return responses, timestamps + else: + return responses def load_config(self, commands, return_error=False, opts=None, replace=None): """Sends the ordered set of commands to the device @@ -435,8 +449,8 @@ class LocalNxapi: commands = to_list(commands) - msg = self.send_request(commands, output='config', check_status=True, - return_error=return_error, opts=opts) + msg, msg_timestamps = self.send_request(commands, output='config', check_status=True, + return_error=return_error, opts=opts) if return_error: return msg else: @@ -515,7 +529,7 @@ class HttpApi: return self._connection_obj - def run_commands(self, commands, check_rc=True): + def run_commands(self, commands, check_rc=True, return_timestamps=False): """Runs list of commands on remote device and returns results """ try: @@ -702,9 +716,9 @@ def get_config(module, flags=None): return conn.get_config(flags=flags) -def run_commands(module, commands, check_rc=True): +def run_commands(module, commands, check_rc=True, return_timestamps=False): conn = get_connection(module) - return conn.run_commands(to_command(module, commands), check_rc) + return conn.run_commands(to_command(module, commands), check_rc, return_timestamps) def load_config(module, config, return_error=False, opts=None, replace=None): diff --git a/lib/ansible/modules/network/nxos/nxos_command.py b/lib/ansible/modules/network/nxos/nxos_command.py index d207a528315..2dcda538ecd 100644 --- a/lib/ansible/modules/network/nxos/nxos_command.py +++ b/lib/ansible/modules/network/nxos/nxos_command.py @@ -188,8 +188,7 @@ def main(): match = module.params['match'] while retries > 0: - responses = run_commands(module, commands) - + responses, timestamps = run_commands(module, commands, return_timestamps=True) for item in list(conditionals): try: if item(responses): @@ -214,6 +213,7 @@ def main(): result.update({ 'stdout': responses, 'stdout_lines': list(to_lines(responses)), + 'timestamps': timestamps }) module.exit_json(**result) diff --git a/lib/ansible/plugins/cliconf/nxos.py b/lib/ansible/plugins/cliconf/nxos.py index 00129eac0e3..e3f75815aa1 100644 --- a/lib/ansible/plugins/cliconf/nxos.py +++ b/lib/ansible/plugins/cliconf/nxos.py @@ -23,6 +23,7 @@ import json import re from ansible.errors import AnsibleConnectionFailure +from ansible.module_utils.basic import get_timestamp from ansible.module_utils._text import to_bytes, to_text from ansible.module_utils.common._collections_compat import Mapping from ansible.module_utils.connection import ConnectionError @@ -187,6 +188,7 @@ class Cliconf(CliconfBase): raise ValueError("'commands' value is required") responses = list() + timestamps = list() for cmd in to_list(commands): if not isinstance(cmd, Mapping): cmd = {'command': cmd} @@ -196,6 +198,7 @@ class Cliconf(CliconfBase): cmd['command'] = self._get_command_with_output(cmd['command'], output) try: + timestamp = get_timestamp() out = self.send_command(**cmd) except AnsibleConnectionFailure as e: if check_rc is True: @@ -214,7 +217,8 @@ class Cliconf(CliconfBase): pass responses.append(out) - return responses + timestamps.append(timestamp) + return responses, timestamps def get_device_operations(self): return { diff --git a/test/units/modules/network/nxos/test_nxos_command.py b/test/units/modules/network/nxos/test_nxos_command.py index a3c148212a3..2e043daf5a3 100644 --- a/test/units/modules/network/nxos/test_nxos_command.py +++ b/test/units/modules/network/nxos/test_nxos_command.py @@ -22,6 +22,7 @@ __metaclass__ = type import json from units.compat.mock import patch +from ansible.module_utils.basic import get_timestamp from ansible.modules.network.nxos import nxos_command from .nxos_module import TestNxosModule, load_fixture, set_module_args @@ -44,6 +45,7 @@ class TestNxosCommandModule(TestNxosModule): def load_from_file(*args, **kwargs): module, commands = args output = list() + timestamps = list() for item in commands: try: @@ -53,7 +55,8 @@ class TestNxosCommandModule(TestNxosModule): command = item['command'] filename = '%s.txt' % str(command).replace(' ', '_') output.append(load_fixture('nxos_command', filename)) - return output + timestamps.append(get_timestamp()) + return output, timestamps self.run_commands.side_effect = load_from_file