diff --git a/changelogs/fragments/T7010-lag-interfaces-integration-tests.yaml b/changelogs/fragments/T7010-lag-interfaces-integration-tests.yaml
new file mode 100644
index 00000000..8a236f5b
--- /dev/null
+++ b/changelogs/fragments/T7010-lag-interfaces-integration-tests.yaml
@@ -0,0 +1,4 @@
+---
+minor_changes:
+ - fix integration tests for `lag_interfaces`
+ - add unit tests for `lag_interfaces`
diff --git a/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py b/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py
index 835615b9..6890fe0c 100644
--- a/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py
+++ b/plugins/module_utils/network/vyos/config/lag_interfaces/lag_interfaces.py
@@ -1,435 +1,433 @@
# 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.six import iteritems
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
ConfigBase,
)
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
dict_diff,
to_list,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (
get_lst_diff_for_dicts,
list_diff_have_only,
list_diff_want_only,
search_obj_in_list,
)
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, data=None):
"""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,
data=data,
)
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}
warnings = list()
commands = list()
if self.state in self.ACTION_STATES:
existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
else:
existing_lag_interfaces_facts = []
if self.state in self.ACTION_STATES or self.state == "rendered":
commands.extend(self.set_config(existing_lag_interfaces_facts))
if commands and self.state in self.ACTION_STATES:
if not self._module.check_mode:
self._connection.edit_config(commands)
result["changed"] = True
if self.state in self.ACTION_STATES:
result["commands"] = commands
if self.state in self.ACTION_STATES or self.state == "gathered":
changed_lag_interfaces_facts = self.get_lag_interfaces_facts()
elif self.state == "rendered":
result["rendered"] = commands
elif self.state == "parsed":
running_config = self._module.params["running_config"]
if not running_config:
self._module.fail_json(
msg="value of running_config parameter must not be empty for state parsed",
)
result["parsed"] = self.get_lag_interfaces_facts(data=running_config)
else:
changed_lag_interfaces_facts = []
if self.state in self.ACTION_STATES:
result["before"] = existing_lag_interfaces_facts
if result["changed"]:
result["after"] = changed_lag_interfaces_facts
elif self.state == "gathered":
result["gathered"] = 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 = []
if self.state in ("merged", "replaced", "overridden", "rendered") and not want:
self._module.fail_json(
msg="value of config parameter must not be empty for state {0}".format(self.state),
)
if self.state == "overridden":
commands.extend(self._state_overridden(want, have))
elif self.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 self.state in ("merged", "rendered"):
commands.extend(self._state_merged(want_item, obj_in_have))
elif self.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",
+ "member interface",
+ key["member"],
),
)
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=want["name"] + " arp-monitor",
attrib="interval",
value=str(arp_monitor["interval"]),
),
)
if diff_targets:
for target in diff_targets:
commands.append(
self._compute_command(
key=want["name"] + " arp-monitor",
attrib="target",
value=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"],
+ "member interface",
+ member["member"],
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 {}
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(
self._compute_command(
key=have["name"] + " arp-monitor",
attrib="interval",
remove=True,
),
)
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(
self._compute_command(
key=have["name"] + " arp-monitor",
attrib="target",
value=target,
remove=True,
),
)
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["member"],
"bond-group",
have["name"],
True,
"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
diff --git a/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py b/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py
index 78638bb7..8e1c8624 100644
--- a/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py
+++ b/plugins/module_utils/network/vyos/facts/lag_interfaces/lag_interfaces.py
@@ -1,137 +1,145 @@
#
# -*- 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 copy import deepcopy
from re import M, findall, search
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
from ansible_collections.vyos.vyos.plugins.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 get_config(self, connection):
+ """Get the configuration from the device
+ :param connection: the device connection
+ :rtype: string
+ :returns: The configuration
+ """
+ return connection.get_config()
+
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()
+ data = self.get_config(connection)
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)
members = []
member = {}
- group_regex = r".*eth.* '%s'" % lag
+ group_regex = r"%s member interface .*eth.*" % lag
g_cfg = findall(group_regex, data, M)
for item in g_cfg:
- output = search("^set interfaces ethernet (\\S+)", item, M)
+ output = search("member interface '(\\S+)'", item, M)
if output:
member["member"] = output.group(1).strip("'")
- members.append(member)
+ members.append(deepcopy(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
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_add_bond.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_add_bond.yaml
index fa191ed3..3c6743c2 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_add_bond.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_add_bond.yaml
@@ -1,8 +1,8 @@
---
- ansible.builtin.include_tasks: _remove_bond.yaml
- name: Add Bond
- vars:
- lines: "set interfaces bonding bond0\nset interfaces bonding bond1\n"
ansible.netcommon.cli_config:
- config: "{{ lines }}"
+ config: |-
+ set interfaces bonding bond0
+ set interfaces bonding bond1
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_parsed_config.cfg
index 1a275bdd..d9f18551 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_parsed_config.cfg
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_parsed_config.cfg
@@ -1,8 +1,8 @@
set interfaces bonding bond0 hash-policy 'layer2'
set interfaces bonding bond0 mode 'active-backup'
set interfaces bonding bond0 primary 'eth1'
set interfaces bonding bond1 hash-policy 'layer2+3'
set interfaces bonding bond1 mode 'active-backup'
set interfaces bonding bond1 primary 'eth2'
-set interfaces ethernet eth1 bond-group 'bond0'
-set interfaces ethernet eth2 bond-group 'bond1'
+set interfaces bonding bond0 member interface 'eth1'
+set interfaces bonding bond1 member interface 'eth2'
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_populate.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_populate.yaml
index be0d6351..728a8cf0 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_populate.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_populate.yaml
@@ -1,18 +1,18 @@
---
- ansible.builtin.include_tasks: _add_bond.yaml
- name: Setup
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 bond0 member interface 'eth1'
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 member interface 'eth2'
set interfaces bonding bond1 primary 'eth2'
ansible.netcommon.cli_config:
config: "{{ lines }}"
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_remove_bond.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_remove_bond.yaml
index e22a6ca7..3643ae32 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/_remove_bond.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/_remove_bond.yaml
@@ -1,21 +1,21 @@
- name: Remove Config
vars:
lines: |-
delete interfaces bonding bond0 hash-policy
- delete interfaces ethernet eth1 bond-group bond0
+ delete interfaces bonding bond0 member interface 'eth1'
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 member interface 'eth2'
delete interfaces bonding bond1 mode
delete interfaces bonding bond1 primary
ansible.netcommon.cli_config:
config: "{{ lines }}"
- name: Remove Bond
vars:
lines: |
delete interfaces bonding bond0
delete interfaces bonding bond1
ansible.netcommon.cli_config:
config: "{{ lines }}"
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/deleted.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/deleted.yaml
index e30be078..d273f040 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/deleted.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/deleted.yaml
@@ -1,46 +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.
register: result
vyos.vyos.vyos_lag_interfaces: &id001
config:
- name: bond0
- name: bond1
state: deleted
- name: Assert that the before dicts were correctly generated
assert:
that:
- - "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
+ - 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 }}"
+ - 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 }}"
+ - deleted['after'] | symmetric_difference(result['after']) |length == 0
- name: Delete attributes of given interfaces (IDEMPOTENT)
register: result
vyos.vyos.vyos_lag_interfaces: *id001
- 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 }}"
+ - deleted['after'] | symmetric_difference(result['before']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/gathered.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/gathered.yaml
index f6c281f5..ff7f9c7d 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/gathered.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/gathered.yaml
@@ -1,20 +1,20 @@
---
- debug:
msg: START vyos_lag_interfaces gathered integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Gather the provided configuration with the existing running configuration
register: result
vyos.vyos.vyos_lag_interfaces:
config:
state: gathered
- name: Assert that gathered dicts was correctly generated
assert:
that:
- - "{{ populate | symmetric_difference(result['gathered']) |length == 0 }}"
+ - populate | symmetric_difference(result['gathered']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/merged.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/merged.yaml
index 64ac9a4a..2274f301 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/merged.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/merged.yaml
@@ -1,55 +1,55 @@
---
- debug:
msg: START vyos_lag_interfaces merged integration tests on connection={{ ansible_connection }}
- include_tasks: _add_bond.yaml
- block:
- name: Merge the provided configuration with the existing running configuration
register: result
vyos.vyos.vyos_lag_interfaces: &id001
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
- name: Assert that before dicts were correctly generated
assert:
- that: "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}"
+ 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 }}"
+ - 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 }}"
+ - merged['after'] | symmetric_difference(result['after']) |length == 0
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
register: result
vyos.vyos.vyos_lag_interfaces: *id001
- 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 }}"
+ - merged['after'] | symmetric_difference(result['before']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/overridden.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/overridden.yaml
index 482d54d1..b1f0065c 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/overridden.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/overridden.yaml
@@ -1,49 +1,49 @@
---
- debug:
msg: START vyos_lag_interfaces overridden integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Overrides all device configuration with provided configuration
register: result
vyos.vyos.vyos_lag_interfaces: &id001
config:
- name: bond1
mode: active-backup
members:
- member: eth2
primary: eth2
hash_policy: layer2
state: overridden
- name: Assert that before dicts were correctly generated
assert:
that:
- - "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
+ - populate | symmetric_difference(result['before']) |length == 0
- name: Assert that correct commands were generated
assert:
that:
- - "{{ overridden['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
+ - 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 }}"
+ - overridden['after'] | symmetric_difference(result['after']) |length == 0
- name: Overrides all device configuration with provided configurations (IDEMPOTENT)
register: result
vyos.vyos.vyos_lag_interfaces: *id001
- 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 }}"
+ - overridden['after'] | symmetric_difference(result['before']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/parsed.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/parsed.yaml
index 81a7b46d..c3dd4ff2 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/parsed.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/parsed.yaml
@@ -1,27 +1,27 @@
---
- debug:
msg: START vyos_lag_interfaces parsed integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Gather lag_interfaces facts
register: lag_interfaces_facts
vyos.vyos.vyos_facts:
gather_subset:
- default
gather_network_resources:
- lag_interfaces
- name: Provide the running configuration for parsing (config to be parsed)
register: result
vyos.vyos.vyos_lag_interfaces:
running_config: "{{ lookup('file', '_parsed_config.cfg') }}"
state: parsed
- name: Assert that correct parsing done
assert:
- that: "{{ ansible_facts['network_resources']['lag_interfaces'] | symmetric_difference(result['parsed']) |length == 0 }}"
+ that: ansible_facts['network_resources']['lag_interfaces'] | symmetric_difference(result['parsed']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/rendered.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/rendered.yaml
index 7d86a3ae..0241b7c4 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/rendered.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/rendered.yaml
@@ -1,32 +1,32 @@
---
- debug:
msg: START vyos_lag_interfaces rendered integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Structure provided configuration into device specific commands
register: result
vyos.vyos.vyos_lag_interfaces:
config:
- 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
state: rendered
- name: Assert that correct set of commands were generated
assert:
that:
- - "{{ rendered['commands'] | symmetric_difference(result['rendered']) |length == 0 }}"
+ - rendered['commands'] | symmetric_difference(result['rendered']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/replaced.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/replaced.yaml
index 66e55df7..caf3f1d1 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/replaced.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/replaced.yaml
@@ -1,48 +1,48 @@
---
- debug:
msg: START vyos_lag_interfaces replaced integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Replace device configurations of listed LAG interfaces with provided configurations
register: result
vyos.vyos.vyos_lag_interfaces: &id001
config:
- name: bond1
mode: 802.3ad
hash_policy: layer2
members:
- member: eth2
state: replaced
- name: Assert that correct set of commands were generated
assert:
that:
- - "{{ replaced['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
+ - 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 }}"
+ - 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 }}"
+ - replaced['after'] | symmetric_difference(result['after']) |length == 0
- name: Replace device configurations of listed LAG interfaces with provided configurarions (IDEMPOTENT)
register: result
vyos.vyos.vyos_lag_interfaces: *id001
- 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 }}"
+ - replaced['after'] | symmetric_difference(result['before']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/cli/rtt.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/cli/rtt.yaml
index 5e9dc752..b4c07abe 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/cli/rtt.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/cli/rtt.yaml
@@ -1,65 +1,65 @@
---
- debug:
msg: START vyos_lag_interfaces round trip integration tests on connection={{ ansible_connection }}
- include_tasks: _remove_bond.yaml
- block:
- name: Apply the provided configuration (base config)
register: base_config
vyos.vyos.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
- name: Gather lag_interfaces facts
vyos.vyos.vyos_facts:
gather_subset:
- default
gather_network_resources:
- lag_interfaces
- name: Apply the provided configuration (config to be reverted)
register: result
vyos.vyos.vyos_lag_interfaces:
config:
- name: bond0
hash_policy: layer2+3
- mode: 802.3ad
+ mode: transmit-load-balance
members:
- member: eth1
- name: bond1
hash_policy: layer2
- mode: xor-hash
+ mode: adaptive-load-balance
members:
- member: eth2
state: merged
- name: Assert that changes were applied
assert:
- that: "{{ round_trip['after'] | symmetric_difference(result['after']) |length == 0 }}"
+ that: round_trip['after'] | symmetric_difference(result['after']) |length == 0
- name: Revert back to base config using facts round trip
register: revert
vyos.vyos.vyos_lag_interfaces:
config: "{{ ansible_facts['network_resources']['lag_interfaces'] }}"
state: overridden
- name: Assert that config was reverted
assert:
- that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length == 0 }}"
+ that: base_config['after'] | symmetric_difference(revert['after']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/tests/redirection/cli/shortname.yaml b/tests/integration/targets/vyos_lag_interfaces/tests/redirection/cli/shortname.yaml
index 40c5fe2b..fd2c10a5 100644
--- a/tests/integration/targets/vyos_lag_interfaces/tests/redirection/cli/shortname.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/tests/redirection/cli/shortname.yaml
@@ -1,55 +1,55 @@
---
- debug:
msg: START lag_interfaces merged on connection={{ ansible_connection }}
- include_tasks: _add_bond.yaml
- block:
- name: Merge the provided configuration with the existing running configuration
register: result
vyos.vyos.lag_interfaces: &id001
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
- name: Assert that before dicts were correctly generated
assert:
- that: "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}"
+ 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 }}"
+ - 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 }}"
+ - merged['after'] | symmetric_difference(result['after']) |length == 0
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
register: result
vyos.vyos.lag_interfaces: *id001
- 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 }}"
+ - merged['after'] | symmetric_difference(result['before']) |length == 0
always:
- include_tasks: _remove_bond.yaml
diff --git a/tests/integration/targets/vyos_lag_interfaces/vars/main.yaml b/tests/integration/targets/vyos_lag_interfaces/vars/main.yaml
index 9784fb97..40b6a9d8 100644
--- a/tests/integration/targets/vyos_lag_interfaces/vars/main.yaml
+++ b/tests/integration/targets/vyos_lag_interfaces/vars/main.yaml
@@ -1,109 +1,109 @@
---
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 member interface 'eth1'
- 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 member interface 'eth2'
- 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 member interface 'eth1'
- 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 member interface 'eth1'
- 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 member interface 'eth2'
- delete interfaces bonding bond1 mode
- delete interfaces bonding bond1 primary
after:
- name: bond0
- name: bond1
rendered:
commands:
- set interfaces bonding bond0 hash-policy 'layer2'
- - set interfaces ethernet eth1 bond-group 'bond0'
+ - set interfaces bonding bond0 member interface 'eth1'
- set interfaces bonding bond0 mode 'active-backup'
- set interfaces bonding bond0 primary 'eth1'
- set interfaces bonding bond1 hash-policy 'layer2+3'
- - set interfaces ethernet eth2 bond-group 'bond1'
+ - set interfaces bonding bond1 member interface 'eth2'
- set interfaces bonding bond1 mode 'active-backup'
- set interfaces bonding bond1 primary 'eth2'
round_trip:
after:
- name: bond0
hash_policy: layer2+3
members:
- member: eth1
- mode: 802.3ad
+ mode: transmit-load-balance
primary: eth1
- name: bond1
hash_policy: layer2
members:
- member: eth2
- mode: xor-hash
+ mode: adaptive-load-balance
primary: eth2
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_lag_interfaces_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_lag_interfaces_config.cfg
new file mode 100644
index 00000000..645cbdb1
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_lag_interfaces_config.cfg
@@ -0,0 +1,5 @@
+set interfaces bonding bond0 member interface 'eth0'
+set interfaces bonding bond0 member interface 'eth1'
+set interfaces bonding bond0 primary 'eth0'
+set interfaces bonding bond0 mode '802.3ad'
+set interfaces bonding bond0 hash-policy 'layer2+3'
diff --git a/tests/unit/modules/network/vyos/test_vyos_interfaces.py b/tests/unit/modules/network/vyos/test_vyos_interfaces.py
index 8549d768..f4a5d2a5 100644
--- a/tests/unit/modules/network/vyos/test_vyos_interfaces.py
+++ b/tests/unit/modules/network/vyos/test_vyos_interfaces.py
@@ -1,452 +1,452 @@
# (c) 2016 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see .
# Make coding more python3-ish
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from unittest.mock import patch
from ansible_collections.vyos.vyos.plugins.modules import vyos_interfaces
from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args
from .vyos_module import TestVyosModule, load_fixture
-class TestVyosFirewallInterfacesModule(TestVyosModule):
+class TestVyosInterfacesModule(TestVyosModule):
module = vyos_interfaces
def setUp(self):
- super(TestVyosFirewallInterfacesModule, self).setUp()
+ super(TestVyosInterfacesModule, self).setUp()
self.mock_get_config = patch(
"ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config",
)
self.get_config = self.mock_get_config.start()
self.mock_load_config = patch(
"ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config",
)
self.load_config = self.mock_load_config.start()
self.mock_get_resource_connection_config = patch(
"ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection",
)
self.get_resource_connection_config = self.mock_get_resource_connection_config.start()
self.mock_get_resource_connection_facts = patch(
"ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection",
)
self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start()
self.mock_execute_show_command = patch(
"ansible_collections.vyos.vyos.plugins.module_utils.network.vyos."
"facts.interfaces.interfaces.InterfacesFacts.get_device_data",
)
self.execute_show_command = self.mock_execute_show_command.start()
# define the default fixture for the vyos_interfaces module
self.fixture_path = "vyos_interfaces_config.cfg"
def tearDown(self):
- super(TestVyosFirewallInterfacesModule, self).tearDown()
+ super(TestVyosInterfacesModule, self).tearDown()
self.mock_get_resource_connection_config.stop()
self.mock_get_resource_connection_facts.stop()
self.mock_get_config.stop()
self.mock_load_config.stop()
self.mock_execute_show_command.stop()
def load_fixtures(self, commands=None, filename=None):
def load_from_file(*args, **kwargs):
return load_fixture(self.fixture_path)
self.execute_show_command.side_effect = load_from_file
def test_vyos_interfaces_merged(self):
set_module_args(
dict(
config=[
dict(name="bond1", description="Bond - 1", enabled=True),
dict(name="vtun1", description="vtun - 1", enabled=True),
dict(name="wg01", description="wg - 1", enabled=True),
],
state="merged",
),
)
commands = [
"set interfaces bonding bond1 description 'Bond - 1'",
"set interfaces openvpn vtun1 description 'vtun - 1'",
"set interfaces wireguard wg01 description 'wg - 1'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_merged_retain_vif(self):
# we have a vif in eth1 at this point, so that should be retained
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(name="bond1", description="Bond - 1", enabled=True),
dict(name="vtun1", description="vtun - 1", enabled=True),
dict(name="wg01", description="wg - 1", enabled=True),
],
state="merged",
),
)
commands = [
"set interfaces bonding bond1 description 'Bond - 1'",
"set interfaces openvpn vtun1 description 'vtun - 1'",
"set interfaces wireguard wg01 description 'wg - 1'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_merged_additional_vif(self):
# we have a vif in eth1 at this point, so that should be retained
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(
name="eth1",
vifs=[
dict(
vlan_id=105,
description="vlan 105",
),
],
),
],
state="merged",
),
)
commands = [
"set interfaces ethernet eth1 vif 105 description 'vlan 105'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_merged_idempotent(self):
set_module_args(
dict(
config=[
dict(
name="wg02",
description="wire guard int 2",
enabled=True,
),
],
state="merged",
),
)
self.execute_module(changed=False, commands=[])
def test_vyos_interfaces_merged_newinterface(self):
set_module_args(
dict(
config=[
dict(
name="eth4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
dict(name="eth1", description="Configured by Ansible"),
],
state="merged",
),
)
commands = [
"set interfaces ethernet eth1 description 'Configured by Ansible'",
"set interfaces ethernet eth4 description 'Ethernet 4'",
"set interfaces ethernet eth4 duplex 'auto'",
"set interfaces ethernet eth4 speed 'auto'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_replaced_newinterface(self):
set_module_args(
dict(
config=[
dict(
name="eth4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
dict(name="eth1", description="Configured by Ansible"),
],
state="replaced",
),
)
commands = [
"set interfaces ethernet eth1 description 'Configured by Ansible'",
"set interfaces ethernet eth4 description 'Ethernet 4'",
"set interfaces ethernet eth4 duplex 'auto'",
"set interfaces ethernet eth4 speed 'auto'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_replaced_remove_vif(self):
# we have a vif in eth1 at this point, so that should be removed
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(
name="eth4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
dict(name="eth1", description="Configured by Ansible"),
],
state="replaced",
),
)
commands = [
"delete interfaces ethernet eth1 vif 200",
"delete interfaces ethernet eth1 vif 201",
"set interfaces ethernet eth1 description 'Configured by Ansible'",
"set interfaces ethernet eth4 description 'Ethernet 4'",
"set interfaces ethernet eth4 duplex 'auto'",
"set interfaces ethernet eth4 speed 'auto'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_merged_enable_vif(self):
# merge in enabling vif
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(
name="eth1",
vifs=[
dict(
vlan_id=201,
enabled=True,
),
],
),
],
state="merged",
),
)
commands = [
"delete interfaces ethernet eth1 vif 201 disable",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_replaced_retain_vif(self):
# we have a vif in eth1 at this point, so that should be removed
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(
name="eth4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
dict(
name="eth1",
description="Configured by Ansible",
vifs=[
dict(
vlan_id=200,
),
dict(
vlan_id=201,
description="VIF eth1.201",
enabled=True,
),
],
),
],
state="replaced",
),
)
commands = [
"delete interfaces ethernet eth1 vif 200 description",
"delete interfaces ethernet eth1 vif 201 disable",
"set interfaces ethernet eth1 description 'Configured by Ansible'",
"set interfaces ethernet eth4 description 'Ethernet 4'",
"set interfaces ethernet eth4 duplex 'auto'",
"set interfaces ethernet eth4 speed 'auto'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_overridden_newinterface(self):
set_module_args(
dict(
config=[
dict(
name="eth4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
dict(name="eth1", description="Configured by Ansible"),
],
state="overridden",
),
)
commands = [
"set interfaces ethernet eth1 description 'Configured by Ansible'",
"set interfaces ethernet eth4 description 'Ethernet 4'",
"set interfaces ethernet eth4 duplex 'auto'",
"set interfaces ethernet eth4 speed 'auto'",
"delete interfaces wireguard wg02 description",
"delete interfaces ethernet eth3 description",
"delete interfaces ethernet eth3 disable",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_overridden_remove_vif(self):
# we have a vif in eth1 at this point, so that should be removed
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(
name="eth4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
dict(name="eth1", description="Configured by Ansible"),
],
state="overridden",
),
)
commands = [
"set interfaces ethernet eth1 description 'Configured by Ansible'",
"set interfaces ethernet eth4 description 'Ethernet 4'",
"set interfaces ethernet eth4 duplex 'auto'",
"set interfaces ethernet eth4 speed 'auto'",
"delete interfaces wireguard wg02 description",
"delete interfaces ethernet eth3 description",
"delete interfaces ethernet eth3 disable",
"delete interfaces ethernet eth1 vif 200",
"delete interfaces ethernet eth1 vif 201",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_idempotent_disable(self):
set_module_args(
dict(
config=[
dict(
name="eth3",
description="Ethernet 3",
enabled=False,
),
],
state="merged",
),
)
commands = []
self.execute_module(changed=False, commands=commands)
def test_vyos_interfaces_idempotent_disable_replace(self):
set_module_args(
dict(
config=[
dict(
name="eth3",
description="Ethernet 3",
enabled=False,
),
],
state="replaced",
),
)
commands = []
self.execute_module(changed=False, commands=commands)
def test_vyos_interfaces_deleted_remove_vif(self):
# we have a vif in eth1 at this point, so that should be removed
self.fixture_path = "vyos_interfaces_config_vif.cfg"
set_module_args(
dict(
config=[
dict(name="eth1"),
],
state="deleted",
),
)
commands = [
"delete interfaces ethernet eth1 vif 200",
"delete interfaces ethernet eth1 vif 201",
"delete interfaces ethernet eth1 description",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_deleted_remove_all(self):
# we have a vif in eth1 at this point, so that should be removed
set_module_args(
dict(
config=[],
state="deleted",
),
)
commands = [
"delete interfaces ethernet eth1 description",
"delete interfaces ethernet eth3 description",
"delete interfaces ethernet eth3 disable",
"delete interfaces wireguard wg02 description",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_interfaces_replaced_bad_name(self):
set_module_args(
dict(
config=[
dict(
name="int4",
description="Ethernet 4",
enabled=True,
speed="auto",
duplex="auto",
),
],
state="replaced",
),
)
self.execute_module(failed=True)
diff --git a/tests/unit/modules/network/vyos/test_vyos_lag_interfaces.py b/tests/unit/modules/network/vyos/test_vyos_lag_interfaces.py
new file mode 100644
index 00000000..406ca598
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_lag_interfaces.py
@@ -0,0 +1,157 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from unittest.mock import patch
+
+from ansible_collections.vyos.vyos.plugins.modules import vyos_lag_interfaces
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args
+
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosLagInterfacesModule(TestVyosModule):
+ module = vyos_lag_interfaces
+
+ def setUp(self):
+ super(TestVyosLagInterfacesModule, self).setUp()
+ self.mock_get_config = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config",
+ )
+ self.get_config = self.mock_get_config.start()
+
+ self.mock_load_config = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config",
+ )
+ self.load_config = self.mock_load_config.start()
+
+ self.mock_get_resource_connection_config = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection",
+ )
+ self.get_resource_connection_config = self.mock_get_resource_connection_config.start()
+
+ self.mock_get_resource_connection_facts = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection",
+ )
+ self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start()
+
+ self.mock_execute_show_command = patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos."
+ "facts.lag_interfaces.lag_interfaces.Lag_interfacesFacts.get_config",
+ )
+ self.execute_show_command = self.mock_execute_show_command.start()
+ # define the default fixture for the vyos_interfaces module
+ self.fixture_path = "vyos_lag_interfaces_config.cfg"
+
+ def tearDown(self):
+ super(TestVyosLagInterfacesModule, self).tearDown()
+ self.mock_get_resource_connection_config.stop()
+ self.mock_get_resource_connection_facts.stop()
+ self.mock_get_config.stop()
+ self.mock_load_config.stop()
+ self.mock_execute_show_command.stop()
+
+ def load_fixtures(self, commands=None, filename=None):
+ def load_from_file(*args, **kwargs):
+ return load_fixture(self.fixture_path)
+
+ self.execute_show_command.side_effect = load_from_file
+
+ def test_vyos_interfaces_merged(self):
+ set_module_args(
+ dict(
+ config=[
+ dict(
+ name="bond1",
+ members=[{"member": "eth2"}, {"member": "eth3"}],
+ mode="802.3ad",
+ hash_policy="layer2+3",
+ primary="eth2",
+ ),
+ ],
+ state="merged",
+ ),
+ )
+
+ commands = [
+ "set interfaces bonding bond1 member interface 'eth2'",
+ "set interfaces bonding bond1 member interface 'eth3'",
+ "set interfaces bonding bond1 primary 'eth2'",
+ "set interfaces bonding bond1 mode '802.3ad'",
+ "set interfaces bonding bond1 hash-policy 'layer2+3'",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_interfaces_replaced(self):
+ set_module_args(
+ dict(
+ config=[
+ dict(
+ name="bond1",
+ members=[{"member": "eth2"}, {"member": "eth3"}],
+ mode="802.3ad",
+ hash_policy="layer2+3",
+ primary="eth2",
+ ),
+ ],
+ state="replaced",
+ ),
+ )
+
+ commands = [
+ "set interfaces bonding bond1 member interface 'eth2'",
+ "set interfaces bonding bond1 member interface 'eth3'",
+ "set interfaces bonding bond1 primary 'eth2'",
+ "set interfaces bonding bond1 mode '802.3ad'",
+ "set interfaces bonding bond1 hash-policy 'layer2+3'",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_interfaces_overridden(self):
+ set_module_args(
+ dict(
+ config=[
+ dict(
+ name="bond1",
+ members=[{"member": "eth2"}, {"member": "eth3"}],
+ mode="802.3ad",
+ hash_policy="layer2+3",
+ primary="eth2",
+ ),
+ ],
+ state="overridden",
+ ),
+ )
+
+ commands = [
+ "delete interfaces bonding bond0 member interface 'eth0'",
+ "delete interfaces bonding bond0 member interface 'eth1'",
+ "delete interfaces bonding bond0 primary",
+ "delete interfaces bonding bond0 mode",
+ "delete interfaces bonding bond0 hash-policy",
+ "set interfaces bonding bond1 member interface 'eth2'",
+ "set interfaces bonding bond1 member interface 'eth3'",
+ "set interfaces bonding bond1 primary 'eth2'",
+ "set interfaces bonding bond1 mode '802.3ad'",
+ "set interfaces bonding bond1 hash-policy 'layer2+3'",
+ ]
+ self.execute_module(changed=True, commands=commands)