diff --git a/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py
index 275aaf3..b4cdadf 100644
--- a/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py
+++ b/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py
@@ -1,269 +1,273 @@
#
# -*- 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)
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
#############################################
# 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_ospfv2 module
"""
class Ospfv2Args(object): # pylint: disable=R0903
"""The arg spec for the vyos_ospfv2 module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
"config": {
"options": {
"auto_cost": {
"options": {"reference_bandwidth": {"type": "int"}},
"type": "dict",
},
"default_information": {
"options": {
"originate": {
"options": {
"always": {"type": "bool"},
"metric": {"type": "int"},
"metric_type": {"type": "int"},
"route_map": {"type": "str"},
},
"type": "dict",
}
},
"type": "dict",
},
"default_metric": {"type": "int"},
"distance": {
"options": {
"global": {"type": "int"},
"ospf": {
"options": {
"external": {"type": "int"},
"inter_area": {"type": "int"},
"intra_area": {"type": "int"},
},
"type": "dict",
},
},
"type": "dict",
},
"log_adjacency_changes": {
"choices": ["detail"],
"type": "str",
},
"max_metric": {
"options": {
"router_lsa": {
"options": {
"administrative": {"type": "bool"},
"on_shutdown": {"type": "int"},
"on_startup": {"type": "int"},
},
"type": "dict",
}
},
"type": "dict",
},
"mpls_te": {
"options": {
"enabled": {"type": "bool"},
"router_address": {"type": "str"},
},
"type": "dict",
},
"neighbor": {
"elements": "dict",
"options": {
"neighbor_id": {"type": "str"},
"poll_interval": {"type": "int"},
"priority": {"type": "int"},
},
"type": "list",
},
"areas": {
"elements": "dict",
"options": {
"area_id": {"type": "str"},
"area_type": {
"options": {
"normal": {"type": "bool"},
"nssa": {
"options": {
"default_cost": {"type": "int"},
"no_summary": {"type": "bool"},
"set": {"type": "bool"},
"translate": {
"choices": [
"always",
"candidate",
"never",
],
"type": "str",
},
},
"type": "dict",
},
"stub": {
"options": {
"default_cost": {"type": "int"},
"no_summary": {"type": "bool"},
"set": {"type": "bool"},
},
"type": "dict",
},
},
"type": "dict",
},
"authentication": {
"choices": ["plaintext-password", "md5"],
"type": "str",
},
"network": {
"elements": "dict",
"options": {
"address": {"required": True, "type": "str"}
},
"type": "list",
},
"range": {
"elements": "dict",
"options": {
"address": {"type": "str"},
"cost": {"type": "int"},
"not_advertise": {"type": "bool"},
"substitute": {"type": "str"},
},
"type": "list",
},
"shortcut": {
"choices": ["default", "disable", "enable"],
"type": "str",
},
"virtual_link": {
"elements": "dict",
"options": {
"address": {"type": "str"},
"authentication": {
"options": {
"md5": {
"elements": "dict",
"options": {
"key_id": {"type": "int"},
"md5_key": {"type": "str"},
},
"type": "list",
},
"plaintext_password": {"type": "str"},
},
"type": "dict",
},
"dead_interval": {"type": "int"},
"hello_interval": {"type": "int"},
"retransmit_interval": {"type": "int"},
"transmit_delay": {"type": "int"},
},
"type": "list",
},
},
"type": "list",
},
"parameters": {
"options": {
"abr_type": {
"choices": [
"cisco",
"ibm",
"shortcut",
"standard",
],
"type": "str",
},
"opaque_lsa": {"type": "bool"},
"rfc1583_compatibility": {"type": "bool"},
"router_id": {"type": "str"},
},
"type": "dict",
},
"passive_interface": {"type": "list"},
"passive_interface_exclude": {"type": "list"},
"redistribute": {
"elements": "dict",
"options": {
"metric": {"type": "int"},
"metric_type": {"type": "int"},
"route_map": {"type": "str"},
"route_type": {
"choices": [
"bgp",
"connected",
"kernel",
"rip",
"static",
],
"type": "str",
},
},
"type": "list",
},
"route_map": {"type": "list"},
"timers": {
"options": {
"refresh": {
"options": {"timers": {"type": "int"}},
"type": "dict",
},
"throttle": {
"options": {
"spf": {
"options": {
"delay": {"type": "int"},
"initial_holdtime": {"type": "int"},
"max_holdtime": {"type": "int"},
},
"type": "dict",
}
},
"type": "dict",
},
},
"type": "dict",
},
},
"type": "dict",
},
"running_config": {"type": "str"},
"state": {
"choices": [
"merged",
"replaced",
"deleted",
"parsed",
"gathered",
"rendered",
],
"default": "merged",
"type": "str",
},
} # pylint: disable=C0301
diff --git a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py
index 66aaa8c..25f979c 100644
--- a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py
+++ b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py
@@ -1,94 +1,98 @@
#
# -*- 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)
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
#############################################
# 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_ospfv3 module
"""
class Ospfv3Args(object): # pylint: disable=R0903
"""The arg spec for the vyos_ospfv3 module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
"config": {
"options": {
"areas": {
"elements": "dict",
"options": {
"area_id": {"type": "str"},
"export_list": {"type": "str"},
"import_list": {"type": "str"},
"range": {
"elements": "dict",
"options": {
"address": {"type": "str"},
"advertise": {"type": "bool"},
"not_advertise": {"type": "bool"},
},
"type": "list",
},
},
"type": "list",
},
"parameters": {
"options": {"router_id": {"type": "str"}},
"type": "dict",
},
"redistribute": {
"elements": "dict",
"options": {
"route_map": {"type": "str"},
"route_type": {
"choices": [
"bgp",
"connected",
"kernel",
"ripng",
"static",
],
"type": "str",
},
},
"type": "list",
},
},
"type": "dict",
},
"running_config": {"type": "str"},
"state": {
"choices": [
"merged",
"replaced",
"deleted",
"parsed",
"gathered",
"rendered",
],
"default": "merged",
"type": "str",
},
} # pylint: disable=C0301
diff --git a/plugins/module_utils/network/vyos/facts/l3_interfaces/l3_interfaces.py b/plugins/module_utils/network/vyos/facts/l3_interfaces/l3_interfaces.py
index 3b99d34..eac8467 100644
--- a/plugins/module_utils/network/vyos/facts/l3_interfaces/l3_interfaces.py
+++ b/plugins/module_utils/network/vyos/facts/l3_interfaces/l3_interfaces.py
@@ -1,148 +1,143 @@
#
# -*- 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 l3_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,
- unicode_literals,
-)
+from __future__ import absolute_import, division, print_function
__metaclass__ = type
import re
from copy import deepcopy
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
utils,
)
from ansible.module_utils.six import iteritems
-from ansible_collections.ansible.netcommon.plugins.module_utils.compat import (
- ipaddress,
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (
+ get_ip_address_version,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.l3_interfaces.l3_interfaces import (
L3_interfacesArgs,
)
class L3_interfacesFacts(object):
""" The vyos l3_interfaces fact class
"""
def __init__(self, module, subspec="config", options="options"):
self._module = module
self.argument_spec = L3_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 l3_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
if not data:
data = connection.get_config()
# operate on a collection of resource x
objs = []
interface_names = re.findall(
r"set interfaces (?:ethernet|bonding|vti|vxlan) (?:\'*)(\S+)(?:\'*)",
data,
re.M,
)
if interface_names:
for interface in set(interface_names):
intf_regex = r" %s .+$" % interface
cfg = re.findall(intf_regex, data, re.M)
obj = self.render_config(cfg)
obj["name"] = interface.strip("'")
if obj:
objs.append(obj)
ansible_facts["ansible_network_resources"].pop("l3_interfaces", None)
facts = {}
if objs:
facts["l3_interfaces"] = []
params = utils.validate_config(
self.argument_spec, {"config": objs}
)
for cfg in params["config"]:
facts["l3_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
"""
vif_conf = "\n".join(filter(lambda x: ("vif" in x), conf))
eth_conf = "\n".join(filter(lambda x: ("vif" not in x), conf))
config = self.parse_attribs(eth_conf)
config["vifs"] = self.parse_vifs(vif_conf)
return utils.remove_empties(config)
def parse_vifs(self, conf):
vif_names = re.findall(r"vif (\d+)", conf, re.M)
vifs_list = None
if vif_names:
vifs_list = []
for vif in set(vif_names):
vif_regex = r" %s .+$" % vif
cfg = "\n".join(re.findall(vif_regex, conf, re.M))
obj = self.parse_attribs(cfg)
obj["vlan_id"] = vif
if obj:
vifs_list.append(obj)
return vifs_list
def parse_attribs(self, conf):
config = {}
ipaddrs = re.findall(r"address (\S+)", conf, re.M)
config["ipv4"] = []
config["ipv6"] = []
for item in ipaddrs:
item = item.strip("'")
if item == "dhcp":
config["ipv4"].append({"address": item})
elif item == "dhcpv6":
config["ipv6"].append({"address": item})
else:
- ip_version = ipaddress.ip_address(item.split("/")[0]).version
+ ip_version = get_ip_address_version(item.split("/")[0])
if ip_version == 4:
config["ipv4"].append({"address": item})
else:
config["ipv6"].append({"address": item})
for key, value in iteritems(config):
if value == []:
config[key] = None
return utils.remove_empties(config)
diff --git a/plugins/modules/vyos_command.py b/plugins/modules/vyos_command.py
index 58e98c9..2871683 100644
--- a/plugins/modules/vyos_command.py
+++ b/plugins/modules/vyos_command.py
@@ -1,219 +1,219 @@
#!/usr/bin/python
#
# 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 .
#
DOCUMENTATION = """
module: vyos_command
author: Nathaniel Case (@Qalthos)
short_description: Run one or more commands on VyOS devices
description:
- The command module allows running one or more commands on remote devices running
VyOS. This module can also be introspected to validate key parameters before returning
successfully. If the conditional statements are not met in the wait period, the
task fails.
- Certain C(show) commands in VyOS produce many lines of output and use a custom pager
that can cause this module to hang. If the value of the environment variable C(ANSIBLE_VYOS_TERMINAL_LENGTH)
is not set, the default number of 10000 is used.
version_added: 1.0.0
extends_documentation_fragment:
- vyos.vyos.vyos
options:
commands:
description:
- The ordered set of commands to execute on the remote device running VyOS. The
output from the command execution is returned to the playbook. If the I(wait_for)
argument is provided, the module is not returned until the condition is satisfied
or the number of retries has been exceeded.
required: true
wait_for:
description:
- Specifies what to evaluate from the output of the command and what conditionals
to apply. This argument will cause the task to wait for a particular conditional
to be true before moving forward. If the conditional is not true by the configured
I(retries), the task fails. See examples.
aliases:
- waitfor
match:
description:
- The I(match) argument is used in conjunction with the I(wait_for) argument to
specify the match policy. Valid values are C(all) or C(any). If the value is
set to C(all) then all conditionals in the wait_for must be satisfied. If the
value is set to C(any) then only one of the values must be satisfied.
default: all
choices:
- any
- all
retries:
description:
- Specifies the number of retries a command should be tried before it is considered
failed. The command is run on the target device every retry and evaluated against
the I(wait_for) conditionals.
default: 10
interval:
description:
- Configures the interval in seconds to wait between I(retries) of the command.
If the command does not pass the specified conditions, the interval indicates
how long to wait before trying the command again.
default: 1
notes:
- Tested against VyOS 1.1.8 (helium).
- Running C(show system boot-messages all) will cause the module to hang since VyOS
is using a custom pager setting to display the output of that command.
- If a command sent to the device requires answering a prompt, it is possible to pass
a dict containing I(command), I(answer) and I(prompt). See examples.
- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
"""
EXAMPLES = """
- name: show configuration on ethernet devices eth0 and eth1
vyos.vyos.vyos_command:
commands:
- show interfaces ethernet {{ item }}
with_items:
- eth0
- eth1
- name: run multiple commands and check if version output contains specific version
string
vyos.vyos.vyos_command:
commands:
- show version
- show hardware cpu
wait_for:
- result[0] contains 'VyOS 1.1.7'
- name: run command that requires answering a prompt
vyos.vyos.vyos_command:
commands:
- command: rollback 1
prompt: Proceed with reboot? [confirm][y]
answer: y
"""
RETURN = """
stdout:
description: The set of responses from the commands
returned: always apart from low level errors (such as action plugin)
type: list
sample: ['...', '...']
stdout_lines:
description: The value of stdout split into a list
returned: always
type: list
sample: [['...', '...'], ['...'], ['...']]
failed_conditions:
description: The list of conditionals that have failed
returned: failed
type: list
sample: ['...', '...']
warnings:
description: The list of warnings (if any) generated by module based on arguments
returned: always
type: list
sample: ['...', '...']
"""
import time
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import (
Conditional,
)
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
transform_commands,
to_lines,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
run_commands,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
vyos_argument_spec,
)
def parse_commands(module, warnings):
commands = transform_commands(module)
if module.check_mode:
for item in list(commands):
if not item["command"].startswith("show"):
warnings.append(
"Only show commands are supported when using check mode, not "
"executing %s" % item["command"]
)
commands.remove(item)
return commands
def main():
spec = dict(
commands=dict(type="list", required=True),
wait_for=dict(type="list", aliases=["waitfor"]),
match=dict(default="all", choices=["all", "any"]),
retries=dict(default=10, type="int"),
interval=dict(default=1, type="int"),
)
spec.update(vyos_argument_spec)
module = AnsibleModule(argument_spec=spec, supports_check_mode=True)
warnings = list()
result = {"changed": False, "warnings": warnings}
commands = parse_commands(module, warnings)
wait_for = module.params["wait_for"] or list()
try:
conditionals = [Conditional(c) for c in wait_for]
except AttributeError as exc:
module.fail_json(msg=to_text(exc))
retries = module.params["retries"]
interval = module.params["interval"]
match = module.params["match"]
for _ in range(retries):
responses = run_commands(module, commands)
for item in list(conditionals):
if item(responses):
if match == "any":
conditionals = list()
break
conditionals.remove(item)
if not conditionals:
break
time.sleep(interval)
if conditionals:
failed_conditions = [item.raw for item in conditionals]
msg = "One or more conditional statements have not been satisfied"
module.fail_json(msg=msg, failed_conditions=failed_conditions)
result.update(
- {"stdout": responses, "stdout_lines": list(to_lines(responses)),}
+ {"stdout": responses, "stdout_lines": list(to_lines(responses))}
)
module.exit_json(**result)
if __name__ == "__main__":
main()
diff --git a/plugins/modules/vyos_interface.py b/plugins/modules/vyos_interface.py
index 11a1d49..fe4fce3 100644
--- a/plugins/modules/vyos_interface.py
+++ b/plugins/modules/vyos_interface.py
@@ -1,468 +1,471 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
#
# This file is part of Ansible by Red Hat
#
# 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 .
#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
DOCUMENTATION = """
module: vyos_interface
author: Ganesh Nalawade (@ganeshrn)
short_description: (deprecated) Manage Interface on VyOS network devices
description:
- This module provides declarative management of Interfaces on VyOS network devices.
version_added: 1.0.0
deprecated:
removed_in: '2.13'
alternative: vyos_interfaces
why: Updated modules released with more functionality.
notes:
- Tested against VYOS 1.1.7
options:
name:
description:
- Name of the Interface.
required: true
description:
description:
- Description of Interface.
enabled:
description:
- Interface link status.
type: bool
speed:
description:
- Interface link speed.
mtu:
description:
- Maximum size of transmit packet.
duplex:
description:
- Interface link status.
default: auto
choices:
- full
- half
- auto
delay:
description:
- Time in seconds to wait before checking for the operational state on remote
device. This wait is applicable for operational state argument which are I(state)
with values C(up)/C(down) and I(neighbors).
default: 10
neighbors:
description:
- Check the operational state of given interface C(name) for LLDP neighbor.
- The following suboptions are available.
suboptions:
host:
description:
- LLDP neighbor host for given interface C(name).
port:
description:
- LLDP neighbor port to which given interface C(name) is connected.
aggregate:
description: List of Interfaces definitions.
state:
description:
- State of the Interface configuration, C(up) means present and operationally
up and C(down) means present and operationally C(down)
default: present
choices:
- present
- absent
- up
- down
extends_documentation_fragment:
- vyos.vyos.vyos
"""
EXAMPLES = """
- name: configure interface
vyos.vyos.vyos_interface:
name: eth0
description: test-interface
- name: remove interface
vyos.vyos.vyos_interface:
name: eth0
state: absent
- name: make interface down
vyos.vyos.vyos_interface:
name: eth0
enabled: false
- name: make interface up
vyos.vyos.vyos_interface:
name: eth0
enabled: true
- name: Configure interface speed, mtu, duplex
vyos.vyos.vyos_interface:
name: eth5
state: present
speed: 100
mtu: 256
duplex: full
- name: Set interface using aggregate
vyos.vyos.vyos_interface:
aggregate:
- {name: eth1, description: test-interface-1, speed: 100, duplex: half, mtu: 512}
- {name: eth2, description: test-interface-2, speed: 1000, duplex: full, mtu: 256}
- name: Disable interface on aggregate
net_interface:
aggregate:
- name: eth1
- name: eth2
enabled: false
- name: Delete interface using aggregate
net_interface:
aggregate:
- name: eth1
- name: eth2
state: absent
- name: Check lldp neighbors intent arguments
vyos.vyos.vyos_interface:
name: eth0
neighbors:
- port: eth0
host: netdev
- name: Config + intent
vyos.vyos.vyos_interface:
name: eth1
enabled: false
state: down
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always, except for the platforms that use Netconf transport to manage the device.
type: list
sample:
- set interfaces ethernet eth0 description "test-interface"
- set interfaces ethernet eth0 speed 100
- set interfaces ethernet eth0 mtu 256
- set interfaces ethernet eth0 duplex full
"""
import re
from copy import deepcopy
from time import sleep
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import exec_command
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
conditional,
remove_default_spec,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
load_config,
get_config,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
vyos_argument_spec,
)
def search_obj_in_list(name, lst):
for o in lst:
if o["name"] == name:
return o
return None
def map_obj_to_commands(updates):
commands = list()
want, have = updates
params = ("speed", "description", "duplex", "mtu")
for w in want:
name = w["name"]
disable = w["disable"]
state = w["state"]
obj_in_have = search_obj_in_list(name, have)
set_interface = "set interfaces ethernet " + name
delete_interface = "delete interfaces ethernet " + name
if state == "absent" and obj_in_have:
commands.append(delete_interface)
elif state in ("present", "up", "down"):
if obj_in_have:
for item in params:
value = w.get(item)
if value and value != obj_in_have.get(item):
if item == "description":
value = "'" + str(value) + "'"
commands.append(
set_interface + " " + item + " " + str(value)
)
if disable and not obj_in_have.get("disable", False):
commands.append(set_interface + " disable")
elif not disable and obj_in_have.get("disable", False):
commands.append(delete_interface + " disable")
else:
commands.append(set_interface)
for item in params:
value = w.get(item)
if value:
if item == "description":
value = "'" + str(value) + "'"
commands.append(
set_interface + " " + item + " " + str(value)
)
if disable:
commands.append(set_interface + " disable")
return commands
def map_config_to_obj(module):
data = get_config(module, flags=["| grep interface"])
obj = []
for line in data.split("\n"):
if line.startswith("set interfaces ethernet"):
match = re.search(r"set interfaces ethernet (\S+)", line, re.M)
name = match.group(1)
if name:
interface = {}
for item in obj:
if item["name"] == name:
interface = item
break
if not interface:
interface = {"name": name}
obj.append(interface)
match = re.search(r"%s (\S+)" % name, line, re.M)
if match:
param = match.group(1)
if param == "description":
match = re.search(r"description (.+)", line, re.M)
description = match.group(1).strip("'")
interface["description"] = description
elif param == "speed":
match = re.search(r"speed (\S+)", line, re.M)
speed = match.group(1).strip("'")
interface["speed"] = speed
elif param == "mtu":
match = re.search(r"mtu (\S+)", line, re.M)
mtu = match.group(1).strip("'")
interface["mtu"] = int(mtu)
elif param == "duplex":
match = re.search(r"duplex (\S+)", line, re.M)
duplex = match.group(1).strip("'")
interface["duplex"] = duplex
elif param.strip("'") == "disable":
interface["disable"] = True
return obj
def map_params_to_obj(module):
obj = []
aggregate = module.params.get("aggregate")
if aggregate:
for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
d = item.copy()
if d["enabled"]:
d["disable"] = False
else:
d["disable"] = True
obj.append(d)
else:
params = {
"name": module.params["name"],
"description": module.params["description"],
"speed": module.params["speed"],
"mtu": module.params["mtu"],
"duplex": module.params["duplex"],
"delay": module.params["delay"],
"state": module.params["state"],
"neighbors": module.params["neighbors"],
}
if module.params["enabled"]:
params.update({"disable": False})
else:
params.update({"disable": True})
obj.append(params)
return obj
def check_declarative_intent_params(module, want, result):
failed_conditions = []
have_neighbors = None
for w in want:
want_state = w.get("state")
want_neighbors = w.get("neighbors")
if want_state not in ("up", "down") and not want_neighbors:
continue
if result["changed"]:
sleep(w["delay"])
command = "show interfaces ethernet %s" % w["name"]
rc, out, err = exec_command(module, command)
if rc != 0:
module.fail_json(
msg=to_text(err, errors="surrogate_then_replace"),
command=command,
rc=rc,
)
if want_state in ("up", "down"):
match = re.search(r"%s (\w+)" % "state", out, re.M)
have_state = None
if match:
have_state = match.group(1)
if have_state is None or not conditional(
want_state, have_state.strip().lower()
):
failed_conditions.append("state " + "eq(%s)" % want_state)
if want_neighbors:
have_host = []
have_port = []
if have_neighbors is None:
rc, have_neighbors, err = exec_command(
module, "show lldp neighbors detail"
)
if rc != 0:
module.fail_json(
msg=to_text(err, errors="surrogate_then_replace"),
command=command,
rc=rc,
)
if have_neighbors:
lines = have_neighbors.strip().split("Interface: ")
for line in lines:
field = line.split("\n")
if field[0].split(",")[0].strip() == w["name"]:
for item in field:
if item.strip().startswith("SysName:"):
have_host.append(item.split(":")[1].strip())
if item.strip().startswith("PortDescr:"):
have_port.append(item.split(":")[1].strip())
for item in want_neighbors:
host = item.get("host")
port = item.get("port")
if host and host not in have_host:
failed_conditions.append("host " + host)
if port and port not in have_port:
failed_conditions.append("port " + port)
return failed_conditions
def main():
""" main entry point for module execution
"""
neighbors_spec = dict(host=dict(), port=dict())
element_spec = dict(
name=dict(),
description=dict(),
speed=dict(),
mtu=dict(type="int"),
duplex=dict(choices=["full", "half", "auto"]),
enabled=dict(default=True, type="bool"),
neighbors=dict(type="list", elements="dict", options=neighbors_spec),
delay=dict(default=10, type="int"),
state=dict(
default="present", choices=["present", "absent", "up", "down"]
),
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec["name"] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type="list", elements="dict", options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(vyos_argument_spec)
required_one_of = [["name", "aggregate"]]
mutually_exclusive = [["name", "aggregate"]]
required_together = [["speed", "duplex"]]
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
required_together=required_together,
supports_check_mode=True,
)
warnings = list()
result = {"changed": False}
if warnings:
result["warnings"] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands((want, have))
result["commands"] = commands
if commands:
commit = not module.check_mode
diff = load_config(module, commands, commit=commit)
if diff:
if module._diff:
result["diff"] = {"prepared": diff}
result["changed"] = True
failed_conditions = check_declarative_intent_params(module, want, result)
if failed_conditions:
msg = "One or more conditional statements have not been satisfied"
module.fail_json(msg=msg, failed_conditions=failed_conditions)
module.exit_json(**result)
if __name__ == "__main__":
main()
diff --git a/plugins/modules/vyos_l3_interface.py b/plugins/modules/vyos_l3_interface.py
index 3e43f7c..2feb824 100644
--- a/plugins/modules/vyos_l3_interface.py
+++ b/plugins/modules/vyos_l3_interface.py
@@ -1,326 +1,329 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
#
# This file is part of Ansible by Red Hat
#
# 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 .
#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
DOCUMENTATION = """
module: vyos_l3_interface
author: Ricardo Carrillo Cruz (@rcarrillocruz)
short_description: (deprecated) Manage L3 interfaces on VyOS network devices
description:
- This module provides declarative management of L3 interfaces on VyOS network devices.
version_added: 1.0.0
deprecated:
removed_in: '2.13'
alternative: vyos_l3_interfaces
why: Updated modules released with more functionality.
notes:
- Tested against VYOS 1.1.7
options:
name:
description:
- Name of the L3 interface.
ipv4:
description:
- IPv4 of the L3 interface.
ipv6:
description:
- IPv6 of the L3 interface.
aggregate:
description: List of L3 interfaces definitions
state:
description:
- State of the L3 interface configuration.
default: present
choices:
- present
- absent
extends_documentation_fragment:
- vyos.vyos.vyos
"""
EXAMPLES = """
- name: Set eth0 IPv4 address
vyos.vyos.vyos_l3_interface:
name: eth0
ipv4: 192.168.0.1/24
- name: Remove eth0 IPv4 address
vyos.vyos.vyos_l3_interface:
name: eth0
state: absent
- name: Set IP addresses on aggregate
vyos.vyos.vyos_l3_interface:
aggregate:
- {name: eth1, ipv4: 192.168.2.10/24}
- {name: eth2, ipv4: 192.168.3.10/24, ipv6: fd5d:12c9:2201:1::1/64}
- name: Remove IP addresses on aggregate
vyos.vyos.vyos_l3_interface:
aggregate:
- {name: eth1, ipv4: 192.168.2.10/24}
- {name: eth2, ipv4: 192.168.3.10/24, ipv6: fd5d:12c9:2201:1::1/64}
state: absent
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always, except for the platforms that use Netconf transport to manage the device.
type: list
sample:
- set interfaces ethernet eth0 address '192.168.0.1/24'
"""
import socket
import re
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
is_masklen,
validate_ip_address,
)
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
remove_default_spec,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
load_config,
run_commands,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
vyos_argument_spec,
)
def is_ipv4(value):
if value:
address = value.split("/")
if is_masklen(address[1]) and validate_ip_address(address[0]):
return True
return False
def is_ipv6(value):
if value:
address = value.split("/")
if 0 <= int(address[1]) <= 128:
try:
socket.inet_pton(socket.AF_INET6, address[0])
except socket.error:
return False
return True
return False
def search_obj_in_list(name, lst):
for o in lst:
if o["name"] == name:
return o
return None
def map_obj_to_commands(updates, module):
commands = list()
want, have = updates
for w in want:
name = w["name"]
ipv4 = w["ipv4"]
ipv6 = w["ipv6"]
state = w["state"]
obj_in_have = search_obj_in_list(name, have)
if state == "absent" and obj_in_have:
if (
not ipv4
and not ipv6
and (obj_in_have["ipv4"] or obj_in_have["ipv6"])
):
if name == "lo":
commands.append("delete interfaces loopback lo address")
else:
commands.append(
"delete interfaces ethernet " + name + " address"
)
else:
if ipv4 and ipv4 in obj_in_have["ipv4"]:
if name == "lo":
commands.append(
"delete interfaces loopback lo address " + ipv4
)
else:
commands.append(
"delete interfaces ethernet "
+ name
+ " address "
+ ipv4
)
if ipv6 and ipv6 in obj_in_have["ipv6"]:
if name == "lo":
commands.append(
"delete interfaces loopback lo address " + ipv6
)
else:
commands.append(
"delete interfaces ethernet "
+ name
+ " address "
+ ipv6
)
elif state == "present" and obj_in_have:
if ipv4 and ipv4 not in obj_in_have["ipv4"]:
if name == "lo":
commands.append(
"set interfaces loopback lo address " + ipv4
)
else:
commands.append(
"set interfaces ethernet " + name + " address " + ipv4
)
if ipv6 and ipv6 not in obj_in_have["ipv6"]:
if name == "lo":
commands.append(
"set interfaces loopback lo address " + ipv6
)
else:
commands.append(
"set interfaces ethernet " + name + " address " + ipv6
)
return commands
def map_config_to_obj(module):
obj = []
output = run_commands(module, ["show interfaces"])
lines = re.split(r"\n[e|l]", output[0])[1:]
if len(lines) > 0:
for line in lines:
splitted_line = line.split()
if len(splitted_line) > 0:
ipv4 = []
ipv6 = []
if splitted_line[0].lower().startswith("th"):
name = "e" + splitted_line[0].lower()
elif splitted_line[0].lower().startswith("o"):
name = "l" + splitted_line[0].lower()
for i in splitted_line[1:]:
if ("." in i or ":" in i) and "/" in i:
value = i.split(r"\n")[0]
if is_ipv4(value):
ipv4.append(value)
elif is_ipv6(value):
ipv6.append(value)
obj.append({"name": name, "ipv4": ipv4, "ipv6": ipv6})
return obj
def map_params_to_obj(module):
obj = []
aggregate = module.params.get("aggregate")
if aggregate:
for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
obj.append(item.copy())
else:
obj.append(
{
"name": module.params["name"],
"ipv4": module.params["ipv4"],
"ipv6": module.params["ipv6"],
"state": module.params["state"],
}
)
return obj
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
ipv4=dict(),
ipv6=dict(),
state=dict(default="present", choices=["present", "absent"]),
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec["name"] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type="list", elements="dict", options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(vyos_argument_spec)
required_one_of = [["name", "aggregate"]]
mutually_exclusive = [["name", "aggregate"]]
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
warnings = list()
result = {"changed": False}
if warnings:
result["warnings"] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands((want, have), module)
result["commands"] = commands
if commands:
commit = not module.check_mode
load_config(module, commands, commit=commit)
result["changed"] = True
module.exit_json(**result)
if __name__ == "__main__":
main()
diff --git a/plugins/modules/vyos_linkagg.py b/plugins/modules/vyos_linkagg.py
index 0d939b2..a68197b 100644
--- a/plugins/modules/vyos_linkagg.py
+++ b/plugins/modules/vyos_linkagg.py
@@ -1,324 +1,327 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
#
# This file is part of Ansible by Red Hat
#
# 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 .
#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
DOCUMENTATION = """
module: vyos_linkagg
author: Ricardo Carrillo Cruz (@rcarrillocruz)
short_description: (deprecated) Manage link aggregation groups on VyOS network devices
description:
- This module provides declarative management of link aggregation groups on VyOS network
devices.
version_added: 1.0.0
deprecated:
removed_in: '2.13'
alternative: vyos_lag_interfaces
why: Updated modules released with more functionality.
notes:
- Tested against VYOS 1.1.7
options:
name:
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.vyos.vyos
"""
EXAMPLES = """
- name: configure link aggregation group
vyos.vyos.vyos_linkagg:
name: bond0
members:
- eth0
- eth1
- name: remove configuration
vyos.vyos.vyos_linkagg:
name: bond0
state: absent
- name: Create aggregate of linkagg definitions
vyos.vyos.vyos_linkagg:
aggregate:
- {name: bond0, members: [eth1]}
- {name: bond1, members: [eth2]}
- name: Remove aggregate of linkagg definitions
vyos.vyos.vyos_linkagg:
aggregate:
- name: bond0
- name: bond1
state: absent
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always, except for the platforms that use Netconf transport to manage the device.
type: list
sample:
- set interfaces bonding bond0
- set interfaces ethernet eth0 bond-group 'bond0'
- set interfaces ethernet eth1 bond-group 'bond0'
"""
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
remove_default_spec,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
load_config,
run_commands,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
vyos_argument_spec,
)
def search_obj_in_list(name, lst):
for o in lst:
if o["name"] == name:
return o
return None
def map_obj_to_commands(updates, module):
commands = list()
want, have = updates
for w in want:
name = w["name"]
members = w.get("members") or []
mode = w["mode"]
if mode == "on":
mode = "802.3ad"
state = w["state"]
obj_in_have = search_obj_in_list(name, have)
if state == "absent":
if obj_in_have:
for m in obj_in_have["members"]:
commands.append(
"delete interfaces ethernet " + m + " bond-group"
)
commands.append("delete interfaces bonding " + name)
else:
if not obj_in_have:
commands.append(
"set interfaces bonding " + name + " mode " + mode
)
for m in members:
commands.append(
"set interfaces ethernet " + m + " bond-group " + name
)
if state == "down":
commands.append(
"set interfaces bonding " + name + " disable"
)
else:
if mode != obj_in_have["mode"]:
commands.append(
"set interfaces bonding " + name + " mode " + mode
)
missing_members = list(
set(members) - set(obj_in_have["members"])
)
for m in missing_members:
commands.append(
"set interfaces ethernet " + m + " bond-group " + name
)
if state == "down" and obj_in_have["state"] == "up":
commands.append(
"set interfaces bonding " + name + " disable"
)
elif state == "up" and obj_in_have["state"] == "down":
commands.append(
"delete interfaces bonding " + name + " disable"
)
return commands
def map_config_to_obj(module):
obj = []
output = run_commands(module, ["show interfaces bonding slaves"])
lines = output[0].splitlines()
if len(lines) > 1:
for line in lines[1:]:
splitted_line = line.split()
name = splitted_line[0]
mode = splitted_line[1]
state = splitted_line[2]
if len(splitted_line) > 4:
members = splitted_line[4:]
else:
members = []
obj.append(
{
"name": name,
"mode": mode,
"members": members,
"state": state,
}
)
return obj
def map_params_to_obj(module):
obj = []
aggregate = module.params.get("aggregate")
if aggregate:
for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
obj.append(item.copy())
else:
obj.append(
{
"name": module.params["name"],
"mode": module.params["mode"],
"members": module.params["members"],
"state": module.params["state"],
}
)
return obj
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
mode=dict(
choices=[
"802.3ad",
"active-backup",
"broadcast",
"round-robin",
"transmit-load-balance",
"adaptive-load-balance",
"xor-hash",
"on",
],
default="802.3ad",
),
members=dict(type="list"),
state=dict(
default="present", choices=["present", "absent", "up", "down"]
),
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec["name"] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type="list", elements="dict", options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(vyos_argument_spec)
required_one_of = [["name", "aggregate"]]
mutually_exclusive = [["name", "aggregate"]]
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
warnings = list()
result = {"changed": False}
if warnings:
result["warnings"] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands((want, have), module)
result["commands"] = commands
if commands:
commit = not module.check_mode
load_config(module, commands, commit=commit)
result["changed"] = True
module.exit_json(**result)
if __name__ == "__main__":
main()
diff --git a/plugins/modules/vyos_lldp_interface.py b/plugins/modules/vyos_lldp_interface.py
index 80d4dbf..90e123d 100644
--- a/plugins/modules/vyos_lldp_interface.py
+++ b/plugins/modules/vyos_lldp_interface.py
@@ -1,261 +1,264 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
#
# This file is part of Ansible by Red Hat
#
# 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 .
#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
DOCUMENTATION = """
module: vyos_lldp_interface
author: Ricardo Carrillo Cruz (@rcarrillocruz)
short_description: (deprecated) Manage LLDP interfaces configuration on VyOS network
devices
description:
- This module provides declarative management of LLDP interfaces configuration on
VyOS network devices.
version_added: 1.0.0
deprecated:
removed_in: '2.13'
alternative: vyos_lldp_interfaces
why: Updated modules released with more functionality.
notes:
- Tested against VYOS 1.1.7
options:
name:
description:
- Name of the interface LLDP should be configured on.
type: str
aggregate:
description: List of interfaces LLDP should be configured on.
type: list
state:
description:
- State of the LLDP configuration.
default: present
choices:
- present
- absent
- enabled
- disabled
type: str
extends_documentation_fragment:
- vyos.vyos.vyos
"""
EXAMPLES = """
- name: Enable LLDP on eth1
net_lldp_interface:
state: present
- name: Enable LLDP on specific interfaces
net_lldp_interface:
interfaces:
- eth1
- eth2
state: present
- name: Disable LLDP globally
net_lldp_interface:
state: disabled
- name: Create aggregate of LLDP interface configurations
vyos.vyos.vyos_lldp_interface:
aggregate:
- name: eth1
- name: eth2
state: present
- name: Delete aggregate of LLDP interface configurations
vyos.vyos.vyos_lldp_interface:
aggregate:
- name: eth1
- name: eth2
state: absent
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always, except for the platforms that use Netconf transport to manage the device.
type: list
sample:
- set service lldp eth1
- set service lldp eth2 disable
"""
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
remove_default_spec,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
get_config,
load_config,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
vyos_argument_spec,
)
def search_obj_in_list(name, lst):
for o in lst:
if o["name"] == name:
return o
return None
def map_obj_to_commands(updates, module):
commands = list()
want, have = updates
for w in want:
name = w["name"]
state = w["state"]
obj_in_have = search_obj_in_list(name, have)
if state == "absent" and obj_in_have:
commands.append("delete service lldp interface " + name)
elif state in ("present", "enabled"):
if not obj_in_have:
commands.append("set service lldp interface " + name)
elif (
obj_in_have
and obj_in_have["state"] == "disabled"
and state == "enabled"
):
commands.append(
"delete service lldp interface " + name + " disable"
)
elif state == "disabled":
if not obj_in_have:
commands.append("set service lldp interface " + name)
commands.append(
"set service lldp interface " + name + " disable"
)
elif obj_in_have and obj_in_have["state"] != "disabled":
commands.append(
"set service lldp interface " + name + " disable"
)
return commands
def map_config_to_obj(module):
obj = []
config = get_config(module).splitlines()
output = [c for c in config if c.startswith("set service lldp interface")]
for i in output:
splitted_line = i.split()
if len(splitted_line) > 5:
new_obj = {"name": splitted_line[4]}
if splitted_line[5] == "'disable'":
new_obj["state"] = "disabled"
else:
new_obj = {"name": splitted_line[4][1:-1]}
new_obj["state"] = "present"
obj.append(new_obj)
return obj
def map_params_to_obj(module):
obj = []
aggregate = module.params.get("aggregate")
if aggregate:
for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
obj.append(item.copy())
else:
obj.append(
{"name": module.params["name"], "state": module.params["state"]}
)
return obj
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
state=dict(
default="present",
choices=["present", "absent", "enabled", "disabled"],
),
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec["name"] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type="list", elements="dict", options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(vyos_argument_spec)
required_one_of = [["name", "aggregate"]]
mutually_exclusive = [["name", "aggregate"]]
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
warnings = list()
result = {"changed": False}
if warnings:
result["warnings"] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands((want, have), module)
result["commands"] = commands
if commands:
commit = not module.check_mode
load_config(module, commands, commit=commit)
result["changed"] = True
module.exit_json(**result)
if __name__ == "__main__":
main()
diff --git a/plugins/modules/vyos_static_route.py b/plugins/modules/vyos_static_route.py
index 7859467..4724d5f 100644
--- a/plugins/modules/vyos_static_route.py
+++ b/plugins/modules/vyos_static_route.py
@@ -1,299 +1,302 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
#
# This file is part of Ansible by Red Hat
#
# 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 .
#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
DOCUMENTATION = """
module: vyos_static_route
author: Trishna Guha (@trishnaguha)
short_description: (deprecated) Manage static IP routes on Vyatta VyOS network devices
description:
- This module provides declarative management of static IP routes on Vyatta VyOS network
devices.
version_added: 1.0.0
deprecated:
removed_in: '2.13'
alternative: vyos_static_routes
why: Updated modules released with more functionality.
notes:
- Tested against VyOS 1.1.8 (helium).
- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
options:
prefix:
description:
- Network prefix of the static route. C(mask) param should be ignored if C(prefix)
is provided with C(mask) value C(prefix/mask).
type: str
mask:
description:
- Network prefix mask of the static route.
type: str
next_hop:
description:
- Next hop IP of the static route.
type: str
admin_distance:
description:
- Admin distance of the static route.
type: int
aggregate:
description: List of static route definitions
type: list
state:
description:
- State of the static route configuration.
default: present
choices:
- present
- absent
type: str
extends_documentation_fragment:
- vyos.vyos.vyos
"""
EXAMPLES = """
- name: configure static route
vyos.vyos.vyos_static_route:
prefix: 192.168.2.0
mask: 24
next_hop: 10.0.0.1
- name: configure static route prefix/mask
vyos.vyos.vyos_static_route:
prefix: 192.168.2.0/16
next_hop: 10.0.0.1
- name: remove configuration
vyos.vyos.vyos_static_route:
prefix: 192.168.2.0
mask: 16
next_hop: 10.0.0.1
state: absent
- name: configure aggregates of static routes
vyos.vyos.vyos_static_route:
aggregate:
- {prefix: 192.168.2.0, mask: 24, next_hop: 10.0.0.1}
- {prefix: 192.168.3.0, mask: 16, next_hop: 10.0.2.1}
- {prefix: 192.168.3.0/16, next_hop: 10.0.2.1}
- name: Remove static route collections
vyos.vyos.vyos_static_route:
aggregate:
- {prefix: 172.24.1.0/24, next_hop: 192.168.42.64}
- {prefix: 172.24.3.0/24, next_hop: 192.168.42.64}
state: absent
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always
type: list
sample:
- set protocols static route 192.168.2.0/16 next-hop 10.0.0.1
"""
import re
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
remove_default_spec,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
get_config,
load_config,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import (
vyos_argument_spec,
)
def spec_to_commands(updates, module):
commands = list()
want, have = updates
for w in want:
prefix = w["prefix"]
mask = w["mask"]
next_hop = w["next_hop"]
admin_distance = w["admin_distance"]
state = w["state"]
del w["state"]
if state == "absent" and w in have:
commands.append(
"delete protocols static route %s/%s" % (prefix, mask)
)
elif state == "present" and w not in have:
cmd = "set protocols static route %s/%s next-hop %s" % (
prefix,
mask,
next_hop,
)
if admin_distance != "None":
cmd += " distance %s" % (admin_distance)
commands.append(cmd)
return commands
def config_to_dict(module):
data = get_config(module)
obj = []
for line in data.split("\n"):
if line.startswith("set protocols static route"):
match = re.search(r"static route (\S+)", line, re.M)
prefix = match.group(1).split("/")[0]
mask = match.group(1).split("/")[1]
if "next-hop" in line:
match_hop = re.search(r"next-hop (\S+)", line, re.M)
next_hop = match_hop.group(1).strip("'")
match_distance = re.search(r"distance (\S+)", line, re.M)
if match_distance is not None:
admin_distance = match_distance.group(1)[1:-1]
else:
admin_distance = None
if admin_distance is not None:
obj.append(
{
"prefix": prefix,
"mask": mask,
"next_hop": next_hop,
"admin_distance": admin_distance,
}
)
else:
obj.append(
{
"prefix": prefix,
"mask": mask,
"next_hop": next_hop,
"admin_distance": "None",
}
)
return obj
def map_params_to_obj(module, required_together=None):
obj = []
aggregate = module.params.get("aggregate")
if aggregate:
for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
module._check_required_together(required_together, item)
d = item.copy()
if "/" in d["prefix"]:
d["mask"] = d["prefix"].split("/")[1]
d["prefix"] = d["prefix"].split("/")[0]
if "admin_distance" in d:
d["admin_distance"] = str(d["admin_distance"])
obj.append(d)
else:
prefix = module.params["prefix"].strip()
if "/" in prefix:
mask = prefix.split("/")[1]
prefix = prefix.split("/")[0]
else:
mask = module.params["mask"].strip()
next_hop = module.params["next_hop"].strip()
admin_distance = str(module.params["admin_distance"])
state = module.params["state"]
obj.append(
{
"prefix": prefix,
"mask": mask,
"next_hop": next_hop,
"admin_distance": admin_distance,
"state": state,
}
)
return obj
def main():
""" main entry point for module execution
"""
element_spec = dict(
prefix=dict(type="str"),
mask=dict(type="str"),
next_hop=dict(type="str"),
admin_distance=dict(type="int"),
state=dict(default="present", choices=["present", "absent"]),
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec["prefix"] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type="list", elements="dict", options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(vyos_argument_spec)
required_one_of = [["aggregate", "prefix"]]
required_together = [["prefix", "next_hop"]]
mutually_exclusive = [["aggregate", "prefix"]]
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=required_one_of,
required_together=required_together,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)
warnings = list()
result = {"changed": False}
if warnings:
result["warnings"] = warnings
want = map_params_to_obj(module, required_together=required_together)
have = config_to_dict(module)
commands = spec_to_commands((want, have), module)
result["commands"] = commands
if commands:
commit = not module.check_mode
load_config(module, commands, commit=commit)
result["changed"] = True
module.exit_json(**result)
if __name__ == "__main__":
main()
diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index a62f497..0000000
--- a/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-plugins/module_utils/network/vyos/vyos.py future-import-boilerplate
-plugins/module_utils/network/vyos/vyos.py metaclass-boilerplate
-plugins/modules/vyos_banner.py future-import-boilerplate
-plugins/modules/vyos_banner.py metaclass-boilerplate
-plugins/modules/vyos_banner.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_banner.py validate-modules:doc-missing-type
-plugins/modules/vyos_banner.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_command.py future-import-boilerplate
-plugins/modules/vyos_command.py metaclass-boilerplate
-plugins/modules/vyos_command.py pylint:blacklisted-name
-plugins/modules/vyos_command.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_command.py validate-modules:doc-missing-type
-plugins/modules/vyos_command.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_command.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_command.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_config.py future-import-boilerplate
-plugins/modules/vyos_config.py metaclass-boilerplate
-plugins/modules/vyos_config.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_config.py validate-modules:doc-missing-type
-plugins/modules/vyos_config.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_config.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_config.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_facts.py future-import-boilerplate
-plugins/modules/vyos_facts.py metaclass-boilerplate
-plugins/modules/vyos_facts.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_facts.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_facts.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_facts.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_interfaces.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_lag_interfaces.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_lag_interfaces.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_lldp_global.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_lldp_interfaces.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_lldp_interfaces.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_logging.py future-import-boilerplate
-plugins/modules/vyos_logging.py metaclass-boilerplate
-plugins/modules/vyos_logging.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/vyos_logging.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_logging.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_logging.py validate-modules:doc-missing-type
-plugins/modules/vyos_logging.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_logging.py validate-modules:missing-suboption-docs
-plugins/modules/vyos_logging.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_logging.py validate-modules:undocumented-parameter
-plugins/modules/vyos_ping.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_ping.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_ping.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_system.py future-import-boilerplate
-plugins/modules/vyos_system.py metaclass-boilerplate
-plugins/modules/vyos_system.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_system.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_system.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_system.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_user.py future-import-boilerplate
-plugins/modules/vyos_user.py metaclass-boilerplate
-plugins/modules/vyos_user.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/vyos_user.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_user.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_user.py validate-modules:doc-missing-type
-plugins/modules/vyos_user.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_user.py validate-modules:missing-suboption-docs
-plugins/modules/vyos_user.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_user.py validate-modules:undocumented-parameter
-plugins/modules/vyos_vlan.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/vyos_vlan.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_vlan.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_vlan.py validate-modules:doc-missing-type
-plugins/modules/vyos_vlan.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_vlan.py validate-modules:missing-suboption-docs
-plugins/modules/vyos_vlan.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_vlan.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_vlan.py validate-modules:undocumented-parameter
-plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
-plugins/doc_fragments/vyos.py future-import-boilerplate
-plugins/doc_fragments/vyos.py metaclass-boilerplate
-tests/unit/mock/path.py future-import-boilerplate
-tests/unit/mock/path.py metaclass-boilerplate
-tests/unit/mock/yaml_helper.py future-import-boilerplate
-tests/unit/mock/yaml_helper.py metaclass-boilerplate
-tests/unit/modules/conftest.py future-import-boilerplate
-tests/unit/modules/conftest.py metaclass-boilerplate
-tests/unit/modules/utils.py future-import-boilerplate
-tests/unit/modules/utils.py metaclass-boilerplate
\ No newline at end of file
diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt
index a62f497..68c5fc2 100644
--- a/tests/sanity/ignore-2.9.txt
+++ b/tests/sanity/ignore-2.9.txt
@@ -1,83 +1,105 @@
-plugins/module_utils/network/vyos/vyos.py future-import-boilerplate
-plugins/module_utils/network/vyos/vyos.py metaclass-boilerplate
+plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/doc_fragments/vyos.py future-import-boilerplate
+plugins/doc_fragments/vyos.py metaclass-boilerplate
plugins/modules/vyos_banner.py future-import-boilerplate
plugins/modules/vyos_banner.py metaclass-boilerplate
plugins/modules/vyos_banner.py validate-modules:doc-default-does-not-match-spec
plugins/modules/vyos_banner.py validate-modules:doc-missing-type
-plugins/modules/vyos_banner.py validate-modules:doc-required-mismatch
plugins/modules/vyos_command.py future-import-boilerplate
plugins/modules/vyos_command.py metaclass-boilerplate
plugins/modules/vyos_command.py pylint:blacklisted-name
plugins/modules/vyos_command.py validate-modules:doc-default-does-not-match-spec
plugins/modules/vyos_command.py validate-modules:doc-missing-type
-plugins/modules/vyos_command.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_command.py validate-modules:parameter-list-no-elements
plugins/modules/vyos_command.py validate-modules:parameter-type-not-in-doc
plugins/modules/vyos_config.py future-import-boilerplate
plugins/modules/vyos_config.py metaclass-boilerplate
plugins/modules/vyos_config.py validate-modules:doc-default-does-not-match-spec
plugins/modules/vyos_config.py validate-modules:doc-missing-type
-plugins/modules/vyos_config.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_config.py validate-modules:parameter-list-no-elements
plugins/modules/vyos_config.py validate-modules:parameter-type-not-in-doc
plugins/modules/vyos_facts.py future-import-boilerplate
plugins/modules/vyos_facts.py metaclass-boilerplate
plugins/modules/vyos_facts.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_facts.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_facts.py validate-modules:parameter-list-no-elements
plugins/modules/vyos_facts.py validate-modules:parameter-type-not-in-doc
-plugins/modules/vyos_interfaces.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_lag_interfaces.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_lag_interfaces.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_lldp_global.py validate-modules:parameter-list-no-elements
-plugins/modules/vyos_lldp_interfaces.py validate-modules:doc-elements-mismatch
-plugins/modules/vyos_lldp_interfaces.py validate-modules:doc-required-mismatch
+plugins/modules/vyos_firewall_global.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/vyos_interface.py validate-modules:deprecation-mismatch
+plugins/modules/vyos_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/vyos_interface.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/vyos_interface.py validate-modules:doc-missing-type
+plugins/modules/vyos_interface.py validate-modules:invalid-documentation
+plugins/modules/vyos_interface.py validate-modules:missing-suboption-docs
+plugins/modules/vyos_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vyos_interface.py validate-modules:undocumented-parameter
+plugins/modules/vyos_l3_interface.py validate-modules:deprecation-mismatch
+plugins/modules/vyos_l3_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/vyos_l3_interface.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/vyos_l3_interface.py validate-modules:doc-missing-type
+plugins/modules/vyos_l3_interface.py validate-modules:invalid-documentation
+plugins/modules/vyos_l3_interface.py validate-modules:missing-suboption-docs
+plugins/modules/vyos_l3_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vyos_l3_interface.py validate-modules:undocumented-parameter
+plugins/modules/vyos_linkagg.py validate-modules:deprecation-mismatch
+plugins/modules/vyos_linkagg.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/vyos_linkagg.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/vyos_linkagg.py validate-modules:doc-missing-type
+plugins/modules/vyos_linkagg.py validate-modules:invalid-documentation
+plugins/modules/vyos_linkagg.py validate-modules:missing-suboption-docs
+plugins/modules/vyos_linkagg.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vyos_linkagg.py validate-modules:undocumented-parameter
+plugins/modules/vyos_lldp_interface.py validate-modules:deprecation-mismatch
+plugins/modules/vyos_lldp_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/vyos_lldp_interface.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/vyos_lldp_interface.py validate-modules:doc-missing-type
+plugins/modules/vyos_lldp_interface.py validate-modules:invalid-documentation
+plugins/modules/vyos_lldp_interface.py validate-modules:missing-suboption-docs
+plugins/modules/vyos_lldp_interface.py validate-modules:undocumented-parameter
+plugins/modules/vyos_lldp.py validate-modules:deprecation-mismatch
+plugins/modules/vyos_lldp.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/vyos_lldp.py validate-modules:invalid-documentation
plugins/modules/vyos_logging.py future-import-boilerplate
plugins/modules/vyos_logging.py metaclass-boilerplate
plugins/modules/vyos_logging.py validate-modules:doc-choices-do-not-match-spec
plugins/modules/vyos_logging.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_logging.py validate-modules:doc-elements-mismatch
plugins/modules/vyos_logging.py validate-modules:doc-missing-type
-plugins/modules/vyos_logging.py validate-modules:doc-required-mismatch
plugins/modules/vyos_logging.py validate-modules:missing-suboption-docs
plugins/modules/vyos_logging.py validate-modules:parameter-type-not-in-doc
plugins/modules/vyos_logging.py validate-modules:undocumented-parameter
+plugins/modules/vyos_ospfv2.py validate-modules:invalid-documentation
+plugins/modules/vyos_ospfv3.py validate-modules:invalid-documentation
plugins/modules/vyos_ping.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_ping.py validate-modules:doc-required-mismatch
plugins/modules/vyos_ping.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vyos_static_route.py validate-modules:deprecation-mismatch
+plugins/modules/vyos_static_route.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/vyos_static_route.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/vyos_static_route.py validate-modules:doc-missing-type
+plugins/modules/vyos_static_route.py validate-modules:invalid-documentation
+plugins/modules/vyos_static_route.py validate-modules:missing-suboption-docs
+plugins/modules/vyos_static_route.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vyos_static_route.py validate-modules:undocumented-parameter
plugins/modules/vyos_system.py future-import-boilerplate
plugins/modules/vyos_system.py metaclass-boilerplate
plugins/modules/vyos_system.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_system.py validate-modules:doc-required-mismatch
-plugins/modules/vyos_system.py validate-modules:parameter-list-no-elements
plugins/modules/vyos_system.py validate-modules:parameter-type-not-in-doc
plugins/modules/vyos_user.py future-import-boilerplate
plugins/modules/vyos_user.py metaclass-boilerplate
plugins/modules/vyos_user.py validate-modules:doc-choices-do-not-match-spec
plugins/modules/vyos_user.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_user.py validate-modules:doc-elements-mismatch
plugins/modules/vyos_user.py validate-modules:doc-missing-type
-plugins/modules/vyos_user.py validate-modules:doc-required-mismatch
plugins/modules/vyos_user.py validate-modules:missing-suboption-docs
plugins/modules/vyos_user.py validate-modules:parameter-type-not-in-doc
plugins/modules/vyos_user.py validate-modules:undocumented-parameter
plugins/modules/vyos_vlan.py validate-modules:doc-choices-do-not-match-spec
plugins/modules/vyos_vlan.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/vyos_vlan.py validate-modules:doc-elements-mismatch
plugins/modules/vyos_vlan.py validate-modules:doc-missing-type
-plugins/modules/vyos_vlan.py validate-modules:doc-required-mismatch
plugins/modules/vyos_vlan.py validate-modules:missing-suboption-docs
-plugins/modules/vyos_vlan.py validate-modules:parameter-list-no-elements
plugins/modules/vyos_vlan.py validate-modules:parameter-type-not-in-doc
plugins/modules/vyos_vlan.py validate-modules:undocumented-parameter
-plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
-plugins/doc_fragments/vyos.py future-import-boilerplate
-plugins/doc_fragments/vyos.py metaclass-boilerplate
+plugins/module_utils/network/vyos/vyos.py future-import-boilerplate
+plugins/module_utils/network/vyos/vyos.py metaclass-boilerplate
tests/unit/mock/path.py future-import-boilerplate
tests/unit/mock/path.py metaclass-boilerplate
tests/unit/mock/yaml_helper.py future-import-boilerplate
tests/unit/mock/yaml_helper.py metaclass-boilerplate
tests/unit/modules/conftest.py future-import-boilerplate
tests/unit/modules/conftest.py metaclass-boilerplate
tests/unit/modules/utils.py future-import-boilerplate
-tests/unit/modules/utils.py metaclass-boilerplate
\ No newline at end of file
+tests/unit/modules/utils.py metaclass-boilerplate
diff --git a/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py b/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py
index 92d2a4f..2a9a81c 100644
--- a/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py
+++ b/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py
@@ -1,430 +1,430 @@
# (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 ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
from ansible_collections.vyos.vyos.plugins.modules import (
vyos_firewall_interfaces,
)
from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
set_module_args,
)
from .vyos_module import TestVyosModule, load_fixture
class TestVyosFirewallInterfacesModule(TestVyosModule):
module = vyos_firewall_interfaces
def setUp(self):
super(TestVyosFirewallInterfacesModule, 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.firewall_interfaces.firewall_interfaces.Firewall_interfacesFacts.get_device_data"
)
self.execute_show_command = self.mock_execute_show_command.start()
def tearDown(self):
super(TestVyosFirewallInterfacesModule, 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):
def load_from_file(*args, **kwargs):
return load_fixture("vyos_firewall_interfaces_config.cfg")
self.execute_show_command.side_effect = load_from_file
def test_vyos_firewall_rule_set_01_merged(self):
set_module_args(
dict(
config=[
dict(
name="eth1",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
dict(
name="eth3",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
],
state="merged",
)
)
commands = [
"set interfaces ethernet eth1 firewall in name 'INBOUND'",
"set interfaces ethernet eth1 firewall out name 'OUTBOUND'",
"set interfaces ethernet eth1 firewall local name 'LOCAL'",
"set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'",
"set interfaces ethernet eth3 firewall in name 'INBOUND'",
"set interfaces ethernet eth3 firewall out name 'OUTBOUND'",
"set interfaces ethernet eth3 firewall local name 'LOCAL'",
"set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_02_merged_idem(self):
set_module_args(
dict(
config=[
dict(
name="eth0",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
dict(
name="eth2",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
],
state="merged",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_firewall_rule_set_01_deleted_per_afi(self):
set_module_args(
dict(
config=[
dict(
name="eth0",
access_rules=[dict(afi="ipv4"), dict(afi="ipv6")],
)
],
state="deleted",
)
)
commands = [
"delete interfaces ethernet eth0 firewall in name",
"delete interfaces ethernet eth0 firewall local name",
"delete interfaces ethernet eth0 firewall out name",
"delete interfaces ethernet eth0 firewall local ipv6-name",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_03_deleted_per_interface(self):
set_module_args(
dict(
config=[dict(name="eth0"), dict(name="eth2")], state="deleted"
)
)
commands = [
"delete interfaces ethernet eth0 firewall",
"delete interfaces ethernet eth2 firewall",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_03_deleted_all(self):
set_module_args(dict(config=[], state="deleted"))
commands = [
"delete interfaces ethernet eth0 firewall",
"delete interfaces ethernet eth2 firewall",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_03_deleted(self):
set_module_args(
dict(
config=[dict(name="eth0"), dict(name="eth2")], state="deleted"
)
)
commands = [
"delete interfaces ethernet eth0 firewall",
"delete interfaces ethernet eth2 firewall",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_04_deleted_interface_idem(self):
set_module_args(
dict(
config=[dict(name="eth1"), dict(name="eth3")], state="deleted"
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_firewall_rule_set_02_replaced_idem(self):
set_module_args(
dict(
config=[
dict(
name="eth0",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
dict(
name="eth2",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
],
state="replaced",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_firewall_rule_set_01_replaced(self):
set_module_args(
dict(
config=[
dict(
name="eth0",
access_rules=[
dict(
afi="ipv4",
- rules=[dict(name="INBOUND", direction="in"),],
+ rules=[dict(name="INBOUND", direction="in")],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
dict(
name="eth2",
access_rules=[
dict(
afi="ipv4",
rules=[dict(name="LOCAL", direction="local")],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
dict(
name="eth3",
access_rules=[
dict(
afi="ipv4",
rules=[dict(name="LOCAL", direction="local")],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
],
state="replaced",
)
)
commands = [
"delete interfaces ethernet eth0 firewall out name",
"delete interfaces ethernet eth0 firewall local name",
"delete interfaces ethernet eth2 firewall in name",
"delete interfaces ethernet eth2 firewall out name",
"set interfaces ethernet eth3 firewall local name 'LOCAL'",
"set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_01_overridden(self):
set_module_args(
dict(
config=[
dict(
name="eth1",
access_rules=[
dict(
afi="ipv4",
rules=[dict(name="INBOUND", direction="in")],
)
],
)
],
state="overridden",
)
)
commands = [
"delete interfaces ethernet eth0 firewall",
"delete interfaces ethernet eth2 firewall",
"set interfaces ethernet eth1 firewall in name 'INBOUND'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_02_overridden_idem(self):
set_module_args(
dict(
config=[
dict(
name="eth0",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
dict(
name="eth2",
access_rules=[
dict(
afi="ipv4",
rules=[
dict(name="INBOUND", direction="in"),
dict(name="OUTBOUND", direction="out"),
dict(name="LOCAL", direction="local"),
],
),
dict(
afi="ipv6",
rules=[
dict(name="V6-LOCAL", direction="local")
],
),
],
),
],
state="overridden",
)
)
self.execute_module(changed=False, commands=[])
diff --git a/tests/unit/modules/network/vyos/test_vyos_firewall_rules.py b/tests/unit/modules/network/vyos/test_vyos_firewall_rules.py
index 86fcc65..8d59e19 100644
--- a/tests/unit/modules/network/vyos/test_vyos_firewall_rules.py
+++ b/tests/unit/modules/network/vyos/test_vyos_firewall_rules.py
@@ -1,1039 +1,1037 @@
# (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 ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
from ansible_collections.vyos.vyos.plugins.modules import vyos_firewall_rules
from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
set_module_args,
)
from .vyos_module import TestVyosModule, load_fixture
class TestVyosFirewallRulesModule(TestVyosModule):
module = vyos_firewall_rules
def setUp(self):
super(TestVyosFirewallRulesModule, 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.static_routes.static_routes.Static_routesFacts.get_device_data"
)
self.mock_execute_show_command = patch(
"ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_rules.firewall_rules.Firewall_rulesFacts.get_device_data"
)
self.execute_show_command = self.mock_execute_show_command.start()
def tearDown(self):
super(TestVyosFirewallRulesModule, 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):
def load_from_file(*args, **kwargs):
return load_fixture("vyos_firewall_rules_config.cfg")
self.execute_show_command.side_effect = load_from_file
def test_vyos_firewall_rule_set_01_merged(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="V6-INBOUND",
description="This is IPv6 INBOUND rule set",
default_action="reject",
enable_default_log=True,
rules=[],
),
dict(
name="V6-OUTBOUND",
description="This is IPv6 OUTBOUND rule set",
default_action="accept",
enable_default_log=False,
rules=[],
),
],
),
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INBOUND",
description="This is IPv4 INBOUND rule set",
default_action="reject",
enable_default_log=True,
rules=[],
),
dict(
name="V4-OUTBOUND",
description="This is IPv4 OUTBOUND rule set",
default_action="accept",
enable_default_log=False,
rules=[],
),
],
),
],
state="merged",
)
)
commands = [
"set firewall ipv6-name V6-INBOUND default-action 'reject'",
"set firewall ipv6-name V6-INBOUND description 'This is IPv6 INBOUND rule set'",
"set firewall ipv6-name V6-INBOUND enable-default-log",
"set firewall ipv6-name V6-OUTBOUND default-action 'accept'",
"set firewall ipv6-name V6-OUTBOUND description 'This is IPv6 OUTBOUND rule set'",
"set firewall name V4-INBOUND default-action 'reject'",
"set firewall name V4-INBOUND description 'This is IPv4 INBOUND rule set'",
"set firewall name V4-INBOUND enable-default-log",
"set firewall name V4-OUTBOUND default-action 'accept'",
"set firewall name V4-OUTBOUND description 'This is IPv4 OUTBOUND rule set'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_rule_set_02_merged(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="V6-INBOUND",
description="This is IPv6 INBOUND rule set",
default_action="reject",
enable_default_log=True,
rules=[],
),
dict(
name="V6-OUTBOUND",
description="This is IPv6 OUTBOUND rule set",
default_action="accept",
enable_default_log=False,
rules=[],
),
],
),
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INBOUND",
description="This is IPv4 INBOUND rule set",
default_action="reject",
enable_default_log=True,
rules=[],
),
dict(
name="V4-OUTBOUND",
description="This is IPv4 OUTBOUND rule set",
default_action="accept",
enable_default_log=False,
rules=[],
),
],
),
],
state="merged",
)
)
commands = [
"set firewall ipv6-name V6-INBOUND default-action 'reject'",
"set firewall ipv6-name V6-INBOUND description 'This is IPv6 INBOUND rule set'",
"set firewall ipv6-name V6-INBOUND enable-default-log",
"set firewall ipv6-name V6-OUTBOUND default-action 'accept'",
"set firewall ipv6-name V6-OUTBOUND description 'This is IPv6 OUTBOUND rule set'",
"set firewall name V4-INBOUND default-action 'reject'",
"set firewall name V4-INBOUND description 'This is IPv4 INBOUND rule set'",
"set firewall name V4-INBOUND enable-default-log",
"set firewall name V4-OUTBOUND default-action 'accept'",
"set firewall name V4-OUTBOUND description 'This is IPv4 OUTBOUND rule set'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_rule_merged_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="INBOUND",
description="This is IPv4 INBOUND rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="101",
action="accept",
description="Rule 101 is configured by Ansible",
ipsec="match-ipsec",
protocol="icmp",
fragment="match-frag",
disabled=True,
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall name INBOUND default-action 'accept'",
"set firewall name INBOUND description 'This is IPv4 INBOUND rule set'",
"set firewall name INBOUND enable-default-log",
"set firewall name INBOUND rule 101 protocol 'icmp'",
"set firewall name INBOUND rule 101 description 'Rule 101 is configured by Ansible'",
"set firewall name INBOUND rule 101 fragment 'match-frag'",
"set firewall name INBOUND rule 101",
"set firewall name INBOUND rule 101 disabled",
"set firewall name INBOUND rule 101 action 'accept'",
"set firewall name INBOUND rule 101 ipsec 'match-ipsec'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_rule_merged_02(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
protocol="tcp",
source=dict(
address="192.0.2.0",
mac_address="38:00:25:19:76:0c",
port=2127,
),
destination=dict(
address="192.0.1.0", port=2124
),
limit=dict(
burst=10,
rate=dict(
number=20, unit="second"
),
),
recent=dict(count=10, time=20),
state=dict(
established=True,
related=True,
invalid=True,
new=True,
),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall name INBOUND rule 101 protocol 'tcp'",
"set firewall name INBOUND rule 101 destination address 192.0.1.0",
"set firewall name INBOUND rule 101 destination port 2124",
"set firewall name INBOUND rule 101",
"set firewall name INBOUND rule 101 source address 192.0.2.0",
"set firewall name INBOUND rule 101 source mac-address 38:00:25:19:76:0c",
"set firewall name INBOUND rule 101 source port 2127",
"set firewall name INBOUND rule 101 state new enable",
"set firewall name INBOUND rule 101 state invalid enable",
"set firewall name INBOUND rule 101 state related enable",
"set firewall name INBOUND rule 101 state established enable",
"set firewall name INBOUND rule 101 limit burst 10",
"set firewall name INBOUND rule 101 limit rate 20/second",
"set firewall name INBOUND rule 101 recent count 10",
"set firewall name INBOUND rule 101 recent time 20",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_rule_merged_03(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
destination=dict(
group=dict(
address_group="OUT-ADDR-GROUP",
network_group="OUT-NET-GROUP",
port_group="OUT-PORT-GROUP",
)
),
source=dict(
group=dict(
address_group="IN-ADDR-GROUP",
network_group="IN-NET-GROUP",
port_group="IN-PORT-GROUP",
)
),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall name INBOUND rule 101 source group address-group IN-ADDR-GROUP",
"set firewall name INBOUND rule 101 source group network-group IN-NET-GROUP",
"set firewall name INBOUND rule 101 source group port-group IN-PORT-GROUP",
"set firewall name INBOUND rule 101 destination group address-group OUT-ADDR-GROUP",
"set firewall name INBOUND rule 101 destination group network-group OUT-NET-GROUP",
"set firewall name INBOUND rule 101 destination group port-group OUT-PORT-GROUP",
"set firewall name INBOUND rule 101",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_rule_merged_04(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
time=dict(
monthdays="2",
startdate="2020-01-24",
starttime="13:20:00",
stopdate="2020-01-28",
stoptime="13:30:00",
weekdays="!Sat,Sun",
utc=True,
),
tcp=dict(flags="ALL"),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall name INBOUND rule 101",
"set firewall name INBOUND rule 101 tcp flags ALL",
"set firewall name INBOUND rule 101 time utc",
"set firewall name INBOUND rule 101 time monthdays 2",
"set firewall name INBOUND rule 101 time startdate 2020-01-24",
"set firewall name INBOUND rule 101 time stopdate 2020-01-28",
"set firewall name INBOUND rule 101 time weekdays !Sat,Sun",
"set firewall name INBOUND rule 101 time stoptime 13:30:00",
"set firewall name INBOUND rule 101 time starttime 13:20:00",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v6_rule_sets_rule_merged_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="INBOUND",
description="This is IPv6 INBOUND rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="101",
action="accept",
description="Rule 101 is configured by Ansible",
ipsec="match-ipsec",
protocol="icmp",
disabled=True,
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall ipv6-name INBOUND default-action 'accept'",
"set firewall ipv6-name INBOUND description 'This is IPv6 INBOUND rule set'",
"set firewall ipv6-name INBOUND enable-default-log",
"set firewall ipv6-name INBOUND rule 101 protocol 'icmp'",
"set firewall ipv6-name INBOUND rule 101 description 'Rule 101 is configured by Ansible'",
"set firewall ipv6-name INBOUND rule 101",
"set firewall ipv6-name INBOUND rule 101 disabled",
"set firewall ipv6-name INBOUND rule 101 action 'accept'",
"set firewall ipv6-name INBOUND rule 101 ipsec 'match-ipsec'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v6_rule_sets_rule_merged_02(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
protocol="tcp",
source=dict(
address="2001:db8::12",
mac_address="38:00:25:19:76:0c",
port=2127,
),
destination=dict(
address="2001:db8::11", port=2124
),
limit=dict(
burst=10,
rate=dict(
number=20, unit="second"
),
),
recent=dict(count=10, time=20),
state=dict(
established=True,
related=True,
invalid=True,
new=True,
),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall ipv6-name INBOUND rule 101 protocol 'tcp'",
"set firewall ipv6-name INBOUND rule 101 destination address 2001:db8::11",
"set firewall ipv6-name INBOUND rule 101 destination port 2124",
"set firewall ipv6-name INBOUND rule 101",
"set firewall ipv6-name INBOUND rule 101 source address 2001:db8::12",
"set firewall ipv6-name INBOUND rule 101 source mac-address 38:00:25:19:76:0c",
"set firewall ipv6-name INBOUND rule 101 source port 2127",
"set firewall ipv6-name INBOUND rule 101 state new enable",
"set firewall ipv6-name INBOUND rule 101 state invalid enable",
"set firewall ipv6-name INBOUND rule 101 state related enable",
"set firewall ipv6-name INBOUND rule 101 state established enable",
"set firewall ipv6-name INBOUND rule 101 limit burst 10",
"set firewall ipv6-name INBOUND rule 101 recent count 10",
"set firewall ipv6-name INBOUND rule 101 recent time 20",
"set firewall ipv6-name INBOUND rule 101 limit rate 20/second",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v6_rule_sets_rule_merged_03(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
destination=dict(
group=dict(
address_group="OUT-ADDR-GROUP",
network_group="OUT-NET-GROUP",
port_group="OUT-PORT-GROUP",
)
),
source=dict(
group=dict(
address_group="IN-ADDR-GROUP",
network_group="IN-NET-GROUP",
port_group="IN-PORT-GROUP",
)
),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall ipv6-name INBOUND rule 101 source group address-group IN-ADDR-GROUP",
"set firewall ipv6-name INBOUND rule 101 source group network-group IN-NET-GROUP",
"set firewall ipv6-name INBOUND rule 101 source group port-group IN-PORT-GROUP",
"set firewall ipv6-name INBOUND rule 101 destination group address-group OUT-ADDR-GROUP",
"set firewall ipv6-name INBOUND rule 101 destination group network-group OUT-NET-GROUP",
"set firewall ipv6-name INBOUND rule 101 destination group port-group OUT-PORT-GROUP",
"set firewall ipv6-name INBOUND rule 101",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v6_rule_sets_rule_merged_04(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
time=dict(
monthdays="2",
startdate="2020-01-24",
starttime="13:20:00",
stopdate="2020-01-28",
stoptime="13:30:00",
weekdays="!Sat,Sun",
utc=True,
),
tcp=dict(flags="ALL"),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall ipv6-name INBOUND rule 101",
"set firewall ipv6-name INBOUND rule 101 tcp flags ALL",
"set firewall ipv6-name INBOUND rule 101 time utc",
"set firewall ipv6-name INBOUND rule 101 time monthdays 2",
"set firewall ipv6-name INBOUND rule 101 time startdate 2020-01-24",
"set firewall ipv6-name INBOUND rule 101 time stopdate 2020-01-28",
"set firewall ipv6-name INBOUND rule 101 time weekdays !Sat,Sun",
"set firewall ipv6-name INBOUND rule 101 time stoptime 13:30:00",
"set firewall ipv6-name INBOUND rule 101 time starttime 13:20:00",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v6_rule_sets_rule_merged_icmp_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv6",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
protocol="icmp",
icmp=dict(
type_name="port-unreachable"
),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall ipv6-name INBOUND rule 101 icmpv6 type port-unreachable",
"set firewall ipv6-name INBOUND rule 101 protocol 'icmp'",
"set firewall ipv6-name INBOUND rule 101",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_rule_merged_icmp_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
protocol="icmp",
icmp=dict(type=1, code=1),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall name INBOUND rule 101 icmp type 1",
"set firewall name INBOUND rule 101 icmp code 1",
"set firewall name INBOUND rule 101 protocol 'icmp'",
"set firewall name INBOUND rule 101",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_rule_merged_icmp_02(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="INBOUND",
rules=[
dict(
number="101",
protocol="icmp",
icmp=dict(type_name="echo-request"),
)
],
),
],
)
],
state="merged",
)
)
commands = [
"set firewall name INBOUND rule 101 icmp type-name echo-request",
"set firewall name INBOUND rule 101 protocol 'icmp'",
"set firewall name INBOUND rule 101",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4_rule_sets_del_01(self):
set_module_args(
dict(
- config=[
- dict(afi="ipv4", rule_sets=[dict(name="V4-INGRESS"),])
- ],
+ config=[dict(afi="ipv4", rule_sets=[dict(name="V4-INGRESS")])],
state="deleted",
)
)
commands = ["delete firewall name V4-INGRESS"]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4v6_rule_sets_del_02(self):
set_module_args(
dict(
config=[
- dict(afi="ipv4", rule_sets=[dict(name="V4-INGRESS"),]),
- dict(afi="ipv6", rule_sets=[dict(name="V6-INGRESS"),]),
+ dict(afi="ipv4", rule_sets=[dict(name="V4-INGRESS")]),
+ dict(afi="ipv6", rule_sets=[dict(name="V6-INGRESS")]),
],
state="deleted",
)
)
commands = [
"delete firewall name V4-INGRESS",
"delete firewall ipv6-name V6-INGRESS",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4v6_rule_sets_del_03(self):
set_module_args(dict(config=[], state="deleted"))
commands = ["delete firewall name", "delete firewall ipv6-name"]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4v6_rule_sets_del_04(self):
set_module_args(
dict(
config=[
- dict(afi="ipv4", rule_sets=[dict(name="V4-ING"),]),
- dict(afi="ipv6", rule_sets=[dict(name="V6-ING"),]),
+ dict(afi="ipv4", rule_sets=[dict(name="V4-ING")]),
+ dict(afi="ipv6", rule_sets=[dict(name="V6-ING")]),
],
state="deleted",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_firewall_v4v6_rule_sets_rule_rep_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INGRESS",
description="This is IPv4 INGRESS rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="101",
action="reject",
description="Rule 101 is configured by Ansible RM",
ipsec="match-ipsec",
protocol="tcp",
fragment="match-frag",
disabled=False,
),
dict(
number="102",
action="accept",
description="Rule 102 is configured by Ansible RM",
protocol="icmp",
disabled=True,
),
],
),
],
),
dict(
afi="ipv6",
rule_sets=[
dict(
name="V6-INGRESS",
default_action="accept",
description="This rule-set is configured by Ansible RM",
),
dict(
name="V6-EGRESS",
default_action="reject",
description="This rule-set is configured by Ansible RM",
),
],
),
],
state="replaced",
)
)
commands = [
"delete firewall name V4-INGRESS rule 101 disabled",
"delete firewall name V4-EGRESS default-action",
"set firewall name V4-INGRESS description 'This is IPv4 INGRESS rule set'",
"set firewall name V4-INGRESS rule 101 protocol 'tcp'",
"set firewall name V4-INGRESS rule 101 description 'Rule 101 is configured by Ansible RM'",
"set firewall name V4-INGRESS rule 101 action 'reject'",
"set firewall name V4-INGRESS rule 102 disabled",
"set firewall name V4-INGRESS rule 102 action 'accept'",
"set firewall name V4-INGRESS rule 102 protocol 'icmp'",
"set firewall name V4-INGRESS rule 102 description 'Rule 102 is configured by Ansible RM'",
"set firewall name V4-INGRESS rule 102",
"set firewall ipv6-name V6-INGRESS description 'This rule-set is configured by Ansible RM'",
"set firewall ipv6-name V6-EGRESS description 'This rule-set is configured by Ansible RM'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4v6_rule_sets_rule_rep_02(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INGRESS",
description="This is IPv4 V4-INGRESS rule set",
default_action="accept",
enable_default_log=False,
rules=[
dict(
number="101",
action="accept",
description="Rule 101 is configured by Ansible",
ipsec="match-ipsec",
protocol="icmp",
fragment="match-frag",
disabled=True,
),
],
),
],
),
dict(
afi="ipv6",
rule_sets=[
dict(name="V6-INGRESS", default_action="accept",),
dict(name="V6-EGRESS", default_action="reject",),
],
),
],
state="replaced",
)
)
commands = [
"delete firewall name V4-INGRESS enable-default-log",
"delete firewall name V4-EGRESS default-action",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4v6_rule_sets_rule_rep_idem_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INGRESS",
description="This is IPv4 V4-INGRESS rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="101",
action="accept",
description="Rule 101 is configured by Ansible",
ipsec="match-ipsec",
protocol="icmp",
fragment="match-frag",
disabled=True,
)
],
),
dict(name="V4-EGRESS", default_action="reject",),
],
),
dict(
afi="ipv6",
rule_sets=[
dict(name="V6-INGRESS", default_action="accept",),
dict(name="V6-EGRESS", default_action="reject",),
],
),
],
state="replaced",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_firewall_v4v6_rule_sets_rule_mer_idem_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INGRESS",
description="This is IPv4 V4-INGRESS rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="101",
action="accept",
description="Rule 101 is configured by Ansible",
ipsec="match-ipsec",
protocol="icmp",
fragment="match-frag",
disabled=True,
)
],
),
dict(name="V4-EGRESS", default_action="reject",),
],
),
dict(
afi="ipv6",
rule_sets=[
dict(name="V6-INGRESS", default_action="accept",),
dict(name="V6-EGRESS", default_action="reject",),
],
),
],
state="merged",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_firewall_v4v6_rule_sets_rule_ovr_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-IN",
description="This is IPv4 INGRESS rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="1",
action="reject",
description="Rule 1 is configured by Ansible RM",
ipsec="match-ipsec",
protocol="tcp",
fragment="match-frag",
disabled=False,
),
dict(
number="2",
action="accept",
description="Rule 102 is configured by Ansible RM",
protocol="icmp",
disabled=True,
),
],
),
],
),
dict(
afi="ipv6",
rule_sets=[
dict(
name="V6-IN",
default_action="accept",
description="This rule-set is configured by Ansible RM",
),
dict(
name="V6-EG",
default_action="reject",
description="This rule-set is configured by Ansible RM",
),
],
),
],
state="overridden",
)
)
commands = [
"delete firewall ipv6-name V6-INGRESS",
"delete firewall ipv6-name V6-EGRESS",
"delete firewall name V4-INGRESS",
"delete firewall name V4-EGRESS",
"set firewall name V4-IN default-action 'accept'",
"set firewall name V4-IN description 'This is IPv4 INGRESS rule set'",
"set firewall name V4-IN enable-default-log",
"set firewall name V4-IN rule 1 protocol 'tcp'",
"set firewall name V4-IN rule 1 description 'Rule 1 is configured by Ansible RM'",
"set firewall name V4-IN rule 1 fragment 'match-frag'",
"set firewall name V4-IN rule 1",
"set firewall name V4-IN rule 1 action 'reject'",
"set firewall name V4-IN rule 1 ipsec 'match-ipsec'",
"set firewall name V4-IN rule 2 disabled",
"set firewall name V4-IN rule 2 action 'accept'",
"set firewall name V4-IN rule 2 protocol 'icmp'",
"set firewall name V4-IN rule 2 description 'Rule 102 is configured by Ansible RM'",
"set firewall name V4-IN rule 2",
"set firewall ipv6-name V6-IN default-action 'accept'",
"set firewall ipv6-name V6-IN description 'This rule-set is configured by Ansible RM'",
"set firewall ipv6-name V6-EG default-action 'reject'",
"set firewall ipv6-name V6-EG description 'This rule-set is configured by Ansible RM'",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_firewall_v4v6_rule_sets_rule_ovr_idem_01(self):
set_module_args(
dict(
config=[
dict(
afi="ipv4",
rule_sets=[
dict(
name="V4-INGRESS",
description="This is IPv4 V4-INGRESS rule set",
default_action="accept",
enable_default_log=True,
rules=[
dict(
number="101",
action="accept",
description="Rule 101 is configured by Ansible",
ipsec="match-ipsec",
protocol="icmp",
fragment="match-frag",
disabled=True,
)
],
),
dict(name="V4-EGRESS", default_action="reject",),
],
),
dict(
afi="ipv6",
rule_sets=[
dict(name="V6-INGRESS", default_action="accept",),
dict(name="V6-EGRESS", default_action="reject",),
],
),
],
state="overridden",
)
)
self.execute_module(changed=False, commands=[])
diff --git a/tests/unit/modules/network/vyos/test_vyos_ospfv2.py b/tests/unit/modules/network/vyos/test_vyos_ospfv2.py
index b825066..3d558b8 100644
--- a/tests/unit/modules/network/vyos/test_vyos_ospfv2.py
+++ b/tests/unit/modules/network/vyos/test_vyos_ospfv2.py
@@ -1,435 +1,435 @@
# (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 ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
from ansible_collections.vyos.vyos.plugins.modules import vyos_ospfv2
from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
set_module_args,
)
from .vyos_module import TestVyosModule, load_fixture
class TestVyosFirewallRulesModule(TestVyosModule):
module = vyos_ospfv2
def setUp(self):
super(TestVyosFirewallRulesModule, 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.ospfv2.ospfv2.Ospfv2Facts.get_device_data"
)
self.execute_show_command = self.mock_execute_show_command.start()
def tearDown(self):
super(TestVyosFirewallRulesModule, 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, transport="cli", filename=None):
if filename is None:
filename = "vyos_ospfv2_config.cfg"
def load_from_file(*args, **kwargs):
output = load_fixture(filename)
return output
self.execute_show_command.side_effect = load_from_file
def test_vyos_ospfv2_merged_new_config(self):
set_module_args(
dict(
config=dict(
log_adjacency_changes="detail",
mpls_te=dict(enabled=True, router_address="192.0.11.11"),
auto_cost=dict(reference_bandwidth=2),
areas=[
dict(
area_id="2",
area_type=dict(normal=True),
authentication="plaintext-password",
shortcut="enable",
),
dict(
area_id="4",
area_type=dict(stub=dict(default_cost=10)),
- network=[dict(address="192.0.2.0/24"),],
+ network=[dict(address="192.0.2.0/24")],
range=[
dict(address="192.0.3.0/24", cost=10),
dict(address="192.0.4.0/24", cost=12),
],
),
],
),
state="merged",
)
)
commands = [
"set protocols ospf mpls-te enable",
"set protocols ospf mpls-te router-address '192.0.11.11'",
"set protocols ospf auto-cost reference-bandwidth '2'",
"set protocols ospf log-adjacency-changes 'detail'",
"set protocols ospf area '2'",
"set protocols ospf area 2 authentication plaintext-password",
"set protocols ospf area 2 shortcut enable",
"set protocols ospf area 2 area-type normal",
"set protocols ospf area 4 range 192.0.3.0/24 cost 10",
"set protocols ospf area 4 range 192.0.3.0/24",
"set protocols ospf area 4 range 192.0.4.0/24 cost 12",
"set protocols ospf area 4 range 192.0.4.0/24",
"set protocols ospf area 4 area-type stub default-cost 10",
"set protocols ospf area '4'",
"set protocols ospf area 4 network 192.0.2.0/24",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv2_merged_idem(self):
set_module_args(
dict(
config=dict(
areas=[
dict(
area_id="12",
area_type=dict(normal=True),
authentication="plaintext-password",
shortcut="enable",
),
dict(
area_id="14",
area_type=dict(stub=dict(default_cost=20)),
- network=[dict(address="192.0.12.0/24"),],
+ network=[dict(address="192.0.12.0/24")],
range=[
dict(address="192.0.13.0/24", cost=10),
dict(address="192.0.14.0/24", cost=12),
],
),
],
),
state="merged",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_ospfv2_merged_update_existing(self):
set_module_args(
dict(
config=dict(
areas=[
dict(
area_id="12",
area_type=dict(normal=True),
authentication="plaintext-password",
shortcut="enable",
),
dict(
area_id="14",
area_type=dict(stub=dict(set=False)),
network=[
dict(address="192.0.12.0/24"),
dict(address="192.0.22.0/24"),
],
range=[
dict(address="192.0.13.0/24", cost=10),
dict(address="192.0.14.0/24", cost=12),
],
),
],
),
state="merged",
)
)
commands = [
"delete protocols ospf area 14 area-type stub",
"set protocols ospf area 14 network 192.0.22.0/24",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv2_replaced(self):
set_module_args(
dict(
config=dict(
log_adjacency_changes="detail",
mpls_te=dict(enabled=True, router_address="192.0.11.11"),
auto_cost=dict(reference_bandwidth=2),
areas=[
dict(
area_id="12",
area_type=dict(normal=True),
authentication="plaintext-password",
shortcut="enable",
),
dict(
area_id="15",
area_type=dict(stub=dict(default_cost=10)),
- network=[dict(address="192.0.12.0/24"),],
+ network=[dict(address="192.0.12.0/24")],
range=[
dict(address="192.0.13.0/24", cost=10),
dict(address="192.0.14.0/24", cost=12),
dict(address="192.0.15.0/24", cost=14),
],
),
],
),
state="replaced",
)
)
commands = [
"set protocols ospf mpls-te enable",
"set protocols ospf mpls-te router-address '192.0.11.11'",
"set protocols ospf auto-cost reference-bandwidth '2'",
"set protocols ospf log-adjacency-changes 'detail'",
"delete protocols ospf area 14",
"set protocols ospf area 15 range 192.0.13.0/24 cost 10",
"set protocols ospf area 15 range 192.0.13.0/24",
"set protocols ospf area 15 range 192.0.14.0/24 cost 12",
"set protocols ospf area 15 range 192.0.14.0/24",
"set protocols ospf area 15 range 192.0.15.0/24 cost 14",
"set protocols ospf area 15 range 192.0.15.0/24",
"set protocols ospf area 15 area-type stub default-cost 10",
"set protocols ospf area '15'",
"set protocols ospf area 15 network 192.0.12.0/24",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv2_replaced_idem(self):
set_module_args(
dict(
config=dict(
areas=[
dict(
area_id="12",
area_type=dict(normal=True),
authentication="plaintext-password",
shortcut="enable",
),
dict(
area_id="14",
area_type=dict(stub=dict(default_cost=20)),
- network=[dict(address="192.0.12.0/24"),],
+ network=[dict(address="192.0.12.0/24")],
range=[
dict(address="192.0.13.0/24", cost=10),
dict(address="192.0.14.0/24", cost=12),
],
),
],
),
state="replaced",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_ospfv2_deleted_no_config(self):
set_module_args(dict(config=None, state="deleted"))
commands = ["delete protocols ospf"]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv2_gathered(self):
set_module_args(dict(state="gathered"))
result = self.execute_module(
changed=False, filename="vyos_ospfv2_config.cfg"
)
gather_dict = {
"areas": [
{
"area_id": "2",
"area_type": {"normal": True},
"authentication": "plaintext-password",
"shortcut": "enable",
},
{
"area_id": "14",
"area_type": {"stub": {"default_cost": 20, "set": True}},
"network": [{"address": "192.0.12.0/24"}],
"range": [
{"address": "192.0.13.0/24", "cost": 10},
{"address": "192.0.14.0/24", "cost": 12},
],
},
],
}
self.assertEqual(sorted(gather_dict), sorted(result["gathered"]))
def test_vyos_ospfv2_parsed(self):
parsed_str = """set protocols ospf area 2 area-type 'normal'
set protocols ospf area 2 authentication 'plaintext-password'
set protocols ospf area 2 shortcut 'enable'
set protocols ospf area 3 area-type 'nssa'
set protocols ospf area 4 area-type stub default-cost '20'
set protocols ospf area 4 network '192.0.2.0/24'
set protocols ospf area 4 range 192.0.3.0/24 cost '10'
set protocols ospf area 4 range 192.0.4.0/24 cost '12'
set protocols ospf default-information originate 'always'
set protocols ospf default-information originate metric '10'
set protocols ospf default-information originate metric-type '2'
set protocols ospf auto-cost reference-bandwidth '2'
set protocols ospf default-information originate route-map 'ingress'
set protocols ospf log-adjacency-changes 'detail'
set protocols ospf max-metric router-lsa 'administrative'
set protocols ospf max-metric router-lsa on-shutdown '10'
set protocols ospf max-metric router-lsa on-startup '10'
set protocols ospf mpls-te 'enable'
set protocols ospf mpls-te router-address '192.0.11.11'
set protocols ospf neighbor 192.0.11.12 poll-interval '10'
set protocols ospf neighbor 192.0.11.12 priority '2'
set protocols ospf parameters abr-type 'cisco'
set protocols ospf parameters 'opaque-lsa'
set protocols ospf parameters 'rfc1583-compatibility'
set protocols ospf parameters router-id '192.0.1.1'
set protocols ospf passive-interface 'eth1'
set protocols ospf passive-interface 'eth2'
set protocols ospf redistribute bgp metric '10'
set protocols ospf redistribute bgp metric-type '2'"""
set_module_args(dict(running_config=parsed_str, state="parsed"))
result = self.execute_module(changed=False)
parsed_list = {
"areas": [
{
"area_id": "2",
"area_type": {"normal": True},
"authentication": "plaintext-password",
"shortcut": "enable",
},
{"area_id": "3", "area_type": {"nssa": {"set": True}}},
{
"area_id": "4",
"area_type": {"stub": {"default_cost": 20, "set": True}},
"network": [{"address": "192.0.2.0/24"}],
"range": [
{"address": "192.0.3.0/24", "cost": 10},
{"address": "192.0.4.0/24", "cost": 12},
],
},
],
"auto_cost": {"reference_bandwidth": 2},
"default_information": {
"originate": {
"always": True,
"metric": 10,
"metric_type": 2,
"route_map": "ingress",
}
},
"log_adjacency_changes": "detail",
"max_metric": {
"router_lsa": {
"administrative": True,
"on_shutdown": 10,
"on_startup": 10,
}
},
"mpls_te": {"enabled": True, "router_address": "192.0.11.11"},
"neighbor": [
{
"neighbor_id": "192.0.11.12",
"poll_interval": 10,
"priority": 2,
}
],
"parameters": {
"abr_type": "cisco",
"opaque_lsa": True,
"rfc1583_compatibility": True,
"router_id": "192.0.1.1",
},
"passive_interface": ["eth2", "eth1"],
"redistribute": [
{"metric": 10, "metric_type": 2, "route_type": "bgp"}
],
}
self.assertEqual(sorted(parsed_list), sorted(result["parsed"]))
def test_vyos_ospfv2_rendered(self):
set_module_args(
dict(
config=dict(
log_adjacency_changes="detail",
mpls_te=dict(enabled=True, router_address="192.0.11.11"),
auto_cost=dict(reference_bandwidth=2),
areas=[
dict(
area_id="2",
area_type=dict(normal=True),
authentication="plaintext-password",
shortcut="enable",
),
dict(
area_id="4",
area_type=dict(stub=dict(default_cost=10)),
- network=[dict(address="192.0.2.0/24"),],
+ network=[dict(address="192.0.2.0/24")],
range=[
dict(address="192.0.3.0/24", cost=10),
dict(address="192.0.4.0/24", cost=12),
],
),
],
),
state="rendered",
)
)
commands = [
"set protocols ospf mpls-te enable",
"set protocols ospf mpls-te router-address '192.0.11.11'",
"set protocols ospf auto-cost reference-bandwidth '2'",
"set protocols ospf log-adjacency-changes 'detail'",
"set protocols ospf area '2'",
"set protocols ospf area 2 authentication plaintext-password",
"set protocols ospf area 2 shortcut enable",
"set protocols ospf area 2 area-type normal",
"set protocols ospf area 4 range 192.0.3.0/24 cost 10",
"set protocols ospf area 4 range 192.0.3.0/24",
"set protocols ospf area 4 range 192.0.4.0/24 cost 12",
"set protocols ospf area 4 range 192.0.4.0/24",
"set protocols ospf area 4 area-type stub default-cost 10",
"set protocols ospf area '4'",
"set protocols ospf area 4 network 192.0.2.0/24",
]
result = self.execute_module(changed=False)
self.assertEqual(
sorted(result["rendered"]), sorted(commands), result["rendered"]
)
diff --git a/tests/unit/modules/network/vyos/test_vyos_ospfv3.py b/tests/unit/modules/network/vyos/test_vyos_ospfv3.py
index 1d9cb3a..9c016da 100644
--- a/tests/unit/modules/network/vyos/test_vyos_ospfv3.py
+++ b/tests/unit/modules/network/vyos/test_vyos_ospfv3.py
@@ -1,348 +1,348 @@
# (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 ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
from ansible_collections.vyos.vyos.plugins.modules import vyos_ospfv3
from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
set_module_args,
)
from .vyos_module import TestVyosModule, load_fixture
class TestVyosFirewallRulesModule(TestVyosModule):
module = vyos_ospfv3
def setUp(self):
super(TestVyosFirewallRulesModule, 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.ospfv3.ospfv3.Ospfv3Facts.get_device_data"
)
self.execute_show_command = self.mock_execute_show_command.start()
def tearDown(self):
super(TestVyosFirewallRulesModule, 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, transport="cli", filename=None):
if filename is None:
filename = "vyos_ospfv3_config.cfg"
def load_from_file(*args, **kwargs):
output = load_fixture(filename)
return output
self.execute_show_command.side_effect = load_from_file
def test_vyos_ospfv3_merged_new_config(self):
set_module_args(
dict(
config=dict(
redistribute=[dict(route_type="bgp")],
parameters=dict(router_id="192.0.2.10"),
areas=[
dict(
area_id="2",
export_list="export1",
import_list="import1",
range=[
dict(address="2001:db10::/32"),
dict(address="2001:db20::/32"),
dict(address="2001:db30::/32"),
],
),
dict(
area_id="3",
- range=[dict(address="2001:db40::/32"),],
+ range=[dict(address="2001:db40::/32")],
),
],
),
state="merged",
)
)
commands = [
"set protocols ospfv3 redistribute bgp",
"set protocols ospfv3 parameters router-id '192.0.2.10'",
"set protocols ospfv3 area 2 range 2001:db10::/32",
"set protocols ospfv3 area 2 range 2001:db20::/32",
"set protocols ospfv3 area 2 range 2001:db30::/32",
"set protocols ospfv3 area '2'",
"set protocols ospfv3 area 2 export-list export1",
"set protocols ospfv3 area 2 import-list import1",
"set protocols ospfv3 area '3'",
"set protocols ospfv3 area 3 range 2001:db40::/32",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv3_merged_idem(self):
set_module_args(
dict(
config=dict(
areas=[
dict(
area_id="12",
export_list="export1",
import_list="import1",
range=[
dict(address="2001:db11::/32"),
dict(address="2001:db22::/32"),
dict(address="2001:db33::/32"),
],
),
dict(
area_id="13",
- range=[dict(address="2001:db44::/32"),],
+ range=[dict(address="2001:db44::/32")],
),
],
),
state="merged",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_ospfv3_merged_update_existing(self):
set_module_args(
dict(
config=dict(
redistribute=[dict(route_type="bgp")],
parameters=dict(router_id="192.0.2.10"),
areas=[
dict(
area_id="12",
export_list="export1",
import_list="import1",
range=[
dict(address="2001:db11::/32"),
dict(address="2001:db22::/32"),
dict(address="2001:db33::/32"),
],
),
dict(
area_id="13",
range=[
dict(address="2001:db44::/32"),
dict(address="2001:db55::/32"),
],
),
],
),
state="merged",
)
)
commands = [
"set protocols ospfv3 redistribute bgp",
"set protocols ospfv3 parameters router-id '192.0.2.10'",
"set protocols ospfv3 area 13 range 2001:db55::/32",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv3_replaced(self):
set_module_args(
dict(
config=dict(
redistribute=[dict(route_type="bgp")],
parameters=dict(router_id="192.0.2.10"),
areas=[
dict(
area_id="12",
export_list="export1",
import_list="import1",
range=[
dict(address="2001:db10::/32"),
dict(address="2001:db22::/32"),
dict(address="2001:db33::/32"),
],
),
dict(
area_id="14",
- range=[dict(address="2001:db40::/32"),],
+ range=[dict(address="2001:db40::/32")],
),
],
),
state="replaced",
)
)
commands = [
"set protocols ospfv3 redistribute bgp",
"set protocols ospfv3 parameters router-id '192.0.2.10'",
"delete protocols ospfv3 area 12 range 2001:db11::/32",
"set protocols ospfv3 area 12 range 2001:db10::/32",
"delete protocols ospfv3 area 13",
"set protocols ospfv3 area '14'",
"set protocols ospfv3 area 14 range 2001:db40::/32",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv3_replaced_idem(self):
set_module_args(
dict(
config=dict(
areas=[
dict(
area_id="12",
export_list="export1",
import_list="import1",
range=[
dict(address="2001:db11::/32"),
dict(address="2001:db22::/32"),
dict(address="2001:db33::/32"),
],
),
dict(
area_id="13",
- range=[dict(address="2001:db44::/32"),],
+ range=[dict(address="2001:db44::/32")],
),
],
),
state="replaced",
)
)
self.execute_module(changed=False, commands=[])
def test_vyos_ospfv3_deleted_no_config(self):
set_module_args(dict(config=None, state="deleted"))
commands = ["delete protocols ospfv3"]
self.execute_module(changed=True, commands=commands)
def test_vyos_ospfv3_gathered(self):
set_module_args(dict(state="gathered"))
result = self.execute_module(
changed=False, filename="vyos_ospfv3_config.cfg"
)
gather_dict = {
"areas": [
{
"area_id": "12",
"export_list": "export1",
"import_list": "import1",
"range": [
{"address": "2001:db11::/32"},
{"address": "2001:db22::/32"},
{"address": "2001:db33::/32"},
],
},
{"area_id": "13", "range": [{"address": "2001:db44::/32"}]},
],
}
self.assertEqual(sorted(gather_dict), sorted(result["gathered"]))
def test_vyos_ospfv3_parsed(self):
parsed_str = """set protocols ospfv3 area 2 export-list 'export1'
set protocols ospfv3 area 2 import-list 'import1'
set protocols ospfv3 area 2 range '2001:db10::/32'
set protocols ospfv3 area 2 range '2001:db20::/32'
set protocols ospfv3 area 2 range '2001:db30::/32'
set protocols ospfv3 area 3 range '2001:db40::/32'
set protocols ospfv3 parameters router-id '192.0.2.10'
set protocols ospfv3 redistribute 'bgp'"""
set_module_args(dict(running_config=parsed_str, state="parsed"))
result = self.execute_module(changed=False)
parsed_dict = {
"areas": [
{
"area_id": "2",
"export_list": "export1",
"import_list": "import1",
"range": [
{"address": "2001:db10::/32"},
{"address": "2001:db20::/32"},
{"address": "2001:db30::/32"},
],
},
{"area_id": "3", "range": [{"address": "2001:db40::/32"}]},
],
"parameters": {"router_id": "192.0.2.10"},
"redistribute": [{"route_type": "bgp"}],
}
self.assertEqual(sorted(parsed_dict), sorted(result["parsed"]))
def test_vyos_ospfv3_rendered(self):
set_module_args(
dict(
config=dict(
redistribute=[dict(route_type="bgp")],
parameters=dict(router_id="192.0.2.10"),
areas=[
dict(
area_id="2",
export_list="export1",
import_list="import1",
range=[
dict(address="2001:db10::/32"),
dict(address="2001:db20::/32"),
dict(address="2001:db30::/32"),
],
),
dict(
area_id="3",
- range=[dict(address="2001:db40::/32"),],
+ range=[dict(address="2001:db40::/32")],
),
],
),
state="rendered",
)
)
commands = [
"set protocols ospfv3 redistribute bgp",
"set protocols ospfv3 parameters router-id '192.0.2.10'",
"set protocols ospfv3 area 2 range 2001:db10::/32",
"set protocols ospfv3 area 2 range 2001:db20::/32",
"set protocols ospfv3 area 2 range 2001:db30::/32",
"set protocols ospfv3 area '2'",
"set protocols ospfv3 area 2 export-list export1",
"set protocols ospfv3 area 2 import-list import1",
"set protocols ospfv3 area '3'",
"set protocols ospfv3 area 3 range 2001:db40::/32",
]
result = self.execute_module(changed=False)
self.assertEqual(
sorted(result["rendered"]), sorted(commands), result["rendered"]
)
diff --git a/tox.ini b/tox.ini
index 3a6d05a..4aaa22a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,32 +1,32 @@
[tox]
minversion = 1.4.2
envlist = linters
skipsdist = True
[testenv]
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
[testenv:black]
install_command = pip install {opts} {packages}
commands =
black -v -l79 {toxinidir}
[testenv:linters]
install_command = pip install {opts} {packages}
commands =
black -v -l79 --check {toxinidir}
flake8 {posargs}
yamllint -s .
[testenv:venv]
commands = {posargs}
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
-ignore = E123,E125,E231,E402,W503
+ignore = E123,E125,E402,W503
max-line-length = 160
builtins = _
exclude = .git,.tox,tests/unit/compat/