diff --git a/changelogs/fragments/nxos_file_copy.yaml b/changelogs/fragments/nxos_file_copy.yaml new file mode 100644 index 00000000000..13e28eb2949 --- /dev/null +++ b/changelogs/fragments/nxos_file_copy.yaml @@ -0,0 +1,2 @@ +bugfixes: +- Add md5sum check in nxos_file_copy module (https://github.com/ansible/ansible/pull/43423). diff --git a/changelogs/fragments/nxos_interface.yaml b/changelogs/fragments/nxos_interface.yaml new file mode 100644 index 00000000000..62fc10e2f2c --- /dev/null +++ b/changelogs/fragments/nxos_interface.yaml @@ -0,0 +1,2 @@ +bugfixes: +- nxos_interface port-channel idempotence fix for mode (https://github.com/ansible/ansible/pull/44248). diff --git a/changelogs/fragments/nxos_linkagg.yaml b/changelogs/fragments/nxos_linkagg.yaml new file mode 100644 index 00000000000..d1a6bd3fd2f --- /dev/null +++ b/changelogs/fragments/nxos_linkagg.yaml @@ -0,0 +1,2 @@ +bugfixes: +- nxos_linkagg mode fix (https://github.com/ansible/ansible/pull/44294). diff --git a/changelogs/fragments/nxos_static_route_fix.yaml b/changelogs/fragments/nxos_static_route_fix.yaml new file mode 100644 index 00000000000..7d708ecd585 --- /dev/null +++ b/changelogs/fragments/nxos_static_route_fix.yaml @@ -0,0 +1,2 @@ +bugfixes: +- Fix check_mode in nxos_static_route module (https://github.com/ansible/ansible/pull/44252). diff --git a/changelogs/fragments/terminal_plugin.yaml b/changelogs/fragments/terminal_plugin.yaml new file mode 100644 index 00000000000..15b6dd365fb --- /dev/null +++ b/changelogs/fragments/terminal_plugin.yaml @@ -0,0 +1,2 @@ +bugfixes: +- Fix Python2.6 regex bug terminal plugin nxos, iosxr (https://github.com/ansible/ansible/pull/45135). diff --git a/lib/ansible/modules/network/nxos/nxos_file_copy.py b/lib/ansible/modules/network/nxos/nxos_file_copy.py index 8da6d8455af..bebae7133c9 100644 --- a/lib/ansible/modules/network/nxos/nxos_file_copy.py +++ b/lib/ansible/modules/network/nxos/nxos_file_copy.py @@ -92,6 +92,7 @@ remote_file: sample: '/path/to/remote/file' ''' +import hashlib import os import re import time @@ -99,6 +100,7 @@ import time from ansible.module_utils.network.nxos.nxos import run_commands from ansible.module_utils.network.nxos.nxos import nxos_argument_spec, check_args from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_text, to_bytes try: import paramiko @@ -113,12 +115,34 @@ except ImportError: HAS_SCP = False +def md5sum_check(module, dst, file_system): + command = 'show file {0}{1} md5sum'.format(file_system, dst) + remote_filehash = run_commands(module, {'command': command, 'output': 'text'})[0] + remote_filehash = to_bytes(remote_filehash, errors='surrogate_or_strict') + + local_file = module.params['local_file'] + try: + with open(local_file, 'r') as f: + filecontent = f.read() + except (OSError, IOError) as exc: + module.fail_json(msg="Error reading the file: %s" % to_text(exc)) + + filecontent = to_bytes(filecontent, errors='surrogate_or_strict') + local_filehash = hashlib.md5(filecontent).hexdigest() + + if local_filehash == remote_filehash: + return True + else: + return False + + def remote_file_exists(module, dst, file_system='bootflash:'): command = 'dir {0}/{1}'.format(file_system, dst) body = run_commands(module, {'command': command, 'output': 'text'})[0] if 'No such file' in body: return False - return True + else: + return md5sum_check(module, dst, file_system) def verify_remote_file_exists(module, dst, file_system='bootflash:'): diff --git a/lib/ansible/modules/network/nxos/nxos_interface.py b/lib/ansible/modules/network/nxos/nxos_interface.py index aa5f6859d6b..091fa4dcd7e 100644 --- a/lib/ansible/modules/network/nxos/nxos_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_interface.py @@ -592,7 +592,11 @@ def map_config_to_obj(want, module): obj['name'] = normalize_interface(interface_table.get('interface')) obj['admin_state'] = interface_table.get('admin_state') obj['description'] = interface_table.get('desc') - obj['mode'] = interface_table.get('eth_mode') + mode = interface_table.get('eth_mode') + if mode == 'access': + obj['mode'] = 'layer2' + else: + obj['mode'] = 'layer3' objs.append(obj) diff --git a/lib/ansible/modules/network/nxos/nxos_linkagg.py b/lib/ansible/modules/network/nxos/nxos_linkagg.py index f3f47a316aa..8b936137483 100644 --- a/lib/ansible/modules/network/nxos/nxos_linkagg.py +++ b/lib/ansible/modules/network/nxos/nxos_linkagg.py @@ -161,6 +161,19 @@ def search_obj_in_list(group, lst): return o +def get_diff(w, obj): + c = deepcopy(w) + o = deepcopy(obj) + + if o['group'] == c['group'] and o.get('members') == c.get('members'): + if 'members' in o: + del o['members'] + if 'members' in c: + del c['members'] + diff_dict = dict(set(c.items()) - set(o.items())) + return diff_dict + + def map_obj_to_commands(updates, module): commands = list() want, have = updates @@ -230,6 +243,18 @@ def map_obj_to_commands(updates, module): commands.append('exit') commands.append('interface {0}'.format(m)) commands.append('no channel-group {0}'.format(group)) + + else: + diff = get_diff(w, obj_in_have) + if diff and 'mode' in diff: + mode = diff['mode'] + for i in members: + commands.append('interface {0}'.format(i)) + if force: + commands.append('channel-group {0} force mode {1}'.format(group, mode)) + else: + commands.append('channel-group {0} mode {1}'.format(group, mode)) + if purge: for h in have: obj_in_want = search_obj_in_list(h['group'], want) @@ -332,7 +357,7 @@ def parse_channel_options(module, output, channel): group = channel['group'] obj['group'] = group - obj['min-links'] = parse_min_links(module, group) + obj['min_links'] = parse_min_links(module, group) members = parse_members(output, group) obj['members'] = members for m in members: @@ -411,7 +436,16 @@ def main(): if commands: if not module.check_mode: - load_config(module, commands) + resp = load_config(module, commands, True) + if resp: + for item in resp: + if item: + if isinstance(item, dict): + err_str = item['clierror'] + else: + err_str = item + if 'cannot add' in err_str.lower(): + module.fail_json(msg=err_str) result['changed'] = True module.exit_json(**result) diff --git a/lib/ansible/modules/network/nxos/nxos_static_route.py b/lib/ansible/modules/network/nxos/nxos_static_route.py index 8460996d7be..abe17647059 100644 --- a/lib/ansible/modules/network/nxos/nxos_static_route.py +++ b/lib/ansible/modules/network/nxos/nxos_static_route.py @@ -280,13 +280,11 @@ def main(): candidate = CustomNetworkConfig(indent=3) reconcile_candidate(module, candidate, prefix, w) - if candidate: + if not module.check_mode and candidate: candidate = candidate.items_text() load_config(module, candidate) result['commands'].extend(candidate) result['changed'] = True - else: - result['commands'] = [] module.exit_json(**result) diff --git a/lib/ansible/plugins/terminal/iosxr.py b/lib/ansible/plugins/terminal/iosxr.py index 6a9657d0ab5..100b3d5863a 100644 --- a/lib/ansible/plugins/terminal/iosxr.py +++ b/lib/ansible/plugins/terminal/iosxr.py @@ -29,7 +29,7 @@ from ansible.errors import AnsibleConnectionFailure class TerminalModule(TerminalBase): terminal_stdout_re = [ - re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), + re.compile(br"[\r\n][\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), re.compile(br']]>]]>[\r\n]?') ] diff --git a/lib/ansible/plugins/terminal/nxos.py b/lib/ansible/plugins/terminal/nxos.py index a7edf1e01bf..ac9218118f6 100644 --- a/lib/ansible/plugins/terminal/nxos.py +++ b/lib/ansible/plugins/terminal/nxos.py @@ -30,7 +30,7 @@ from ansible.module_utils._text import to_bytes, to_text class TerminalModule(TerminalBase): terminal_stdout_re = [ - re.compile(br'[\r\n]?(?!\s*<)?(\x1b\S+)*[a-zA-Z_0-9]{1}[a-zA-Z0-9-_.]*[>|#](?:\s*)*(\x1b\S+)*$'), + re.compile(br'[\r\n](?!\s*<)?(\x1b\S+)*[a-zA-Z_0-9]{1}[a-zA-Z0-9-_.]*[>|#](?:\s*)*(\x1b\S+)*$'), re.compile(br'[\r\n]?[a-zA-Z0-9]{1}[a-zA-Z0-9-_.]*\(.+\)#(?:\s*)$') ]