diff --git a/lib/ansible/modules/network/nxos/nxos_ip_interface.py b/lib/ansible/modules/network/nxos/nxos_ip_interface.py index d9561d32b0..94d0ca1d0b 100644 --- a/lib/ansible/modules/network/nxos/nxos_ip_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_ip_interface.py @@ -37,6 +37,7 @@ notes: - C(mask) must be inserted in decimal format (i.e. 24) for both IPv6 and IPv4. - A single interface can have multiple IPv6 configured. + - C(tag) is not idempotent for IPv6 addresses and I2 system image. options: interface: description: @@ -168,9 +169,10 @@ def find_same_addr(existing, addr, mask, full=False, **kwargs): if full: if kwargs['version'] == 'v4' and int(address['tag']) == kwargs['tag']: return address - elif kwargs['version'] == 'v6': + elif kwargs['version'] == 'v6' and kwargs['tag'] == 0: # Currently we don't get info about IPv6 address tag - return False + # But let's not break idempotence for the default case + return address else: return address return False @@ -274,7 +276,7 @@ def parse_unstructured_data(body, interface_name, version, module): address = each_line.strip().split(' ')[0] if address not in address_list: address_list.append(address) - interface['prefixes'].append(str(ipaddress.ip_interface(address).network)) + interface['prefixes'].append(str(ipaddress.ip_interface(u"%s" % address).network)) if address_list: for ipv6 in address_list: @@ -289,7 +291,7 @@ def parse_unstructured_data(body, interface_name, version, module): if "IP address" in splitted_body[index]: regex = '.*IP\saddress:\s(?P\d{1,3}(?:\.\d{1,3}){3}),\sIP\ssubnet:' + \ '\s\d{1,3}(?:\.\d{1,3}){3}\/(?P\d+)(?:\s(?Psecondary)\s)?' + \ - '.+?tag:\s(?P\d+).*' + '(.+?tag:\s(?P\d+).*)?' match = re.match(regex, splitted_body[index]) if match: match_dict = match.groupdict() @@ -297,7 +299,10 @@ def parse_unstructured_data(body, interface_name, version, module): match_dict['secondary'] = False else: match_dict['secondary'] = True - match_dict['tag'] = int(match_dict['tag']) + if match_dict['tag'] is None: + match_dict['tag'] = 0 + else: + match_dict['tag'] = int(match_dict['tag']) interface['addresses'].append(match_dict) prefix = str(ipaddress.ip_interface(u"%(addr)s/%(mask)s" % match_dict).network) interface['prefixes'].append(prefix) @@ -349,7 +354,9 @@ def get_remove_ip_config_commands(interface, addr, mask, existing, version): commands.append('no ip address {0}/{1}'.format(addr, mask)) break else: - commands.append('no ipv6 address {0}/{1}'.format(addr, mask)) + for address in existing['addresses']: + if address['addr'] == addr: + commands.append('no ipv6 address {0}/{1}'.format(addr, mask)) return commands diff --git a/test/integration/nxos.yaml b/test/integration/nxos.yaml index a8f8c2a316..e32d01d957 100644 --- a/test/integration/nxos.yaml +++ b/test/integration/nxos.yaml @@ -258,6 +258,15 @@ failed_modules: "{{ failed_modules }} + [ 'nxos_interface_ospf' ]" test_failed: true + - block: + - include_role: + name: nxos_ip_interface + when: "limit_to in ['*', 'nxos_ip_interface']" + rescue: + - set_fact: + failed_modules: "{{ failed_modules }} + [ 'nxos_ip_interface' ]" + test_failed: true + - block: - include_role: name: nxos_logging diff --git a/test/integration/targets/nxos_ip_interface/defaults/main.yaml b/test/integration/targets/nxos_ip_interface/defaults/main.yaml new file mode 100644 index 0000000000..5f709c5aac --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/defaults/main.yaml @@ -0,0 +1,2 @@ +--- +testcase: "*" diff --git a/test/integration/targets/nxos_ip_interface/meta/main.yml b/test/integration/targets/nxos_ip_interface/meta/main.yml new file mode 100644 index 0000000000..ae741cbdc7 --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - prepare_nxos_tests diff --git a/test/integration/targets/nxos_ip_interface/tasks/cli.yaml b/test/integration/targets/nxos_ip_interface/tasks/cli.yaml new file mode 100644 index 0000000000..d675462dd0 --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/tasks/cli.yaml @@ -0,0 +1,15 @@ +--- +- name: collect all cli test cases + find: + paths: "{{ role_path }}/tests/cli" + patterns: "{{ testcase }}.yaml" + register: test_cases + +- name: set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: run test case + include: "{{ test_case_to_run }}" + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/nxos_ip_interface/tasks/main.yaml b/test/integration/targets/nxos_ip_interface/tasks/main.yaml new file mode 100644 index 0000000000..fea9337c14 --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/tasks/main.yaml @@ -0,0 +1,7 @@ +--- +# Use block to ensure that both cli and nxapi tests +# will run even if there are failures or errors. +- block: + - { include: cli.yaml, tags: ['cli'] } + always: + - { include: nxapi.yaml, tags: ['nxapi'] } diff --git a/test/integration/targets/nxos_ip_interface/tasks/nxapi.yaml b/test/integration/targets/nxos_ip_interface/tasks/nxapi.yaml new file mode 100644 index 0000000000..ea525379f7 --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/tasks/nxapi.yaml @@ -0,0 +1,28 @@ +--- +- name: collect all nxapi test cases + find: + paths: "{{ role_path }}/tests/nxapi" + patterns: "{{ testcase }}.yaml" + register: test_cases + +- name: set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: enable nxapi + nxos_config: + lines: + - feature nxapi + - nxapi http port 80 + provider: "{{ cli }}" + +- name: run test case + include: "{{ test_case_to_run }}" + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run + +- name: disable nxapi + nxos_config: + lines: + - no feature nxapi + provider: "{{ cli }}" diff --git a/test/integration/targets/nxos_ip_interface/tests/cli/sanity.yaml b/test/integration/targets/nxos_ip_interface/tests/cli/sanity.yaml new file mode 100644 index 0000000000..9e0f1ffd01 --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/tests/cli/sanity.yaml @@ -0,0 +1,99 @@ +--- +- debug: msg="START TRANSPORT:CLI nxos_ip_interface sanity test" + +- set_fact: testint1="{{ nxos_int1 }}" +- set_fact: testint2="{{ nxos_int2 }}" + +- name: "Put interface {{testint1}} into default state" + nxos_config: &intdefault1 + lines: + - "default interface {{ testint1 }}" + provider: "{{ cli }}" + ignore_errors: yes + +- name: "Put interface {{testint2}} into default state" + nxos_config: &intdefault2 + lines: + - "default interface {{ testint2 }}" + provider: "{{ cli }}" + ignore_errors: yes + +- name: "Make {{testint1}} a layer3 interface" + nxos_interface: &l3int1 + interface: "{{ testint1 }}" + mode: layer3 + description: 'Configured by Ansible - Layer3' + admin_state: 'up' + state: present + provider: "{{ cli }}" + +- name: "Make {{testint2}} a layer3 interface" + nxos_interface: &l3int2 + interface: "{{ testint2 }}" + mode: layer3 + description: 'Configured by Ansible - Layer3' + admin_state: 'up' + state: present + provider: "{{ cli }}" + +# For titanium +- name: Clear interface v4 + nxos_ip_interface: + interface: "{{ testint1 }}" + version: v4 + state: absent + addr: 20.20.20.20 + mask: 24 + provider: "{{ cli }}" + +# For titanium +- name: Clear interface v6 + nxos_ip_interface: + interface: "{{ testint2 }}" + version: v6 + state: absent + addr: 'fd56:31f7:e4ad:5585::1' + mask: 64 + provider: "{{ cli }}" + +- name: Ensure ipv4 address is configured + nxos_ip_interface: &ipv4 + interface: "{{ testint1 }}" + version: v4 + state: present + addr: 20.20.20.20 + mask: 24 + provider: "{{ cli }}" + register: result + +- assert: &true + that: + - "result.changed == true" + +- name: "Check Idempotence" + nxos_ip_interface: *ipv4 + register: result + +- assert: &false + that: + - "result.changed == false" + +- name: Ensure ipv6 address is configured + nxos_ip_interface: &ipv6 + interface: "{{ testint2 }}" + version: v6 + state: present + addr: 'fd56:31f7:e4ad:5585::1' + mask: 64 + provider: "{{ cli }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_ip_interface: *ipv6 + register: result + +- assert: *false + +- debug: msg="END TRANSPORT:CLI nxos_ip_interface sanity test" diff --git a/test/integration/targets/nxos_ip_interface/tests/nxapi/sanity.yaml b/test/integration/targets/nxos_ip_interface/tests/nxapi/sanity.yaml new file mode 100644 index 0000000000..f57a5f62ea --- /dev/null +++ b/test/integration/targets/nxos_ip_interface/tests/nxapi/sanity.yaml @@ -0,0 +1,99 @@ +--- +- debug: msg="START TRANSPORT:NXAPI nxos_ip_interface sanity test" + +- set_fact: testint1="{{ nxos_int1 }}" +- set_fact: testint2="{{ nxos_int2 }}" + +- name: "Put interface {{testint1}} into default state" + nxos_config: &intdefault1 + lines: + - "default interface {{ testint1 }}" + provider: "{{ nxapi }}" + ignore_errors: yes + +- name: "Put interface {{testint2}} into default state" + nxos_config: &intdefault2 + lines: + - "default interface {{ testint2 }}" + provider: "{{ nxapi }}" + ignore_errors: yes + +- name: "Make {{testint1}} a layer3 interface" + nxos_interface: &l3int1 + interface: "{{ testint1 }}" + mode: layer3 + description: 'Configured by Ansible - Layer3' + admin_state: 'up' + state: present + provider: "{{ nxapi }}" + +- name: "Make {{testint2}} a layer3 interface" + nxos_interface: &l3int2 + interface: "{{ testint2 }}" + mode: layer3 + description: 'Configured by Ansible - Layer3' + admin_state: 'up' + state: present + provider: "{{ nxapi }}" + +# For titanium +- name: Clear interface v4 + nxos_ip_interface: + interface: "{{ testint1 }}" + version: v4 + state: absent + addr: 20.20.20.20 + mask: 24 + provider: "{{ nxapi }}" + +# For titanium +- name: Clear interface v6 + nxos_ip_interface: + interface: "{{ testint2 }}" + version: v6 + state: absent + addr: 'fd56:31f7:e4ad:5585::1' + mask: 64 + provider: "{{ nxapi }}" + +- name: Ensure ipv4 address is configured + nxos_ip_interface: &ipv4 + interface: "{{ testint1 }}" + version: v4 + state: present + addr: 20.20.20.20 + mask: 24 + provider: "{{ nxapi }}" + register: result + +- assert: &true + that: + - "result.changed == true" + +- name: "Check Idempotence" + nxos_ip_interface: *ipv4 + register: result + +- assert: &false + that: + - "result.changed == false" + +- name: Ensure ipv6 address is configured + nxos_ip_interface: &ipv6 + interface: "{{ testint2 }}" + version: v6 + state: present + addr: 'fd56:31f7:e4ad:5585::1' + mask: 64 + provider: "{{ nxapi }}" + register: result + +- assert: *true + +- name: "Check Idempotence" + nxos_ip_interface: *ipv6 + register: result + +- assert: *false + +- debug: msg="END TRANSPORT:NXAPI nxos_ip_interface sanity test"