nxos_lldp_interfaces resource module (#67802)

* Added nxos_lldp_interfaces module

* Linting

* Added RTT, resolved shippable errors

* Added new states

* New states edit

* Updated states

* Updated tests

* Show all interfaces in facts

* Test changes

* Added unit tests

* Linting

* Handled portchannel failing condition
pull/67897/head
Adharsh Srivats R 5 years ago committed by GitHub
parent 4b718ed58b
commit 3558651d39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,75 @@
#
# -*- 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_lldp_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lldp_interfacesArgs(object): # pylint: disable=R0903
"""The arg spec for the nxos_lldp_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
'config': {
'elements': 'dict',
'options': {
'name': {
'required': True,
'type': 'str'
},
'receive': {
'type': 'bool'
},
'tlv_set': {
'options': {
'management_address': {
'type': 'str'
},
'vlan': {
'type': 'int'
}
},
'type': 'dict'
},
'transmit': {
'type': 'bool'
}
},
'type': 'list'
},
'running_config': {
'type': 'str'
},
'state': {
'choices': ['deleted', 'gathered', 'merged', 'overridden', 'rendered',
'replaced', 'parsed'],
'default': 'merged',
'type': 'str'
}
} # pylint: disable=C0301

@ -0,0 +1,304 @@
#
# -*- 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_lldp_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 to_list, remove_empties, dict_diff
from ansible.module_utils.network.nxos.facts.facts import Facts
from ansible.module_utils.network.nxos.utils.utils import flatten_dict, search_obj_in_list, get_interface_type, normalize_interface
class Lldp_interfaces(ConfigBase):
"""
The nxos_lldp_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lldp_interfaces',
]
def __init__(self, module):
super(Lldp_interfaces, self).__init__(module)
def get_lldp_interfaces_facts(self, data=None):
""" 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, data=data)
lldp_interfaces_facts = facts['ansible_network_resources'].get(
'lldp_interfaces')
if not lldp_interfaces_facts:
return []
return lldp_interfaces_facts
def edit_config(self, commands):
"""Wrapper method for `_connection.edit_config()`
This exists solely to allow the unit test framework to mock device connection calls.
"""
return self._connection.edit_config(commands)
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
commands = list()
warnings = list()
state = self._module.params['state']
action_states = ['merged', 'replaced', 'deleted', 'overridden']
if state == 'gathered':
result['gathered'] = self.get_lldp_interfaces_facts()
elif state == 'rendered':
result['rendered'] = self.set_config({})
elif state == 'parsed':
result['parsed'] = self.set_config({})
else:
existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
commands.extend(self.set_config(existing_lldp_interfaces_facts))
if commands and state in action_states:
if not self._module.check_mode:
self._connection.edit_config(commands)
result['changed'] = True
result['before'] = existing_lldp_interfaces_facts
result['commands'] = commands
result['commands'] = commands
changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
if result['changed']:
result['after'] = changed_lldp_interfaces_facts
result['warnings'] = warnings
return result
def set_config(self, existing_lldp_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['config']
want = []
if config:
for w in config:
if get_interface_type(w['name']) not in ('management',
'ethernet'):
self._module.fail_json(
msg='This module works with either management or ethernet')
w.update({'name': normalize_interface(w['name'])})
want.append(remove_empties(w))
have = existing_lldp_interfaces_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
"""
commands = []
state = self._module.params['state']
if state == 'overridden':
commands = self._state_overridden(want, have)
elif state == 'deleted':
commands = self._state_deleted(want, have)
elif state == 'rendered':
commands = self._state_rendered(want)
elif state == 'parsed':
want = self._module.params['running_config']
commands = self._state_parsed(want)
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_parsed(self, want):
return self.get_lldp_interfaces_facts(want)
def _state_rendered(self, want):
commands = []
for w in want:
commands.extend(self.set_commands(w, {}))
return commands
def _state_gathered(self, have):
""" The command generator when state is gathered
:rtype: A list
:returns: the commands necessary to reproduce the current configuration
"""
commands = []
want = {}
commands.append(self.set_commands(want, have))
return commands
def _state_replaced(self, want, 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 = []
del_commands = []
delete_dict = {}
obj_in_have = flatten_dict(
search_obj_in_list(want['name'], have, 'name'))
for k1 in obj_in_have.keys():
if k1 not in want.keys():
delete_dict.update({k1: obj_in_have[k1]})
if delete_dict:
delete_dict.update({'name': want['name']})
del_commands = self.del_commands(delete_dict)
merged_commands = self.set_commands(want, have)
if merged_commands:
cmds = set(del_commands).intersection(set(merged_commands))
for cmd in cmds:
merged_commands.remove(cmd)
commands.extend(del_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 = []
want_intfs = [w['name'] for w in want]
for h in have:
h = flatten_dict(h)
delete_dict = {}
if h['name'] in want_intfs:
for w in want:
if w['name'] == h['name']:
delete_keys = list(set(h) - set(flatten_dict(w)))
for k in delete_keys:
delete_dict.update({k: h[k]})
delete_dict.update({'name': h['name']})
break
else:
delete_dict.update(h)
commands.extend(self.del_commands(delete_dict))
for w in want:
commands.extend(self.set_commands(flatten_dict(w), have))
return commands
def _state_merged(self, want, 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(want, 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_commands(obj_in_have))
else:
if not have:
return commands
for h in have:
commands.extend(self.del_commands(flatten_dict(h)))
return commands
def set_commands(self, want, have):
commands = []
obj_in_have = flatten_dict(
search_obj_in_list(want['name'], have, 'name'))
if not obj_in_have:
commands = self.add_commands(flatten_dict(want))
else:
diff = dict_diff(obj_in_have, want)
if diff:
diff.update({'name': want['name']})
commands = self.add_commands(diff)
return commands
def add_commands(self, d):
commands = []
if not d:
return commands
commands.append('interface ' + d['name'])
if 'transmit' in d:
if (d['transmit']):
commands.append('lldp transmit')
else:
commands.append('no lldp transmit')
if 'receive' in d:
if (d['receive']):
commands.append('lldp receive')
else:
commands.append('no lldp receive')
if 'management_address' in d:
commands.append('lldp tlv-set management-address ' +
d['management_address'])
if 'vlan' in d:
commands.append('lldp tlv-set vlan ' + str(d['vlan']))
return commands
def del_commands(self, obj):
commands = []
if not obj or len(obj.keys()) == 1:
return commands
commands.append('interface ' + obj['name'])
if 'transmit' in obj:
commands.append('lldp transmit')
if 'receive' in obj:
commands.append('lldp receive')
if 'management_address' in obj:
commands.append('no lldp tlv-set management-address ' +
obj['management_address'])
if 'vlan' in obj:
commands.append('no lldp tlv-set vlan ' + str(obj['vlan']))
return commands

@ -22,6 +22,7 @@ from ansible.module_utils.network.nxos.facts.telemetry.telemetry import Telemetr
from ansible.module_utils.network.nxos.facts.vlans.vlans import VlansFacts
from ansible.module_utils.network.nxos.facts.lacp_interfaces.lacp_interfaces import Lacp_interfacesFacts
from ansible.module_utils.network.nxos.facts.lldp_global.lldp_global import Lldp_globalFacts
from ansible.module_utils.network.nxos.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts
FACT_LEGACY_SUBSETS = dict(
@ -44,6 +45,7 @@ FACT_RESOURCE_SUBSETS = dict(
interfaces=InterfacesFacts,
l3_interfaces=L3_interfacesFacts,
l2_interfaces=L2_interfacesFacts,
lldp_interfaces=Lldp_interfacesFacts,
)

@ -0,0 +1,121 @@
#
# -*- 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 lldp_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.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs
from ansible.module_utils.network.nxos.utils.utils import get_interface_type
class Lldp_interfacesFacts(object):
""" The nxos lldp_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Lldp_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 get_device_data(self, connection):
return connection.get('show running-config | section ^interface')
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for lldp_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
if not data:
data = self.get_device_data(connection)
objs = []
data = data.split('interface')
resources = []
for i in range(len(data)):
intf = data[i].split('\n')
for l in range(1, len(intf)):
if not re.search('lldp', intf[l]):
intf[l] = ''
intf = list(filter(None, intf))
intf = ''.join(i for i in intf)
resources.append(intf)
for resource in resources:
if resource: # and re.search(r'lldp', resource):
obj = self.render_config(self.generated_spec, resource)
if obj and len(obj.keys()) >= 1:
objs.append(obj)
ansible_facts['ansible_network_resources'].pop('lldp_interfaces', None)
facts = {}
if objs:
facts['lldp_interfaces'] = []
params = utils.validate_config(
self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['lldp_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)
if match is None:
return {}
intf = match.group(1)
if get_interface_type(intf) not in ['management', 'ethernet']:
return {}
config['name'] = intf
if 'lldp receive' in conf: # for parsed state only
config['receive'] = True
if 'no lldp receive' in conf:
config['receive'] = False
if 'lldp transmit' in conf: # for parsed state only
config['transmit'] = True
if 'no lldp transmit' in conf:
config['transmit'] = False
if 'management-address' in conf:
config['tlv_set']['management_address'] = re.search(
r'management-address (\S*)', conf).group(1)
if 'vlan' in conf:
config['tlv_set']['vlan'] = re.search(
r'vlan (\S*)', conf).group(1)
return utils.remove_empties(config)

@ -0,0 +1,250 @@
#!/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_lldp_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_lldp_interfaces
version_added: "2.10"
short_description: Manages interfaces' configuration for Link Layer Discovery Protocol (LLDP) on NX-OS platforms.
description: This module manages interfaces' configuration for Link Layer Discovery Protocol (LLDP) on NX-OS platforms.
author: Adharsh Srivats Rangarajan (@adharshsrivatsr)
notes:
- Tested against NXOS 7.3.(0)D1(1) on VIRL
- The LLDP feature needs to be enabled before using this module
options:
running_config:
description:
- Used to parse given commands into structured format, only in parsed state
type: str
config:
description:
- A list of link layer discovery configurations for interfaces.
type: list
elements: dict
suboptions:
name:
description:
- Name of the interface
required: true
type: str
receive:
description:
- Used to enable or disable the reception of LLDP packets on that interface. By default, this is enabled after LLDP is enabled globally.
type: bool
transmit:
description:
- Used to enable or disable the transmission of LLDP packets on that interface. By default, this is enabled after LLDP is enabled globally.
type: bool
tlv_set:
description:
- Used to configure TLV parameters on the interface
type: dict
suboptions:
management_address:
description:
- Used to mention the IPv4 or IPv6 management address for the interface
type: str
vlan:
description:
- Used to mention the VLAN for the interface
type: int
state:
description:
- The state the configuration should be left in
type: str
choices:
- merged
- replaced
- overridden
- deleted
- gathered
- rendered
- parsed
default: merged
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
#
- name : Merge provided configuration with device configuration
nxos_lldp_interfaces:
config:
- name : Ethernet1/4
receive: false
transmit: true
tlv_set:
management_address: 192.168.122.64
vlan: 12
state: merged
# After state:
# -------------
#
# interface Ethernet1/4
# no lldp receive
# lldp tlv-set management-address 192.168.122.64
# lldp tlv-set vlan 12
# Using replaced
# Before state:
# ------------
#
# interface Ethernet1/4
# no lldp receive
# lldp tlv-set management-address 192.168.122.64
# interface Ethernet1/5
# no lldp transmit
# lldp tlv-set vlan 10
- name: Replace LLDP configuration on interfaces with given configuration
nxos_lldp_interfaces:
config:
- name: Ethernet1/4
transmit: no
tlv_set:
vlan: 2
state: replaced
# After state:
# -----------
#
# interface Ethernet1/4
# no lldp transmit
# lldp tlv_set vlan 2
# interface Ethernet1/5
# no lldp transmit
# lldp tlv-set vlan 10
# Using overridden
# Before state:
# ------------
#
# interface Ethernet1/4
# no lldp receive
# lldp tlv-set management-address 192.168.122.64
# interface Ethernet1/5
# no lldp transmit
# lldp tlv-set vlan 10
- name: Override LLDP configuration on all interfaces with given configuration
nxos_lldp_interfaces:
config:
- name: Ethernet1/7
receive: no
tlv_set:
vlan: 12
state: overridden
# After state:
# -----------
#
# interface Ethernet1/7
# no lldp receive
# lldp tlv_set vlan 12
# Using deleted
# Before state:
# ------------
#
# interface Ethernet1/4
# lldp tlv-set management vlan 24
# no lldp transmit
# interface mgmt0
# no lldp receive
- name: Delete LLDP interfaces configuration
nxos_lldp_interfaces:
state: deleted
# After state:
# ------------
#
"""
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: ['interface Ethernet1/2', 'lldp receive', 'lldp tlv-set vlan 12']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.nxos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs
from ansible.module_utils.network.nxos.config.lldp_interfaces.lldp_interfaces import Lldp_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
module = AnsibleModule(argument_spec=Lldp_interfacesArgs.argument_spec,
supports_check_mode=True)
result = Lldp_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

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

@ -0,0 +1,20 @@
---
- name: collect common test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yml"
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,73 @@
---
- debug:
msg: "Start nxos_lldp_interfaces deleted integration tests connection = {{ ansible_connection }}"
- name: Enable LLDP feature
nxos_feature:
feature: lldp
state: enabled
- block:
- name: Setup
cli_config:
config: |
interface Ethernet1/1
lldp receive
no lldp transmit
interface Ethernet1/2
no lldp receive
lldp tlv-set vlan 12
interface Ethernet1/3
lldp tlv-set management-address 192.0.2.12
- name: Delete on single interface
nxos_lldp_interfaces:
config:
- name: Ethernet1/2
state: deleted
register: result
- assert:
that:
- "result.changed == true"
- "'interface Ethernet1/2' in result.commands"
- "'lldp receive' in result.commands"
- "'no lldp tlv-set vlan 12' in result.commands"
- "result.commands | length == 3"
- name: Gather lldp_interfaces facts
nxos_facts: &facts
gather_subset:
- "!all"
- "!min"
gather_network_resources: lldp_interfaces
- name: Deleted
nxos_lldp_interfaces: &deleted
state: deleted
register: result
- assert:
that:
- "ansible_facts.network_resources.lldp_interfaces == result.before"
- "'interface Ethernet1/1' in result.commands"
- "'lldp transmit' in result.commands"
- "'interface Ethernet1/3' in result.commands"
- "'no lldp tlv-set management-address 192.0.2.12' in result.commands"
- "result.changed == true "
- "result.commands | length == 4"
- name: Idempotence - deleted
nxos_lldp_interfaces: *deleted
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,52 @@
---
- debug:
msg: Start nxos_lldp_interfaces gathered integration tests connection={{ansible_connection}}"
- name: Enable LLDP feature
nxos_feature:
feature: lldp
state: enabled
- block:
- name: Setup
cli_config:
config: |
interface Ethernet1/1
lldp receive
no lldp transmit
interface Ethernet1/2
no lldp receive
lldp tlv-set vlan 12
interface Ethernet1/3
lldp tlv-set management-address 192.0.2.12
- name: Gather lldp interfaces facts
nxos_facts: &facts
gather_subset:
- "!all"
- "!min"
gather_network_resources: lldp_interfaces
- name: Gathered
nxos_lldp_interfaces: &gathered
state: gathered
register: result
- assert:
that:
- "result.changed == false"
- "ansible_facts.network_resources.lldp_interfaces == result.gathered"
- name: Idempotence - Gathered
nxos_lldp_interfaces: *gathered
register: result
- assert:
that:
- "result.changed == false"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,60 @@
---
- debug:
msg: "Start nxos_lldp_interfaces merged integration tests connection={{ansible_connection}}"
- name: Enable lldp
nxos_feature:
feature: lldp
- block:
- name: Merged
nxos_lldp_interfaces: &merged
config:
- name: Ethernet 1/1
receive: false
tlv_set:
vlan: 123
- name: Ethernet1/2
transmit: false
tlv_set:
management_address: 10.0.0.1
state: merged
register: result
- assert:
that:
- "result.changed == true"
- "'interface Ethernet1/1' in result.commands"
- "'no lldp receive' in result.commands"
- "'lldp tlv-set vlan 123' in result.commands"
- "'interface Ethernet1/2' in result.commands"
- "'no lldp transmit' in result.commands"
- "'lldp tlv-set management-address 10.0.0.1' in result.commands"
- "result.commands | length == 6"
- name: Gather lldp_interfaces facts
nxos_facts:
gather_subset:
- '!all'
- '!min'
gather_network_resources: lldp_interfaces
- assert:
that:
- "ansible_facts.network_resources.lldp_interfaces == result.after"
- name: Idempotence - Merged
nxos_lldp_interfaces: *merged
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,66 @@
---
- debug:
msg: "Start nxos_lldp_interfaces overridden tests connection={{ ansible_connection }}"
- name: Enable LLDP feature
nxos_feature:
feature: lldp
state: enabled
- block:
- name: Setup
cli_config:
config: |
interface Ethernet1/1
no lldp receive
lldp tlv-set management-address 12.12.12.12
- name: Gather lldp_interfaces facts
nxos_facts: &facts
gather_subset:
- '!all'
- '!min'
gather_network_resources: lldp_interfaces
- name: Overridden
nxos_lldp_interfaces: &overridden
config:
- name: Ethernet1/2
receive: no
tlv_set:
vlan: 12
state: overridden
register: result
- assert:
that:
- "ansible_facts.network_resources.lldp_interfaces == result.before"
- "'interface Ethernet1/1' in result.commands"
- "'lldp receive' in result.commands"
- "'no lldp tlv-set management-address 12.12.12.12' in result.commands"
- "'interface Ethernet1/2' in result.commands"
- "'no lldp receive' in result.commands"
- "'lldp tlv-set vlan 12' in result.commands"
- "result.commands | length == 6"
- name: Gather lldp_interfaces post facts
nxos_facts: *facts
- assert:
that:
- "ansible_facts.network_resources.lldp_interfaces == result.after"
- name: Idempotence - overridden
nxos_lldp_interfaces: *overridden
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,47 @@
---
- debug:
msg: Start nxos_lldp_interfaces parsed integration tests connection={{ansible_connection}}"
- name: Enable lldp
nxos_feature:
feature: lldp
- block:
- name: Gather lldp interfaces facts
nxos_facts: &facts
gather_subset:
- "!all"
- "!min"
gather_network_resources: lldp_interfaces
- name: Parsed
nxos_lldp_interfaces: &parsed
running_config: |
interface Ethernet1/1
lldp receive
no lldp transmit
interface Ethernet1/2
no lldp receive
lldp tlv-set vlan 12
interface Ethernet1/3
lldp tlv-set management-address 192.0.2.12
state: parsed
register: result
- assert:
that:
- "result.changed == false"
- "result.parsed == parsed"
- name: Idempotence - Parsed
nxos_lldp_interfaces: *parsed
register: result
- assert:
that: "result.changed == false"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,8 @@
---
- cli_config:
config: |
no interface port-channel1
no interface port-channel2
no interface port-channel12
ignore_errors: yes
#this is just for RTT to remove spill overs from other modules and pass in ZUUL

@ -0,0 +1,42 @@
---
- debug:
msg: "Start nxos_lldp_interfaces rendered tests connection={{ ansible_connection }}"
- name: Rendered
nxos_lldp_interfaces: &rendered
config:
- name: Ethernet1/1
receive: true
transmit: false
- name: Ethernet1/2
receive: false
tlv_set:
vlan: 12
- name: Ethernet1/3
tlv_set:
management_address: 192.0.2.12
state: rendered
register: result
- assert:
that:
- "result.changed == false"
- "'interface Ethernet1/1' in result.rendered"
- "'lldp receive' in result.rendered"
- "'no lldp transmit' in result.rendered"
- "'interface Ethernet1/2' in result.rendered"
- "'no lldp receive' in result.rendered"
- "'lldp tlv-set vlan 12' in result.rendered"
- "'interface Ethernet1/3' in result.rendered"
- "'lldp tlv-set management-address 192.0.2.12' in result.rendered"
- "result.rendered | length == 8"
- name: Idempotence - Rendered
nxos_lldp_interfaces: *rendered
register: result
- assert:
that:
- "result.changed == false"

@ -0,0 +1,62 @@
---
- debug:
msg: "Start nxos_lldp_interfaces replaced integration tests connection = {{ansible_connection}}"
- name: Enable lldp feature
nxos_feature:
feature: lldp
state: enabled
- block:
- name: Setup
cli_config:
config: |
interface Ethernet1/2
no lldp receive
lldp tlv-set management-address 192.168.122.64
- name: Replaced
nxos_lldp_interfaces: &replaced
config:
- name: Ethernet1/2
transmit: false
tlv_set:
vlan: 2
state: replaced
register: result
- assert:
that:
- "result.changed == true"
- "'interface Ethernet1/2' in result.commands"
- "'lldp receive' in result.commands"
- "'no lldp tlv-set management-address 192.168.122.64' in result.commands"
- "'no lldp transmit' in result.commands"
- "'lldp tlv-set vlan 2' in result.commands"
- "result.commands|length == 5"
- name: Gather lldp_interfaces post facts
nxos_facts:
gather_subset:
- '!all'
- '!min'
gather_network_resources: lldp_interfaces
- assert:
that:
- "ansible_facts.network_resources.lldp_interfaces == result.after"
- name: Idempotence - Replaced
nxos_lldp_interfaces: *replaced
register: result
- assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,70 @@
---
- debug:
msg: "Start nxos_lldp_interfaces round trip integration tests on connection={{ ansible_connection }}"
- name: Enable lldp
nxos_feature:
feature: lldp
- include_tasks: remove_config.yaml
- block:
- name: RTT - Apply the provided configuration (base config)
nxos_lldp_interfaces:
config:
- name: Ethernet1/1
transmit: false
tlv_set:
vlan: 5
state: merged
register: base_config
- name: Gather interfaces facts
nxos_facts:
gather_subset:
- "!all"
- "!min"
gather_network_resources:
- lldp_interfaces
- name: Apply provided configuration (this will be reverted)
nxos_lldp_interfaces:
config:
- name: Ethernet1/1
transmit: false
- name: Ethernet1/2
transmit: true
tlv_set:
vlan: 12
management_address: 10.1.1.2
state: overridden
register: result
- name: Assert that changes were applied
assert:
that:
- "result.changed == true"
- "'interface Ethernet1/1' in result.commands"
- "'no lldp tlv-set vlan 5' in result.commands"
- "'interface Ethernet1/2' in result.commands"
- "'lldp transmit' in result.commands"
- "'lldp tlv-set vlan 12' in result.commands"
- "'lldp tlv-set management-address 10.1.1.2' in result.commands"
- "result.commands | length == 6"
- name: Revert back to base configuration
nxos_lldp_interfaces:
config: "{{ ansible_facts['network_resources']['lldp_interfaces'] }}"
state: overridden
register: revert
- name: Assert that config was reverted
assert:
that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length == 0 }}"
always:
- name: teardown
nxos_feature:
feature: lldp
state: disabled

@ -0,0 +1,14 @@
---
parsed:
- name: Ethernet1/1
receive: true
transmit: false
- name: Ethernet1/2
receive: false
tlv_set:
vlan: 12
- name: Ethernet1/3
tlv_set:
management_address: 192.0.2.12

@ -0,0 +1,236 @@
#
# (c) 2019, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.modules.network.nxos import nxos_lldp_interfaces
from units.compat.mock import patch, MagicMock
from units.modules.utils import set_module_args
from .nxos_module import TestNxosModule, load_fixture
class TestNxosLldpInterfacesModule(TestNxosModule):
module = nxos_lldp_interfaces
def setUp(self):
super(TestNxosLldpInterfacesModule, self).setUp()
self.mock_get_config = patch(
'ansible.module_utils.network.common.network.Config.get_config')
self.get_config = self.mock_get_config.start()
self.mock_load_config = patch(
'ansible.module_utils.network.common.network.Config.load_config')
self.load_config = self.mock_load_config.start()
self.mock_get_resource_connection_config = patch(
'ansible.module_utils.network.common.cfg.base.get_resource_connection'
)
self.get_resource_connection_config = self.mock_get_resource_connection_config.start(
)
self.mock_get_resource_connection_facts = patch(
'ansible.module_utils.network.common.facts.facts.get_resource_connection'
)
self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start()
self.mock_edit_config = patch(
'ansible.module_utils.network.nxos.config.lldp_interfaces.lldp_interfaces.Lldp_interfaces.edit_config'
)
self.edit_config = self.mock_edit_config.start()
self.mock_execute_show_command = patch(
'ansible.module_utils.network.nxos.facts.lldp_interfaces.lldp_interfaces.Lldp_interfacesFacts.get_device_data'
)
self.execute_show_command = self.mock_execute_show_command.start()
def tearDown(self):
super(TestNxosLldpInterfacesModule, self).tearDown()
self.mock_get_resource_connection_config.stop()
self.mock_get_resource_connection_facts.stop()
self.mock_edit_config.stop()
self.mock_get_config.stop()
self.mock_load_config.stop()
self.mock_execute_show_command.stop()
def load_fixtures(self, commands=None, device=''):
def load_from_file(*args, **kwargs):
output = '''interface Ethernet1/1
lldp receive
no lldp transmit
interface Ethernet1/2
no lldp receive
lldp tlv-set vlan 12'''
return output
self.execute_show_command.side_effect = load_from_file
def test_nxos_lldp_interfaces_merged(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/3",
receive=False,
tlv_set=dict(
vlan=123
)
)
], state="merged"))
commands = ['interface Ethernet1/3',
'no lldp receive',
'lldp tlv-set vlan 123']
self.execute_module(changed=True, commands=commands)
def test_nxos_lldp_interfaces_merged_idempotent(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/2",
receive=False,
tlv_set=dict(
vlan=12
)
),
dict(name="Ethernet1/1",
receive=True,
transmit=False)
], state="merged"))
self.execute_module(changed=False, commands=[])
def test_nxos_lldp_interfaces_replaced(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/2",
receive=True,
transmit=False,
tlv_set=dict(
management_address='192.0.2.123'
)
)
], state="replaced"))
commands = ['interface Ethernet1/2',
'lldp receive',
'no lldp transmit',
'no lldp tlv-set vlan 12',
'lldp tlv-set management-address 192.0.2.123']
self.execute_module(changed=True, commands=commands)
def test_nxos_lldp_interfaces_replaced_idempotent(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/2",
receive=False,
tlv_set=dict(
vlan=12
)
),
dict(name="Ethernet1/1",
receive=True,
transmit=False)
], state="replaced"))
self.execute_module(changed=False, commands=[])
def test_nxos_lldp_interfaces_overridden(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/4",
receive=True,
transmit=False
)
], state="overridden"))
commands = ['interface Ethernet1/4',
'lldp receive',
'no lldp transmit',
'interface Ethernet1/1',
'lldp receive',
'lldp transmit',
'interface Ethernet1/2',
'lldp receive',
'no lldp tlv-set vlan 12']
self.execute_module(changed=True, commands=commands)
def test_nxos_lldp_interfaces_overridden_idempotent(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/2",
receive=False,
tlv_set=dict(
vlan=12
)
),
dict(name="Ethernet1/1",
receive=True,
transmit=False)
], state="overridden"))
self.execute_module(changed=False, commands=[])
def test_nxos_lldp_interfaces_deleted_intf(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/2")
], state="deleted"))
commands = ['interface Ethernet1/2',
'lldp receive',
'no lldp tlv-set vlan 12']
self.execute_module(changed=True, commands=commands)
def test_nxos_lldp_interfaces_deleted_all(self):
set_module_args(
dict(state="deleted"))
commands = ['interface Ethernet1/2',
'lldp receive',
'no lldp tlv-set vlan 12',
'interface Ethernet1/1',
'lldp receive',
'lldp transmit']
self.execute_module(changed=True, commands=commands)
def test_nxos_lldp_interfaces_rendered(self):
set_module_args(
dict(config=[
dict(name="Ethernet1/2",
receive=False,
tlv_set=dict(
vlan=12
)
),
dict(name="Ethernet1/1",
receive=True,
transmit=False)
], state="rendered"))
commands = ['interface Ethernet1/1',
'lldp receive',
'no lldp transmit',
'interface Ethernet1/2',
'no lldp receive',
'lldp tlv-set vlan 12']
result = self.execute_module(changed=False)
self.assertEqual(sorted(result['rendered']), sorted(
commands), result['rendered'])
def test_nxos_lldp_interfaces_parsed(self):
set_module_args(dict(running_config='''interface Ethernet1/1
lldp receive
no lldp transmit
interface Ethernet1/2
no lldp receive
lldp tlv-set vlan 12''', state="parsed"))
result = self.execute_module(changed=False)
compare_list = [{'name': 'Ethernet1/1', 'receive': True, 'transmit': False},
{'name': 'Ethernet1/2', 'receive': False, 'tlv_set': {
'vlan': 12
}}]
self.assertEqual(result['parsed'],
compare_list, result['parsed'])
def test_nxos_lldp_interfaces_gathered(self):
set_module_args(dict(state="gathered"))
result = self.execute_module(changed=False)
compare_list = [{'name': 'Ethernet1/1', 'receive': True, 'transmit': False},
{'name': 'Ethernet1/2', 'receive': False, 'tlv_set': {
'vlan': 12
}}]
self.assertEqual(result['gathered'],
compare_list, result['gathered'])
Loading…
Cancel
Save