Resource module for ios_lacp_interfaces (#59516)

* ios lacp interfaces

Signed-off-by: Sumit Jaiswal <sjaiswal@redhat.com>
pull/60929/head
Sumit Jaiswal 5 years ago committed by GitHub
parent 642e54f958
commit 8a8798c373
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,6 +31,8 @@ class FactsArgs(object):
'!lag_interfaces',
'lacp',
'!lacp',
'lacp_interfaces',
'!lacp_interfaces',
]
argument_spec = {

@ -0,0 +1,48 @@
#
# -*- 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_lacp_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lacp_InterfacesArgs(object):
"""The arg spec for the ios_lacp_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'name': {'required': True, 'type': 'str'},
'port_priority': {'type': 'int'},
'fast_switchover': {'type': 'bool'},
'max_bundle': {'type': 'int'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -0,0 +1,255 @@
#
# -*- 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_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.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 Lacp_Interfaces(ConfigBase):
"""
The ios_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
"""
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']
want_dict = dict_to_set(want)
have_dict = dict_to_set(have)
diff = want_dict - have_dict
if diff:
port_priotity = dict(diff).get('port_priority')
max_bundle = dict(diff).get('max_bundle')
fast_switchover = dict(diff).get('fast_switchover')
if port_priotity:
cmd = 'lacp port-priority {0}'.format(port_priotity)
add_command_to_config_list(interface, cmd, commands)
if max_bundle:
cmd = 'lacp max-bundle {0}'.format(max_bundle)
add_command_to_config_list(interface, cmd, commands)
if fast_switchover:
cmd = 'lacp fast-switchover'
add_command_to_config_list(interface, cmd, 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('port_priority') and have.get('port_priority') != want.get('port_priority'):
cmd = 'lacp port-priority'
remove_command_from_config_list(interface, cmd, commands)
if have.get('max_bundle') and have.get('max_bundle') != want.get('max_bundle'):
cmd = 'lacp max-bundle'
remove_command_from_config_list(interface, cmd, commands)
if have.get('fast_switchover'):
cmd = 'lacp fast-switchover'
remove_command_from_config_list(interface, cmd, commands)
return commands

@ -20,6 +20,7 @@ from ansible.module_utils.network.ios.facts.l2_interfaces.l2_interfaces import L
from ansible.module_utils.network.ios.facts.vlans.vlans import VlansFacts
from ansible.module_utils.network.ios.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
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.legacy.base import Default, Hardware, Interfaces, Config
@ -36,6 +37,7 @@ FACT_RESOURCE_SUBSETS = dict(
vlans=VlansFacts,
lag_interfaces=Lag_interfacesFacts,
lacp=LacpFacts,
lacp_interfaces=Lacp_InterfacesFacts,
)

@ -0,0 +1,102 @@
#
# -*- 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_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.ios.utils.utils import get_interface_type, normalize_interface
from ansible.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import Lacp_InterfacesArgs
class Lacp_InterfacesFacts(object):
""" The ios_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 connection:
pass
objs = []
if not data:
data = connection.get('show running-config | section ^interface')
# operate on a collection of resource x
config = data.split('interface ')
for conf in config:
if conf:
obj = self.render_config(self.generated_spec, conf)
if obj:
objs.append(obj)
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'^(\S+)', conf)
intf = match.group(1)
if get_interface_type(intf) == 'unknown':
return {}
config['name'] = normalize_interface(intf)
port_priority = utils.parse_conf_arg(conf, 'lacp port-priority')
max_bundle = utils.parse_conf_arg(conf, 'lacp max-bundle')
if port_priority:
config['port_priority'] = int(port_priority)
if 'lacp fast-switchover' in conf:
config['fast_switchover'] = True
if max_bundle:
config['max_bundle'] = int(max_bundle)
return utils.remove_empties(config)

