diff --git a/lib/ansible/modules/network/nxos/nxos_vlan.py b/lib/ansible/modules/network/nxos/nxos_vlan.py index 41aed15638..347d0cc480 100644 --- a/lib/ansible/modules/network/nxos/nxos_vlan.py +++ b/lib/ansible/modules/network/nxos/nxos_vlan.py @@ -38,10 +38,10 @@ options: - Range of VLANs such as 2-10 or 2,5,10-15, etc. name: description: - - Name of VLAN. + - Name of VLAN or keyword 'default'. interfaces: description: - - List of interfaces that should be associated to the VLAN. + - List of interfaces that should be associated to the VLAN or keyword 'default'. version_added: "2.5" associated_interfaces: description: @@ -52,7 +52,6 @@ options: vlan_state: description: - Manage the vlan operational state of the VLAN - This is being deprecated in favor of state. default: active choices: ['active','suspend'] admin_state: @@ -69,9 +68,8 @@ options: state: description: - Manage the state of the resource. - Active and Suspend will assume the vlan is present. default: present - choices: ['present','absent', 'active', 'suspend'] + choices: ['present','absent'] mode: description: - Set VLAN mode to classical ethernet or fabricpath. @@ -162,19 +160,28 @@ def search_obj_in_list(vlan_id, lst): def get_diff(w, obj): c = deepcopy(w) - entries = ('interfaces', 'associated_interfaces', 'name', 'delay', 'vlan_range') + entries = ('interfaces', 'associated_interfaces', 'delay', 'vlan_range') for key in entries: if key in c: del c[key] o = deepcopy(obj) del o['interfaces'] - del o['name'] if o['vlan_id'] == w['vlan_id']: diff_dict = dict(set(c.items()) - set(o.items())) return diff_dict +def is_default_name(obj, vlan_id): + cname = obj['name'] + if ('VLAN' in cname): + vid = int(cname[4:]) + if vid == int(vlan_id): + return True + + return False + + def map_obj_to_commands(updates, module, os_platform): commands = list() want, have = updates @@ -208,13 +215,13 @@ def map_obj_to_commands(updates, module, os_platform): if not obj_in_have: commands.append('vlan {0}'.format(vlan_id)) - if name: + if name and name != 'default': commands.append('name {0}'.format(name)) if mode: commands.append('mode {0}'.format(mode)) if vlan_state: commands.append('state {0}'.format(vlan_state)) - if mapped_vni != 'None': + if mapped_vni != 'None' and mapped_vni != 'default': commands.append('vn-segment {0}'.format(mapped_vni)) if admin_state == 'up': commands.append('no shutdown') @@ -222,7 +229,7 @@ def map_obj_to_commands(updates, module, os_platform): commands.append('shutdown') commands.append('exit') - if interfaces: + if interfaces and interfaces[0] != 'default': for i in interfaces: commands.append('interface {0}'.format(i)) commands.append('switchport') @@ -230,7 +237,38 @@ def map_obj_to_commands(updates, module, os_platform): commands.append('switchport access vlan {0}'.format(vlan_id)) else: - if interfaces: + diff = get_diff(w, obj_in_have) + if diff: + commands.append('vlan {0}'.format(vlan_id)) + for key, value in diff.items(): + if key == 'name': + if name != 'default': + if name is not None: + commands.append('name {0}'.format(value)) + else: + if not is_default_name(obj_in_have, vlan_id): + commands.append('no name') + if key == 'vlan_state': + commands.append('state {0}'.format(value)) + if key == 'mapped_vni': + if value == 'default': + if obj_in_have['mapped_vni'] != 'None': + commands.append('no vn-segment') + elif value != 'None': + commands.append('vn-segment {0}'.format(value)) + if key == 'admin_state': + if value == 'up': + commands.append('no shutdown') + elif value == 'down': + commands.append('shutdown') + if key == 'mode': + commands.append('mode {0}'.format(value)) + if len(commands) > 1: + commands.append('exit') + else: + del commands[:] + + if interfaces and interfaces[0] != 'default': if not obj_in_have['interfaces']: for i in interfaces: commands.append('vlan {0}'.format(vlan_id)) @@ -259,24 +297,15 @@ def map_obj_to_commands(updates, module, os_platform): commands.append('switchport mode access') commands.append('no switchport access vlan {0}'.format(vlan_id)) - else: - diff = get_diff(w, obj_in_have) - if diff: - commands.append('vlan {0}'.format(vlan_id)) - for key, value in diff.items(): - if key == 'vlan_state': - commands.append('state {0}'.format(value)) - if key == 'mapped_vni': - if value != 'None': - commands.append('vn-segment {0}'.format(value)) - if key == 'admin_state': - if value == 'up': - commands.append('no shutdown') - elif value == 'down': - commands.append('shutdown') - if key == 'mode': - commands.append('mode {0}'.format(value)) - commands.append('exit') + elif interfaces and interfaces[0] == 'default': + if obj_in_have['interfaces']: + for i in obj_in_have['interfaces']: + commands.append('vlan {0}'.format(vlan_id)) + commands.append('exit') + commands.append('interface {0}'.format(i)) + commands.append('switchport') + commands.append('switchport mode access') + commands.append('no switchport access vlan {0}'.format(vlan_id)) return commands @@ -493,9 +522,9 @@ def main(): interfaces=dict(type='list'), associated_interfaces=dict(type='list'), vlan_state=dict(choices=['active', 'suspend'], required=False, default='active'), - mapped_vni=dict(required=False, type='int'), + mapped_vni=dict(required=False), delay=dict(default=10, type='int'), - state=dict(choices=['present', 'absent', 'active', 'suspend'], default='present', required=False), + state=dict(choices=['present', 'absent'], default='present', required=False), admin_state=dict(choices=['up', 'down'], required=False, default='up'), mode=dict(choices=['ce', 'fabricpath'], required=False, default='ce'), ) diff --git a/test/integration/targets/nxos_vlan/tests/common/interface.yaml b/test/integration/targets/nxos_vlan/tests/common/interface.yaml index cba7372ce5..6e7453760e 100644 --- a/test/integration/targets/nxos_vlan/tests/common/interface.yaml +++ b/test/integration/targets/nxos_vlan/tests/common/interface.yaml @@ -7,6 +7,7 @@ lines: - no vlan 100 provider: "{{ connection }}" + ignore_errors: yes - name: setup - remove vlan from interfaces used in test(part1) nxos_config: diff --git a/test/integration/targets/nxos_vlan/tests/common/sanity.yaml b/test/integration/targets/nxos_vlan/tests/common/sanity.yaml index 50237efec0..4f9428cab4 100644 --- a/test/integration/targets/nxos_vlan/tests/common/sanity.yaml +++ b/test/integration/targets/nxos_vlan/tests/common/sanity.yaml @@ -3,6 +3,9 @@ - debug: msg="Using provider={{ connection.transport }}" when: ansible_connection == "local" +- set_fact: testint1="{{ nxos_int1 }}" +- set_fact: testint2="{{ nxos_int2 }}" + - block: - name: "Enable feature vn segment" nxos_config: @@ -44,7 +47,7 @@ - assert: *true when: platform is search('N9K') - - name: "web Idempotence" + - name: "web1 Idempotence" nxos_vlan: *web1 register: result when: platform is search('N9K') @@ -52,8 +55,30 @@ - assert: *false when: platform is search('N9K') - - name: Ensure VLAN 50 exists with the name WEB and is in the shutdown state + - name: change name and vni to default nxos_vlan: &web2 + vlan_id: 50 + vlan_state: active + admin_state: up + name: default + mapped_vni: default + provider: "{{ connection }}" + register: result + when: platform is search('N9K') + + - assert: *true + when: platform is search('N9K') + + - name: "web2 Idempotence" + nxos_vlan: *web2 + register: result + when: platform is search('N9K') + + - assert: *false + when: platform is search('N9K') + + - name: Ensure VLAN 50 exists with the name WEB and is in the shutdown state + nxos_vlan: &web3 vlan_id: 50 vlan_state: suspend admin_state: down @@ -65,14 +90,74 @@ - assert: *true when: platform is search('N3K|N7K') - - name: "web Idempotence" - nxos_vlan: *web2 + - name: "web3 Idempotence" + nxos_vlan: *web3 register: result when: platform is search('N3K|N7K') - assert: *false when: platform is search('N3K|N7K') + - name: Change name to default + nxos_vlan: &web4 + vlan_id: 50 + vlan_state: active + admin_state: up + name: default + provider: "{{ connection }}" + register: result + when: platform is search('N3K|N7K') + + - assert: *true + when: platform is search('N3K|N7K') + + - name: "web4 Idempotence" + nxos_vlan: *web4 + register: result + when: platform is search('N3K|N7K') + + - assert: *false + when: platform is search('N3K|N7K') + +# Uncomment this once the get_capabilities() work on nxapi as well +# - name: Change mode +# nxos_vlan: &mode1 +# vlan_id: 50 +# mode: fabricpath +# provider: "{{ connection }}" +# register: result +# when: platform is search('N5k|N7K') +# +# - assert: *true +# when: platform is search('N5k|N7K') +# +# - name: "mode1 Idempotence" +# nxos_vlan: *mode1 +# register: result +# when: platform is search('N5k|N7K') +# +# - assert: *false +# when: platform is search('N5k|N7K') +# +# - name: Change mode again +# nxos_vlan: &mode2 +# vlan_id: 50 +# mode: ce +# provider: "{{ connection }}" +# register: result +# when: platform is search('N5k|N7K') +# +# - assert: *true +# when: platform is search('N5k|N7K') +# +# - name: "mode2 Idempotence" +# nxos_vlan: *mode2 +# register: result +# when: platform is search('N5k|N7K') +# +# - assert: *false +# when: platform is search('N5k|N7K') + - name: Ensure VLAN is NOT on the device nxos_vlan: &no_vlan vlan_id: 50 @@ -88,7 +173,44 @@ - assert: *false + - name: Add interfaces to vlan + nxos_vlan: &addint + vlan_id: 101 + vlan_state: suspend + interfaces: + - "{{ testint1 }}" + - "{{ testint2 }}" + provider: "{{ connection }}" + register: result + + - assert: *true + + - name: "Addint idempotence" + nxos_vlan: *addint + register: result + + - assert: *false + + - name: Remove interfaces from vlan + nxos_vlan: &remint + vlan_id: 101 + interfaces: default + provider: "{{ connection }}" + register: result + + - assert: *true + + - name: "Remint idempotence" + nxos_vlan: *remint + register: result + + - assert: *false + always: + - name: Remove int from vlan + nxos_vlan: *remint + ignore_errors: yes + - name: remove vlans nxos_vlan: vlan_range: "2-10,20,50,55-60,100-150"