diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py index a86becf69e3..fdf7e5a6ef1 100644 --- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py +++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py @@ -61,6 +61,28 @@ options: description: - Suppresses advertisement of the NVE loopback address until the overlay has converged. + global_mcast_group_L3: + description: + - Global multicast ip prefix for L3 VNIs or the keyword 'default' + This is available on NX-OS 9K series running 9.2.x or higher. + version_added: "2.8" + global_mcast_group_L2: + description: + - Global multicast ip prefix for L2 VNIs or the keyword 'default' + This is available on NX-OS 9K series running 9.2.x or higher. + version_added: "2.8" + global_suppress_arp: + description: + - Enables ARP suppression for all VNIs + This is available on NX-OS 9K series running 9.2.x or higher. + type: bool + version_added: "2.8" + global_ingress_replication_bgp: + description: + - Configures ingress replication protocol as bgp for all VNIs + This is available on NX-OS 9K series running 9.2.x or higher. + type: bool + version_added: "2.8" state: description: - Determines whether the config should be present or not @@ -97,10 +119,16 @@ from ansible.module_utils.network.common.config import CustomNetworkConfig BOOL_PARAMS = [ 'shutdown', - 'host_reachability' + 'host_reachability', + 'global_ingress_replication_bgp', + 'global_suppress_arp', ] PARAM_TO_COMMAND_KEYMAP = { 'description': 'description', + 'global_suppress_arp': 'global suppress-arp', + 'global_ingress_replication_bgp': 'global ingress-replication protocol bgp', + 'global_mcast_group_L3': 'global mcast-group L3', + 'global_mcast_group_L2': 'global mcast-group L2', 'host_reachability': 'host-reachability protocol bgp', 'interface': 'interface', 'shutdown': 'shutdown', @@ -151,6 +179,22 @@ def get_value(arg, config, module): break except AttributeError: value = '' + elif arg == 'global_mcast_group_L2': + for line in config.splitlines(): + try: + if 'global mcast-group' in line and 'L2' in line: + value = line.split()[2].strip() + break + except AttributeError: + value = '' + elif arg == 'global_mcast_group_L3': + for line in config.splitlines(): + try: + if 'global mcast-group' in line and 'L3' in line: + value = line.split()[2].strip() + break + except AttributeError: + value = '' else: if PARAM_TO_COMMAND_KEYMAP[arg] in config: value = REGEX.search(config).group('value').strip() @@ -194,6 +238,8 @@ def apply_key_map(key_map, table): def fix_commands(commands, module): source_interface_command = '' no_source_interface_command = '' + no_host_reachability_command = '' + host_reachability_command = '' for command in commands: if 'no source-interface hold-down-time' in command: @@ -204,14 +250,28 @@ def fix_commands(commands, module): no_source_interface_command = command elif 'source-interface' in command: source_interface_command = command + elif 'no host-reachability' in command: + no_host_reachability_command = command + elif 'host-reachability' in command: + host_reachability_command = command + + if host_reachability_command: + commands.pop(commands.index(host_reachability_command)) + commands.insert(0, host_reachability_command) if source_interface_command: commands.pop(commands.index(source_interface_command)) commands.insert(0, source_interface_command) + if no_host_reachability_command: + commands.pop(commands.index(no_host_reachability_command)) + commands.append(no_host_reachability_command) + if no_source_interface_command: commands.pop(commands.index(no_source_interface_command)) commands.append(no_source_interface_command) + + commands.insert(0, 'terminal dont-ask') return commands @@ -229,14 +289,22 @@ def state_present(module, existing, proposed, candidate): elif value == 'default': if existing_commands.get(key): existing_value = existing_commands.get(key) - commands.append('no {0} {1}'.format(key, existing_value)) + if 'global mcast-group' in key: + commands.append('no {0}'.format(key)) + else: + commands.append('no {0} {1}'.format(key, existing_value)) else: if key.replace(' ', '_').replace('-', '_') in BOOL_PARAMS: commands.append('no {0}'.format(key.lower())) module.exit_json(commands=commands) else: - command = '{0} {1}'.format(key, value.lower()) - commands.append(command) + if 'L2' in key: + commands.append('global mcast-group ' + value + ' L2') + elif 'L3' in key: + commands.append('global mcast-group ' + value + ' L3') + else: + command = '{0} {1}'.format(key, value.lower()) + commands.append(command) if commands: commands = fix_commands(commands, module) @@ -258,6 +326,10 @@ def main(): interface=dict(required=True, type='str'), description=dict(required=False, type='str'), host_reachability=dict(required=False, type='bool'), + global_ingress_replication_bgp=dict(required=False, type='bool'), + global_suppress_arp=dict(required=False, type='bool'), + global_mcast_group_L2=dict(required=False, type='str'), + global_mcast_group_L3=dict(required=False, type='str'), shutdown=dict(required=False, type='bool'), source_interface=dict(required=False, type='str'), source_interface_hold_down_time=dict(required=False, type='str'), @@ -266,7 +338,13 @@ def main(): argument_spec.update(nxos_argument_spec) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + mutually_exclusive = [('global_ingress_replication_bgp', 'global_mcast_group_L2')] + + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) warnings = list() result = {'changed': False, 'commands': [], 'warnings': warnings} @@ -279,7 +357,6 @@ def main(): existing = get_existing(module, args) proposed_args = dict((k, v) for k, v in module.params.items() if v is not None and k in args) - proposed = {} for key, value in proposed_args.items(): if key != 'interface': diff --git a/test/integration/targets/nxos_vxlan_vtep/tests/common/sanity.yaml b/test/integration/targets/nxos_vxlan_vtep/tests/common/sanity.yaml index e8360fdcba8..bbb05174250 100644 --- a/test/integration/targets/nxos_vxlan_vtep/tests/common/sanity.yaml +++ b/test/integration/targets/nxos_vxlan_vtep/tests/common/sanity.yaml @@ -3,6 +3,30 @@ - debug: msg="Using provider={{ connection.transport }}" when: ansible_connection == "local" +- set_fact: global_ingress_replication_bgp="true" + when: platform is search('N9K$') and (major_version is version('9.2', 'ge')) + +- set_fact: def_global_ingress_replication_bgp="false" + when: platform is search('N9K$') and (major_version is version('9.2', 'ge')) + +- set_fact: global_mcast_group_L3="225.1.1.1" + when: platform is search('N9K$') and (major_version is version('9.2', 'ge')) + +- set_fact: def_global_mcast_group_L3="default" + when: platform is search('N9K$') and (major_version is version('9.2', 'ge')) + +- set_fact: global_mcast_group_L2="225.1.1.2" + when: platform is search('N9K') and (major_version is version('9.2', 'ge')) + +- set_fact: def_global_mcast_group_L2="default" + when: platform is search('N9K') and (major_version is version('9.2', 'ge')) + +- set_fact: global_suppress_arp="true" + when: platform is search('N9K') and (major_version is version('9.2', 'ge')) + +- set_fact: def_global_suppress_arp="false" + when: platform is search('N9K') and (major_version is version('9.2', 'ge')) + - block: - name: "Apply N7K specific setup config" include: targets/nxos_vxlan_vtep/tasks/platform/n7k/setup.yaml @@ -12,6 +36,7 @@ nxos_config: commands: - feature nv overlay + - nv overlay evpn match: none provider: "{{ connection }}" @@ -23,6 +48,9 @@ host_reachability: true source_interface: Loopback0 source_interface_hold_down_time: 30 + global_ingress_replication_bgp: "{{ global_ingress_replication_bgp|default(omit) }}" + global_suppress_arp: "{{ global_suppress_arp|default(omit) }}" + global_mcast_group_L3: "{{ global_mcast_group_L3|default(omit) }}" shutdown: false provider: "{{ connection }}" register: result @@ -46,6 +74,9 @@ host_reachability: false source_interface_hold_down_time: default source_interface: default + global_ingress_replication_bgp: "{{ def_global_ingress_replication_bgp|default(omit) }}" + global_suppress_arp: "{{ def_global_suppress_arp|default(omit) }}" + global_mcast_group_L3: "{{ def_global_mcast_group_L3|default(omit) }}" shutdown: true provider: "{{ connection }}" register: result @@ -58,6 +89,38 @@ - assert: *false + - name: configure global mcast L2 + nxos_vxlan_vtep: &gml2 + interface: nve1 + host_reachability: true + global_mcast_group_L2: "{{ global_mcast_group_L2|default(omit) }}" + provider: "{{ connection }}" + register: result + + - assert: *true + + - name: "Conf Idempotence" + nxos_vxlan_vtep: *gml2 + register: result + + - assert: *false + + - name: reset global mcast L2 + nxos_vxlan_vtep: &rgml2 + interface: nve1 + host_reachability: false + global_mcast_group_L2: "{{ def_global_mcast_group_L2|default(omit) }}" + provider: "{{ connection }}" + register: result + + - assert: *true + + - name: "reset Idempotence" + nxos_vxlan_vtep: *rgml2 + register: result + + - assert: *false + when: (platform is search('N9K')) - block: @@ -134,6 +197,14 @@ include: targets/nxos_vxlan_vtep/tasks/platform/n7k/cleanup.yaml when: platform is match('N7K') + - name: "Disable nv overlay evpn" + nxos_config: + commands: + - no nv overlay evpn + match: none + provider: "{{ connection }}" + ignore_errors: yes + - name: "Disable feature nv overlay" nxos_feature: feature: nve diff --git a/test/units/modules/network/nxos/test_nxos_vxlan_vtep.py b/test/units/modules/network/nxos/test_nxos_vxlan_vtep.py index f1369867530..c609f515e60 100644 --- a/test/units/modules/network/nxos/test_nxos_vxlan_vtep.py +++ b/test/units/modules/network/nxos/test_nxos_vxlan_vtep.py @@ -48,7 +48,7 @@ class TestNxosVxlanVtepVniModule(TestNxosModule): def test_nxos_vxlan_vtep(self): set_module_args(dict(interface='nve1', description='simple description')) - self.execute_module(changed=True, commands=['interface nve1', 'description simple description']) + self.execute_module(changed=True, commands=['interface nve1', 'terminal dont-ask', 'description simple description']) def test_nxos_vxlan_vtep_present_no_change(self): set_module_args(dict(interface='nve1'))