Add nxos_vlans resource module (#59294)

* Add nxos_vlans resource module

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>

* address review comments

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>

* fix CI failure and udpate tests

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>

* Add commands in module doc

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
pull/57003/head
Trishna Guha 5 years ago committed by GitHub
parent 9610f2b8ac
commit 021b1810c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,6 +11,7 @@ CHOICES = [
'all', 'all',
'lag_interfaces', 'lag_interfaces',
'telemetry', 'telemetry',
'vlans',
] ]

@ -0,0 +1,51 @@
#
# -*- 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_vlans module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class VlansArgs(object):
"""The arg spec for the nxos_vlans module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'enabled': {'type': 'bool'},
'mapped_vni': {'type': 'int'},
'mode': {'choices': ['ce', 'fabricpath'],
'type': 'str'},
'name': {'type': 'str'},
'vlan_id': {'required': True, 'type': 'int'},
'state': {'choices': ['active', 'suspend'],
'type': 'str'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -0,0 +1,257 @@
#
# -*- 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_vlans 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 get_interface_type, normalize_interface, search_obj_in_list
class Vlans(ConfigBase):
"""
The nxos_vlans class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'vlans',
]
exclude_params = ['name', 'state']
def __init__(self, module):
super(Vlans, self).__init__(module)
def get_vlans_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)
vlans_facts = facts['ansible_network_resources'].get('vlans')
if not vlans_facts:
return []
return vlans_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_vlans_facts = self.get_vlans_facts()
commands.extend(self.set_config(existing_vlans_facts))
if commands:
if not self._module.check_mode:
self._connection.edit_config(commands)
result['changed'] = True
result['commands'] = commands
changed_vlans_facts = self.get_vlans_facts()
result['before'] = existing_vlans_facts
if result['changed']:
result['after'] = changed_vlans_facts
result['warnings'] = warnings
return result
def set_config(self, existing_vlans_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:
want.append(remove_empties(w))
have = existing_vlans_facts
resp = self.set_state(want, have)
return to_list(resp)
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(w, have))
elif state == 'replaced':
commands.extend(self._state_replaced(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 = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
diff = dict_diff(w, obj_in_have)
merged_commands = self.set_commands(w, have)
if 'vlan_id' not in diff:
diff['vlan_id'] = w['vlan_id']
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:
obj_in_want = search_obj_in_list(h['vlan_id'], want, 'vlan_id')
if h == obj_in_want:
continue
for w in want:
if h['vlan_id'] == w['vlan_id']:
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(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 = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
commands.append('no vlan ' + str(obj_in_have['vlan_id']))
else:
if not have:
return commands
for h in have:
commands.append('no vlan ' + str(h['vlan_id']))
return commands
def del_attribs(self, obj):
commands = []
if not obj or len(obj.keys()) == 1:
return commands
commands.append('vlan ' + str(obj['vlan_id']))
if 'name' in obj:
commands.append('no' + ' ' + 'name')
if 'state' in obj:
commands.append('no state')
if 'enabled' in obj:
commands.append('no shutdown')
if 'mode' in obj:
commands.append('mode ce')
if 'mapped_vni' in obj:
commands.append('no vn-segment')
return commands
def diff_of_dicts(self, w, obj):
diff = set(w.items()) - set(obj.items())
diff = dict(diff)
if diff and w['vlan_id'] == obj['vlan_id']:
diff.update({'vlan_id': w['vlan_id']})
return diff
def add_commands(self, d):
commands = []
if not d:
return commands
commands.append('vlan' + ' ' + str(d['vlan_id']))
if 'name' in d:
commands.append('name ' + d['name'])
if 'state' in d:
commands.append('state ' + d['state'])
if 'enabled' in d:
if d['enabled'] == 'True':
commands.append('no shutdown')
else:
commands.append('shutdown')
if 'mode' in d:
commands.append('mode ' + d['mode'])
if 'mapped_vni' in d:
commands.append('vn-segment ' + d['mapped_vni'])
return commands
def set_commands(self, w, have):
commands = []
obj_in_have = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
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

@ -14,6 +14,7 @@ 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.legacy.base import Default, Legacy, Hardware, Config, Interfaces, Features
from ansible.module_utils.network.nxos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts from ansible.module_utils.network.nxos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
from ansible.module_utils.network.nxos.facts.telemetry.telemetry import TelemetryFacts from ansible.module_utils.network.nxos.facts.telemetry.telemetry import TelemetryFacts
from ansible.module_utils.network.nxos.facts.vlans.vlans import VlansFacts
FACT_LEGACY_SUBSETS = dict( FACT_LEGACY_SUBSETS = dict(
@ -27,6 +28,7 @@ FACT_LEGACY_SUBSETS = dict(
FACT_RESOURCE_SUBSETS = dict( FACT_RESOURCE_SUBSETS = dict(
lag_interfaces=Lag_interfacesFacts, lag_interfaces=Lag_interfacesFacts,
telemetry=TelemetryFacts, telemetry=TelemetryFacts,
vlans=VlansFacts,
) )

@ -0,0 +1,110 @@
#
# -*- 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 vlans 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.common.utils import parse_conf_arg, parse_conf_cmd_arg
from ansible.module_utils.network.nxos.argspec.vlans.vlans import VlansArgs
class VlansFacts(object):
""" The nxos vlans fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = VlansArgs.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 vlans
: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 ^vlan')
vlans = re.split(r'(,|-)', data.split()[1])
for v in vlans:
if not v.isdigit():
vlans.remove(v)
config = re.split(r'(^|\n)vlan', data)
for conf in config:
conf = conf.strip()
if conf:
if conf[0] in vlans:
vlans.remove(conf[0])
obj = self.render_config(self.generated_spec, conf)
if obj and len(obj.keys()) > 1:
objs.append(obj)
for v in vlans:
obj = self.render_config(self.generated_spec, v)
if obj:
objs.append(obj)
ansible_facts['ansible_network_resources'].pop('vlans', None)
facts = {}
if objs:
facts['vlans'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['vlans'].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)
if len(conf) == 1:
return utils.remove_empties({'vlan_id': conf})
match = re.search(r'^(\S+)?', conf, re.M)
if match:
if len(match.group(1)) == 1:
config['vlan_id'] = match.group(1)
config['name'] = parse_conf_arg(conf, 'name')
config['mode'] = parse_conf_arg(conf, 'mode')
config['mapped_vni'] = parse_conf_arg(conf, 'vn-segment')
config['state'] = parse_conf_arg(conf, 'state')
admin_state = parse_conf_cmd_arg(conf, 'shutdown', 'down', 'up')
if admin_state == 'up':
config['enabled'] = True
elif admin_state == 'down':
config['enabled'] = False
vlans_cfg = utils.remove_empties(config)
return vlans_cfg

@ -16,8 +16,11 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'], 'status': ['deprecated'],
'supported_by': 'network'} 'supported_by': 'network'}
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -28,58 +31,73 @@ version_added: "2.1"
short_description: Manages VLAN resources and attributes. short_description: Manages VLAN resources and attributes.
description: description:
- Manages VLAN configurations on NX-OS switches. - Manages VLAN configurations on NX-OS switches.
deprecated:
removed_in: '2.13'
alternative: nxos_vlans
why: Updated modules released with more functionality
author: Jason Edelman (@jedelman8) author: Jason Edelman (@jedelman8)
options: options:
vlan_id: vlan_id:
description: description:
- Single VLAN ID. - Single VLAN ID.
type: int
vlan_range: vlan_range:
description: description:
- Range of VLANs such as 2-10 or 2,5,10-15, etc. - Range of VLANs such as 2-10 or 2,5,10-15, etc.
type: str
name: name:
description: description:
- Name of VLAN or keyword 'default'. - Name of VLAN or keyword 'default'.
type: str
interfaces: interfaces:
description: description:
- List of interfaces that should be associated to the VLAN or keyword 'default'. - List of interfaces that should be associated to the VLAN or keyword 'default'.
version_added: "2.5" version_added: "2.5"
type: list
associated_interfaces: associated_interfaces:
description: description:
- This is a intent option and checks the operational state of the for given vlan C(name) - This is a intent option and checks the operational state of the for given vlan C(name)
for associated interfaces. If the value in the C(associated_interfaces) does not match with for associated interfaces. If the value in the C(associated_interfaces) does not match with
the operational state of vlan interfaces on device it will result in failure. the operational state of vlan interfaces on device it will result in failure.
version_added: "2.5" version_added: "2.5"
type: list
vlan_state: vlan_state:
description: description:
- Manage the vlan operational state of the VLAN - Manage the vlan operational state of the VLAN
default: active default: active
choices: ['active','suspend'] choices: ['active','suspend']
type: str
admin_state: admin_state:
description: description:
- Manage the VLAN administrative state of the VLAN equivalent - Manage the VLAN administrative state of the VLAN equivalent
to shut/no shut in VLAN config mode. to shut/no shut in VLAN config mode.
default: up default: up
choices: ['up','down'] choices: ['up','down']
type: str
mapped_vni: mapped_vni:
description: description:
- The Virtual Network Identifier (VNI) ID that is mapped to the - The Virtual Network Identifier (VNI) ID that is mapped to the
VLAN. Valid values are integer and keyword 'default'. Range 4096-16773119. VLAN. Valid values are integer and keyword 'default'. Range 4096-16773119.
version_added: "2.2" version_added: "2.2"
type: str
state: state:
description: description:
- Manage the state of the resource. - Manage the state of the resource.
default: present default: present
choices: ['present','absent'] choices: ['present','absent']
type: str
mode: mode:
description: description:
- Set VLAN mode to classical ethernet or fabricpath. - Set VLAN mode to classical ethernet or fabricpath.
This is a valid option for Nexus 5000 and 7000 series. This is a valid option for Nexus 5000 and 7000 series.
choices: ['ce','fabricpath'] choices: ['ce','fabricpath']
default: 'ce' default: 'ce'
type: str
version_added: "2.4" version_added: "2.4"
aggregate: aggregate:
description: List of VLANs definitions. description: List of VLANs definitions.
version_added: "2.5" version_added: "2.5"
type: list
purge: purge:
description: description:
- Purge VLANs not defined in the I(aggregate) parameter. - Purge VLANs not defined in the I(aggregate) parameter.
@ -92,6 +110,7 @@ options:
- Time in seconds to wait before checking for the operational state on remote - Time in seconds to wait before checking for the operational state on remote
device. This wait is applicable for operational state arguments. device. This wait is applicable for operational state arguments.
default: 10 default: 10
type: int
''' '''
EXAMPLES = ''' EXAMPLES = '''

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

@ -0,0 +1,247 @@
#!/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_vlans
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: nxos_vlans
version_added: 2.9
short_description: Create VLAN and manage VLAN configurations on NX-OS Interfaces
description: This module creates and manages VLAN configurations on Cisco NX-OS Interfaces.
author: Trishna Guha (@trishnaguha)
notes:
- Tested against NXOS 7.3.(0)D1(1) on VIRL
options:
config:
description: A dictionary of Vlan options
type: list
suboptions:
vlan_id:
description:
- Vlan ID.
type: int
required: true
name:
description:
- Name of VLAN.
type: str
state:
description:
- Manage operational state of the vlan.
type: str
choices: ['active', 'suspend']
enabled:
description:
- Manage administrative state of the vlan.
type: bool
mode:
description:
- Set vlan mode to classical ethernet or fabricpath.
This is a valid option for Nexus 5000, 6000 and 7000 series.
type: str
choices: ['ce','fabricpath']
mapped_vni:
description:
- The Virtual Network Identifier (VNI) ID that is mapped to the
VLAN.
type: int
state:
description:
- The state the configuration should be left in.
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
# vlan 1
- name: Merge provided configuration with device configuration.
nxos_vlans:
config:
- vlan_id: 5
name: test-vlan5
- vlan_id: 10
enabled: False
state: merged
# After state:
# ------------
# vlan 5
# name test-vlan5
# state active
# no shutdown
# vlan 10
# state active
# shutdown
# Using replaced
# Before state:
# -------------
# vlan 1
# vlan 5
# name test-vlan5
# vlan 10
# shutdown
- name: Replace device configuration of specified vlan with provided configuration.
nxos_vlans:
config:
- vlan_id: 5
name: test-vlan
enabled: False
- vlan_id: 10
enabled: False
state: replaced
# After state:
# ------------
# vlan 1
# vlan 5
# name test-vlan
# state active
# shutdown
# vlan 10
# state active
# shutdown
# Using overridden
# Before state:
# -------------
# vlan 1
# vlan 3
# name testing
# vlan 5
# name test-vlan5
# shutdown
# vlan 10
# shutdown
- name: Override device configuration of all vlans with provided configuration.
nxos_vlans:
config:
- vlan_id: 5
name: test-vlan
- vlan_id: 10
state: active
state: overridden
# After state:
# ------------
# vlan 1
# vlan 5
# name test-vlan
# state active
# no shutdown
# vlan 10
# state active
# no shutdown
# Using deleted
# Before state:
# -------------
# vlan 1
# vlan 5
# vlan 10
- name: Delete vlans.
nxos_vlans:
config:
- vlan_id: 5
- vlan_id: 10
state: deleted
# After state:
# ------------
# vlan 1
"""
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: ['vlan 5', 'name test-vlan5', 'state suspend']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.nxos.argspec.vlans.vlans import VlansArgs
from ansible.module_utils.network.nxos.config.vlans.vlans import Vlans
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
module = AnsibleModule(argument_spec=VlansArgs.argument_spec,
supports_check_mode=True)
result = Vlans(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -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

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

@ -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

@ -0,0 +1,47 @@
---
- debug:
msg: "Start nxos_vlans deleted integration tests connection={{ ansible_connection }}"
- name: setup
cli_config:
config: |
vlan 5
vlan 6
- block:
- name: Gather vlans facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: vlans
- name: deleted
nxos_vlans: &deleted
state: deleted
register: result
- assert:
that:
- "ansible_facts.network_resources.vlans|symmetric_difference(result.before)|length == 0"
- "result.after|length == 0"
- "result.changed == true"
- "'no vlan 5' in result.commands"
- "'no vlan 6' in result.commands"
- "result.commands|length == 2"
- name: Idempotence - deleted
nxos_vlans: *deleted
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config:
config: |
no vlan 5
no vlan 6

@ -0,0 +1,56 @@
---
- debug:
msg: "Start nxos_vlans merged integration tests connection={{ ansible_connection }}"
- name: setup
cli_config: &cleanup
config: |
no vlan 5
no vlan 6
- block:
- name: Merged
nxos_vlans: &merged
config:
- vlan_id: 5
name: vlan5
- vlan_id: 6
name: vlan6
state: suspend
state: merged
register: result
- assert:
that:
- "result.changed == true"
- "result.before|length == 0"
- "'vlan 5' in result.commands"
- "'name vlan5' in result.commands"
- "'vlan 6' in result.commands"
- "'name vlan6' in result.commands"
- "'state suspend' in result.commands"
- "result.commands|length == 5"
- name: Gather vlans facts
nxos_facts:
gather_subset:
- '!all'
- '!min'
gather_network_resources: vlans
- assert:
that:
- "ansible_facts.network_resources.vlans|symmetric_difference(result.after)|length == 0"
- name: Idempotence - Merged
nxos_vlans: *merged
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup

@ -0,0 +1,67 @@
---
- debug:
msg: "Start nxos_vlans overridden integration tests connection={{ ansible_connection }}"
- name: setup1
cli_config: &cleanup
config: |
no vlan 5
no vlan 6
no vlan 9
- block:
- name: setup
cli_config:
config: |
vlan 5
name test-vlan5
state suspend
vlan 6
- name: Gather vlans facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: vlans
- name: Overridden
nxos_vlans: &overridden
config:
- vlan_id: 9
name: test-vlan9
enabled: false
state: overridden
register: result
- assert:
that:
- "ansible_facts.network_resources.vlans|symmetric_difference(result.before)|length == 0"
- "result.changed == true"
- "'vlan 5' in result.commands"
- "'no name' in result.commands"
- "'no state' in result.commands"
- "'vlan 9' in result.commands"
- "'name test-vlan9' in result.commands"
- "'shutdown' in result.commands"
- "result.commands|length == 6"
- name: Gather vlans post facts
nxos_facts: *facts
- assert:
that:
- "ansible_facts.network_resources.vlans|symmetric_difference(result.after)|length == 0"
- name: Idempotence - Overridden
nxos_vlans: *overridden
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup

@ -0,0 +1,62 @@
---
- debug:
msg: "Start nxos_vlans replaced integration tests connection={{ ansible_connection }}"
- name: setup1
cli_config: &cleanup
config: |
no vlan 5
no vlan 6
- block:
- name: setup2
cli_config:
config: |
vlan 5
name test-vlan5
vlan 6
name test-vlan6
- name: Gather vlans facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: vlans
- name: Replaced
nxos_vlans: &replaced
config:
- vlan_id: 6
state: suspend
state: replaced
register: result
- assert:
that:
- "ansible_facts.network_resources.vlans|symmetric_difference(result.before)|length == 0"
- "result.changed == true"
- "'vlan 6' in result.commands"
- "'no name' in result.commands"
- "'state suspend' in result.commands"
- "result.commands|length == 3"
- name: Gather vlans post facts
nxos_facts: *facts
- assert:
that:
- "ansible_facts.network_resources.vlans|symmetric_difference(result.after)|length == 0"
- name: Idempotence - Replaced
nxos_vlans: *replaced
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
cli_config: *cleanup

@ -5445,15 +5445,13 @@ lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E327
lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E337 lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E337
lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E338 lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E338
lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E340 lib/ansible/modules/network/nxos/nxos_user.py validate-modules:E340
lib/ansible/modules/network/nxos/nxos_vlan.py future-import-boilerplate lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E322
lib/ansible/modules/network/nxos/nxos_vlan.py metaclass-boilerplate lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E324
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E322 lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E326
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E324 lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E327
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E326 lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E337
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E327 lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E338
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E337 lib/ansible/modules/network/nxos/_nxos_vlan.py validate-modules:E340
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E338
lib/ansible/modules/network/nxos/nxos_vlan.py validate-modules:E340
lib/ansible/modules/network/nxos/nxos_vpc.py future-import-boilerplate lib/ansible/modules/network/nxos/nxos_vpc.py future-import-boilerplate
lib/ansible/modules/network/nxos/nxos_vpc.py metaclass-boilerplate lib/ansible/modules/network/nxos/nxos_vpc.py metaclass-boilerplate
lib/ansible/modules/network/nxos/nxos_vpc.py validate-modules:E324 lib/ansible/modules/network/nxos/nxos_vpc.py validate-modules:E324

@ -22,27 +22,27 @@ __metaclass__ = type
import json import json
from units.compat.mock import patch from units.compat.mock import patch
from ansible.modules.network.nxos import nxos_vlan from ansible.modules.network.nxos import _nxos_vlan
from .nxos_module import TestNxosModule, load_fixture, set_module_args from .nxos_module import TestNxosModule, load_fixture, set_module_args
class TestNxosVlanModule(TestNxosModule): class TestNxosVlanModule(TestNxosModule):
module = nxos_vlan module = _nxos_vlan
def setUp(self): def setUp(self):
super(TestNxosVlanModule, self).setUp() super(TestNxosVlanModule, self).setUp()
self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_vlan.run_commands') self.mock_run_commands = patch('ansible.modules.network.nxos._nxos_vlan.run_commands')
self.run_commands = self.mock_run_commands.start() self.run_commands = self.mock_run_commands.start()
self.mock_load_config = patch('ansible.modules.network.nxos.nxos_vlan.load_config') self.mock_load_config = patch('ansible.modules.network.nxos._nxos_vlan.load_config')
self.load_config = self.mock_load_config.start() self.load_config = self.mock_load_config.start()
self.mock_get_config = patch('ansible.modules.network.nxos.nxos_vlan.get_config') self.mock_get_config = patch('ansible.modules.network.nxos._nxos_vlan.get_config')
self.get_config = self.mock_get_config.start() self.get_config = self.mock_get_config.start()
self.mock_get_capabilities = patch('ansible.modules.network.nxos.nxos_vlan.get_capabilities') self.mock_get_capabilities = patch('ansible.modules.network.nxos._nxos_vlan.get_capabilities')
self.get_capabilities = self.mock_get_capabilities.start() self.get_capabilities = self.mock_get_capabilities.start()
self.get_capabilities.return_value = {'device_info': {'network_os_platform': 'N9K-9000v'}, 'network_api': 'cliconf'} self.get_capabilities.return_value = {'device_info': {'network_os_platform': 'N9K-9000v'}, 'network_api': 'cliconf'}

Loading…
Cancel
Save