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.
|
||||
|
||||
* 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.
|
||||
|
||||
* ``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.
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
@ -22,7 +20,9 @@ class FactsArgs(object): # pylint: disable=R0903
|
|||
'interfaces',
|
||||
'!interfaces',
|
||||
'l3_interfaces',
|
||||
'!l3_interfaces'
|
||||
'!l3_interfaces',
|
||||
'lag_interfaces',
|
||||
'!lag_interfaces'
|
||||
]
|
||||
|
||||
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.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.lag_interfaces.lag_interfaces import Lag_interfacesFacts
|
||||
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(
|
||||
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)
|
||||
|
||||
# utils
|
||||
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
@ -66,3 +64,34 @@ def diff_list_of_dicts(want, have):
|
|||
diff.append(dict((x, y) for x, y in element))
|
||||
|
||||
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',
|
||||
'status': ['preview'],
|
||||
'status': ['deprecated'],
|
||||
'supported_by': 'network'}
|
||||
|
||||
|
||||
|
@ -33,6 +33,10 @@ short_description: Manage link aggregation groups on VyOS network devices
|
|||
description:
|
||||
- This module provides declarative management of link aggregation groups
|
||||
on VyOS network devices.
|
||||
deprecated:
|
||||
removed_in: '2.13'
|
||||
alternative: vyos_lag_interfaces
|
||||
why: Updated modules released with more functionality.
|
||||
notes:
|
||||
- Tested against VYOS 1.1.7
|
||||
options:
|
||||
|
@ -40,22 +44,27 @@ options:
|
|||
description:
|
||||
- Name of the link aggregation group.
|
||||
required: true
|
||||
type: str
|
||||
mode:
|
||||
description:
|
||||
- Mode of the link aggregation group.
|
||||
choices: ['802.3ad', 'active-backup', 'broadcast',
|
||||
'round-robin', 'transmit-load-balance',
|
||||
'adaptive-load-balance', 'xor-hash', 'on']
|
||||
type: str
|
||||
members:
|
||||
description:
|
||||
- List of members of the link aggregation group.
|
||||
type: list
|
||||
aggregate:
|
||||
description: List of link aggregation definitions.
|
||||
type: list
|
||||
state:
|
||||
description:
|
||||
- State of the link aggregation group.
|
||||
default: present
|
||||
choices: ['present', 'absent', 'up', 'down']
|
||||
type: str
|
||||
extends_documentation_fragment: vyos
|
||||
"""
|
||||
|
|
@ -27,6 +27,7 @@ description:
|
|||
author:
|
||||
- Nathaniel Case (@qalthos)
|
||||
- Nilashish Chakraborty (@Nilashishc)
|
||||
- Rohit Thakur (@rohitthakur2590)
|
||||
extends_documentation_fragment: vyos
|
||||
notes:
|
||||
- Tested against VyOS 1.1.8
|
||||
|
@ -51,7 +52,7 @@ options:
|
|||
specific subset should not be collected.
|
||||
required: false
|
||||
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 = """
|
||||
|
|
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:E338
|
||||
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 metaclass-boilerplate
|
||||
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:E326
|
||||
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:E340
|
||||
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 validate-modules:E322
|
||||
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:E337
|
||||
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_lldp.py future-import-boilerplate
|
||||
lib/ansible/modules/network/vyos/vyos_lldp.py metaclass-boilerplate
|
||||
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
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
|
||||
from units.compat.mock import patch
|
||||
from ansible.modules.network.vyos import vyos_facts
|
||||
from units.modules.utils import set_module_args
|
||||
|
@ -28,7 +25,6 @@ from .vyos_module import TestVyosModule, load_fixture
|
|||
|
||||
|
||||
class TestVyosFactsModule(TestVyosModule):
|
||||
|
||||
module = vyos_facts
|
||||
|
||||
def setUp(self):
|
||||
|
@ -61,7 +57,6 @@ class TestVyosFactsModule(TestVyosModule):
|
|||
def load_from_file(*args, **kwargs):
|
||||
module, commands = args
|
||||
output = list()
|
||||
|
||||
for item in commands:
|
||||
try:
|
||||
obj = json.loads(item)
|
||||
|
@ -71,7 +66,6 @@ class TestVyosFactsModule(TestVyosModule):
|
|||
filename = str(command).replace(' ', '_')
|
||||
output.append(load_fixture(filename))
|
||||
return output
|
||||
|
||||
self.run_commands.side_effect = load_from_file
|
||||
|
||||
def test_vyos_facts_default(self):
|
||||
|
|
Loading…
Reference in a new issue