Resource module for ios_lldp_interfaces (#61012)

* ios_lldp_interfaces resource

* fix shippable n reviews

* fix shippable

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>

* add enable lldp tc
This commit is contained in:
Sumit Jaiswal 2019-08-22 10:02:25 +05:30 committed by GitHub
parent 62feb18210
commit a5a1f01d1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1303 additions and 2 deletions

View file

@ -35,6 +35,8 @@ class FactsArgs(object):
'!lacp_interfaces', '!lacp_interfaces',
'lldp_global', 'lldp_global',
'!lldp_global', '!lldp_global',
'lldp_interfaces',
'!lldp_interfaces',
] ]
argument_spec = { argument_spec = {

View file

@ -0,0 +1,52 @@
#
# -*- 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 ios_lldp_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lldp_InterfacesArgs(object):
"""The arg spec for the ios_lldp_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'name': {'required': True, 'type': 'str'},
'transmit': {'type': 'bool'},
'receive': {'type': 'bool'},
'med_tlv_select': {'options': {'inventory_management': {'type': 'bool'}},
'type': 'dict'},
'tlv_select': {'options': {'power_management': {'type': 'bool'}},
'type': 'dict'}
},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

View file

@ -0,0 +1,267 @@
#
# -*- 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 ios_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 its 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
from ansible.module_utils.network.ios.facts.facts import Facts
from ansible.module_utils.network.ios.utils.utils import dict_to_set
from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list
from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
class Lldp_Interfaces(ConfigBase):
"""
The ios_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):
""" 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)
lldp_interfaces_facts = facts['ansible_network_resources'].get('lldp_interfaces')
if not lldp_interfaces_facts:
return []
return lldp_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_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
commands.extend(self.set_config(existing_lldp_interfaces_facts))
if commands:
if not self._module.check_mode:
self._connection.edit_config(commands)
result['changed'] = True
result['commands'] = commands
changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
result['before'] = existing_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
"""
want = self._module.params['config']
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
"""
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 == 'merged':
commands = self._state_merged(want, have)
elif state == 'replaced':
commands = self._state_replaced(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 = []
for interface in want:
for each in have:
if each['name'] == interface['name']:
break
else:
continue
have_dict = filter_dict_having_none_value(interface, each)
commands.extend(self._clear_config(dict(), have_dict))
commands.extend(self._set_config(interface, each))
# Remove the duplicate interface call
commands = remove_duplicate_interface(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 each in have:
for interface in want:
if each['name'] == interface['name']:
break
else:
# We didn't find a matching desired state, which means we can
# pretend we recieved an empty desired state.
interface = dict(name=each['name'])
commands.extend(self._clear_config(interface, each))
continue
have_dict = filter_dict_having_none_value(interface, each)
commands.extend(self._clear_config(dict(), have_dict))
commands.extend(self._set_config(interface, each))
# Remove the duplicate interface call
commands = remove_duplicate_interface(commands)
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
"""
commands = []
for interface in want:
for each in have:
if interface['name'] == each['name']:
break
else:
continue
commands.extend(self._set_config(interface, each))
return commands
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 interface in want:
for each in have:
if each['name'] == interface['name']:
break
else:
continue
interface = dict(name=interface['name'])
commands.extend(self._clear_config(interface, each))
else:
for each in have:
commands.extend(self._clear_config(dict(), each))
return commands
def _set_config(self, want, have):
# Set the interface config based on the want and have config
commands = []
interface = 'interface ' + have['name']
# Get the diff b/w want and have
want_dict = dict_to_set(want)
have_dict = dict_to_set(have)
diff = want_dict - have_dict
if diff:
diff = dict(diff)
receive = diff.get('receive')
transmit = diff.get('transmit')
med_tlv_select = diff.get('med_tlv_select')
tlv_select = diff.get('tlv_select')
if receive:
cmd = 'lldp receive'
add_command_to_config_list(interface, cmd, commands)
elif receive is False:
cmd = 'no lldp receive'
add_command_to_config_list(interface, cmd, commands)
if transmit:
cmd = 'lldp transmit'
add_command_to_config_list(interface, cmd, commands)
elif transmit is False:
cmd = 'no lldp transmit'
add_command_to_config_list(interface, cmd, commands)
if med_tlv_select:
med_tlv_select = dict(med_tlv_select)
if med_tlv_select.get('inventory_management'):
add_command_to_config_list(interface, 'lldp med-tlv-select inventory-management', commands)
if tlv_select:
tlv_select = dict(tlv_select)
if tlv_select.get('power_management'):
add_command_to_config_list(interface, 'lldp tlv-select power-management', commands)
return commands
def _clear_config(self, want, have):
# Delete the interface config based on the want and have config
commands = []
if want.get('name'):
interface = 'interface ' + want['name']
else:
interface = 'interface ' + have['name']
if have.get('receive') and have.get('receive') != want.get('receive'):
cmd = 'lldp receive'
remove_command_from_config_list(interface, cmd, commands)
if have.get('transmit') and have.get('transmit') != want.get('transmit'):
cmd = 'lldp transmit'
remove_command_from_config_list(interface, cmd, commands)
return commands

View file

@ -22,6 +22,7 @@ from ansible.module_utils.network.ios.facts.lag_interfaces.lag_interfaces import
from ansible.module_utils.network.ios.facts.lacp.lacp import LacpFacts from ansible.module_utils.network.ios.facts.lacp.lacp import LacpFacts
from ansible.module_utils.network.ios.facts.lacp_interfaces.lacp_interfaces import Lacp_InterfacesFacts from ansible.module_utils.network.ios.facts.lacp_interfaces.lacp_interfaces import Lacp_InterfacesFacts
from ansible.module_utils.network.ios.facts.lldp_global.lldp_global import Lldp_globalFacts from ansible.module_utils.network.ios.facts.lldp_global.lldp_global import Lldp_globalFacts
from ansible.module_utils.network.ios.facts.lldp_interfaces.lldp_interfaces import Lldp_InterfacesFacts
from ansible.module_utils.network.ios.facts.legacy.base import Default, Hardware, Interfaces, Config from ansible.module_utils.network.ios.facts.legacy.base import Default, Hardware, Interfaces, Config
@ -39,7 +40,8 @@ FACT_RESOURCE_SUBSETS = dict(
lag_interfaces=Lag_interfacesFacts, lag_interfaces=Lag_interfacesFacts,
lacp=LacpFacts, lacp=LacpFacts,
lacp_interfaces=Lacp_InterfacesFacts, lacp_interfaces=Lacp_InterfacesFacts,
lldp_global=Lldp_globalFacts lldp_global=Lldp_globalFacts,
lldp_interfaces=Lldp_InterfacesFacts,
) )