@ -10,6 +10,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.six import iteritems
from ansible.module_utils.network.common.utils import is_masklen, to_netmask
def remove_command_from_config_list(interface, cmd, commands):
@ -60,6 +61,8 @@ def filter_dict_having_none_value(want, have):
test_dict = dict()
test_key_dict = dict()
test_dict['name'] = want.get('name')
diff_ip = False
want_ip = ''
for k, v in iteritems(want):
if isinstance(v, dict):
for key, value in iteritems(v):
@ -67,6 +70,25 @@ def filter_dict_having_none_value(want, have):
dict_val = have.get(k).get(key)
test_key_dict.update({key: dict_val})
test_dict.update({k: test_key_dict})
if isinstance(v, list):
for key, value in iteritems(v[0]):
if value is None:
dict_val = have.get(k).get(key)
test_key_dict.update({key: dict_val})
# below conditions checks are added to check if
# secondary IP is configured, if yes then delete
# the already configured IP if want and have IP
# is different else if it's same no need to delete
if isinstance(value, str):
want_ip = value.split('/')
have_ip = have.get('ipv4')
if len(want_ip) > 1 and have_ip:
have_ip = have_ip[0]['address'].split(' ')[0]
if have_ip != want_ip[0]:
diff_ip = True
if key == 'secondary' and value is True and diff_ip is True:
test_key_dict.update({key: value})
test_dict.update({k: test_key_dict})
if v is None:
val = have.get(k)
test_dict.update({k: val})
@ -86,6 +108,37 @@ def remove_duplicate_interface(commands):
return set_cmd
def validate_ipv4(value, module):
if value:
address = value.split('/')
if len(address) != 2:
module.fail_json(msg='address format is <ipv4 address>/<mask>, got invalid format {0}'.format(value))
if not is_masklen(address[1]):
module.fail_json(msg='invalid value for mask: {0}, mask should be in range 0-32'.format(address[1]))
def validate_ipv6(value, module):
if value:
address = value.split('/')
if len(address) != 2:
module.fail_json(msg='address format is <ipv6 address>/<mask>, got invalid format {0}'.format(value))
else:
if not 0 <= int(address[1]) <= 128:
module.fail_json(msg='invalid value for mask: {0}, mask should be in range 0-128'.format(address[1]))
def validate_n_expand_ipv4(module, want):
# Check if input IPV4 is valid IP and expand IPV4 with its subnet mask
ip_addr_want = want.get('address')
validate_ipv4(ip_addr_want, module)
ip = ip_addr_want.split('/')
if len(ip) == 2:
ip_addr_want = '{0} {1}'.format(ip[0], to_netmask(ip[1]))
return ip_addr_want
def normalize_interface(name):
"""Return the normalized interface name
"""
@ -116,7 +169,7 @@ def normalize_interface(name):
elif name.lower().startswith('lo'):
if_type = 'loopback'
elif name.lower().startswith('po'):
if_type = 'port-channel'
if_type = 'Port-channel'
elif name.lower().startswith('nv'):
if_type = 'nve'
elif name.lower().startswith('twe'):
@ -161,7 +214,7 @@ def get_interface_type(interface):
elif interface.upper().startswith('LO'):
return 'loopback'
elif interface.upper().startswith('PO'):
return 'port-channel'
return 'Port-channel'
elif interface.upper().startswith('NV'):
return 'nve'
elif interface.upper().startswith('TWE'):

