Add iosxr_lacp_resource module (#59724)

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>
This commit is contained in:
Nilashish Chakraborty 2019-08-08 00:13:06 +05:30 committed by GitHub
parent 47796af64f
commit 7b90e8aec4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 1509 additions and 6 deletions

View file

@ -20,7 +20,10 @@ class FactsArgs(object): # pylint: disable=R0903
choices = [
'all',
'lacp'
'lacp',
'!lacp',
'lacp_interfaces',
'!lacp_interfaces'
]
argument_spec = {

View file

@ -0,0 +1,79 @@
#
# -*- 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 iosxr_lacp_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lacp_interfacesArgs(object): # pylint: disable=R0903
"""The arg spec for the iosxr_lacp_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
'config': {
'elements': 'dict',
'options': {
'churn_logging': {
'choices': ['actor', 'partner', 'both'],
'type': 'str'
},
'collector_max_delay': {
'type': 'int'
},
'name': {
'type': 'str'
},
'period': {
'type': 'int'
},
'switchover_suppress_flaps': {
'type': 'int'
},
'system': {
'options': {
'mac': {
'type': 'str'
},
'priority': {
'type': 'int'
}
},
'type': 'dict'
}
},
'type': 'list'
},
'state': {
'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'
}
} # pylint: disable=C0301

View file

@ -0,0 +1,261 @@
#
# -*- 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 iosxr_lacp_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
from ansible.module_utils.network.iosxr.facts.facts import Facts
from ansible.module_utils.network.common.utils import dict_diff, remove_empties
from ansible.module_utils.six import iteritems
from ansible.module_utils.network.iosxr. \
utils.utils import search_obj_in_list, dict_delete, pad_commands, flatten_dict
class Lacp_interfaces(ConfigBase):
"""
The iosxr_lacp_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lacp_interfaces',
]
def __init__(self, module):
super(Lacp_interfaces, self).__init__(module)
def get_lacp_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)
lacp_interfaces_facts = facts['ansible_network_resources'].get('lacp_interfaces')
if not lacp_interfaces_facts:
return []
return lacp_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_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
commands.extend(self.set_config(existing_lacp_interfaces_facts))
if commands:
if not self._module.check_mode:
self._connection.edit_config(commands)
result['changed'] = True
result['commands'] = commands
changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
result['before'] = existing_lacp_interfaces_facts
if result['changed']:
result['after'] = changed_lacp_interfaces_facts
result['warnings'] = warnings
return result
def set_config(self, existing_lacp_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_lacp_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.extend(
Lacp_interfaces._state_overridden(
want, have
)
)
elif state == 'deleted':
if not want:
for intf in have:
commands.extend(
Lacp_interfaces._state_deleted(
{'name': intf['name']},
intf
)
)
else:
for item in want:
obj_in_have = search_obj_in_list(item['name'], have)
commands.extend(
Lacp_interfaces._state_deleted(
item, obj_in_have
)
)
else:
for item in want:
name = item['name']
obj_in_have = search_obj_in_list(name, have)
if state == 'merged':
commands.extend(
Lacp_interfaces._state_merged(
item, obj_in_have
)
)
elif state == 'replaced':
commands.extend(
Lacp_interfaces._state_replaced(
item, obj_in_have
)
)
return commands
@staticmethod
def _state_replaced(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 = []
replaced_commands = []
merged_commands = []
if have:
replaced_commands = Lacp_interfaces._state_deleted(want, have)
merged_commands = Lacp_interfaces._state_merged(want, have)
if merged_commands and replaced_commands:
del merged_commands[0]
commands.extend(replaced_commands)
commands.extend(merged_commands)
return commands
@staticmethod
def _state_overridden(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 intf in have:
intf_in_want = search_obj_in_list(intf['name'], want)
if not intf_in_want:
commands.extend(Lacp_interfaces._state_deleted({'name': intf['name']}, intf))
for intf in want:
intf_in_have = search_obj_in_list(intf['name'], have)
commands.extend(Lacp_interfaces._state_replaced(intf, intf_in_have))
return commands
@staticmethod
def _state_merged(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 = []
if not have:
have = {'name': want['name']}
for key, value in iteritems(flatten_dict(remove_empties(dict_diff(have, want)))):
commands.append(Lacp_interfaces._compute_commands(key, value))
if commands:
pad_commands(commands, want['name'])
return commands
@staticmethod
def _state_deleted(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 = []
for key, value in iteritems(flatten_dict(dict_delete(have, remove_empties(want)))):
commands.append(Lacp_interfaces._compute_commands(key, value, remove=True))
if commands:
pad_commands(commands, have['name'])
return commands
@staticmethod
def _compute_commands(key, value, remove=False):
if key == "churn_logging":
cmd = "lacp churn logging {0}".format(value)
elif key == "collector_max_delay":
cmd = "lacp collector-max-delay {0}".format(value)
elif key == "period":
cmd = "lacp period {0}".format(value)
elif key == "switchover_suppress_flaps":
cmd = "lacp switchover suppress-flaps {0}".format(value)
elif key == 'mac':
cmd = "lacp system mac {0}".format(value)
elif key == 'priority':
cmd = "lacp system priority {0}".format(value)
if remove:
cmd = "no " + cmd
return cmd

View file

@ -16,6 +16,7 @@ __metaclass__ = type
from ansible.module_utils.network.iosxr.argspec.facts.facts import FactsArgs
from ansible.module_utils.network.common.facts.facts import FactsBase
from ansible.module_utils.network.iosxr.facts.lacp.lacp import LacpFacts
from ansible.module_utils.network.iosxr.facts.lacp_interfaces.lacp_interfaces import Lacp_interfacesFacts
from ansible.module_utils.network.iosxr.facts.legacy.\
base import Default, Hardware, Interfaces, Config
@ -28,6 +29,7 @@ FACT_LEGACY_SUBSETS = dict(
)
FACT_RESOURCE_SUBSETS = dict(
lacp=LacpFacts,
lacp_interfaces=Lacp_interfacesFacts
)

View file

@ -0,0 +1,104 @@
#
# -*- 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 iosxr lacp_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.iosxr.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs
from ansible.module_utils.six import iteritems
class Lacp_interfacesFacts(object):
""" The iosxr lacp_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Lacp_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 lacp_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
if not data:
data = connection.get_config(flags='interface')
interfaces = data.split('interface ')
objs = []
for interface in interfaces:
obj = self.render_config(self.generated_spec, interface)
if obj:
objs.append(obj)
ansible_facts['ansible_network_resources'].pop('lacp_interfaces', None)
facts = {}
if objs:
facts['lacp_interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['lacp_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'(GigabitEthernet|Bundle-Ether|TenGigE|FortyGigE|HundredGigE)(\S+)', conf, re.M)
if match:
config['name'] = match.group(1) + match.group(2)
temp = {
'churn_logging': 'lacp churn logging',
'switchover_suppress_flaps': 'lacp switchover suppress-flaps',
'collector_max_delay': 'lacp collector-max-delay',
'period': 'lacp period'
}
for key, value in iteritems(temp):
config[key] = utils.parse_conf_arg(
conf, value)
for key in config['system'].keys():
config['system'][key] = utils.parse_conf_arg(
conf, 'lacp system {0}'.format(key))
return utils.remove_empties(config)

View file

@ -30,3 +30,34 @@ def flatten_dict(x):
result[key] = value
return result
def dict_delete(base, comparable):
"""
This function generates a dict containing key, value pairs for keys
that are present in the `base` dict but not present in the `comparable`
dict.
:param base: dict object to base the diff on
:param comparable: dict object to compare against base
:returns: new dict object with key, value pairs that needs to be deleted.
"""
to_delete = dict()
for key in base:
if isinstance(base[key], dict):
sub_diff = dict_delete(base[key], comparable.get(key, {}))
if sub_diff:
to_delete[key] = sub_diff
else:
if key not in comparable:
to_delete[key] = base[key]
return to_delete
def pad_commands(commands, interface):
commands.insert(0, 'interface {0}'.format(interface))

View file

@ -51,7 +51,7 @@ options:
can also be used with an initial C(M(!)) to specify that a
specific subset should not be collected.
required: false
choices: ['all', 'lacp']
choices: ['all', 'lacp', '!lacp', 'lacp_interfaces', '!lacp_interfaces']
version_added: "2.9"
"""
@ -71,7 +71,7 @@ EXAMPLES = """
gather_subset:
- "!hardware"
# Collect only the lag_interfaces facts
# Collect only the lacp facts
- iosxr_facts:
gather_subset:
- "!all"
@ -79,12 +79,12 @@ EXAMPLES = """
gather_network_resources:
- lacp
# Do not collect lag_interfaces facts
# Do not collect lacp_interfaces facts
- iosxr_facts:
gather_network_resources:
- "!lacp"
- "!lacp_interfaces"
# Collect lag_interfaces and minimal default facts
# Collect lacp and minimal default facts
- iosxr_facts:
gather_subset: min
gather_network_resources: lacp

View file

@ -0,0 +1,533 @@
#!/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 iosxr_lacp_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: iosxr_lacp_interfaces
version_added: 2.9
short_description: Manage Link Aggregation Control Protocol (LACP) attributes of interfaces on IOS-XR devices.
description:
- This module manages Link Aggregation Control Protocol (LACP) attributes of interfaces on IOS-XR devices.
author: Nilashish Chakraborty (@nilashishc)
options:
config:
description: A dictionary of LACP interfaces options.
type: list
suboptions:
name:
description:
- Name/Identifier of the interface or Ether-Bundle.
type: str
churn_logging:
description:
- Specifies the parameter for logging of LACP churn events.
- Valid only for ether-bundles.
- Mode 'actor' logs actor churn events only.
- Mode 'partner' logs partner churn events only.
- Mode 'both' logs actor and partner churn events only.
type: str
choices: ['actor', 'partner', 'both']
collector_max_delay:
description:
- Specifies the collector max delay to be signaled to the LACP partner.
- Valid only for ether-bundles.
- Refer to vendor documentation for valid values.
type: int
period:
description:
- Specifies the rate at which packets are sent or received.
- For ether-bundles, this specifies the period to be used
by its member links.
- Refer to vendor documentation for valid values.
type: int
switchover_suppress_flaps:
description:
- Specifies the time for which to suppress flaps during
a LACP switchover.
- Valid only for ether-bundles.
- Refer to vendor documentation for valid values.
type: int
system:
description:
- This dict object contains configurable options related to LACP
system parameters for ether-bundles.
type: dict
suboptions:
priority:
description:
- Specifies the system priority to use in LACP negotiations for
the bundle.
- Refer to vendor documentation for valid values.
type: int
mac:
description:
- Specifies the system ID to use in LACP negotiations for
the bundle, encoded as a MAC address.
type: str
state:
description:
- The state the configuration should be left in.
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
#
#
# ------------
# Before state
# ------------
#
#
#
# RP/0/0/CPU0:an-iosxr#sh running-config interface
# Sun Jul 21 18:01:35.079 UTC
# interface Bundle-Ether10
# !
# interface Bundle-Ether11
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1'
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
#
- name: Merge provided configuration with device configuration
iosxr_lacp_interfaces:
config:
- name: Bundle-Ether10
churn_logging: actor
collector_max_delay: 100
switchover_suppress_flaps: 500
- name: Bundle-Ether11
system:
mac: 00c2.4c00.bd15
- name: GigabitEthernet0/0/0/1
period: 200
state: merged
#
#
# -----------
# After state
# -----------
#
#
# RP/0/0/CPU0:an-iosxr#sh run int
# Sun Jul 21 18:24:52.413 UTC
# interface Bundle-Ether10
# lacp churn logging actor
# lacp switchover suppress-flaps 500
# lacp collector-max-delay 100
# !
# interface Bundle-Ether11
# lacp system mac 00c2.4c00.bd15
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# lacp period 200
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
# Using replaced
#
#
# ------------
# Before state
# ------------
#
#
# RP/0/0/CPU0:an-iosxr#sh run int
# Sun Jul 21 18:24:52.413 UTC
# interface Bundle-Ether10
# lacp churn logging actor
# lacp switchover suppress-flaps 500
# lacp collector-max-delay 100
# !
# interface Bundle-Ether11
# lacp system mac 00c2.4c00.bd15
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# lacp period 200
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
- name: Replace LACP configuration of listed interfaces with provided configuration
iosxr_lacp_interfaces:
config:
- name: Bundle-Ether10
churn_logging: partner
- name: GigabitEthernet0/0/0/2
period: 300
state: replaced
#
#
# -----------
# After state
# -----------
#
#
# RP/0/0/CPU0:an-iosxr#sh run int
# Sun Jul 21 18:50:21.929 UTC
# interface Bundle-Ether10
# lacp churn logging partner
# !
# interface Bundle-Ether11
# lacp system mac 00c2.4c00.bd15
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# lacp period 200
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# lacp period 300
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
#
# Using overridden
#
#
# ------------
# Before state
# ------------
#
#
# RP/0/0/CPU0:an-iosxr#sh run int
# Sun Jul 21 18:24:52.413 UTC
# interface Bundle-Ether10
# lacp churn logging actor
# lacp switchover suppress-flaps 500
# lacp collector-max-delay 100
# !
# interface Bundle-Ether11
# lacp system mac 00c2.4c00.bd15
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# lacp period 200
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# lacp period 200
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
#
- name: Overridde all interface LACP configuration with provided configuration
iosxr_lacp_interfaces:
config:
- name: Bundle-Ether12
churn_logging: both
collector_max_delay: 100
switchover_suppress_flaps: 500
- name: GigabitEthernet0/0/0/1
period: 300
state: overridden
#
#
# -----------
# After state
# -----------
#
#
# RP/0/0/CPU0:an-iosxr(config-if)#do sh run int
# Sun Jul 21 19:32:36.115 UTC
# interface Bundle-Ether10
# !
# interface Bundle-Ether11
# !
# interface Bundle-Ether12
# lacp churn logging both
# lacp switchover suppress-flaps 500
# lacp collector-max-delay 100
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# lacp period 300
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
# Using deleted
#
#
# ------------
# Before state
# ------------
#
#
# RP/0/0/CPU0:an-iosxr#sh run int
# Sun Jul 21 18:24:52.413 UTC
# interface Bundle-Ether10
# lacp churn logging actor
# lacp switchover suppress-flaps 500
# lacp collector-max-delay 100
# !
# interface Bundle-Ether11
# lacp non-revertive
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# lacp period 200
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# lacp period 300
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
- name: Deleted LACP configurations of provided interfaces (Note - This won't delete the interface itself)
iosxr_lacp_interfaces:
config:
- name: Bundle-Ether10
- name: Bundle-Ether11
- name: GigabitEthernet0/0/0/1
- name: GigabitEthernet0/0/0/2
state: deleted
#
#
# -----------
# After state
# -----------
#
#
# RP/0/0/CPU0:an-iosxr#sh run int
# Sun Jul 21 19:51:03.499 UTC
# interface Bundle-Ether10
# !
# interface Bundle-Ether11
# !
# interface Bundle-Ether12
# !
# interface Loopback888
# description test for ansible
# shutdown
# !
# interface MgmtEth0/0/CPU0/0
# ipv4 address 192.0.2.11 255.255.255.0
# !
# interface GigabitEthernet0/0/0/1
# description 'GigabitEthernet - 1"
# !
# interface GigabitEthernet0/0/0/2
# description "GigabitEthernet - 2"
# !
# interface GigabitEthernet0/0/0/3
# description "GigabitEthernet - 3"
# !
# interface GigabitEthernet0/0/0/4
# description "GigabitEthernet - 4"
# !
#
"""
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 Bundle-Ether10', 'lacp churn logging partner', 'lacp period 150']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.iosxr.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs
from ansible.module_utils.network.iosxr.config.lacp_interfaces.lacp_interfaces import Lacp_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
module = AnsibleModule(argument_spec=Lacp_interfacesArgs.argument_spec,
supports_check_mode=True)
result = Lacp_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -231,6 +231,8 @@
- name: Delete interface aggregate
iosxr_interface:
aggregate:
- name: GigabitEthernet0/0/0/2
- name: GigabitEthernet0/0/0/3
- name: GigabitEthernet0/0/0/4
- name: GigabitEthernet0/0/0/5
state: absent
@ -246,6 +248,8 @@
- name: Delete interface aggregate (idempotent)
iosxr_interface:
aggregate:
- name: GigabitEthernet0/0/0/2
- name: GigabitEthernet0/0/0/3
- name: GigabitEthernet0/0/0/4
- name: GigabitEthernet0/0/0/5
state: absent

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,26 @@
---
- name: Setup Bundle-Ether10
iosxr_config:
lines:
- lacp churn logging actor
- lacp switchover suppress-flaps 500
- lacp collector-max-delay 100
parents: interface Bundle-Ether10
- name: Setup Bundle-Ether11
iosxr_config:
lines:
- lacp system mac 00c2.4c00.bd15
parents: interface Bundle-Ether11
- name: Setup GigE0
iosxr_config:
lines:
- lacp period 100
parents: interface GigabitEthernet0/0/0/0
- name: Setup GigE1
iosxr_config:
lines:
- lacp period 200
parents: interface GigabitEthernet0/0/0/1

View file

@ -0,0 +1,32 @@
---
- name: Remove Bundles
cli_config:
config: "{{ lines }}"
vars:
lines: |
no interface Bundle-Ether10
no interface Bundle-Ether11
no interface Bundle-Ether12
- name: Remove LACP interface config
iosxr_config:
lines:
- no lacp period
- shutdown
parents: "interface GigabitEthernet{{ item }}"
loop:
- 0/0/0/0
- 0/0/0/1
# To make sure our assertions are not affected by
# spill overs from previous tests
- name: Remove unwanted interfaces from config
iosxr_config:
lines:
- "no interface GigabitEthernet{{ item }}"
loop:
- 0/0/0/2
- 0/0/0/3
- 0/0/0/4
- 0/0/0/5
ignore_errors: yes

View file

@ -0,0 +1,46 @@
---
- debug:
msg: "Start iosxr_lacp_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- include_tasks: _populate.yaml
- block:
- name: Delete LACP attributes of all interfaces
iosxr_lacp_interfaces: &deleted
state: deleted
register: result
- name: Assert that the before dicts were correctly generated
assert:
that:
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
- name: Assert that the correct set of commands were generated
assert:
that:
- "{{ deleted['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
- name: Assert that the after dicts were correctly generated
assert:
that:
- "{{ deleted['after'] | symmetric_difference(result['after']) |length == 0 }}"
- name: Delete LACP attributes of all interfaces (IDEMPOTENT)
iosxr_lacp_interfaces: *deleted
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result.changed == false"
- "result.commands|length == 0"
- name: Assert that the before dicts were correctly generated
assert:
that:
- "{{ deleted['after'] | symmetric_difference(result['before']) |length == 0 }}"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,54 @@
---
- debug:
msg: "START iosxr_lacp_interfaces merged integration tests on connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- block:
- name: Merge the provided configuration with the exisiting running configuration
iosxr_lacp_interfaces: &merged
config:
- name: Bundle-Ether10
churn_logging: actor
collector_max_delay: 100
switchover_suppress_flaps: 500
- name: Bundle-Ether11
system:
mac: 00c2.4c00.bd15
- name: GigabitEthernet0/0/0/1
period: 100
state: merged
register: result
- name: Assert that before dicts were correctly generated
assert:
that: "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}"
- name: Assert that correct set of commands were generated
assert:
that:
- "{{ merged['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
- name: Assert that after dicts was correctly generated
assert:
that:
- "{{ merged['after'] | symmetric_difference(result['after']) |length == 0 }}"
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
iosxr_lacp_interfaces: *merged
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result['changed'] == false"
- "result.commands|length == 0"
- name: Assert that before dicts were correctly generated
assert:
that:
- "{{ merged['after'] | symmetric_difference(result['before']) |length == 0 }}"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,54 @@
---
- debug:
msg: "START iosxr_lacp_interfaces overridden integration tests on connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- include_tasks: _populate.yaml
- block:
- name: Overridde all interface LACP configuration with provided configuration
iosxr_lacp_interfaces: &overridden
config:
- name: Bundle-Ether12
churn_logging: both
collector_max_delay: 100
switchover_suppress_flaps: 500
- name: GigabitEthernet0/0/0/1
period: 300
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:
- "{{ populate | 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: Overridde all interface LACP configuration with provided configuration (IDEMPOTENT)
iosxr_lacp_interfaces: *overridden
register: result
- name: Assert that task was idempotent
assert:
that:
- "result['changed'] == false"
- "result.commands|length == 0"
- name: Assert that before dict is correctly generated
assert:
that:
- "{{ overridden['after'] | symmetric_difference(result['before']) |length == 0 }}"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,52 @@
---
- debug:
msg: "START iosxr_lacp_interfaces replaced integration tests on connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- include_tasks: _populate.yaml
- block:
- name: Replace device configurations of listed interfaces with provided configurations
iosxr_lacp_interfaces: &replaced
config:
- name: Bundle-Ether10
churn_logging: partner
- name: GigabitEthernet0/0/0/1
period: 300
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:
- "{{ populate | 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: Replace device configurations of listed interfaces with provided configurarions (IDEMPOTENT)
iosxr_lacp_interfaces: *replaced
register: result
- name: Assert that task was idempotent
assert:
that:
- "result['changed'] == false"
- "result.commands|length == 0"
- name: Assert that before dict is correctly generated
assert:
that:
- "{{ replaced['after'] | symmetric_difference(result['before']) |length == 0 }}"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,60 @@
---
- debug:
msg: "START isoxr_lacp_interfaces round trip integration tests on connection={{ ansible_connection }}"
- block:
- include_tasks: _remove_config.yaml
- name: Apply the provided configuration (base config)
iosxr_lacp_interfaces:
config:
- name: Bundle-Ether10
churn_logging: actor
collector_max_delay: 200
- name: Bundle-Ether11
period: 100
- name: GigabitEthernet0/0/0/0
period: 200
state: merged
register: base_config
- name: Gather interfaces facts
iosxr_facts:
gather_subset:
- "!all"
- "!min"
gather_network_resources:
- lacp_interfaces
- name: Apply the provided configuration (config to be reverted)
iosxr_lacp_interfaces:
config:
- name: Bundle-Ether10
churn_logging: partner
- name: Bundle-Ether11
period: 200
- name: GigabitEthernet0/0/0/0
period: 300
state: overridden
register: result
- name: Assert that changes were applied
assert:
that: "{{ round_trip['after'] | symmetric_difference(result['after']) |length == 0 }}"
- name: Revert back to base config using facts round trip
iosxr_lacp_interfaces:
config: "{{ ansible_facts['network_resources']['lacp_interfaces'] }}"
state: overridden
register: revert
- name: Assert that config was reverted
assert:
that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length == 0 }}"
always:
- include_tasks: _remove_config.yaml

View file

@ -0,0 +1,137 @@
---
merged:
before:
- name: GigabitEthernet0/0/0/0
- name: GigabitEthernet0/0/0/1
commands:
- "interface Bundle-Ether10"
- "lacp churn logging actor"
- "lacp switchover suppress-flaps 500"
- "lacp collector-max-delay 100"
- "interface Bundle-Ether11"
- "lacp system mac 00c2.4c00.bd15"
- "interface GigabitEthernet0/0/0/1"
- "lacp period 100"
after:
- name: Bundle-Ether10
churn_logging: actor
switchover_suppress_flaps: 500
collector_max_delay: 100
- name: Bundle-Ether11
system:
mac: 00c2.4c00.bd15
- name: GigabitEthernet0/0/0/0
- name: GigabitEthernet0/0/0/1
period: 100
populate:
- name: Bundle-Ether10
churn_logging: actor
switchover_suppress_flaps: 500
collector_max_delay: 100
- name: Bundle-Ether11
system:
mac: 00c2.4c00.bd15
- name: GigabitEthernet0/0/0/0
period: 100
- name: GigabitEthernet0/0/0/1
period: 200
replaced:
commands:
- "interface Bundle-Ether10"
- "no lacp switchover suppress-flaps 500"
- "no lacp collector-max-delay 100"
- "lacp churn logging partner"
- "interface GigabitEthernet0/0/0/1"
- "lacp period 300"
after:
- name: Bundle-Ether10
churn_logging: partner
- name: Bundle-Ether11
system:
mac: 00c2.4c00.bd15
- name: GigabitEthernet0/0/0/0
period: 100
- name: GigabitEthernet0/0/0/1
period: 300
overridden:
commands:
- "interface Bundle-Ether10"
- "no lacp switchover suppress-flaps 500"
- "no lacp collector-max-delay 100"
- "no lacp churn logging actor"
- "interface Bundle-Ether11"
- "no lacp system mac 00c2.4c00.bd15"
- "interface GigabitEthernet0/0/0/0"
- "no lacp period 100"
- "interface Bundle-Ether12"
- "lacp churn logging both"
- "lacp collector-max-delay 100"
- "lacp switchover suppress-flaps 500"
- "interface GigabitEthernet0/0/0/1"
- "lacp period 300"
after:
- name: Bundle-Ether10
- name: Bundle-Ether11
- name: Bundle-Ether12
churn_logging: both
collector_max_delay: 100
switchover_suppress_flaps: 500
- name: GigabitEthernet0/0/0/0
- name: GigabitEthernet0/0/0/1
period: 300
deleted:
commands:
- "interface Bundle-Ether10"
- "no lacp switchover suppress-flaps 500"
- "no lacp collector-max-delay 100"
- "no lacp churn logging actor"
- "interface Bundle-Ether11"
- "no lacp system mac 00c2.4c00.bd15"
- "interface GigabitEthernet0/0/0/0"
- "no lacp period 100"
- "interface GigabitEthernet0/0/0/1"
- "no lacp period 200"
after:
- name: Bundle-Ether10
- name: Bundle-Ether11
- name: GigabitEthernet0/0/0/0
- name: GigabitEthernet0/0/0/1
round_trip:
after:
- name: Bundle-Ether10
churn_logging: partner
- name: Bundle-Ether11
period: 200
- name: GigabitEthernet0/0/0/0
period: 300
- name: GigabitEthernet0/0/0/1