diff --git a/changelogs/fragments/nxos_bugfixes.yaml b/changelogs/fragments/nxos_bugfixes.yaml index 72bcc979292..367d7515f20 100644 --- a/changelogs/fragments/nxos_bugfixes.yaml +++ b/changelogs/fragments/nxos_bugfixes.yaml @@ -9,3 +9,9 @@ bugfixes: - nxos_vrf_af - Fix nxos_vrf_af issues (https://github.com/ansible/ansible/pull/37211) - nxos_udld - Fix nxos_udld issues (https://github.com/ansible/ansible/pull/37418) - nxos_vlan - Fix nxos_vlan issues (https://github.com/ansible/ansible/pull/38008) +- nxos_vlan - nxos_vlan purge (https://github.com/ansible/ansible/pull/38202) +- nxos_aaa_server - Fix nxos_aaa_server (https://github.com/ansible/ansible/pull/38117) +- nxos_aaa_server_host - Fix nxos_aaa_server_host (https://github.com/ansible/ansible/pull/38188) +- nxos_acl - Fix nxos_acl (https://github.com/ansible/ansible/pull/38283) +- nxos_static_route - Fix nxos_static_route (https://github.com/ansible/ansible/pull/37614) +- nxos_acl_interface test - Fix nxos_acl_interface test (https://github.com/ansible/ansible/pull/38230) diff --git a/lib/ansible/modules/network/nxos/nxos_aaa_server.py b/lib/ansible/modules/network/nxos/nxos_aaa_server.py index e95fd4283cd..6d705a4758b 100644 --- a/lib/ansible/modules/network/nxos/nxos_aaa_server.py +++ b/lib/ansible/modules/network/nxos/nxos_aaa_server.py @@ -39,7 +39,6 @@ notes: stored as encrypted (type 7). - Changes to the global AAA server key with encrypt_type=0 are not idempotent. - - If global AAA server key is not found, it's shown as "unknown" - state=default will set the supplied parameters to their default values. The parameters that you want to default must also be set to default. If global_key=default, the global key will be removed. @@ -51,9 +50,7 @@ options: choices: ['radius', 'tacacs'] global_key: description: - - Global AAA shared secret. - required: false - default: null + - Global AAA shared secret or keyword 'default'. encrypt_type: description: - The state of encryption applied to the entered global key. @@ -64,18 +61,17 @@ options: deadtime: description: - Duration for which a non-reachable AAA server is skipped, - in minutes. Range is 1-1440. Device default is 0. + in minutes or keyword 'default. + Range is 1-1440. Device default is 0. required: false default: null server_timeout: description: - - Global AAA server timeout period, in seconds. Range is 1-60. - Device default is 5. - required: false - default: null + - Global AAA server timeout period, in seconds or keyword 'default. + Range is 1-60. Device default is 5. directed_request: description: - - Enables direct authentication requests to AAA server. + - Enables direct authentication requests to AAA server or keyword 'default' Device default is disabled. required: false default: null @@ -127,7 +123,14 @@ from ansible.module_utils.network.nxos.nxos import nxos_argument_spec, check_arg from ansible.module_utils.basic import AnsibleModule -def execute_show_command(command, module, command_type='cli_show'): +PARAM_TO_DEFAULT_KEYMAP = { + 'server_timeout': '5', + 'deadtime': '0', + 'directed_request': 'disabled', +} + + +def execute_show_command(command, module): command = { 'command': command, 'output': 'text', @@ -153,8 +156,7 @@ def get_aaa_server_info(server_type, module): global_key_command = 'show run | sec {0}'.format(server_type) aaa_regex = r'.*{0}-server\skey\s\d\s+(?P\S+).*'.format(server_type) - server_body = execute_show_command( - server_command, module, command_type='cli_show_ascii')[0] + server_body = execute_show_command(server_command, module)[0] split_server = server_body.splitlines() @@ -165,30 +167,25 @@ def get_aaa_server_info(server_type, module): elif line.startswith('deadtime'): aaa_server_info['deadtime'] = line.split(':')[1] - request_body = execute_show_command( - request_command, module, command_type='cli_show_ascii')[0] - aaa_server_info['directed_request'] = request_body.replace('\n', '') + request_body = execute_show_command(request_command, module)[0] - key_body = execute_show_command( - global_key_command, module, command_type='cli_show_ascii')[0] + if bool(request_body): + aaa_server_info['directed_request'] = request_body.replace('\n', '') + else: + aaa_server_info['directed_request'] = 'disabled' + + key_body = execute_show_command(global_key_command, module)[0] try: match_global_key = re.match(aaa_regex, key_body, re.DOTALL) group_key = match_global_key.groupdict() aaa_server_info['global_key'] = group_key["key"].replace('\"', '') except (AttributeError, TypeError): - aaa_server_info['global_key'] = 'unknown' + aaa_server_info['global_key'] = None return aaa_server_info -def set_aaa_server_global_key(encrypt_type, key, server_type): - if not encrypt_type: - encrypt_type = '' - return '{0}-server key {1} {2}'.format( - server_type, encrypt_type, key) - - def config_aaa_server(params, server_type): cmds = [] @@ -226,13 +223,13 @@ def default_aaa_server(existing, params, server_type): global_key = params.get('global_key') existing_key = existing.get('global_key') - if deadtime is not None: + if deadtime is not None and existing.get('deadtime') != PARAM_TO_DEFAULT_KEYMAP['deadtime']: cmds.append('no {0}-server deadtime 1'.format(server_type)) - if server_timeout is not None: + if server_timeout is not None and existing.get('server_timeout') != PARAM_TO_DEFAULT_KEYMAP['server_timeout']: cmds.append('no {0}-server timeout 1'.format(server_type)) - if directed_request is not None: + if directed_request is not None and existing.get('directed_request') != PARAM_TO_DEFAULT_KEYMAP['directed_request']: cmds.append('no {0}-server directed-request'.format(server_type)) if global_key is not None and existing_key is not None: diff --git a/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py b/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py index 916ca1ea57e..0c1d6bc6f41 100644 --- a/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py +++ b/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py @@ -33,7 +33,7 @@ description: author: Jason Edelman (@jedelman8) notes: - Tested against NXOSv 7.3.(0)D1(1) on VIRL - - Changes to the AAA server host key (shared secret) are not idempotent. + - Changes to the host key (shared secret) are not idempotent for type 0. - If C(state=absent) removes the whole host configuration. options: server_type: @@ -47,41 +47,29 @@ options: required: true key: description: - - Shared secret for the specified host. - required: false - default: null + - Shared secret for the specified host or keyword 'default'. encrypt_type: description: - The state of encryption applied to the entered key. O for clear text, 7 for encrypted. Type-6 encryption is not supported. - required: false - default: null choices: ['0', '7'] host_timeout: description: - - Timeout period for specified host, in seconds. Range is 1-60. - required: false - default: null + - Timeout period for specified host, in seconds or keyword 'default. + Range is 1-60. auth_port: description: - - Alternate UDP port for RADIUS authentication. - required: false - default: null + - Alternate UDP port for RADIUS authentication or keyword 'default'. acct_port: description: - - Alternate UDP port for RADIUS accounting. - required: false - default: null + - Alternate UDP port for RADIUS accounting or keyword 'default'. tacacs_port: description: - - Alternate TCP port TACACS Server. - required: false - default: null + - Alternate TCP port TACACS Server or keyword 'default'. state: description: - Manage the state of the resource. - required: false default: present choices: ['present','absent'] ''' @@ -160,13 +148,11 @@ from ansible.module_utils.network.nxos.nxos import get_capabilities, nxos_argume from ansible.module_utils.basic import AnsibleModule -def execute_show_command(command, module, command_type='cli_show'): +def execute_show_command(command, module): device_info = get_capabilities(module) network_api = device_info.get('network_api', 'nxapi') if network_api == 'cliconf': - if 'show run' not in command: - command += ' | json' cmds = [command] body = run_commands(module, cmds) elif network_api == 'nxapi': @@ -186,40 +172,36 @@ def flatten_list(command_lists): return flat_command_list -def _match_dict(match_list, key_map): - no_blanks = [] - match_dict = {} - - for match_set in match_list: - match_set = tuple(v for v in match_set if v) - no_blanks.append(match_set) - - for info in no_blanks: - words = info[0].strip().split() - length = len(words) - alt_key = key_map.get(words[0]) - first = alt_key or words[0] - last = words[length - 1] - match_dict[first] = last.replace('\"', '') - - return match_dict - - def get_aaa_host_info(module, server_type, address): aaa_host_info = {} command = 'show run | inc {0}-server.host.{1}'.format(server_type, address) - body = execute_show_command(command, module, command_type='cli_show_ascii') - - if body[0]: + body = execute_show_command(command, module)[0] + if body: try: - pattern = (r'(acct-port \d+)|(timeout \d+)|(auth-port \d+)|' - r'(key 7 "\w+")|( port \d+)') - raw_match = re.findall(pattern, body[0]) - aaa_host_info = _match_dict(raw_match, {'acct-port': 'acct_port', - 'auth-port': 'auth_port', - 'port': 'tacacs_port', - 'timeout': 'host_timeout'}) + if 'radius' in body: + pattern = (r'\S+ host \S+(?:\s+key 7\s+(\S+))?(?:\s+auth-port (\d+))?' + r'(?:\s+acct-port (\d+))?(?:\s+authentication)?' + r'(?:\s+accounting)?(?:\s+timeout (\d+))?') + match = re.search(pattern, body) + aaa_host_info['key'] = match.group(1) + if aaa_host_info['key']: + aaa_host_info['key'] = aaa_host_info['key'].replace('"', '') + aaa_host_info['encrypt_type'] = '7' + aaa_host_info['auth_port'] = match.group(2) + aaa_host_info['acct_port'] = match.group(3) + aaa_host_info['host_timeout'] = match.group(4) + elif 'tacacs' in body: + pattern = (r'\S+ host \S+(?:\s+key 7\s+(\S+))?(?:\s+port (\d+))?' + r'(?:\s+timeout (\d+))?') + match = re.search(pattern, body) + aaa_host_info['key'] = match.group(1) + if aaa_host_info['key']: + aaa_host_info['key'] = aaa_host_info['key'].replace('"', '') + aaa_host_info['encrypt_type'] = '7' + aaa_host_info['tacacs_port'] = match.group(2) + aaa_host_info['host_timeout'] = match.group(3) + aaa_host_info['server_type'] = server_type aaa_host_info['address'] = address except TypeError: @@ -230,35 +212,41 @@ def get_aaa_host_info(module, server_type, address): return aaa_host_info -def config_aaa_host(server_type, address, params, clear=False): +def config_aaa_host(server_type, address, params, existing): cmds = [] - - if clear: - cmds.append('no {0}-server host {1}'.format(server_type, address)) - cmd_str = '{0}-server host {1}'.format(server_type, address) + cmd_no_str = 'no ' + cmd_str key = params.get('key') enc_type = params.get('encrypt_type', '') - host_timeout = params.get('host_timeout') - auth_port = params.get('auth_port') - acct_port = params.get('acct_port') - port = params.get('tacacs_port') - - if auth_port: - cmd_str += ' auth-port {0}'.format(auth_port) - if acct_port: - cmd_str += ' acct-port {0}'.format(acct_port) - if port: - cmd_str += ' port {0}'.format(port) - if host_timeout: - cmd_str += ' timeout {0}'.format(host_timeout) + + defval = False + nondef = False + if key: - cmds.append('{0}-server host {1} key {2} {3}'.format(server_type, - address, - enc_type, key)) + if key != 'default': + cmds.append(cmd_str + ' key {0} {1}'.format(enc_type, key)) + else: + cmds.append(cmd_no_str + ' key 7 {0}'.format(existing.get('key'))) + + locdict = {'auth_port': 'auth-port', 'acct_port': 'acct-port', + 'tacacs_port': 'port', 'host_timeout': 'timeout'} + + # platform CLI needs the keywords in the following order + for key in ['auth_port', 'acct_port', 'tacacs_port', 'host_timeout']: + item = params.get(key) + if item: + if item != 'default': + cmd_str += ' {0} {1}'.format(locdict.get(key), item) + nondef = True + else: + cmd_no_str += ' {0} 1'.format(locdict.get(key)) + defval = True + if defval: + cmds.append(cmd_no_str) + if nondef or not existing: + cmds.append(cmd_str) - cmds.append(cmd_str) return cmds @@ -315,24 +303,19 @@ def main(): end_state = existing commands = [] + delta = {} if state == 'present': - host_timeout = proposed.get('host_timeout') - if host_timeout: - try: - if int(host_timeout) < 1 or int(host_timeout) > 60: - raise ValueError - except ValueError: - module.fail_json( - msg='host_timeout must be an integer between 1 and 60') - - delta = dict( - set(proposed.items()).difference(existing.items())) - if delta: - union = existing.copy() - union.update(delta) - command = config_aaa_host(server_type, address, union) - if command: - commands.append(command) + if not existing: + delta = proposed + else: + for key, value in proposed.items(): + if value != existing.get(key): + if value != 'default' or existing.get(key): + delta[key] = value + + command = config_aaa_host(server_type, address, delta, existing) + if command: + commands.append(command) elif state == 'absent': intersect = dict( diff --git a/lib/ansible/modules/network/nxos/nxos_acl.py b/lib/ansible/modules/network/nxos/nxos_acl.py index 1c464d84ee2..9801abcc160 100644 --- a/lib/ansible/modules/network/nxos/nxos_acl.py +++ b/lib/ansible/modules/network/nxos/nxos_acl.py @@ -252,6 +252,7 @@ def get_acl(module, acl_name, seq_number): for acl in all_acl_body: if acl.get('acl_name') == acl_name: acl_body = acl + break try: acl_entries = acl_body['TABLE_seqno']['ROW_seqno'] @@ -275,7 +276,7 @@ def get_acl(module, acl_name, seq_number): temp['action'] = 'remark' else: temp['action'] = each.get('permitdeny') - temp['proto'] = each.get('proto', each.get('proto_str', each.get('ip'))) + temp['proto'] = str(each.get('proto', each.get('proto_str', each.get('ip')))) temp['src'] = each.get('src_any', each.get('src_ip_prefix')) temp['src_port_op'] = each.get('src_port_op') temp['src_port1'] = each.get('src_port1_num') @@ -507,13 +508,35 @@ def main(): delta_options = {} if not existing_core.get('remark'): - delta_core = dict( + dcore = dict( set(proposed_core.items()).difference( existing_core.items()) ) - delta_options = dict( - set(proposed_options.items()).difference( - existing_options.items()) + if not dcore: + # check the diff in the other way just in case + dcore = dict( + set(existing_core.items()).difference( + proposed_core.items()) + ) + delta_core = dcore + if delta_core: + delta_options = proposed_options + else: + doptions = dict( + set(proposed_options.items()).difference( + existing_options.items()) + ) + # check the diff in the other way just in case + if not doptions: + doptions = dict( + set(existing_options.items()).difference( + proposed_options.items()) + ) + delta_options = doptions + else: + delta_core = dict( + set(proposed_core.items()).difference( + existing_core.items()) ) if state == 'present': diff --git a/lib/ansible/modules/network/nxos/nxos_static_route.py b/lib/ansible/modules/network/nxos/nxos_static_route.py index 8a563dbc841..8460996d7be 100644 --- a/lib/ansible/modules/network/nxos/nxos_static_route.py +++ b/lib/ansible/modules/network/nxos/nxos_static_route.py @@ -49,23 +49,16 @@ options: vrf: description: - VRF for static route. - required: false default: default tag: description: - - Route tag value (numeric). - required: false - default: null + - Route tag value (numeric) or keyword 'default'. route_name: description: - - Name of the route. Used with the name parameter on the CLI. - required: false - default: null + - Name of the route or keyword 'default'. Used with the name parameter on the CLI. pref: description: - - Preference or administrative difference of route (range 1-255). - required: false - default: null + - Preference or administrative difference of route (range 1-255) or keyword 'default'. aliases: - admin_distance aggregate: @@ -74,8 +67,8 @@ options: state: description: - Manage the state of the resource. - required: true choices: ['present','absent'] + default: 'present' ''' EXAMPLES = ''' @@ -112,66 +105,41 @@ def reconcile_candidate(module, candidate, prefix, w): parents = [] commands = [] + yrc = remove_command.replace('no ', '') if w['vrf'] == 'default': - config = netcfg.get_section(set_command) - if config and state == 'absent': + netcfg = str(netcfg).split('\n') + ncfg = [] + for line in netcfg: + # remove ip route commands of non-default vrfs from + # the running config just in case the same commands + # exist in default and non-default vrfs + if ' ip route' not in line: + ncfg.append(line) + if any(yrc in s for s in ncfg) and state == 'absent': commands = [remove_command] - elif not config and state == 'present': - commands = [set_command] + elif set_command not in ncfg and state == 'present': + if any(yrc in s for s in ncfg): + commands = [remove_command, set_command] + else: + commands = [set_command] else: parents = ['vrf context {0}'.format(w['vrf'])] config = netcfg.get_section(parents) if not isinstance(config, list): config = config.split('\n') config = [line.strip() for line in config] - if set_command in config and state == 'absent': + if any(yrc in s for s in config) and state == 'absent': commands = [remove_command] elif set_command not in config and state == 'present': - commands = [set_command] + if any(yrc in s for s in config): + commands = [remove_command, set_command] + else: + commands = [set_command] if commands: candidate.add(commands, parents=parents) -def fix_prefix_to_regex(prefix): - prefix = prefix.replace('.', r'\.').replace('/', r'\/') - return prefix - - -def get_existing(module, prefix, warnings): - key_map = ['tag', 'pref', 'route_name', 'next_hop'] - netcfg = CustomNetworkConfig(indent=2, contents=get_config(module)) - parents = 'vrf context {0}'.format(module.params['vrf']) - prefix_to_regex = fix_prefix_to_regex(prefix) - - route_regex = r'.*ip\sroute\s{0}\s(?P\S+)(\sname\s(?P\S+))?(\stag\s(?P\d+))?(\s(?P\d+))?.*'.format(prefix_to_regex) - - if module.params['vrf'] == 'default': - config = str(netcfg) - else: - config = netcfg.get_section(parents) - - if config: - try: - match_route = re.match(route_regex, config, re.DOTALL) - group_route = match_route.groupdict() - - for key in key_map: - if key not in group_route: - group_route[key] = '' - group_route['prefix'] = prefix - group_route['vrf'] = module.params['vrf'] - except (AttributeError, TypeError): - group_route = {} - else: - group_route = {} - msg = ("VRF {0} didn't exist.".format(module.params['vrf'])) - if msg not in warnings: - warnings.append(msg) - - return group_route - - def remove_route_command(prefix, w): return 'no ip route {0} {1}'.format(prefix, w['next_hop']) @@ -179,11 +147,12 @@ def remove_route_command(prefix, w): def set_route_command(prefix, w): route_cmd = 'ip route {0} {1}'.format(prefix, w['next_hop']) - if w['route_name']: + if w['route_name'] and w['route_name'] != 'default': route_cmd += ' name {0}'.format(w['route_name']) if w['tag']: - route_cmd += ' tag {0}'.format(w['tag']) - if w['pref']: + if w['tag'] != 'default' and w['tag'] != '0': + route_cmd += ' tag {0}'.format(w['tag']) + if w['pref'] and w['pref'] != 'default': route_cmd += ' {0}'.format(w['pref']) return route_cmd diff --git a/lib/ansible/modules/network/nxos/nxos_vlan.py b/lib/ansible/modules/network/nxos/nxos_vlan.py index 11ffe577f6b..09e29bbe07f 100644 --- a/lib/ansible/modules/network/nxos/nxos_vlan.py +++ b/lib/ansible/modules/network/nxos/nxos_vlan.py @@ -96,6 +96,8 @@ options: purge: description: - Purge VLANs not defined in the I(aggregate) parameter. + This parameter can be used without aggregate as well. + type: bool default: no delay: description: @@ -143,6 +145,14 @@ EXAMPLES = ''' aggregate: - { vlan_id: 4000, mode: ce } - { vlan_id: 4001, name: vlan-4001 } + +- name: purge vlans - removes all other vlans except the ones mentioned in aggregate) + nxos_vlan: + aggregate: + - vlan_id: 1 + - vlan_id: 4001 + purge: yes + ''' RETURN = ''' @@ -196,6 +206,7 @@ def is_default_name(obj, vlan_id): def map_obj_to_commands(updates, module, os_platform): commands = list() + purge = module.params['purge'] want, have = updates for w in want: @@ -319,6 +330,12 @@ def map_obj_to_commands(updates, module, os_platform): commands.append('switchport mode access') commands.append('no switchport access vlan {0}'.format(vlan_id)) + if purge: + for h in have: + obj_in_want = search_obj_in_list(h['vlan_id'], want) + if not obj_in_want: + commands.append('no vlan {0}'.format(h['vlan_id'])) + return commands diff --git a/test/integration/targets/nxos_aaa_server/tests/common/radius.yaml b/test/integration/targets/nxos_aaa_server/tests/common/radius.yaml index 46e46720ac3..517c2472086 100644 --- a/test/integration/targets/nxos_aaa_server/tests/common/radius.yaml +++ b/test/integration/targets/nxos_aaa_server/tests/common/radius.yaml @@ -73,7 +73,7 @@ - assert: *false - name: "Remove radius server configuration" - nxos_aaa_server: + nxos_aaa_server: &rad_def server_type: radius deadtime: default server_timeout: default @@ -85,6 +85,12 @@ - assert: *true + - name: "Check Idempotence" + nxos_aaa_server: *rad_def + register: result + + - assert: *false + rescue: - debug: msg="connection={{ ansible_connection }} nxos_aaa_server failure detected" @@ -94,4 +100,4 @@ nxos_aaa_server: *remove register: result - - debug: msg="END connection={{ ansible_connection }} nxos_aaa_server radius.yaml sanity test" +- debug: msg="END connection={{ ansible_connection }} nxos_aaa_server radius.yaml sanity test" diff --git a/test/integration/targets/nxos_aaa_server/tests/common/tacacs.yaml b/test/integration/targets/nxos_aaa_server/tests/common/tacacs.yaml index 255d9f7a17f..0ad7effb4ad 100644 --- a/test/integration/targets/nxos_aaa_server/tests/common/tacacs.yaml +++ b/test/integration/targets/nxos_aaa_server/tests/common/tacacs.yaml @@ -79,11 +79,24 @@ - assert: *false - name: "Remove tacacs server configuration" - nxos_aaa_server: *remove + nxos_aaa_server: &tac_def + server_type: tacacs + deadtime: default + server_timeout: default + global_key: default + directed_request: default + state: default + provider: "{{ connection }}" register: result - assert: *true + - name: "Check Idempotence" + nxos_aaa_server: *tac_def + register: result + + - assert: *false + rescue: - debug: msg="connection={{ ansible_connection }} nxos_aaa_server failure detected" @@ -100,4 +113,4 @@ state: disabled provider: "{{ connection }}" - - debug: msg="END connection={{ ansible_connection }} nxos_aaa_server tacacs.yaml sanity test" +- debug: msg="END connection={{ ansible_connection }} nxos_aaa_server tacacs.yaml sanity test" diff --git a/test/integration/targets/nxos_aaa_server_host/tests/common/radius.yaml b/test/integration/targets/nxos_aaa_server_host/tests/common/radius.yaml index 572650e97e0..cf9a65556b2 100644 --- a/test/integration/targets/nxos_aaa_server_host/tests/common/radius.yaml +++ b/test/integration/targets/nxos_aaa_server_host/tests/common/radius.yaml @@ -43,7 +43,7 @@ register: result - assert: *false - + - name: "Configure radius server non defaults" nxos_aaa_server_host: &configure_radius_non_default server_type: radius @@ -54,7 +54,7 @@ state: present provider: "{{ connection }}" register: result - + - assert: *true - name: "Check Idempotence" @@ -63,25 +63,38 @@ - assert: *false - - name: "Remove radius server configuration" - nxos_aaa_server_host: *remove + - name: "Configure some defaults on radius server" + nxos_aaa_server_host: &configure_some_radius_default + server_type: radius + address: 8.8.8.8 + host_timeout: default + auth_port: 1000 + acct_port: default + state: present + provider: "{{ connection }}" register: result - assert: *true + - name: "Check Idempotence" + nxos_aaa_server_host: *configure_some_radius_default + register: result + + - assert: *false + - name: "Configure radius server with clear text pwd" nxos_aaa_server_host: &configure_radius_clear_text server_type: radius address: 8.8.8.8 host_timeout: 25 - auth_port: 2083 + auth_port: default acct_port: 2084 encrypt_type: 0 key: hello state: present provider: "{{ connection }}" register: result - + - assert: *true - name: "Check NOT Idempotent" @@ -115,8 +128,49 @@ nxos_aaa_server_host: *configure_radius_type7 register: result + - assert: *false + + - name: "Configure radius server with default key" + nxos_aaa_server_host: &configure_radius_defkey + server_type: radius + address: 8.8.8.8 + host_timeout: default + auth_port: 1000 + acct_port: default + encrypt_type: 7 + key: default + state: present + provider: "{{ connection }}" + register: result + + - assert: *true + + - name: "Check Idempotence" + nxos_aaa_server_host: *configure_radius_defkey + register: result + + - assert: *false + + - name: "Configure radius server with all def" + nxos_aaa_server_host: &configure_radius_alldef + server_type: radius + address: 8.8.8.8 + host_timeout: default + auth_port: default + acct_port: default + key: default + state: present + provider: "{{ connection }}" + register: result + - assert: *true + - name: "Check Idempotence" + nxos_aaa_server_host: *configure_radius_alldef + register: result + + - assert: *false + rescue: - debug: msg="connection={{ ansible_connection }} nxos_aaa_server_host failure detected" @@ -127,4 +181,4 @@ nxos_aaa_server_host: *remove register: result - - debug: msg="END connection={{ ansible_connection }} nxos_aaa_server_host radius.yaml sanity test" + - debug: msg="END connection={{ ansible_connection }} nxos_aaa_server_host radius.yaml sanity test" diff --git a/test/integration/targets/nxos_aaa_server_host/tests/common/tacacs.yaml b/test/integration/targets/nxos_aaa_server_host/tests/common/tacacs.yaml index 4229f9affbd..63073167342 100644 --- a/test/integration/targets/nxos_aaa_server_host/tests/common/tacacs.yaml +++ b/test/integration/targets/nxos_aaa_server_host/tests/common/tacacs.yaml @@ -60,7 +60,7 @@ state: present provider: "{{ connection }}" register: result - + - assert: *true - name: "Check Idempotence" @@ -69,18 +69,30 @@ - assert: *false - - name: "Remove tacacs server configuration" - nxos_aaa_server_host: *remove + - name: "Configure some defaults on tacacs server" + nxos_aaa_server_host: &configure_some_tacacs_default + server_type: tacacs + address: 8.8.8.8 + host_timeout: default + tacacs_port: 100 + state: present + provider: "{{ connection }}" register: result - assert: *true + - name: "Check Idempotence" + nxos_aaa_server_host: *configure_some_tacacs_default + register: result + + - assert: *false + - name: "Configure tacacs server with clear text pwd" nxos_aaa_server_host: &configure_tacacs_clear_text server_type: tacacs address: 8.8.8.8 host_timeout: 25 - tacacs_port: 89 + tacacs_port: default encrypt_type: 0 key: hello state: present @@ -119,8 +131,47 @@ nxos_aaa_server_host: *configure_tacacs_type7 register: result + - assert: *false + + - name: "Configure tacacs server with default key" + nxos_aaa_server_host: &configure_tacacs_defkey + server_type: tacacs + address: 8.8.8.8 + host_timeout: default + tacacs_port: 89 + encrypt_type: 7 + key: default + state: present + provider: "{{ connection }}" + register: result + + - assert: *true + + - name: "Check Idempotence" + nxos_aaa_server_host: *configure_tacacs_defkey + register: result + + - assert: *false + + - name: "Configure tacacs server with all def" + nxos_aaa_server_host: &configure_tacacs_alldef + server_type: tacacs + address: 8.8.8.8 + host_timeout: default + tacacs_port: default + key: default + state: present + provider: "{{ connection }}" + register: result + - assert: *true + - name: "Check Idempotence" + nxos_aaa_server_host: *configure_tacacs_alldef + register: result + + - assert: *false + rescue: - debug: msg="connection={{ ansible_connection }} nxos_aaa_server_host failure detected" @@ -131,7 +182,7 @@ nxos_aaa_server_host: *remove register: result - - name: "Enable feature tacacs+" + - name: "Disable feature tacacs+" nxos_feature: feature: tacacs+ state: disabled diff --git a/test/integration/targets/nxos_acl/tests/common/sanity.yaml b/test/integration/targets/nxos_acl/tests/common/sanity.yaml index 1bf3cb969fc..83d21ab57c1 100644 --- a/test/integration/targets/nxos_acl/tests/common/sanity.yaml +++ b/test/integration/targets/nxos_acl/tests/common/sanity.yaml @@ -10,12 +10,12 @@ nxos_acl: &remove name: TEST_ACL seq: 10 - state: absent + state: delete_acl provider: "{{ connection }}" ignore_errors: yes -- name: "Configure ACL" - nxos_acl: &configure +- name: "Configure ACE10" + nxos_acl: &conf10 name: TEST_ACL seq: 10 action: permit @@ -27,6 +27,8 @@ ack: 'enable' dscp: 'af43' dest: any + dest_port_op: neq + dest_port1: 1899 urg: 'enable' psh: 'enable' established: 'enable' @@ -44,13 +46,187 @@ - "result.changed == true" - name: "Check Idempotence" - nxos_acl: *configure + nxos_acl: *conf10 register: result - assert: &false that: - "result.changed == false" +- name: "Change ACE10" + nxos_acl: &chg10 + name: TEST_ACL + seq: 10 + action: deny + proto: tcp + src: 1.1.1.1/24 + src_port_op: range + src_port1: 1900 + src_port2: 1910 + ack: 'enable' + dscp: 'af43' + dest: any + dest_port_op: neq + dest_port1: 1899 + urg: 'enable' + psh: 'enable' + established: 'enable' + log: 'enable' + fin: 'enable' + rst: 'enable' + syn: 'enable' + time_range: "{{time_range|default(omit)}}" + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *chg10 + register: result + +- assert: *false + +- name: "ace remark" + nxos_acl: &remark + name: TEST_ACL + seq: 20 + action: remark + remark: test_remark + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *remark + register: result + +- assert: *false + +- name: "change remark" + nxos_acl: &chgremark + name: TEST_ACL + seq: 20 + action: remark + remark: changed_remark + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *chgremark + register: result + +- assert: *false + +- name: "ace 30" + nxos_acl: &ace30 + name: TEST_ACL + seq: 30 + action: deny + proto: 24 + src: any + dest: any + fragments: enable + precedence: network + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *ace30 + register: result + +- assert: *false + +- name: "change ace 30 options" + nxos_acl: &chgace30opt + name: TEST_ACL + seq: 30 + action: deny + proto: 24 + src: any + dest: any + precedence: network + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *chgace30opt + register: result + +- assert: *false + +- name: "ace 40" + nxos_acl: &ace40 + name: TEST_ACL + seq: 40 + action: permit + proto: udp + src: any + src_port_op: neq + src_port1: 1200 + dest: any + precedence: network + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *ace40 + register: result + +- assert: *false + +- name: "change ace 40" + nxos_acl: &chgace40 + name: TEST_ACL + seq: 40 + action: permit + proto: udp + src: any + dest: any + precedence: network + state: present + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *chgace40 + register: result + +- assert: *false + +- name: "remove ace 30" + nxos_acl: &remace30 + name: TEST_ACL + seq: 30 + state: absent + provider: "{{ connection }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_acl: *remace30 + register: result + +- assert: *false + - name: "Remove ACL" nxos_acl: *remove register: result diff --git a/test/integration/targets/nxos_acl_interface/tests/common/sanity.yaml b/test/integration/targets/nxos_acl_interface/tests/common/sanity.yaml index 8d463d36956..f397c2c2739 100644 --- a/test/integration/targets/nxos_acl_interface/tests/common/sanity.yaml +++ b/test/integration/targets/nxos_acl_interface/tests/common/sanity.yaml @@ -16,11 +16,21 @@ provider: "{{ connection }}" ignore_errors: yes +- name: "Setup: Put interface into no switch port mode" + nxos_config: + commands: + - "no switchport" + parents: + - "interface {{ intname }}" + match: none + provider: "{{ connection }}" + ignore_errors: yes + - name: "Setup: Cleanup possibly existing acl" nxos_acl: &remove name: ANSIBLE_ACL seq: 10 - state: absent + state: delete_acl provider: "{{ connection }}" ignore_errors: yes @@ -112,9 +122,9 @@ nxos_config: *default ignore_errors: yes + always: - name: Remove possible configured ACL nxos_acl: *remove ignore_errors: yes - always: - debug: msg="END connection={{ ansible_connection }} nxos_acl_interface sanity test" diff --git a/test/integration/targets/nxos_static_route/defaults/main.yaml b/test/integration/targets/nxos_static_route/defaults/main.yaml index 5f709c5aac1..525b7aab903 100644 --- a/test/integration/targets/nxos_static_route/defaults/main.yaml +++ b/test/integration/targets/nxos_static_route/defaults/main.yaml @@ -1,2 +1,5 @@ --- testcase: "*" +vrfs: + - default + - myvrf diff --git a/test/integration/targets/nxos_static_route/tests/common/sanity.yaml b/test/integration/targets/nxos_static_route/tests/common/sanity.yaml index 0a1a9da8015..3518ceff282 100644 --- a/test/integration/targets/nxos_static_route/tests/common/sanity.yaml +++ b/test/integration/targets/nxos_static_route/tests/common/sanity.yaml @@ -11,8 +11,9 @@ route_name: testing pref: 100 tag: 5500 - vrf: testing + vrf: "{{ item }}" provider: "{{ connection }}" + with_items: "{{ vrfs }}" register: result - assert: &true @@ -21,28 +22,51 @@ - name: "Conf Idempotence" nxos_static_route: *configure + with_items: "{{ vrfs }}" register: result - assert: &false that: - "result.changed == false" + - name: change static route + nxos_static_route: &configure1 + prefix: "192.168.20.64/24" + next_hop: "3.3.3.3" + route_name: default + pref: 10 + tag: default + vrf: "{{ item }}" + provider: "{{ connection }}" + with_items: "{{ vrfs }}" + register: result + + - assert: *true + + - name: "Conf1 Idempotence" + nxos_static_route: *configure1 + with_items: "{{ vrfs }}" + register: result + + - assert: *false + - name: remove static route nxos_static_route: &remove prefix: "192.168.20.64/24" next_hop: "3.3.3.3" route_name: testing pref: 100 - tag: 5500 - vrf: testing + vrf: "{{ item }}" state: absent provider: "{{ connection }}" + with_items: "{{ vrfs }}" register: result - assert: *true - name: "Remove Idempotence" nxos_static_route: *remove + with_items: "{{ vrfs }}" register: result - assert: *false @@ -96,9 +120,10 @@ route_name: testing pref: 100 tag: 5500 - vrf: testing + vrf: "{{ item }}" state: absent provider: "{{ connection }}" + with_items: "{{ vrfs }}" ignore_errors: yes - name: remove static route aggregate diff --git a/test/integration/targets/nxos_vlan/tests/common/agg.yaml b/test/integration/targets/nxos_vlan/tests/common/agg.yaml index 3d4fc4b5155..07d95de6b5e 100644 --- a/test/integration/targets/nxos_vlan/tests/common/agg.yaml +++ b/test/integration/targets/nxos_vlan/tests/common/agg.yaml @@ -63,6 +63,27 @@ that: - 'result.changed == false' +- name: purge + nxos_vlan: &purge + vlan_id: 1 + purge: yes + provider: "{{ connection }}" + register: result + +- assert: + that: + - 'result.changed == true' + - '"no vlan 102" in result.commands' + - '"no vlan 103" in result.commands' + +- name: purge - Idempotence + nxos_vlan: *purge + register: result + +- assert: + that: + - 'result.changed == false' + - name: teardown nxos_config: *rm ignore_errors: yes