View file

@ -0,0 +1,106 @@
#
# -*- 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 ios_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.ios.utils.utils import get_interface_type, normalize_interface
from ansible.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import Lldp_InterfacesArgs
class Lldp_InterfacesFacts(object):
""" The ios_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 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 connection:
pass
objs = []
if not data:
data = connection.get('show lldp interface')
# operate on a collection of resource x
config = data.split('\n\n')
for conf in config:
if conf:
obj = self.render_config(self.generated_spec, conf)
if obj:
objs.append(obj)
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)
intf = match.group(1)
if get_interface_type(intf) == 'unknown':
return {}
if intf.lower().startswith('gi'):
config['name'] = normalize_interface(intf)
receive = utils.parse_conf_arg(conf, 'Rx:')
transmit = utils.parse_conf_arg(conf, 'Tx:')
if receive == 'enabled':
config['receive'] = True
elif receive == 'disabled':
config['receive'] = False
if transmit == 'enabled':
config['transmit'] = True
elif transmit == 'disabled':
config['transmit'] = False
return utils.remove_empties(config)

View file

@ -56,7 +56,7 @@ options:
Can specify a list of values to include a larger subset. Can specify a list of values to include a larger subset.
choices: ['all', '!all', 'interfaces', '!interfaces', 'l2_interfaces', '!l2_interfaces', 'vlans', '!vlans', choices: ['all', '!all', 'interfaces', '!interfaces', 'l2_interfaces', '!l2_interfaces', 'vlans', '!vlans',
'lag_interfaces', '!lag_interfaces', 'lacp', '!lacp', 'lacp_interfaces', '!lacp_interfaces', 'lldp_global', 'lag_interfaces', '!lag_interfaces', 'lacp', '!lacp', 'lacp_interfaces', '!lacp_interfaces', 'lldp_global',
'!lldp_global'] '!lldp_global', 'lldp_interfaces', '!lldp_interfaces']
version_added: "2.9" version_added: "2.9"
""" """

View file

@ -0,0 +1,496 @@
#!/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 ios_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: ios_lldp_interfaces
version_added: 2.9
short_description: Manage link layer discovery protocol (LLDP) attributes of interfaces on Cisco IOS devices.
description: This module manages link layer discovery protocol (LLDP) attributes of interfaces on Cisco IOS devices.
author: Sumit Jaiswal (@justjais)
notes:
- Tested against Cisco IOSv Version 15.2 on VIRL
- This module works with connection C(network_cli),
See L(IOS Platform Options,../network/user_guide/platform_ios.html).
options:
config:
description: A dictionary of LLDP options
type: list
elements: dict
suboptions:
name:
description:
- Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
type: str
required: True
receive:
description:
- Enable LLDP reception on interface.
type: bool
transmit:
description:
- Enable LLDP transmission on interface.
type: bool
med_tlv_select:
description:
- Selection of LLDP MED TLVs to send
- NOTE, if med-tlv-select is configured idempotency won't be maintained
as Cisco device doesn't record configured med-tlv-select options. As
such, Ansible cannot verify if the respective med-tlv-select options is
already configured or not from the device side. If you try to apply
med-tlv-select option in every play run, Ansible will show changed as
True.
type: dict
suboptions:
inventory_management:
description:
- LLDP MED Inventory Management TLV
type: bool
tlv_select:
description:
- Selection of LLDP type-length-value i.e. TLVs to send
- NOTE, if tlv-select is configured idempotency won't be maintained
as Cisco device doesn't record configured tlv-select options. As
such, Ansible cannot verify if the respective tlv-select options is
already configured or not from the device side. If you try to apply
tlv-select option in every play run, Ansible will show changed as True.
type: dict
suboptions:
power_management:
description:
- IEEE 802.3 DTE Power via MDI TLV
type: bool
state:
description:
- The state the configuration should be left in
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
#
# Before state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
- name: Merge provided configuration with device configuration
ios_lldp_interfaces:
config:
- name: GigabitEthernet0/1
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
- name: GigabitEthernet0/3
transmit: True
state: merged
# After state:
# ------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: enabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# Using overridden
#
# Before state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
- name: Override device configuration of all lldp_interfaces with provided configuration
ios_lldp_interfaces:
config:
- name: GigabitEthernet0/2
receive: True
transmit: True
state: overridden
# After state:
# ------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
# Using replaced
#
# Before state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
- name: Replaces device configuration of listed lldp_interfaces with provided configuration
ios_lldp_interfaces:
config:
- name: GigabitEthernet0/2
receive: True
transmit: True
- name: GigabitEthernet0/3
receive: True
state: replaced
# After state:
# ------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: disabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# Using Deleted
#
# Before state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
- name: "Delete LLDP attributes of given interfaces (Note: This won't delete the interface itself)"
ios_lldp_interfaces:
config:
- name: GigabitEthernet0/1
state: deleted
# After state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# Using Deleted without any config passed
# "(NOTE: This will delete all of configured LLDP module attributes)"
#
# Before state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: enabled
# Rx: enabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
- name: "Delete LLDP attributes for all configured interfaces (Note: This won't delete the interface itself)"
ios_lldp_interfaces:
state: deleted
# After state:
# -------------
#
# vios#sh lldp interface
# GigabitEthernet0/0:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/1:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
# GigabitEthernet0/2:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: INIT
#
# GigabitEthernet0/3:
# Tx: disabled
# Rx: disabled
# Tx state: IDLE
# Rx state: WAIT FOR FRAME
#
"""
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 GigabitEthernet 0/1', 'lldp transmit', 'lldp receive']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import Lldp_InterfacesArgs
from ansible.module_utils.network.ios.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()