@ -55,7 +55,7 @@ options:
all and the resources like interfaces, vlans etc.
Can specify a list of values to include a larger subset.
choices: ['all', '!all', 'interfaces', '!interfaces', 'l2_interfaces', '!l2_interfaces', 'vlans', '!vlans',
'lag_interfaces', '!lag_interfaces', 'lacp', '!lacp']
'lag_interfaces', '!lag_interfaces', 'lacp', '!lacp', 'lacp_interfaces', '!lacp_interfaces']
version_added: "2.9"
"""

@ -0,0 +1,358 @@
#!/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_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: ios_lacp_interfaces
version_added: 2.9
short_description: Manage Link Aggregation Control Protocol (LACP) on Cisco IOS devices interface.
description: This module provides declarative management of LACP on Cisco IOS network devices lacp_interfaces.
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 LACP lacp_interfaces option
type: list
elements: dict
suboptions:
name:
description:
- Name of the Interface for configuring LACP.
type: str
required: True
port_priority:
description:
- LACP priority on this interface.
- Refer to vendor documentation for valid port values.
type: int
fast_switchover:
description:
- LACP fast switchover supported on this port channel.
type: bool
max_bundle:
description:
- LACP maximum number of ports to bundle in this port channel.
- Refer to vendor documentation for valid port values.
type: int
state:
description:
- The state the configuration should be left in
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
#
# Before state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# interface GigabitEthernet0/2
# shutdown
# interface GigabitEthernet0/3
# shutdown
- name: Merge provided configuration with device configuration
ios_lacp_interfaces:
config:
- name: GigabitEthernet0/1
port_priority: 10
- name: GigabitEthernet0/2
port_priority: 20
- name: GigabitEthernet0/3
port_priority: 30
- name: Port-channel10
fast_switchover: True
max_bundle: 5
state: merged
# After state:
# ------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# lacp fast-switchover
# lacp max-bundle 5
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 10
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 30
# Using overridden
#
# Before state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# lacp fast-switchover
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 10
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 30
- name: Override device configuration of all lacp_interfaces with provided configuration
ios_lacp_interfaces:
config:
- name: GigabitEthernet0/1
port_priority: 20
- name: Port-channel10
max_bundle: 2
state: overridden
# After state:
# ------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# lacp max-bundle 2
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/2
# shutdown
# interface GigabitEthernet0/3
# shutdown
# Using replaced
#
# Before state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# lacp max-bundle 5
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 10
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 30
- name: Replaces device configuration of listed lacp_interfaces with provided configuration
ios_lacp_interfaces:
config:
- name: GigabitEthernet0/3
port_priority: 40
- name: Port-channel10
fast_switchover: True
max_bundle: 2
state: replaced
# After state:
# ------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# lacp fast-switchover
# lacp max-bundle 2
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 10
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 40
# Using Deleted
#
# Before state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# flowcontrol receive on
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 10
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 30
- name: "Delete LACP attributes of given interfaces (Note: This won't delete the interface itself)"
ios_lacp_interfaces:
config:
- name: GigabitEthernet0/1
state: deleted
# After state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 30
# Using Deleted without any config passed
# "(NOTE: This will delete all of configured LLDP module attributes)"
#
# Before state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# lacp fast-switchover
# interface Port-channel20
# lacp max-bundle 2
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# lacp port-priority 10
# interface GigabitEthernet0/2
# shutdown
# lacp port-priority 20
# interface GigabitEthernet0/3
# shutdown
# lacp port-priority 30
- name: "Delete LACP attributes for all configured interfaces (Note: This won't delete the interface itself)"
ios_lacp_interfaces:
state: deleted
# After state:
# -------------
#
# vios#show running-config | section ^interface
# interface Port-channel10
# interface Port-channel20
# interface Port-channel30
# interface GigabitEthernet0/1
# shutdown
# interface GigabitEthernet0/2
# shutdown
# interface GigabitEthernet0/3
# shutdown
"""
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', 'lacp port-priority 30']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import Lacp_InterfacesArgs
from ansible.module_utils.network.ios.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()

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

@ -0,0 +1,24 @@
---
- 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: Get the IOS version
ios_facts:
gather_subset: all
- 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

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

@ -0,0 +1,16 @@
---
- name: Populate Config
cli_config:
config: "{{ lines }}"
vars:
lines: |
interface GigabitEthernet 0/1
lacp port-priority 30
interface GigabitEthernet 0/2
lacp port-priority 20
interface Port-channel 10
lacp fast-switchover
lacp max-bundle 2
interface Port-channel 40
lacp max-bundle 5
when: ansible_net_version != "15.6(2)T"

@ -0,0 +1,17 @@
---
- name: Remove Config
cli_config:
config: "{{ lines }}"
vars:
lines: |
interface GigabitEthernet 0/1
no lacp port-priority
interface GigabitEthernet 0/2
no lacp port-priority
interface Port-channel 10
no lacp fast-switchover
no lacp max-bundle
interface Port-channel 40
no lacp fast-switchover
no lacp max-bundle
when: ansible_net_version != "15.6(2)T"

@ -0,0 +1,41 @@
---
- debug:
msg: "Start Deleted integration state for ios_lacp_interfaces ansible_connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Delete LACP attributes for all configured interfaces
ios_lacp_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 LACP attributes for all configured interfaces (IDEMPOTENT)
ios_lacp_interfaces: *deleted
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result.changed == false"
when: ansible_net_version != "15.6(2)T"
always:
- include_tasks: _remove_config.yaml

