Add nxos_l2_interfaces resource module (#61120)

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
This commit is contained in:
Trishna Guha 2019-08-26 16:46:05 +05:30 committed by GitHub
parent c729f3ba61
commit 5a04b4feb6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1037 additions and 9 deletions

View file

@ -120,6 +120,8 @@ The following modules will be removed in Ansible 2.13. Please update update your
* nxos_l3_interface use :ref:`nxos_l3_interfaces <nxos_l3_interfaces_module>` instead.
* nxos_l2_interface use :ref:`nxos_l2_interfaces <nxos_l2_interfaces_module>` instead.
The following functionality will be removed in Ansible 2.12. Please update update your playbooks accordingly.

View file

@ -16,6 +16,7 @@ CHOICES = [
'lacp_interfaces',
'interfaces',
'l3_interfaces',
'l2_interfaces',
]

View file

@ -0,0 +1,73 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the nxos_l2_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class L2_interfacesArgs(object): # pylint: disable=R0903
"""The arg spec for the nxos_l2_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
'config': {
'elements': 'dict',
'options': {
'access': {
'options': {
'vlan': {
'type': 'int'
}
},
'type': 'dict'
},
'name': {
'required': True,
'type': 'str'
},
'trunk': {
'options': {
'allowed_vlans': {
'type': 'str'
},
'native_vlan': {
'type': 'int'
}
},
'type': 'dict'
}
},
'type': 'list'
},
'state': {
'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'
}
} # pylint: disable=C0301

View file

@ -0,0 +1,273 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The nxos_l2_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import dict_diff, to_list, remove_empties
from ansible.module_utils.network.nxos.facts.facts import Facts
from ansible.module_utils.network.nxos.utils.utils import flatten_dict, get_interface_type, normalize_interface, search_obj_in_list, vlan_range_to_list
class L2_interfaces(ConfigBase):
"""
The nxos_l2_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'l2_interfaces',
]
exclude_params = [
'vlan',
'allowed_vlans',
'native_vlans',
]
def __init__(self, module):
super(L2_interfaces, self).__init__(module)
def get_l2_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
l2_interfaces_facts = facts['ansible_network_resources'].get('l2_interfaces')
if not l2_interfaces_facts:
return []
return l2_interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
commands = list()
warnings = list()
existing_l2_interfaces_facts = self.get_l2_interfaces_facts()
commands.extend(self.set_config(existing_l2_interfaces_facts))
if commands:
if not self._module.check_mode:
self._connection.edit_config(commands)
result['changed'] = True
result['commands'] = commands
changed_l2_interfaces_facts = self.get_l2_interfaces_facts()
result['before'] = existing_l2_interfaces_facts
if result['changed']:
result['after'] = changed_l2_interfaces_facts
result['warnings'] = warnings
return result
def set_config(self, existing_l2_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
config = self._module.params.get('config')
want = []
if config:
for w in config:
w.update({'name': normalize_interface(w['name'])})
self.expand_trunk_allowed_vlans(w)
want.append(remove_empties(w))
have = existing_l2_interfaces_facts
for h in have:
self.expand_trunk_allowed_vlans(h)
resp = self.set_state(want, have)
return to_list(resp)
def expand_trunk_allowed_vlans(self, d):
if not d:
return None
if 'trunk' in d and d['trunk']:
if 'allowed_vlans' in d['trunk']:
allowed_vlans = vlan_range_to_list(d['trunk']['allowed_vlans'])
vlans_list = [str(l) for l in sorted(allowed_vlans)]
d['trunk']['allowed_vlans'] = ",".join(vlans_list)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
state = self._module.params['state']
if state in ('overridden', 'merged', 'replaced') and not want:
self._module.fail_json(msg='config is required for state {0}'.format(state))
commands = list()
if state == 'overridden':
commands.extend(self._state_overridden(want, have))
elif state == 'deleted':
commands.extend(self._state_deleted(want, have))
else:
for w in want:
if state == 'merged':
commands.extend(self._state_merged(flatten_dict(w), have))
elif state == 'replaced':
commands.extend(self._state_replaced(flatten_dict(w), have))
return commands
def _state_replaced(self, w, have):
""" The command generator when state is replaced
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
commands = []
obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
if obj_in_have:
diff = dict_diff(w, obj_in_have)
else:
diff = w
merged_commands = self.set_commands(w, have)
if 'name' not in diff:
diff['name'] = w['name']
wkeys = w.keys()
dkeys = diff.keys()
for k in wkeys:
if k in self.exclude_params and k in dkeys:
del diff[k]
replaced_commands = self.del_attribs(diff)
if merged_commands:
cmds = set(replaced_commands).intersection(set(merged_commands))
for cmd in cmds:
merged_commands.remove(cmd)
commands.extend(replaced_commands)
commands.extend(merged_commands)
return commands
def _state_overridden(self, want, have):
""" The command generator when state is overridden
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
commands = []
for h in have:
h = flatten_dict(h)
obj_in_want = flatten_dict(search_obj_in_list(h['name'], want, 'name'))
if h == obj_in_want:
continue
for w in want:
w = flatten_dict(w)
if h['name'] == w['name']:
wkeys = w.keys()
hkeys = h.keys()
for k in wkeys:
if k in self.exclude_params and k in hkeys:
del h[k]
commands.extend(self.del_attribs(h))
for w in want:
commands.extend(self.set_commands(flatten_dict(w), have))
return commands
def _state_merged(self, w, have):
""" The command generator when state is merged
:rtype: A list
:returns: the commands necessary to merge the provided into
the current configuration
"""
return self.set_commands(w, have)
def _state_deleted(self, want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the commands necessary to remove the current configuration
of the provided objects
"""
commands = []
if want:
for w in want:
obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
commands.extend(self.del_attribs(obj_in_have))
else:
if not have:
return commands
for h in have:
commands.extend(self.del_attribs(flatten_dict(h)))
return commands
def del_attribs(self, obj):
commands = []
if not obj or len(obj.keys()) == 1:
return commands
cmd = 'no switchport '
if 'vlan' in obj:
commands.append(cmd + 'access vlan')
if 'allowed_vlans' in obj:
commands.append(cmd + 'trunk allowed vlan')
if 'native_vlan' in obj:
commands.append(cmd + 'trunk native vlan')
if commands:
commands.insert(0, 'interface ' + obj['name'])
return commands
def diff_of_dicts(self, w, obj):
diff = set(w.items()) - set(obj.items())
diff = dict(diff)
if diff and w['name'] == obj['name']:
diff.update({'name': w['name']})
return diff
def add_commands(self, d):
commands = []
if not d:
return commands
cmd = 'switchport '
if 'vlan' in d:
commands.append(cmd + 'access vlan ' + str(d['vlan']))
if 'allowed_vlans' in d:
commands.append(cmd + 'trunk allowed vlan ' + str(d['allowed_vlans']))
if 'native_vlan' in d:
commands.append(cmd + 'trunk native vlan ' + str(d['native_vlan']))
if commands:
commands.insert(0, 'interface ' + d['name'])
return commands
def set_commands(self, w, have):
commands = []
obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
if not obj_in_have:
commands = self.add_commands(w)
else:
diff = self.diff_of_dicts(w, obj_in_have)
commands = self.add_commands(diff)
return commands

View file

@ -13,6 +13,7 @@ from ansible.module_utils.network.nxos.argspec.facts.facts import FactsArgs
from ansible.module_utils.network.common.facts.facts import FactsBase
from ansible.module_utils.network.nxos.facts.legacy.base import Default, Legacy, Hardware, Config, Interfaces, Features
from ansible.module_utils.network.nxos.facts.interfaces.interfaces import InterfacesFacts
from ansible.module_utils.network.nxos.facts.l2_interfaces.l2_interfaces import L2_interfacesFacts
from ansible.module_utils.network.nxos.facts.lacp.lacp import LacpFacts
from ansible.module_utils.network.nxos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts
from ansible.module_utils.network.nxos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
@ -37,6 +38,7 @@ FACT_RESOURCE_SUBSETS = dict(
lacp_interfaces=Lacp_interfacesFacts,
interfaces=InterfacesFacts,
l3_interfaces=L3_interfacesFacts,
l2_interfaces=L2_interfacesFacts,
)

View file

@ -0,0 +1,93 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)#!/usr/bin/python
"""
The nxos l2_interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import re
from copy import deepcopy
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.nxos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs
from ansible.module_utils.network.nxos.utils.utils import get_interface_type
class L2_interfacesFacts(object):
"""The nxos l2_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = L2_interfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for l2_interfaces
:param connection: the device connection
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
objs = []
if not data:
data = connection.get('show running-config | section ^interface')
config = data.split('interface ')
for conf in config:
conf = conf.strip()
if conf:
obj = self.render_config(self.generated_spec, conf)
if obj and len(obj.keys()) > 1:
objs.append(obj)
ansible_facts['ansible_network_resources'].pop('l2_interfaces', None)
facts = {}
if objs:
facts['l2_interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['l2_interfaces'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The configuration
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
match = re.search(r'^(\S+)', conf)
intf = match.group(1)
if get_interface_type(intf) == 'unknown':
return {}
config['name'] = intf
config['ip_forward'] = utils.parse_conf_arg(conf, 'ip forward')
config['access']['vlan'] = utils.parse_conf_arg(conf, 'switchport access vlan')
config['trunk']['allowed_vlans'] = utils.parse_conf_arg(conf, 'switchport trunk allowed vlan')
config['trunk']['native_vlan'] = utils.parse_conf_arg(conf, 'switchport trunk native vlan')
return utils.remove_empties(config)

View file

@ -9,7 +9,7 @@ __metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
@ -21,6 +21,10 @@ short_description: Manage Layer-2 interface on Cisco NXOS devices.
description:
- This module provides declarative management of Layer-2 interface on
Cisco NXOS devices.
deprecated:
removed_in: '2.13'
alternative: nxos_l2_interfaces
why: Updated modules released with more functionality
author:
- Trishna Guha (@trishnaguha)
notes:

View file

@ -57,7 +57,7 @@ options:
to a given subset. Possible values for this argument include
all and the resources like interfaces, vlans etc.
Can specify a list of values to include a larger subset.
choices: ['all', 'lag_interfaces', 'telemetry', 'vlans', 'lacp', 'lacp_interfaces', 'interfaces', 'l3_interfaces']
choices: ['all', 'lag_interfaces', 'telemetry', 'vlans', 'lacp', 'lacp_interfaces', 'interfaces', 'l3_interfaces', 'l2_interfaces']
required: false
version_added: "2.9"
"""

View file

@ -0,0 +1,275 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for nxos_l2_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: nxos_l2_interfaces
version_added: 2.9
short_description: Manages Layer-2 Interfaces attributes of NX-OS Interfaces
description: This module manages Layer-2 interfaces attributes of NX-OS Interfaces.
author: Trishna Guha (@trishnaguha)
notes:
- Tested against NXOS 7.3.(0)D1(1) on VIRL
options:
config:
description: A dictionary of Layer-2 interface options
type: list
elements: dict
suboptions:
name:
description:
- Full name of interface, i.e. Ethernet1/1.
type: str
required: true
access:
description:
- Switchport mode access command to configure the interface as a
Layer-2 access.
type: dict
suboptions:
vlan:
description:
- Configure given VLAN in access port. It's used as the access
VLAN ID.
type: int
trunk:
description:
- Switchport mode trunk command to configure the interface as a
Layer-2 trunk.
type: dict
suboptions:
native_vlan:
description:
- Native VLAN to be configured in trunk port. It is used as the
trunk native VLAN ID.
type: int
allowed_vlans:
description:
- List of allowed VLANs in a given trunk port. These are the only
VLANs that will be configured on the trunk.
type: str
state:
description:
- The state the configuration should be left in.
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
#
# interface Ethernet1/1
# switchport access vlan 20
# interface Ethernet1/2
# switchport trunk native vlan 20
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
- name: Merge provided configuration with device configuration.
nxos_l2_interfaces:
config:
- name: Ethernet1/1
trunk:
native_vlan: 10
allowed_vlans: 2,4,15
- name: Ethernet1/2
access:
vlan: 30
state: merged
# After state:
# ------------
#
# interface Ethernet1/1
# switchport trunk native vlan 10
# switchport trunk allowed vlans 2,4,15
# interface Ethernet1/2
# switchport access vlan 30
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
# Using replaced
# Before state:
# -------------
#
# interface Ethernet1/1
# switchport access vlan 20
# interface Ethernet1/2
# switchport trunk native vlan 20
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
- name: Replace device configuration of specified L2 interfaces with provided configuration.
nxos_l2_interfaces:
config:
- name: Ethernet1/1
trunk:
native_vlan: 20
trunk_vlans: 5-10, 15
state: replaced
# After state:
# ------------
#
# interface Ethernet1/1
# switchport trunk native vlan 20
# switchport trunk allowed vlan 5-10,15
# interface Ethernet1/2
# switchport trunk native vlan 20
# switchport mode trunk
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
# Using overridden
# Before state:
# -------------
#
# interface Ethernet1/1
# switchport access vlan 20
# interface Ethernet1/2
# switchport trunk native vlan 20
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
- name: Override device configuration of all L2 interfaces on device with provided configuration.
nxos_l2_interfaces:
config:
- name: Ethernet1/2
access:
vlan: 30
state: overridden
# After state:
# ------------
#
# interface Ethernet1/1
# interface Ethernet1/2
# switchport access vlan 30
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
# Using deleted
# Before state:
# -------------
#
# interface Ethernet1/1
# switchport access vlan 20
# interface Ethernet1/2
# switchport trunk native vlan 20
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
- name: Delete L2 attributes of given interfaces (Note This won't delete the interface itself).
nxos_l2_interfaces:
config:
- name: Ethernet1/1
- name: Ethernet1/2
state: deleted
# After state:
# ------------
#
# interface Ethernet1/1
# interface Ethernet1/2
# interface mgmt0
# ip address dhcp
# ipv6 address auto-config
"""
RETURN = """
before:
description: The configuration prior to the model invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The resulting configuration model invocation.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['command 1', 'command 2', 'command 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.nxos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs
from ansible.module_utils.network.nxos.config.l2_interfaces.l2_interfaces import L2_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
module = AnsibleModule(argument_spec=L2_interfacesArgs.argument_spec,
supports_check_mode=True)
result = L2_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,2 @@
---
testcase: "*"

View file

@ -0,0 +1,2 @@
dependencies:
- prepare_nxos_tests

View file

@ -0,0 +1,20 @@
---
- name: collect common test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli connection={{ cli }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

@ -0,0 +1,2 @@
---
- { include: cli.yaml, tags: ['cli'] }

View file

@ -0,0 +1,33 @@
---
- name: collect common test cases
find:
paths: "{{ role_path }}/tests/common"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: collect nxapi test cases
find:
paths: "{{ role_path }}/tests/nxapi"
patterns: "{{ testcase }}.yaml"
connection: local
register: nxapi_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }} + {{ nxapi_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=httpapi connection={{ nxapi }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test cases (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local connection={{ nxapi }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

@ -0,0 +1,59 @@
---
- debug:
msg: "Start nxos_l2_interfaces deleted integration tests connection={{ ansible_connection }}"
- set_fact: test_int1="{{ nxos_int1 }}"
- set_fact: test_int2="{{ nxos_int2 }}"
- name: setup1
cli_config: &cleanup
config: |
default interface {{ test_int1 }}
default interface {{ test_int2 }}
ignore_errors: yes
- block:
- name: setup2
cli_config:
config: |
interface {{ test_int1 }}
switchport trunk native vlan 10
interface {{ test_int2 }}
switchport trunk allowed vlan 20
- name: Gather l2_interfaces facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: l2_interfaces
- name: deleted
nxos_l2_interfaces: &deleted
state: deleted
register: result
- assert:
that:
- "ansible_facts.network_resources.l2_interfaces|symmetric_difference(result.before)|length == 0"
- "result.after|length == 0"
- "result.changed == true"
- "'interface {{ test_int1 }}' in result.commands"
- "'no switchport trunk native vlan' in result.commands"
- "'interface {{ test_int2 }}' in result.commands"
- "'no switchport trunk allowed vlan' in result.commands"
- "result.commands|length == 4"
- name: Idempotence - deleted
nxos_l2_interfaces: *deleted
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup
ignore_errors: yes

View file

@ -0,0 +1,54 @@
---
- debug:
msg: "Start nxos_l2_interfaces merged integration tests connection={{ ansible_connection }}"
- set_fact: test_int1="{{ nxos_int1 }}"
- name: setup
cli_config: &cleanup
config: |
default interface {{ test_int1 }}
ignore_errors: yes
- block:
- name: Merged
nxos_l2_interfaces: &merged
config:
- name: "{{ test_int1 }}"
access:
vlan: 6
state: merged
register: result
- assert:
that:
- "result.changed == true"
- "result.before|length == 0"
- "'interface {{ test_int1 }}' in result.commands"
- "'switchport access vlan 6' in result.commands"
- "result.commands|length == 2"
- name: Gather l2_interfaces facts
nxos_facts:
gather_subset:
- '!all'
- '!min'
gather_network_resources: l2_interfaces
- assert:
that:
- "ansible_facts.network_resources.l2_interfaces|symmetric_difference(result.after)|length == 0"
- name: Idempotence - Merged
nxos_l2_interfaces: *merged
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup
ignore_errors: yes

View file

@ -0,0 +1,66 @@
---
- debug:
msg: "Start nxos_l2_interfaces overridden integration tests connection={{ ansible_connection }}"
- set_fact: test_int1="{{ nxos_int1 }}"
- set_fact: test_int2="{{ nxos_int2 }}"
- name: setup1
cli_config: &cleanup
config: |
default interface {{ test_int1 }}
default interface {{ test_int2 }}
ignore_errors: yes
- block:
- name: setup2
cli_config:
config: |
interface {{ test_int1 }}
switchport trunk allowed vlan 11
- name: Gather l2_interfaces facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: l2_interfaces
- name: Overridden
nxos_l2_interfaces: &overridden
config:
- name: "{{ test_int2 }}"
access:
vlan: 6
state: overridden
register: result
- assert:
that:
- "ansible_facts.network_resources.l2_interfaces|symmetric_difference(result.before)|length == 0"
- "result.changed == true"
- "'interface {{ test_int1 }}' in result.commands"
- "'no switchport trunk allowed vlan' in result.commands"
- "'interface {{ test_int2 }}' in result.commands"
- "'switchport access vlan 6' in result.commands"
- name: Gather l2_interfaces post facts
nxos_facts: *facts
- assert:
that:
- "ansible_facts.network_resources.l2_interfaces|symmetric_difference(result.after)|length == 0"
- name: Idempotence - Overridden
nxos_l2_interfaces: *overridden
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup
ignore_errors: yes

View file

@ -0,0 +1,67 @@
---
- debug:
msg: "Start nxos_l2_interfaces replaced integration tests connection={{ ansible_connection }}"
- set_fact: test_int1="{{ nxos_int1 }}"
- set_fact: test_int2="{{ nxos_int2 }}"
- name: setup1
cli_config: &cleanup
config: |
default interface {{ test_int1 }}
default interface {{ test_int2 }}
ignore_errors: yes
- block:
- name: setup2
cli_config:
config: |
interface {{ test_int1 }}
switchport access vlan 5
interface {{ test_int2 }}
switchport trunk native vlan 15
- name: Gather l2_interfaces facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: l2_interfaces
- name: Replaced
nxos_l2_interfaces: &replaced
config:
- name: "{{ test_int1 }}"
access:
vlan: 8
state: replaced
register: result
- assert:
that:
- "ansible_facts.network_resources.l2_interfaces|symmetric_difference(result.before)|length == 0"
- "result.changed == true"
- "'interface {{ test_int1 }}' in result.commands"
- "'switchport access vlan 8' in result.commands"
- "result.commands|length == 2"
- name: Gather l2_interfaces post facts
nxos_facts: *facts
- assert:
that:
- "ansible_facts.network_resources.l2_interfaces|symmetric_difference(result.after)|length == 0"
- name: Idempotence - Replaced
nxos_l2_interfaces: *replaced
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup
ignore_errors: yes

View file

@ -4449,13 +4449,6 @@ lib/ansible/modules/network/nxos/nxos_interface_ospf.py validate-modules:E324
lib/ansible/modules/network/nxos/nxos_interface_ospf.py validate-modules:E327
lib/ansible/modules/network/nxos/nxos_interface_ospf.py validate-modules:E337
lib/ansible/modules/network/nxos/nxos_interface_ospf.py validate-modules:E338
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E322
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E324
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E326
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E327
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E337
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E338
lib/ansible/modules/network/nxos/nxos_l2_interface.py validate-modules:E340
lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E322
lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E324
lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E326
@ -4463,6 +4456,13 @@ lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E327
lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E337
lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E338
lib/ansible/modules/network/nxos/_nxos_l3_interface.py validate-modules:E340
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E322
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E324
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E326
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E327
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E337
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E338
lib/ansible/modules/network/nxos/_nxos_l2_interface.py validate-modules:E340
lib/ansible/modules/network/nxos/nxos_lag_interfaces.py validate-modules:E326
lib/ansible/modules/network/nxos/nxos_lldp.py validate-modules:E324
lib/ansible/modules/network/nxos/nxos_lldp.py validate-modules:E326