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>
pull/60566/head
Rohit 5 years ago committed by GitHub
parent d8d00c36fa
commit 69bc24f607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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 = """

@ -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

@ -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

@ -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…
Cancel
Save