@ -0,0 +1,47 @@
---
- debug:
msg: "START Merged ios_lacp_interfaces state for integration tests on connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- block:
- name: Merge the provided configuration with the exisiting running configuration
ios_lacp_interfaces: &merged
config:
- name: GigabitEthernet0/1
port_priority: 30
- name: GigabitEthernet0/2
port_priority: 20
- name: Port-channel10
fast_switchover: True
max_bundle: 2
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_lacp_interfaces: *merged
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result['changed'] == false"
when: ansible_net_version != "15.6(2)T"
always:
- include_tasks: _remove_config.yaml

@ -0,0 +1,47 @@
---
- debug:
msg: "START Overridden ios_lacp_interfaces state for integration tests on connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Override device configuration of all lacp_interfaces with provided configuration
ios_lacp_interfaces: &overridden
config:
- name: GigabitEthernet0/2
port_priority: 40
- name: Port-channel40
fast_switchover: True
max_bundle: 2
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 lacp_interfaces with provided configuration (IDEMPOTENT)
ios_lacp_interfaces: *overridden
register: result
- name: Assert that task was idempotent
assert:
that:
- "result['changed'] == false"
when: ansible_net_version != "15.6(2)T"
always:
- include_tasks: _remove_config.yaml

@ -0,0 +1,46 @@
---
- debug:
msg: "START Replaced ios_lacp_interfaces state for integration tests on connection={{ ansible_connection }}"
- include_tasks: _remove_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Replaces device configuration of listed lacp_interfaces with provided configuration
ios_lacp_interfaces: &replaced
config:
- name: GigabitEthernet0/1
port_priority: 10
- name: Port-channel40
fast_switchover: True
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 lacp_interfaces with provided configuration (IDEMPOTENT)
ios_lacp_interfaces: *replaced
register: result
- name: Assert that task was idempotent
assert:
that:
- "result['changed'] == false"
when: ansible_net_version != "15.6(2)T"
always:
- include_tasks: _remove_config.yaml

@ -0,0 +1,126 @@
---
merged:
before:
- name: Port-channel10
- name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
- name: GigabitEthernet0/2
commands:
- "interface GigabitEthernet0/1"
- "lacp port-priority 30"
- "interface GigabitEthernet0/2"
- "lacp port-priority 20"
- "interface Port-channel10"
- "lacp max-bundle 2"
- "lacp fast-switchover"
after:
- fast_switchover: True
max_bundle: 2
name: Port-channel10
- name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
port_priority: 30
- name: GigabitEthernet0/2
port_priority: 20
replaced:
before:
- fast_switchover: True
max_bundle: 2
name: Port-channel10
- max_bundle: 5
name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
port_priority: 30
- name: GigabitEthernet0/2
port_priority: 20
commands:
- "interface GigabitEthernet0/1"
- "lacp port-priority 10"
- "interface Port-channel40"
- "no lacp max-bundle"
- "lacp fast-switchover"
after:
- fast_switchover: True
max_bundle: 2
name: Port-channel10
- fast_switchover: True
name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
port_priority: 10
- name: GigabitEthernet0/2
port_priority: 20
overridden:
before:
- fast_switchover: True
max_bundle: 2
name: Port-channel10
- max_bundle: 5
name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
port_priority: 30
- name: GigabitEthernet0/2
port_priority: 20
commands:
- "interface GigabitEthernet0/1"
- "no lacp port-priority"
- "interface GigabitEthernet0/2"
- "lacp port-priority 40"
- "interface Port-channel10"
- "no lacp fast-switchover"
- "no lacp max-bundle"
- "interface Port-channel40"
- "lacp fast-switchover"
- "lacp max-bundle 2"
after:
- name: Port-channel10
- fast_switchover: True
max_bundle: 2
name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
- name: GigabitEthernet0/2
port_priority: 40
deleted:
before:
- fast_switchover: True
max_bundle: 2
name: Port-channel10
- max_bundle: 5
name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
port_priority: 30
- name: GigabitEthernet0/2
port_priority: 20
commands:
- "interface GigabitEthernet0/1"
- "no lacp port-priority"
- "interface GigabitEthernet0/2"
- "no lacp port-priority"
- "interface Port-channel10"
- "no lacp fast-switchover"
- "no lacp max-bundle"
- "interface Port-channel40"
- "no lacp max-bundle"
after:
- name: Port-channel10
- name: Port-channel40
- name: GigabitEthernet0/0
- name: GigabitEthernet0/1
- name: GigabitEthernet0/2
Loading…
Cancel
Save