lag interfaces resource module (#59175)
* lag interfaces resource module Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * sanity check imports Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * sanity fixes Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * dict_diff usage issue fix Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * new task Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * overridden updated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * dict update Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * comments incorporated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * facts merged Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * rebased and merged Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * new failures added Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * obsolete file removed Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * test cases updated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * comments incorporated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * dependency added Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>
This commit is contained in:
parent
d8d00c36fa
commit
69bc24f607
29 changed files with 1675 additions and 22 deletions
|
@ -74,6 +74,8 @@ The following modules will be removed in Ansible 2.13. Please update update your
|
||||||
|
|
||||||
* nxos_interface use :ref:`nxos_interfaces <nxos_interfaces_module>` instead.
|
* nxos_interface use :ref:`nxos_interfaces <nxos_interfaces_module>` instead.
|
||||||
|
|
||||||
|
* vyos_linkagg use :ref:`vyos_lag_interfaces <vyos_lag_interfaces_module>` instead.
|
||||||
|
|
||||||
The following functionality will be removed in Ansible 2.12. Please update update your playbooks accordingly.
|
The following functionality will be removed in Ansible 2.12. Please update update your playbooks accordingly.
|
||||||
|
|
||||||
* ``vmware_cluster`` DRS, HA and VSAN configuration; use `vmware_cluster_drs <vmware_cluster_drs_module>`, `vmware_cluster_ha <vmware_cluster_ha_module>` and `vmware_cluster_vsan <vmware_cluster_vsan_module>` instead.
|
* ``vmware_cluster`` DRS, HA and VSAN configuration; use `vmware_cluster_drs <vmware_cluster_drs_module>`, `vmware_cluster_ha <vmware_cluster_ha_module>` and `vmware_cluster_vsan <vmware_cluster_vsan_module>` instead.
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
"""
|
"""
|
||||||
The arg spec for the vyos facts module.
|
The arg spec for the vyos facts module.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
@ -22,7 +20,9 @@ class FactsArgs(object): # pylint: disable=R0903
|
||||||
'interfaces',
|
'interfaces',
|
||||||
'!interfaces',
|
'!interfaces',
|
||||||
'l3_interfaces',
|
'l3_interfaces',
|
||||||
'!l3_interfaces'
|
'!l3_interfaces',
|
||||||
|
'lag_interfaces',
|
||||||
|
'!lag_interfaces'
|
||||||
]
|
]
|
||||||
|
|
||||||
argument_spec = {
|
argument_spec = {
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
# 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 vyos_lag_interfaces module
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
class Lag_interfacesArgs(object): # pylint: disable=R0903
|
||||||
|
"""The arg spec for the vyos_lag_interfaces module
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
argument_spec = \
|
||||||
|
{
|
||||||
|
'config': {
|
||||||
|
'elements': 'dict',
|
||||||
|
'options': {
|
||||||
|
'arp_monitor': {
|
||||||
|
'options': {
|
||||||
|
'interval': {'type': 'int'},
|
||||||
|
'target': {'type': 'list'}
|
||||||
|
},
|
||||||
|
'type': 'dict'},
|
||||||
|
'hash_policy': {'choices': ['layer2', 'layer2+3', 'layer3+4'],
|
||||||
|
'type': 'str'},
|
||||||
|
'members': {'elements': 'dict', 'options': {
|
||||||
|
'member': {'type': 'str'}}, 'type': 'list'},
|
||||||
|
'mode': {'choices': ['802.3ad',
|
||||||
|
'active-backup',
|
||||||
|
'broadcast',
|
||||||
|
'round-robin',
|
||||||
|
'transmit-load-balance',
|
||||||
|
'adaptive-load-balance',
|
||||||
|
'xor-hash'],
|
||||||
|
'type': 'str'},
|
||||||
|
'name': {'required': True, 'type': 'str'},
|
||||||
|
'primary': {'type': 'str'}
|
||||||
|
},
|
||||||
|
'type': 'list'
|
||||||
|
},
|
||||||
|
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
|
||||||
|
'default': 'merged',
|
||||||
|
'type': 'str'}
|
||||||
|
} # pylint: disable=C0301
|
|
@ -0,0 +1,378 @@
|
||||||
|
# Copyright 2019 Red Hat
|
||||||
|
# GNU General Public License v3.0+
|
||||||
|
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
"""
|
||||||
|
The vyos_lag_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.vyos.facts.facts import Facts
|
||||||
|
from ansible.module_utils.network.common.utils import to_list, dict_diff
|
||||||
|
from ansible.module_utils.six import iteritems
|
||||||
|
from ansible.module_utils.network. \
|
||||||
|
vyos.utils.utils import search_obj_in_list, \
|
||||||
|
get_lst_diff_for_dicts, list_diff_want_only, list_diff_have_only
|
||||||
|
|
||||||
|
|
||||||
|
class Lag_interfaces(ConfigBase):
|
||||||
|
"""
|
||||||
|
The vyos_lag_interfaces class
|
||||||
|
"""
|
||||||
|
|
||||||
|
gather_subset = [
|
||||||
|
'!all',
|
||||||
|
'!min',
|
||||||
|
]
|
||||||
|
|
||||||
|
gather_network_resources = [
|
||||||
|
'lag_interfaces',
|
||||||
|
]
|
||||||
|
|
||||||
|
params = ['arp_monitor', 'hash_policy', 'members', 'mode', 'name', 'primary']
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(Lag_interfaces, self).__init__(module)
|
||||||
|
|
||||||
|
def get_lag_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)
|
||||||
|
lag_interfaces_facts = facts['ansible_network_resources'].get('lag_interfaces')
|
||||||
|
if not lag_interfaces_facts:
|
||||||
|
return []
|
||||||
|
return lag_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_lag_interfaces_facts = self.get_lag_interfaces_facts()
|
||||||
|
commands.extend(self.set_config(existing_lag_interfaces_facts))
|
||||||
|
if commands:
|
||||||
|
if self._module.check_mode:
|
||||||
|
resp = self._connection.edit_config(commands, commit=False)
|
||||||
|
else:
|
||||||
|
resp = self._connection.edit_config(commands)
|
||||||
|
result['changed'] = True
|
||||||
|
|
||||||
|
result['commands'] = commands
|
||||||
|
|
||||||
|
if self._module._diff:
|
||||||
|
result['diff'] = resp['diff'] if result['changed'] else None
|
||||||
|
|
||||||
|
changed_lag_interfaces_facts = self.get_lag_interfaces_facts()
|
||||||
|
|
||||||
|
result['before'] = existing_lag_interfaces_facts
|
||||||
|
if result['changed']:
|
||||||
|
result['after'] = changed_lag_interfaces_facts
|
||||||
|
|
||||||
|
result['warnings'] = warnings
|
||||||
|
return result
|
||||||
|
|
||||||
|
def set_config(self, existing_lag_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_lag_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(self._state_overridden(want, have))
|
||||||
|
elif state == 'deleted':
|
||||||
|
if want:
|
||||||
|
for want_item in want:
|
||||||
|
name = want_item['name']
|
||||||
|
obj_in_have = search_obj_in_list(name, have)
|
||||||
|
commands.extend(self._state_deleted(obj_in_have))
|
||||||
|
else:
|
||||||
|
for have_item in have:
|
||||||
|
commands.extend(self._state_deleted(have_item))
|
||||||
|
else:
|
||||||
|
for want_item in want:
|
||||||
|
name = want_item['name']
|
||||||
|
obj_in_have = search_obj_in_list(name, have)
|
||||||
|
if state == 'merged':
|
||||||
|
commands.extend(self._state_merged(want_item, obj_in_have))
|
||||||
|
elif state == 'replaced':
|
||||||
|
commands.extend(self._state_replaced(want_item, obj_in_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 = []
|
||||||
|
if have:
|
||||||
|
commands.extend(self._render_del_commands(want, have))
|
||||||
|
commands.extend(self._state_merged(want, have))
|
||||||
|
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 have_item in have:
|
||||||
|
lag_name = have_item['name']
|
||||||
|
obj_in_want = search_obj_in_list(lag_name, want)
|
||||||
|
if not obj_in_want:
|
||||||
|
commands.extend(self._purge_attribs(have_item))
|
||||||
|
|
||||||
|
for want_item in want:
|
||||||
|
name = want_item['name']
|
||||||
|
obj_in_have = search_obj_in_list(name, have)
|
||||||
|
commands.extend(self._state_replaced(want_item, obj_in_have))
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _state_merged(self, want, have):
|
||||||
|
""" The command generator when state is merged
|
||||||
|
|
||||||
|
:rtype: A list
|
||||||
|
:returns: the commands necessary to merge the provided into
|
||||||
|
the current configuration
|
||||||
|
"""
|
||||||
|
commands = []
|
||||||
|
if have:
|
||||||
|
commands.extend(self._render_updates(want, have))
|
||||||
|
else:
|
||||||
|
commands.extend(self._render_set_commands(want))
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _state_deleted(self, 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 have:
|
||||||
|
commands.extend(self._purge_attribs(have))
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _render_updates(self, want, have):
|
||||||
|
commands = []
|
||||||
|
|
||||||
|
temp_have_members = have.pop('members', None)
|
||||||
|
temp_want_members = want.pop('members', None)
|
||||||
|
|
||||||
|
updates = dict_diff(have, want)
|
||||||
|
|
||||||
|
if temp_have_members:
|
||||||
|
have['members'] = temp_have_members
|
||||||
|
if temp_want_members:
|
||||||
|
want['members'] = temp_want_members
|
||||||
|
|
||||||
|
commands.extend(self._add_bond_members(want, have))
|
||||||
|
|
||||||
|
if updates:
|
||||||
|
for key, value in iteritems(updates):
|
||||||
|
if value:
|
||||||
|
if key == 'arp_monitor':
|
||||||
|
commands.extend(
|
||||||
|
self._add_arp_monitor(updates, key, want, have)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
commands.append(self._compute_command(have['name'], key, str(value)))
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _render_set_commands(self, want):
|
||||||
|
commands = []
|
||||||
|
have = []
|
||||||
|
|
||||||
|
params = Lag_interfaces.params
|
||||||
|
|
||||||
|
for attrib in params:
|
||||||
|
value = want[attrib]
|
||||||
|
if value:
|
||||||
|
if attrib == 'arp_monitor':
|
||||||
|
commands.extend(
|
||||||
|
self._add_arp_monitor(want, attrib, want, have)
|
||||||
|
)
|
||||||
|
elif attrib == 'members':
|
||||||
|
commands.extend(
|
||||||
|
self._add_bond_members(want, have)
|
||||||
|
)
|
||||||
|
elif attrib != 'name':
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(want['name'], attrib, value=str(value))
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _purge_attribs(self, have):
|
||||||
|
commands = []
|
||||||
|
for item in Lag_interfaces.params:
|
||||||
|
if have.get(item):
|
||||||
|
if item == 'members':
|
||||||
|
commands.extend(
|
||||||
|
self._delete_bond_members(have)
|
||||||
|
)
|
||||||
|
elif item != 'name':
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(have['name'], attrib=item, remove=True)
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _render_del_commands(self, want, have):
|
||||||
|
commands = []
|
||||||
|
|
||||||
|
params = Lag_interfaces.params
|
||||||
|
for attrib in params:
|
||||||
|
if attrib == 'members':
|
||||||
|
commands.extend(
|
||||||
|
self._update_bond_members(attrib, want, have)
|
||||||
|
)
|
||||||
|
elif attrib == 'arp_monitor':
|
||||||
|
commands.extend(
|
||||||
|
self._update_arp_monitor(attrib, want, have)
|
||||||
|
)
|
||||||
|
elif have.get(attrib) and not want.get(attrib):
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(have['name'], attrib, remove=True)
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _add_bond_members(self, want, have):
|
||||||
|
commands = []
|
||||||
|
diff_members = get_lst_diff_for_dicts(want, have, 'members')
|
||||||
|
if diff_members:
|
||||||
|
for key in diff_members:
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(key['member'], 'bond-group', want['name'], type='ethernet')
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _add_arp_monitor(self, updates, key, want, have):
|
||||||
|
commands = []
|
||||||
|
arp_monitor = updates.get(key) or {}
|
||||||
|
diff_targets = self._get_arp_monitor_target_diff(want, have, key, 'target')
|
||||||
|
|
||||||
|
if 'interval' in arp_monitor:
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(key, 'interval', str(arp_monitor['interval']))
|
||||||
|
)
|
||||||
|
if diff_targets:
|
||||||
|
for target in diff_targets:
|
||||||
|
commands.append(
|
||||||
|
self._compute_commands(key, 'target', target)
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _delete_bond_members(self, have):
|
||||||
|
commands = []
|
||||||
|
for member in have['members']:
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(
|
||||||
|
member['member'], 'bond-group', have['name'], remove=True, type='ethernet'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _update_arp_monitor(self, key, want, have):
|
||||||
|
commands = []
|
||||||
|
want_arp_target = []
|
||||||
|
have_arp_target = []
|
||||||
|
want_arp_monitor = want.get(key) or {}
|
||||||
|
have_arp_monitor = have.get(key) or {}
|
||||||
|
del_cmd = 'delete interface bonding ' + have['name']
|
||||||
|
|
||||||
|
if want_arp_monitor and 'target' in want_arp_monitor:
|
||||||
|
want_arp_target = want_arp_monitor['target']
|
||||||
|
|
||||||
|
if have_arp_monitor and 'target' in have_arp_monitor:
|
||||||
|
have_arp_target = have_arp_monitor['target']
|
||||||
|
|
||||||
|
if 'interval' in have_arp_monitor and not want_arp_monitor:
|
||||||
|
commands.append(del_cmd + ' ' + key + ' interval')
|
||||||
|
if 'target' in have_arp_monitor:
|
||||||
|
target_diff = list_diff_have_only(want_arp_target, have_arp_target)
|
||||||
|
if target_diff:
|
||||||
|
for target in target_diff:
|
||||||
|
commands.append(del_cmd + ' ' + key + ' target ' + target)
|
||||||
|
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _update_bond_members(self, key, want, have):
|
||||||
|
commands = []
|
||||||
|
want_members = want.get(key) or []
|
||||||
|
have_members = have.get(key) or []
|
||||||
|
|
||||||
|
members_diff = list_diff_have_only(want_members, have_members)
|
||||||
|
if members_diff:
|
||||||
|
for member in members_diff:
|
||||||
|
commands.append(
|
||||||
|
self._compute_command(
|
||||||
|
member[key], 'bond-group', have['name'], False, 'ethernet'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def _get_arp_monitor_target_diff(self, want_list, have_list, dict_name, lst):
|
||||||
|
want_arp_target = []
|
||||||
|
have_arp_target = []
|
||||||
|
|
||||||
|
want_arp_monitor = want_list.get(dict_name) or {}
|
||||||
|
if want_arp_monitor and lst in want_arp_monitor:
|
||||||
|
want_arp_target = want_arp_monitor[lst]
|
||||||
|
|
||||||
|
if not have_list:
|
||||||
|
diff = want_arp_target
|
||||||
|
else:
|
||||||
|
have_arp_monitor = have_list.get(dict_name) or {}
|
||||||
|
if have_arp_monitor and lst in have_arp_monitor:
|
||||||
|
have_arp_target = have_arp_monitor[lst]
|
||||||
|
|
||||||
|
diff = list_diff_want_only(want_arp_target, have_arp_target)
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def _compute_command(self, key, attrib, value=None, remove=False, type='bonding'):
|
||||||
|
if remove:
|
||||||
|
cmd = 'delete interfaces ' + type
|
||||||
|
else:
|
||||||
|
cmd = 'set interfaces ' + type
|
||||||
|
cmd += (' ' + key)
|
||||||
|
if attrib == 'arp_monitor':
|
||||||
|
attrib = 'arp-monitor'
|
||||||
|
elif attrib == 'hash_policy':
|
||||||
|
attrib = 'hash-policy'
|
||||||
|
cmd += (' ' + attrib)
|
||||||
|
if value:
|
||||||
|
cmd += (" '" + value + "'")
|
||||||
|
return cmd
|
|
@ -15,6 +15,7 @@ from ansible.module_utils.network.vyos.argspec.facts.facts import FactsArgs
|
||||||
from ansible.module_utils.network.common.facts.facts import FactsBase
|
from ansible.module_utils.network.common.facts.facts import FactsBase
|
||||||
from ansible.module_utils.network.vyos.facts.interfaces.interfaces import InterfacesFacts
|
from ansible.module_utils.network.vyos.facts.interfaces.interfaces import InterfacesFacts
|
||||||
from ansible.module_utils.network.vyos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts
|
from ansible.module_utils.network.vyos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts
|
||||||
|
from ansible.module_utils.network.vyos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
|
||||||
from ansible.module_utils.network.vyos.facts.legacy.base import Default, Neighbors, Config
|
from ansible.module_utils.network.vyos.facts.legacy.base import Default, Neighbors, Config
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +26,8 @@ FACT_LEGACY_SUBSETS = dict(
|
||||||
)
|
)
|
||||||
FACT_RESOURCE_SUBSETS = dict(
|
FACT_RESOURCE_SUBSETS = dict(
|
||||||
interfaces=InterfacesFacts,
|
interfaces=InterfacesFacts,
|
||||||
l3_interfaces=L3_interfacesFacts
|
l3_interfaces=L3_interfacesFacts,
|
||||||
|
lag_interfaces=Lag_interfacesFacts
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
#
|
||||||
|
# -*- 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 vyos lag_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
|
||||||
|
from re import findall, search, M
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from ansible.module_utils.network.common import utils
|
||||||
|
from ansible.module_utils.network.vyos.argspec.lag_interfaces. \
|
||||||
|
lag_interfaces import Lag_interfacesArgs
|
||||||
|
|
||||||
|
|
||||||
|
class Lag_interfacesFacts(object):
|
||||||
|
""" The vyos lag_interfaces fact class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, module, subspec='config', options='options'):
|
||||||
|
self._module = module
|
||||||
|
self.argument_spec = Lag_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 lag_interfaces
|
||||||
|
:param module: the module instance
|
||||||
|
:param connection: the device connection
|
||||||
|
:param data: previously collected conf
|
||||||
|
:rtype: dictionary
|
||||||
|
:returns: facts
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
data = connection.get_config()
|
||||||
|
|
||||||
|
objs = []
|
||||||
|
lag_names = findall(r'^set interfaces bonding (\S+)', data, M)
|
||||||
|
if lag_names:
|
||||||
|
for lag in set(lag_names):
|
||||||
|
lag_regex = r' %s .+$' % lag
|
||||||
|
cfg = findall(lag_regex, data, M)
|
||||||
|
obj = self.render_config(cfg)
|
||||||
|
|
||||||
|
output = connection.run_commands(['show interfaces bonding ' + lag + ' slaves'])
|
||||||
|
lines = output[0].splitlines()
|
||||||
|
members = []
|
||||||
|
member = {}
|
||||||
|
if len(lines) > 1:
|
||||||
|
for line in lines[2:]:
|
||||||
|
splitted_line = line.split()
|
||||||
|
|
||||||
|
if len(splitted_line) > 1:
|
||||||
|
member['member'] = splitted_line[0]
|
||||||
|
members.append(member)
|
||||||
|
else:
|
||||||
|
members = []
|
||||||
|
member = {}
|
||||||
|
obj['name'] = lag.strip("'")
|
||||||
|
if members:
|
||||||
|
obj['members'] = members
|
||||||
|
|
||||||
|
if obj:
|
||||||
|
objs.append(obj)
|
||||||
|
|
||||||
|
facts = {}
|
||||||
|
if objs:
|
||||||
|
facts['lag_interfaces'] = []
|
||||||
|
params = utils.validate_config(self.argument_spec, {'config': objs})
|
||||||
|
for cfg in params['config']:
|
||||||
|
facts['lag_interfaces'].append(utils.remove_empties(cfg))
|
||||||
|
|
||||||
|
ansible_facts['ansible_network_resources'].update(facts)
|
||||||
|
return ansible_facts
|
||||||
|
|
||||||
|
def render_config(self, 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
|
||||||
|
"""
|
||||||
|
arp_monitor_conf = '\n'.join(filter(lambda x: ('arp-monitor' in x), conf))
|
||||||
|
hash_policy_conf = '\n'.join(filter(lambda x: ('hash-policy' in x), conf))
|
||||||
|
lag_conf = '\n'.join(filter(lambda x: ('bond' in x), conf))
|
||||||
|
config = self.parse_attribs(
|
||||||
|
['mode', 'primary'], lag_conf
|
||||||
|
)
|
||||||
|
config['arp_monitor'] = self.parse_arp_monitor(arp_monitor_conf)
|
||||||
|
config['hash_policy'] = self.parse_hash_policy(hash_policy_conf)
|
||||||
|
|
||||||
|
return utils.remove_empties(config)
|
||||||
|
|
||||||
|
def parse_attribs(self, attribs, conf):
|
||||||
|
config = {}
|
||||||
|
for item in attribs:
|
||||||
|
value = utils.parse_conf_arg(conf, item)
|
||||||
|
if value:
|
||||||
|
config[item] = value.strip("'")
|
||||||
|
else:
|
||||||
|
config[item] = None
|
||||||
|
return utils.remove_empties(config)
|
||||||
|
|
||||||
|
def parse_arp_monitor(self, conf):
|
||||||
|
arp_monitor = None
|
||||||
|
if conf:
|
||||||
|
arp_monitor = {}
|
||||||
|
target_list = []
|
||||||
|
interval = search(r'^.*arp-monitor interval (.+)', conf, M)
|
||||||
|
targets = findall(r"^.*arp-monitor target '(.+)'", conf, M)
|
||||||
|
if targets:
|
||||||
|
for target in targets:
|
||||||
|
target_list.append(target)
|
||||||
|
arp_monitor['target'] = target_list
|
||||||
|
if interval:
|
||||||
|
value = interval.group(1).strip("'")
|
||||||
|
arp_monitor['interval'] = int(value)
|
||||||
|
return arp_monitor
|
||||||
|
|
||||||
|
def parse_hash_policy(self, conf):
|
||||||
|
hash_policy = None
|
||||||
|
if conf:
|
||||||
|
hash_policy = search(r'^.*hash-policy (.+)', conf, M)
|
||||||
|
hash_policy = hash_policy.group(1).strip("'")
|
||||||
|
return hash_policy
|
|
@ -4,8 +4,6 @@
|
||||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
@ -66,3 +64,34 @@ def diff_list_of_dicts(want, have):
|
||||||
diff.append(dict((x, y) for x, y in element))
|
diff.append(dict((x, y) for x, y in element))
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
|
|
||||||
|
|
||||||
|
def list_diff_have_only(want_list, have_list):
|
||||||
|
if have_list and not want_list:
|
||||||
|
diff = have_list
|
||||||
|
elif not have_list:
|
||||||
|
diff = None
|
||||||
|
else:
|
||||||
|
diff = [i for i in have_list + want_list if i in have_list and i not in want_list]
|
||||||
|
return diff
|
||||||
|
|
||||||
|
|
||||||
|
def list_diff_want_only(want_list, have_list):
|
||||||
|
if have_list and not want_list:
|
||||||
|
diff = None
|
||||||
|
elif not have_list:
|
||||||
|
diff = want_list
|
||||||
|
else:
|
||||||
|
diff = [i for i in have_list + want_list if i in want_list and i not in have_list]
|
||||||
|
return diff
|
||||||
|
|
||||||
|
|
||||||
|
def get_lst_diff_for_dicts(want, have, lst):
|
||||||
|
if not have:
|
||||||
|
diff = want.get(lst) or []
|
||||||
|
|
||||||
|
else:
|
||||||
|
want_elements = want.get(lst) or {}
|
||||||
|
have_elements = have.get(lst) or {}
|
||||||
|
diff = list_diff_want_only(want_elements, have_elements)
|
||||||
|
return diff
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
'status': ['preview'],
|
'status': ['deprecated'],
|
||||||
'supported_by': 'network'}
|
'supported_by': 'network'}
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,6 +33,10 @@ short_description: Manage link aggregation groups on VyOS network devices
|
||||||
description:
|
description:
|
||||||
- This module provides declarative management of link aggregation groups
|
- This module provides declarative management of link aggregation groups
|
||||||
on VyOS network devices.
|
on VyOS network devices.
|
||||||
|
deprecated:
|
||||||
|
removed_in: '2.13'
|
||||||
|
alternative: vyos_lag_interfaces
|
||||||
|
why: Updated modules released with more functionality.
|
||||||
notes:
|
notes:
|
||||||
- Tested against VYOS 1.1.7
|
- Tested against VYOS 1.1.7
|
||||||
options:
|
options:
|
||||||
|
@ -40,22 +44,27 @@ options:
|
||||||
description:
|
description:
|
||||||
- Name of the link aggregation group.
|
- Name of the link aggregation group.
|
||||||
required: true
|
required: true
|
||||||
|
type: str
|
||||||
mode:
|
mode:
|
||||||
description:
|
description:
|
||||||
- Mode of the link aggregation group.
|
- Mode of the link aggregation group.
|
||||||
choices: ['802.3ad', 'active-backup', 'broadcast',
|
choices: ['802.3ad', 'active-backup', 'broadcast',
|
||||||
'round-robin', 'transmit-load-balance',
|
'round-robin', 'transmit-load-balance',
|
||||||
'adaptive-load-balance', 'xor-hash', 'on']
|
'adaptive-load-balance', 'xor-hash', 'on']
|
||||||
|
type: str
|
||||||
members:
|
members:
|
||||||
description:
|
description:
|
||||||
- List of members of the link aggregation group.
|
- List of members of the link aggregation group.
|
||||||
|
type: list
|
||||||
aggregate:
|
aggregate:
|
||||||
description: List of link aggregation definitions.
|
description: List of link aggregation definitions.
|
||||||
|
type: list
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- State of the link aggregation group.
|
- State of the link aggregation group.
|
||||||
default: present
|
default: present
|
||||||
choices: ['present', 'absent', 'up', 'down']
|
choices: ['present', 'absent', 'up', 'down']
|
||||||
|
type: str
|
||||||
extends_documentation_fragment: vyos
|
extends_documentation_fragment: vyos
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -27,6 +27,7 @@ description:
|
||||||
author:
|
author:
|
||||||
- Nathaniel Case (@qalthos)
|
- Nathaniel Case (@qalthos)
|
||||||
- Nilashish Chakraborty (@Nilashishc)
|
- Nilashish Chakraborty (@Nilashishc)
|
||||||
|
- Rohit Thakur (@rohitthakur2590)
|
||||||
extends_documentation_fragment: vyos
|
extends_documentation_fragment: vyos
|
||||||
notes:
|
notes:
|
||||||
- Tested against VyOS 1.1.8
|
- Tested against VyOS 1.1.8
|
||||||
|
@ -51,7 +52,7 @@ options:
|
||||||
specific subset should not be collected.
|
specific subset should not be collected.
|
||||||
required: false
|
required: false
|
||||||
version_added: "2.9"
|
version_added: "2.9"
|
||||||
choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces']
|
choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces', 'lag_interfaces', '!lag_interfaces']
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
|
|
561
lib/ansible/modules/network/vyos/vyos_lag_interfaces.py
Normal file
561
lib/ansible/modules/network/vyos/vyos_lag_interfaces.py
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
#!/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 vyos_lag_interfaces
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {
|
||||||
|
'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'network'
|
||||||
|
}
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: vyos_lag_interfaces
|
||||||
|
version_added: 2.9
|
||||||
|
short_description: Manages attributes of link aggregation groups on VyOS network devices.
|
||||||
|
description: This module manages attributes of link aggregation groups on VyOS network devices.
|
||||||
|
notes:
|
||||||
|
- Tested against VyOS 1.1.8 (helium).
|
||||||
|
- This module works with connection C(network_cli).
|
||||||
|
author: Rohit Thakur (@rohitthakur2590)
|
||||||
|
options:
|
||||||
|
config:
|
||||||
|
description: A list of link aggregation group configurations.
|
||||||
|
type: list
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the link aggregation group (LAG) or bond.
|
||||||
|
type: str
|
||||||
|
required: True
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- LAG or bond mode.
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- 802.3ad
|
||||||
|
- active-backup
|
||||||
|
- broadcast
|
||||||
|
- round-robin
|
||||||
|
- transmit-load-balance
|
||||||
|
- adaptive-load-balance
|
||||||
|
- xor-hash
|
||||||
|
members:
|
||||||
|
description:
|
||||||
|
- List of member interfaces for the LAG (bond).
|
||||||
|
type: list
|
||||||
|
suboptions:
|
||||||
|
member:
|
||||||
|
description:
|
||||||
|
- Name of the member interface.
|
||||||
|
type: str
|
||||||
|
primary:
|
||||||
|
description:
|
||||||
|
- Primary device interfaces for the LAG (bond).
|
||||||
|
type: str
|
||||||
|
hash_policy:
|
||||||
|
description:
|
||||||
|
- LAG or bonding transmit hash policy.
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- layer2
|
||||||
|
- layer2+3
|
||||||
|
- layer3+4
|
||||||
|
arp_monitor:
|
||||||
|
description:
|
||||||
|
- ARP Link monitoring parameters.
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
interval:
|
||||||
|
description:
|
||||||
|
- ARP link monitoring frequency in milliseconds.
|
||||||
|
type: int
|
||||||
|
target:
|
||||||
|
description:
|
||||||
|
- IP address to use for ARP monitoring.
|
||||||
|
type: list
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- The state the configuration should be left in.
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- merged
|
||||||
|
- replaced
|
||||||
|
- overridden
|
||||||
|
- deleted
|
||||||
|
default: merged
|
||||||
|
|
||||||
|
"""
|
||||||
|
EXAMPLES = """
|
||||||
|
# Using merged
|
||||||
|
#
|
||||||
|
# Before state:
|
||||||
|
# -------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2
|
||||||
|
# set interfaces bonding bond3
|
||||||
|
#
|
||||||
|
- name: Merge provided configuration with device configuration
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config:
|
||||||
|
- name: bond2
|
||||||
|
mode: active-backup
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
- member: eth1
|
||||||
|
hash_policy: layer2
|
||||||
|
primary: eth2
|
||||||
|
|
||||||
|
- name: 'bond3'
|
||||||
|
mode: 'active-backup'
|
||||||
|
hash_policy: 'layer2+3'
|
||||||
|
members:
|
||||||
|
- member: eth3
|
||||||
|
primary: 'eth3'
|
||||||
|
state: merged
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# -------------------------
|
||||||
|
# Module Execution Result
|
||||||
|
# -------------------------
|
||||||
|
#
|
||||||
|
# "before": [
|
||||||
|
# {
|
||||||
|
# "name": "bond2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "name": "bond3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# "commands": [
|
||||||
|
# "set interfaces bonding bond2 hash-policy 'layer2'",
|
||||||
|
# "set interfaces bonding bond2 mode 'active-backup'",
|
||||||
|
# "set interfaces ethernet eth2 bond-group bond2",
|
||||||
|
# "set interfaces ethernet eth1 bond-group bond2",
|
||||||
|
# "set interfaces bonding bond2 primary 'eth2'",
|
||||||
|
# "set interfaces bonding bond3 hash-policy 'layer2+3'",
|
||||||
|
# "set interfaces bonding bond3 mode 'active-backup'",
|
||||||
|
# "set interfaces ethernet eth3 bond-group bond3",
|
||||||
|
# "set interfaces bonding bond3 primary 'eth3'"
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
# "after": [
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth2"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond2",
|
||||||
|
# "primary": "eth2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2+3",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond3",
|
||||||
|
# "primary": "eth3"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
#
|
||||||
|
# After state:
|
||||||
|
# -------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond2 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond2 primary 'eth2'
|
||||||
|
# set interfaces bonding bond3 hash-policy 'layer2+3'
|
||||||
|
# set interfaces bonding bond3 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond3 primary 'eth3'
|
||||||
|
# set interfaces ethernet eth1 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth2 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth3 bond-group 'bond3'
|
||||||
|
|
||||||
|
|
||||||
|
# Using replaced
|
||||||
|
#
|
||||||
|
# Before state:
|
||||||
|
# -------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond2 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond2 primary 'eth2'
|
||||||
|
# set interfaces bonding bond3 hash-policy 'layer2+3'
|
||||||
|
# set interfaces bonding bond3 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond3 primary 'eth3'
|
||||||
|
# set interfaces ethernet eth1 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth2 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth3 bond-group 'bond3'
|
||||||
|
#
|
||||||
|
- name: Replace device configurations of listed LAGs with provided configurations
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config:
|
||||||
|
- name: bond3
|
||||||
|
mode: '802.3ad'
|
||||||
|
hash_policy: 'layer2'
|
||||||
|
members:
|
||||||
|
- member: eth3
|
||||||
|
state: replaced
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# -------------------------
|
||||||
|
# Module Execution Result
|
||||||
|
# -------------------------
|
||||||
|
#
|
||||||
|
# "before": [
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth2"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond2",
|
||||||
|
# "primary": "eth2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2+3",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond3",
|
||||||
|
# "primary": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# "commands": [
|
||||||
|
# "delete interfaces bonding bond3 primary",
|
||||||
|
# "set interfaces bonding bond3 hash-policy 'layer2'",
|
||||||
|
# "set interfaces bonding bond3 mode '802.3ad'"
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# "after": [
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth2"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond2",
|
||||||
|
# "primary": "eth2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "802.3ad",
|
||||||
|
# "name": "bond3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# After state:
|
||||||
|
# -------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond2 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond2 primary 'eth2'
|
||||||
|
# set interfaces bonding bond3 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond3 mode '802.3ad'
|
||||||
|
# set interfaces ethernet eth1 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth2 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth3 bond-group 'bond3'
|
||||||
|
|
||||||
|
|
||||||
|
# Using overridden
|
||||||
|
#
|
||||||
|
# Before state
|
||||||
|
# --------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond2 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond2 primary 'eth2'
|
||||||
|
# set interfaces bonding bond3 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond3 mode '802.3ad'
|
||||||
|
# set interfaces ethernet eth1 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth2 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth3 bond-group 'bond3'
|
||||||
|
#
|
||||||
|
- name: Overrides all device configuration with provided configuration
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config:
|
||||||
|
- name: bond3
|
||||||
|
mode: active-backup
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
- member: eth2
|
||||||
|
- member: eth3
|
||||||
|
primary: eth3
|
||||||
|
hash_policy: layer2
|
||||||
|
state: overridden
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# -------------------------
|
||||||
|
# Module Execution Result
|
||||||
|
# -------------------------
|
||||||
|
#
|
||||||
|
# "before": [
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth2"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond2",
|
||||||
|
# "primary": "eth2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "802.3ad",
|
||||||
|
# "name": "bond3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# "commands": [
|
||||||
|
# "delete interfaces bonding bond2 hash-policy",
|
||||||
|
# "delete interfaces ethernet eth1 bond-group bond2",
|
||||||
|
# "delete interfaces ethernet eth2 bond-group bond2",
|
||||||
|
# "delete interfaces bonding bond2 mode",
|
||||||
|
# "delete interfaces bonding bond2 primary",
|
||||||
|
# "set interfaces bonding bond3 mode 'active-backup'",
|
||||||
|
# "set interfaces ethernet eth1 bond-group bond3",
|
||||||
|
# "set interfaces ethernet eth2 bond-group bond3",
|
||||||
|
# "set interfaces bonding bond3 primary 'eth3'"
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# "after": [
|
||||||
|
# {
|
||||||
|
# "name": "bond2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond3",
|
||||||
|
# "primary": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# After state
|
||||||
|
# ------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2
|
||||||
|
# set interfaces bonding bond3 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond3 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond3 primary 'eth3'
|
||||||
|
# set interfaces ethernet eth1 bond-group 'bond3'
|
||||||
|
# set interfaces ethernet eth2 bond-group 'bond3'
|
||||||
|
# set interfaces ethernet eth3 bond-group 'bond3'
|
||||||
|
|
||||||
|
|
||||||
|
# Using deleted
|
||||||
|
#
|
||||||
|
# Before state
|
||||||
|
# -------------
|
||||||
|
#
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2 hash-policy 'layer2'
|
||||||
|
# set interfaces bonding bond2 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond2 primary 'eth2'
|
||||||
|
# set interfaces bonding bond3 hash-policy 'layer2+3'
|
||||||
|
# set interfaces bonding bond3 mode 'active-backup'
|
||||||
|
# set interfaces bonding bond3 primary 'eth3'
|
||||||
|
# set interfaces ethernet eth1 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth2 bond-group 'bond2'
|
||||||
|
# set interfaces ethernet eth3 bond-group 'bond3'
|
||||||
|
#
|
||||||
|
- name: Delete LAG attributes of given interfaces (Note This won't delete the interface itself)
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config:
|
||||||
|
- name: bond2
|
||||||
|
- name: bond3
|
||||||
|
state: deleted
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ------------------------
|
||||||
|
# Module Execution Results
|
||||||
|
# ------------------------
|
||||||
|
#
|
||||||
|
# "before": [
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth1"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "member": "eth2"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond2",
|
||||||
|
# "primary": "eth2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "hash_policy": "layer2+3",
|
||||||
|
# "members": [
|
||||||
|
# {
|
||||||
|
# "member": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "mode": "active-backup",
|
||||||
|
# "name": "bond3",
|
||||||
|
# "primary": "eth3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "commands": [
|
||||||
|
# "delete interfaces bonding bond2 hash-policy",
|
||||||
|
# "delete interfaces ethernet eth1 bond-group bond2",
|
||||||
|
# "delete interfaces ethernet eth2 bond-group bond2",
|
||||||
|
# "delete interfaces bonding bond2 mode",
|
||||||
|
# "delete interfaces bonding bond2 primary",
|
||||||
|
# "delete interfaces bonding bond3 hash-policy",
|
||||||
|
# "delete interfaces ethernet eth3 bond-group bond3",
|
||||||
|
# "delete interfaces bonding bond3 mode",
|
||||||
|
# "delete interfaces bonding bond3 primary"
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# "after": [
|
||||||
|
# {
|
||||||
|
# "name": "bond2"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "name": "bond3"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
#
|
||||||
|
# After state
|
||||||
|
# ------------
|
||||||
|
# vyos@vyos:~$ show configuration commands | grep bond
|
||||||
|
# set interfaces bonding bond2
|
||||||
|
# set interfaces bonding bond3
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
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:
|
||||||
|
- 'set interfaces bonding bond2'
|
||||||
|
- 'set interfaces bonding bond2 hash-policy layer2'
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.network.vyos.argspec.lag_interfaces. \
|
||||||
|
lag_interfaces import Lag_interfacesArgs
|
||||||
|
from ansible.module_utils.network.vyos.config.lag_interfaces.lag_interfaces import Lag_interfaces
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Main entry point for module execution
|
||||||
|
|
||||||
|
:returns: the result form module invocation
|
||||||
|
"""
|
||||||
|
required_if = [('state', 'merged', ('config',)),
|
||||||
|
('state', 'replaced', ('config',)),
|
||||||
|
('state', 'overridden', ('config',))]
|
||||||
|
module = AnsibleModule(argument_spec=Lag_interfacesArgs.argument_spec, required_if=required_if,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
result = Lag_interfaces(module).execute_module()
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
testcase: "[^_].*"
|
||||||
|
test_items: []
|
|
@ -0,0 +1,2 @@
|
||||||
|
dependencies:
|
||||||
|
- prepare_vyos_tests
|
19
test/integration/targets/vyos_lag_interfaces/tasks/cli.yaml
Normal file
19
test/integration/targets/vyos_lag_interfaces/tasks/cli.yaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
- 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 }}"
|
||||||
|
|
||||||
|
- 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,8 @@
|
||||||
|
---
|
||||||
|
- name: Add Bond
|
||||||
|
cli_config:
|
||||||
|
config: "{{ lines }}"
|
||||||
|
vars:
|
||||||
|
lines: |
|
||||||
|
set interfaces bonding bond0
|
||||||
|
set interfaces bonding bond1
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
- name: Setup
|
||||||
|
cli_config:
|
||||||
|
config: "{{ lines }}"
|
||||||
|
vars:
|
||||||
|
lines: |
|
||||||
|
set interfaces bonding bond0
|
||||||
|
set interfaces bonding bond0 hash-policy 'layer2'
|
||||||
|
set interfaces bonding bond0 mode 'active-backup'
|
||||||
|
set interfaces ethernet eth1 bond-group bond0
|
||||||
|
set interfaces bonding bond1
|
||||||
|
set interfaces bonding bond0 primary 'eth1'
|
||||||
|
set interfaces bonding bond1 hash-policy 'layer2+3'
|
||||||
|
set interfaces bonding bond1 mode 'active-backup'
|
||||||
|
set interfaces ethernet eth2 bond-group bond1
|
||||||
|
set interfaces bonding bond1 primary 'eth2'
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
- name: Remove Bond
|
||||||
|
cli_config:
|
||||||
|
config: "{{ lines }}"
|
||||||
|
vars:
|
||||||
|
lines: |
|
||||||
|
delete interfaces bonding bond0
|
||||||
|
delete interfaces bonding bond1
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
- name: Remove Config
|
||||||
|
cli_config:
|
||||||
|
config: "{{ lines }}"
|
||||||
|
vars:
|
||||||
|
lines: |
|
||||||
|
delete interfaces bonding bond0 hash-policy
|
||||||
|
delete interfaces ethernet eth1 bond-group bond0
|
||||||
|
delete interfaces bonding bond0 mode
|
||||||
|
delete interfaces bonding bond0 primary
|
||||||
|
delete interfaces bonding bond1 hash-policy
|
||||||
|
delete interfaces ethernet eth2 bond-group bond1
|
||||||
|
delete interfaces bonding bond1 mode
|
||||||
|
delete interfaces bonding bond1 primary
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
- debug:
|
||||||
|
msg: "Start vyos_lag_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- include_tasks: _populate.yaml
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Delete attributes of given LAG interfaces.
|
||||||
|
vyos_lag_interfaces: &deleted
|
||||||
|
config:
|
||||||
|
- name: bond0
|
||||||
|
- name: bond1
|
||||||
|
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 attributes of given interfaces (IDEMPOTENT)
|
||||||
|
vyos_lag_interfaces: *deleted
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Assert that the previous task was idempotent
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
|
||||||
|
- 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
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
- debug:
|
||||||
|
msg: "START vyos_lag_interfaces merged integration tests on connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- include_tasks: _remove_config.yaml
|
||||||
|
|
||||||
|
- include_tasks: _remove_bond.yaml
|
||||||
|
|
||||||
|
- include_tasks: _add_bond.yaml
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Merge the provided configuration with the exisiting running configuration
|
||||||
|
vyos_lag_interfaces: &merged
|
||||||
|
config:
|
||||||
|
- name: bond0
|
||||||
|
hash_policy: "layer2"
|
||||||
|
mode: "active-backup"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
primary: eth1
|
||||||
|
|
||||||
|
- name: bond1
|
||||||
|
hash_policy: "layer2+3"
|
||||||
|
mode: "active-backup"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
primary: eth2
|
||||||
|
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)
|
||||||
|
vyos_lag_interfaces: *merged
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Assert that the previous task was idempotent
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "result['changed'] == false"
|
||||||
|
|
||||||
|
- name: Assert that before dicts were correctly generated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ merged['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- include_tasks: _remove_config.yaml
|
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
- debug:
|
||||||
|
msg: "START vyos_lag_interfaces overridden integration tests on connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- include_tasks: _remove_config.yaml
|
||||||
|
|
||||||
|
- include_tasks: _remove_bond.yaml
|
||||||
|
|
||||||
|
- include_tasks: _populate.yaml
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Overrides all device configuration with provided configuration
|
||||||
|
vyos_lag_interfaces: &overridden
|
||||||
|
config:
|
||||||
|
- name: bond1
|
||||||
|
mode: "active-backup"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
primary: eth2
|
||||||
|
hash_policy: layer2
|
||||||
|
state: overridden
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Assert that before dicts were correctly generated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||||
|
|
||||||
|
- name: Assert that correct commands were generated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ overridden['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||||
|
|
||||||
|
- name: Assert that after dicts were correctly generated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ overridden['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||||
|
|
||||||
|
- name: Overrides all device configuration with provided configurations (IDEMPOTENT)
|
||||||
|
vyos_lag_interfaces: *overridden
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Assert that the previous task was idempotent
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "result['changed'] == false"
|
||||||
|
|
||||||
|
- name: Assert that before dicts were correctly generated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ overridden['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- include_tasks: _remove_config.yaml
|
|
@ -0,0 +1,51 @@
|
||||||
|
---
|
||||||
|
- debug:
|
||||||
|
msg: "START vyos_lag_interfaces replaced integration tests on connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- include_tasks: _remove_config.yaml
|
||||||
|
|
||||||
|
- include_tasks: _populate.yaml
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Replace device configurations of listed LAG interfaces with provided configurations
|
||||||
|
vyos_lag_interfaces: &replaced
|
||||||
|
config:
|
||||||
|
- name: bond1
|
||||||
|
mode: "802.3ad"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
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 LAG interfaces with provided configurarions (IDEMPOTENT)
|
||||||
|
vyos_lag_interfaces: *replaced
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Assert that task was idempotent
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "result['changed'] == false"
|
||||||
|
|
||||||
|
- name: Assert that before dict is correctly generated
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ replaced['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- include_tasks: _remove_config.yaml
|
|
@ -0,0 +1,69 @@
|
||||||
|
---
|
||||||
|
- debug:
|
||||||
|
msg: "START vyos_lag_interfaces round trip integration tests on connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- include_tasks: _remove_config.yaml
|
||||||
|
|
||||||
|
- include_tasks: _remove_bond.yaml
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Apply the provided configuration (base config)
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config:
|
||||||
|
- name: bond0
|
||||||
|
hash_policy: "layer2"
|
||||||
|
mode: "active-backup"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
primary: eth1
|
||||||
|
|
||||||
|
- name: bond1
|
||||||
|
hash_policy: "layer2+3"
|
||||||
|
mode: "active-backup"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
primary: eth2
|
||||||
|
|
||||||
|
state: merged
|
||||||
|
register: base_config
|
||||||
|
|
||||||
|
- name: Gather lag_interfaces facts
|
||||||
|
vyos_facts:
|
||||||
|
gather_subset:
|
||||||
|
- default
|
||||||
|
gather_network_resources:
|
||||||
|
- lag_interfaces
|
||||||
|
|
||||||
|
- name: Apply the provided configuration (config to be reverted)
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config:
|
||||||
|
- name: bond0
|
||||||
|
hash_policy: "layer2+3"
|
||||||
|
mode: "802.3ad"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
|
||||||
|
- name: bond1
|
||||||
|
hash_policy: "layer2"
|
||||||
|
mode: "xor-hash"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
state: merged
|
||||||
|
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
|
||||||
|
vyos_lag_interfaces:
|
||||||
|
config: "{{ ansible_facts['network_resources']['lag_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
|
115
test/integration/targets/vyos_lag_interfaces/vars/main.yaml
Normal file
115
test/integration/targets/vyos_lag_interfaces/vars/main.yaml
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
---
|
||||||
|
merged:
|
||||||
|
before:
|
||||||
|
- name: "bond0"
|
||||||
|
|
||||||
|
- name: "bond1"
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- "set interfaces bonding bond0 hash-policy 'layer2'"
|
||||||
|
- "set interfaces bonding bond0 mode 'active-backup'"
|
||||||
|
- "set interfaces ethernet eth1 bond-group 'bond0'"
|
||||||
|
- "set interfaces bonding bond0 primary 'eth1'"
|
||||||
|
- "set interfaces bonding bond1 hash-policy 'layer2+3'"
|
||||||
|
- "set interfaces bonding bond1 mode 'active-backup'"
|
||||||
|
- "set interfaces ethernet eth2 bond-group 'bond1'"
|
||||||
|
- "set interfaces bonding bond1 primary 'eth2'"
|
||||||
|
|
||||||
|
after:
|
||||||
|
- name: "bond0"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
mode: "active-backup"
|
||||||
|
primary: eth1
|
||||||
|
|
||||||
|
- name: "bond1"
|
||||||
|
hash_policy: "layer2+3"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
mode: "active-backup"
|
||||||
|
primary: eth2
|
||||||
|
|
||||||
|
populate:
|
||||||
|
- name: "bond0"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
mode: "active-backup"
|
||||||
|
primary: eth1
|
||||||
|
|
||||||
|
- name: "bond1"
|
||||||
|
hash_policy: "layer2+3"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
mode: "active-backup"
|
||||||
|
primary: eth2
|
||||||
|
|
||||||
|
replaced:
|
||||||
|
commands:
|
||||||
|
- "delete interfaces bonding bond1 primary"
|
||||||
|
- "set interfaces bonding bond1 hash-policy 'layer2'"
|
||||||
|
- "set interfaces bonding bond1 mode '802.3ad'"
|
||||||
|
|
||||||
|
after:
|
||||||
|
- name: "bond0"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
mode: "active-backup"
|
||||||
|
primary: eth1
|
||||||
|
|
||||||
|
- name: "bond1"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
mode: "802.3ad"
|
||||||
|
|
||||||
|
overridden:
|
||||||
|
commands:
|
||||||
|
- "delete interfaces bonding bond0 hash-policy"
|
||||||
|
- "delete interfaces ethernet eth1 bond-group 'bond0'"
|
||||||
|
- "delete interfaces bonding bond0 mode"
|
||||||
|
- "delete interfaces bonding bond0 primary"
|
||||||
|
- "set interfaces bonding bond1 hash-policy 'layer2'"
|
||||||
|
|
||||||
|
after:
|
||||||
|
- name: "bond0"
|
||||||
|
- name: "bond1"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
mode: "active-backup"
|
||||||
|
primary: eth2
|
||||||
|
|
||||||
|
deleted:
|
||||||
|
commands:
|
||||||
|
- "delete interfaces bonding bond0 hash-policy"
|
||||||
|
- "delete interfaces ethernet eth1 bond-group 'bond0'"
|
||||||
|
- "delete interfaces bonding bond0 mode"
|
||||||
|
- "delete interfaces bonding bond0 primary"
|
||||||
|
- "delete interfaces bonding bond1 hash-policy"
|
||||||
|
- "delete interfaces ethernet eth2 bond-group 'bond1'"
|
||||||
|
- "delete interfaces bonding bond1 mode"
|
||||||
|
- "delete interfaces bonding bond1 primary"
|
||||||
|
|
||||||
|
after:
|
||||||
|
- name: "bond0"
|
||||||
|
|
||||||
|
- name: "bond1"
|
||||||
|
|
||||||
|
round_trip:
|
||||||
|
after:
|
||||||
|
- name: "bond0"
|
||||||
|
hash_policy: "layer2+3"
|
||||||
|
members:
|
||||||
|
- member: eth1
|
||||||
|
mode: "802.3ad"
|
||||||
|
primary: eth1
|
||||||
|
|
||||||
|
- name: "bond1"
|
||||||
|
hash_policy: "layer2"
|
||||||
|
members:
|
||||||
|
- member: eth2
|
||||||
|
mode: "xor-hash"
|
||||||
|
primary: eth2
|
|
@ -5228,14 +5228,14 @@ lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E326
|
||||||
lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E337
|
lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E337
|
||||||
lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E338
|
lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E338
|
||||||
lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E340
|
lib/ansible/modules/network/vyos/_vyos_l3_interface.py validate-modules:E340
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py future-import-boilerplate
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py future-import-boilerplate
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py metaclass-boilerplate
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py metaclass-boilerplate
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py validate-modules:E322
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E322
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py validate-modules:E324
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E324
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py validate-modules:E326
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E326
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py validate-modules:E337
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E337
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py validate-modules:E338
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E338
|
||||||
lib/ansible/modules/network/vyos/vyos_linkagg.py validate-modules:E340
|
lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E340
|
||||||
lib/ansible/modules/network/vyos/vyos_lldp.py future-import-boilerplate
|
lib/ansible/modules/network/vyos/vyos_lldp.py future-import-boilerplate
|
||||||
lib/ansible/modules/network/vyos/vyos_lldp.py metaclass-boilerplate
|
lib/ansible/modules/network/vyos/vyos_lldp.py metaclass-boilerplate
|
||||||
lib/ansible/modules/network/vyos/vyos_lldp.py validate-modules:E322
|
lib/ansible/modules/network/vyos/vyos_lldp.py validate-modules:E322
|
||||||
|
|
|
@ -14,13 +14,10 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from units.compat.mock import patch
|
from units.compat.mock import patch
|
||||||
from ansible.modules.network.vyos import vyos_facts
|
from ansible.modules.network.vyos import vyos_facts
|
||||||
from units.modules.utils import set_module_args
|
from units.modules.utils import set_module_args
|
||||||
|
@ -28,7 +25,6 @@ from .vyos_module import TestVyosModule, load_fixture
|
||||||
|
|
||||||
|
|
||||||
class TestVyosFactsModule(TestVyosModule):
|
class TestVyosFactsModule(TestVyosModule):
|
||||||
|
|
||||||
module = vyos_facts
|
module = vyos_facts
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -61,7 +57,6 @@ class TestVyosFactsModule(TestVyosModule):
|
||||||
def load_from_file(*args, **kwargs):
|
def load_from_file(*args, **kwargs):
|
||||||
module, commands = args
|
module, commands = args
|
||||||
output = list()
|
output = list()
|
||||||
|
|
||||||
for item in commands:
|
for item in commands:
|
||||||
try:
|
try:
|
||||||
obj = json.loads(item)
|
obj = json.loads(item)
|
||||||
|
@ -71,7 +66,6 @@ class TestVyosFactsModule(TestVyosModule):
|
||||||
filename = str(command).replace(' ', '_')
|
filename = str(command).replace(' ', '_')
|
||||||
output.append(load_fixture(filename))
|
output.append(load_fixture(filename))
|
||||||
return output
|
return output
|
||||||
|
|
||||||
self.run_commands.side_effect = load_from_file
|
self.run_commands.side_effect = load_from_file
|
||||||
|
|
||||||
def test_vyos_facts_default(self):
|
def test_vyos_facts_default(self):
|
||||||
|
|
Loading…
Reference in a new issue