View file

@ -0,0 +1,3 @@
---
testcase: "[^_].*"
test_items: []

View file

@ -0,0 +1,20 @@
---
- name: Collect all cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
use_regex: true
register: test_cases
delegate_to: localhost
- name: Set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
delegate_to: localhost
- name: Run test case (connection=network_cli)
include: "{{ test_case_to_run }}"
vars:
ansible_connection: network_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,7 @@
---
- name: Enable LLDP Config
cli_config:
config: "{{ lines }}"
vars:
lines: |
lldp run

View file

@ -0,0 +1,15 @@
---
- name: Populate Config
cli_config:
config: "{{ lines }}"
vars:
lines: |
interface GigabitEthernet 0/0
lldp receive
lldp transmit
interface GigabitEthernet 0/1
lldp receive
lldp transmit
interface GigabitEthernet 0/2
lldp receive
lldp transmit

View file

@ -0,0 +1,15 @@
---
- name: Remove Config
cli_config:
config: "{{ lines }}"
vars:
lines: |
interface GigabitEthernet 0/0
no lldp receive
no lldp transmit
interface GigabitEthernet 0/1
no lldp receive
no lldp transmit
interface GigabitEthernet 0/2
no lldp receive
no lldp transmit

View file

@ -0,0 +1,42 @@
---
- debug:
msg: "Start Deleted integration state for ios_lldp_interfaces ansible_connection={{ ansible_connection }}"
- include_tasks: _enable_lldp.yaml
- include_tasks: _remove_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Delete LLDP attributes for respective configured interfaces
ios_lldp_interfaces: &deleted
state: deleted
register: result
- name: Assert that correct set of commands were generated
assert:
that:
- "{{ deleted['commands'] | symmetric_difference(result['commands']) | length == 0 }}"
- name: Assert that before dicts are correctly generated
assert:
that:
- "{{ deleted['before'] | symmetric_difference(result['before']) | length == 0 }}"
- name: Assert that after dict is correctly generated
assert:
that:
- "{{ deleted['after'] | symmetric_difference(result['after']) | length == 0 }}"
- name: Delete LLDP attributes for respective configured interfaces (IDEMPOTENT)
ios_lldp_interfaces: *deleted
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result.changed == false"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,50 @@
---
- debug:
msg: "START Merged ios_lldp_interfaces state for integration tests on connection={{ ansible_connection }}"
- include_tasks: _enable_lldp.yaml
- include_tasks: _remove_config.yaml
- block:
- name: Merge the provided configuration with the exisiting running configuration
ios_lldp_interfaces: &merged
config:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: False
state: merged
register: result
- name: Assert that correct set of commands were generated
assert:
that:
- "{{ merged['commands'] | symmetric_difference(result['commands']) | length == 0 }}"
- name: Assert that before dicts are correctly generated
assert:
that:
- "{{ merged['before'] | symmetric_difference(result['before']) | length == 0 }}"
- name: Assert that after dict is correctly generated
assert:
that:
- "{{ merged['after'] | symmetric_difference(result['after']) | length == 0 }}"
- name: Merge the provided configuration with the exisiting running configuration (IDEMPOTENT)
ios_lldp_interfaces: *merged
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result['changed'] == false"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,48 @@
---
- debug:
msg: "START Overridden ios_lldp_interfaces state for integration tests on connection={{ ansible_connection }}"
- include_tasks: _enable_lldp.yaml
- include_tasks: _remove_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Override device configuration of all lldp_interfaces with provided configuration
ios_lldp_interfaces: &overridden
config:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
state: overridden
register: result
- name: Assert that correct set of commands were generated
assert:
that:
- "{{ overridden['commands'] | symmetric_difference(result['commands']) | length == 0 }}"
- name: Assert that before dicts are correctly generated
assert:
that:
- "{{ overridden['before'] | symmetric_difference(result['before']) | length == 0 }}"
- name: Assert that after dict is correctly generated
assert:
that:
- "{{ overridden['after'] | symmetric_difference(result['after']) | length == 0 }}"
- name: Override device configuration of all lldp_interfaces with provided configuration (IDEMPOTENT)
ios_lldp_interfaces: *overridden
register: result
- name: Assert that task was idempotent
assert:
that:
- "result['changed'] == false"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,48 @@
---
- debug:
msg: "START Replaced ios_lldp_interfaces state for integration tests on connection={{ ansible_connection }}"
- include_tasks: _enable_lldp.yaml
- include_tasks: _remove_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Replaces device configuration of listed lldp_interfaces with provided configuration
ios_lldp_interfaces: &replaced
config:
- name: GigabitEthernet0/1
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: False
state: replaced
register: result
- name: Assert that correct set of commands were generated
assert:
that:
- "{{ replaced['commands'] | symmetric_difference(result['commands']) | length == 0 }}"
- name: Assert that before dicts are correctly generated
assert:
that:
- "{{ replaced['before'] | symmetric_difference(result['before']) | length == 0 }}"
- name: Assert that after dict is correctly generated
assert:
that:
- "{{ replaced['after'] | symmetric_difference(result['after']) | length == 0 }}"
- name: Replaces device configuration of listed lldp_interfaces with provided configuration (IDEMPOTENT)
ios_lldp_interfaces: *replaced
register: result
- name: Assert that task was idempotent
assert:
that:
- "result['changed'] == false"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,126 @@
---
merged:
before:
- name: GigabitEthernet0/0
receive: False
transmit: False
- name: GigabitEthernet0/1
receive: False
transmit: False
- name: GigabitEthernet0/2
receive: False
transmit: False
commands:
- "interface GigabitEthernet0/0"
- "lldp receive"
- "lldp transmit"
- "interface GigabitEthernet0/1"
- "lldp receive"
- "lldp transmit"
- "interface GigabitEthernet0/2"
- "lldp receive"
after:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: False
replaced:
before:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: True
commands:
- "interface GigabitEthernet0/1"
- "no lldp receive"
- "interface GigabitEthernet0/2"
- "no lldp transmit"
after:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: False
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: False
overridden:
before:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: True
commands:
- "interface GigabitEthernet0/1"
- "no lldp receive"
- "no lldp transmit"
- "interface GigabitEthernet0/2"
- "no lldp transmit"
after:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: False
transmit: False
- name: GigabitEthernet0/2
receive: True
transmit: False
deleted:
before:
- name: GigabitEthernet0/0
receive: True
transmit: True
- name: GigabitEthernet0/1
receive: True
transmit: True
- name: GigabitEthernet0/2
receive: True
transmit: True
commands:
- "interface GigabitEthernet0/0"
- "no lldp receive"
- "no lldp transmit"
- "interface GigabitEthernet0/1"
- "no lldp receive"
- "no lldp transmit"
- "interface GigabitEthernet0/2"
- "no lldp receive"
- "no lldp transmit"
after:
- name: GigabitEthernet0/0
receive: False
transmit: False
- name: GigabitEthernet0/1
receive: False
transmit: False
- name: GigabitEthernet0/2
receive: False
transmit: False