diff options
36 files changed, 3818 insertions, 4 deletions
diff --git a/plugins/module_utils/network/vyos/argspec/firewall_interfaces/__init__.py b/plugins/module_utils/network/vyos/argspec/firewall_interfaces/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/firewall_interfaces/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/firewall_interfaces/firewall_interfaces.py b/plugins/module_utils/network/vyos/argspec/firewall_interfaces/firewall_interfaces.py new file mode 100644 index 0000000..f083485 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/firewall_interfaces/firewall_interfaces.py @@ -0,0 +1,85 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the vyos_firewall_interfaces module +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +class Firewall_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the vyos_firewall_interfaces module + """ + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "access_rules": { + "elements": "dict", + "options": { + "afi": { + "choices": ["ipv4", "ipv6"], + "required": True, + "type": "str", + }, + "rules": { + "elements": "dict", + "options": { + "direction": { + "choices": ["in", "local", "out"], + "required": True, + "type": "str", + }, + "name": {"type": "str"}, + }, + "type": "list", + }, + }, + "type": "list", + }, + "name": {"required": True, "type": "str"}, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "parsed", + "rendered", + "gathered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/firewall_interfaces/__init__.py b/plugins/module_utils/network/vyos/config/firewall_interfaces/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/firewall_interfaces/__init__.py diff --git a/plugins/module_utils/network/vyos/config/firewall_interfaces/firewall_interfaces.py b/plugins/module_utils/network/vyos/config/firewall_interfaces/firewall_interfaces.py new file mode 100644 index 0000000..b436bfa --- /dev/null +++ b/plugins/module_utils/network/vyos/config/firewall_interfaces/firewall_interfaces.py @@ -0,0 +1,455 @@ +# +# -*- 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_firewall_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from copy import deepcopy +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + to_list, + dict_diff, + remove_empties, + search_obj_in_list, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( + Facts, +) + + +class Firewall_interfaces(ConfigBase): + """ + The vyos_firewall_interfaces class + """ + + gather_subset = [ + "!all", + "!min", + ] + + gather_network_resources = [ + "firewall_interfaces", + ] + + def __init__(self, module): + super(Firewall_interfaces, self).__init__(module) + + def get_firewall_interfaces_facts(self, data=None): + """ Get the 'facts' (the current configuration) + + :rtype: A dictionary + :returns: The current configuration as a dictionary + """ + facts, _warnings = Facts(self._module).get_facts( + self.gather_subset, self.gather_network_resources, data=data + ) + firewall_interfaces_facts = facts["ansible_network_resources"].get( + "firewall_interfaces" + ) + if not firewall_interfaces_facts: + return [] + return firewall_interfaces_facts + + def execute_module(self): + """ Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_firewall_interfaces_facts = ( + self.get_firewall_interfaces_facts() + ) + else: + existing_firewall_interfaces_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend( + self.set_config(existing_firewall_interfaces_facts) + ) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_firewall_interfaces_facts = ( + self.get_firewall_interfaces_facts() + ) + elif self.state == "rendered": + result["rendered"] = commands + elif self.state == "parsed": + running_config = self._module.params["running_config"] + if not running_config: + self._module.fail_json( + msg="value of running_config parameter must not be empty for state parsed" + ) + result["parsed"] = self.get_firewall_interfaces_facts( + data=running_config + ) + else: + changed_firewall_interfaces_facts = [] + + if self.state in self.ACTION_STATES: + result["before"] = existing_firewall_interfaces_facts + if result["changed"]: + result["after"] = changed_firewall_interfaces_facts + elif self.state == "gathered": + result["gathered"] = changed_firewall_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_firewall_interfaces_facts): + """ Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_firewall_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, w, h): + """ Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + if ( + self.state in ("merged", "replaced", "overridden", "rendered") + and not w + ): + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + self.state + ) + ) + if self.state == "overridden": + commands.extend(self._state_overridden(w, h)) + elif self.state == "deleted": + commands.extend(self._state_deleted(w, h)) + elif w: + if self.state == "merged" or self.state == "rendered": + commands.extend(self._state_merged(w, h)) + elif self.state == "replaced": + commands.extend(self._state_replaced(w, h)) + return commands + + def _state_replaced(self, want, have): + """ The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + if have: + for h in have: + w = search_obj_in_list(h["name"], want) + commands.extend(self._render_access_rules(h, w, opr=False)) + commands.extend(self._state_merged(want, have)) + return commands + + def _state_overridden(self, want, have): + """ The command generator when state is overridden + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + if have: + for h_ar in have: + w_ar = search_obj_in_list(h_ar["name"], want) + if not w_ar and "access_rules" in h_ar: + commands.append( + self._compute_command(name=h_ar["name"], opr=False) + ) + else: + h_rules = h_ar.get("access_rules") or [] + key = "direction" + if w_ar: + w_rules = w_ar.get("access_rules") or [] + if not w_rules and h_rules: + commands.append( + self._compute_command( + name=h_ar["name"], opr=False + ) + ) + if h_rules: + for h_rule in h_rules: + w_rule = search_obj_in_list( + h_rule["afi"], w_rules, key="afi" + ) + have_rules = h_rule.get("rules") or [] + if w_rule: + want_rules = w_rule.get("rules") or [] + for h in have_rules: + if key in h: + w = search_obj_in_list( + h[key], want_rules, key=key + ) + if ( + not w + or key not in w + or ( + "name" in h + and w + and "name" not in w + ) + ): + commands.append( + self._compute_command( + afi=h_rule["afi"], + name=h_ar["name"], + attrib=h[key], + opr=False, + ) + ) + + commands.extend(self._state_merged(want, have)) + return commands + + def _state_merged(self, want, have): + """ The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + for w in want: + h = search_obj_in_list(w["name"], have) + commands.extend(self._render_access_rules(w, h)) + return commands + + def _state_deleted(self, want, have): + """ The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + if want: + for w in want: + h = search_obj_in_list(w["name"], have) + if h and "access_rules" in h: + commands.extend(self._delete_access_rules(w, h, opr=False)) + elif have: + for h in have: + if "access_rules" in h: + commands.append( + self._compute_command(name=h["name"], opr=False) + ) + return commands + + def _delete_access_rules(self, want, have, opr=False): + """ + This function forms the delete commands based on the 'opr' type + for 'access_rules' attributes. + :param want: desired config. + :param have: target config. + :param opr: True/False. + :return: generated commands list. + """ + commands = [] + h_rules = {} + w_rs = deepcopy(remove_empties(want)) + w_rules = w_rs.get("access_rules") or [] + if have: + h_rs = deepcopy(remove_empties(have)) + h_rules = h_rs.get("access_rules") or [] + + # if all firewall config needed to be deleted for specific interface + # when operation is delete. + if not w_rules and h_rules: + commands.append(self._compute_command(name=want["name"], opr=opr)) + if w_rules: + for w in w_rules: + h = search_obj_in_list(w["afi"], h_rules, key="afi") + commands.extend(self._delete_rules(want["name"], w, h)) + return commands + + def _delete_rules(self, name, want, have, opr=False): + """ + This function forms the delete commands based on the 'opr' type + for rules attributes. + :param name: interface id/name. + :param want: desired config. + :param have: target config. + :param opr: True/False. + :return: generated commands list. + """ + commands = [] + h_rules = [] + key = "direction" + w_rules = want.get("rules") or [] + if have: + h_rules = have.get("rules") or [] + # when rule set needed to be removed on + # (inbound|outbound|local interface) + if h_rules and not w_rules: + for h in h_rules: + if key in h: + commands.append( + self._compute_command( + afi=want["afi"], name=name, attrib=h[key], opr=opr + ) + ) + for w in w_rules: + h = search_obj_in_list(w[key], h_rules, key=key) + if ( + key in w + and h + and key in h + and "name" in w + and "name" in h + and w["name"] == h["name"] + ): + commands.append( + self._compute_command( + afi=want["afi"], + name=name, + attrib=w[key], + value=w["name"], + opr=opr, + ) + ) + return commands + + def _render_access_rules(self, want, have, opr=True): + """ + This function forms the set/delete commands based on the 'opr' type + for 'access_rules' attributes. + :param want: desired config. + :param have: target config. + :param opr: True/False. + :return: generated commands list. + """ + commands = [] + h_rules = {} + w_rs = deepcopy(remove_empties(want)) + w_rules = w_rs.get("access_rules") or [] + if have: + h_rs = deepcopy(remove_empties(have)) + h_rules = h_rs.get("access_rules") or [] + if w_rules: + for w in w_rules: + h = search_obj_in_list(w["afi"], h_rules, key="afi") + commands.extend(self._render_rules(want["name"], w, h, opr)) + return commands + + def _render_rules(self, name, want, have, opr=True): + """ + This function forms the set/delete commands based on the 'opr' type + for rules attributes. + :param name: interface id/name. + :param want: desired config. + :param have: target config. + :param opr: True/False. + :return: generated commands list. + """ + commands = [] + h_rules = [] + key = "direction" + w_rules = want.get("rules") or [] + if have: + h_rules = have.get("rules") or [] + for w in w_rules: + h = search_obj_in_list(w[key], h_rules, key=key) + if key in w: + if opr: + if "name" in w and not ( + h and h[key] == w[key] and h["name"] == w["name"] + ): + commands.append( + self._compute_command( + afi=want["afi"], + name=name, + attrib=w[key], + value=w["name"], + ) + ) + elif not (h and key in h): + commands.append( + self._compute_command( + afi=want["afi"], name=name, attrib=w[key] + ) + ) + elif not opr: + if ( + not h + or key not in h + or ("name" in w and h and "name" not in h) + ): + commands.append( + self._compute_command( + afi=want["afi"], + name=name, + attrib=w[key], + opr=opr, + ) + ) + return commands + + def _compute_command( + self, afi=None, name=None, attrib=None, value=None, opr=True + ): + """ + This function construct the add/delete command based on passed attributes. + :param afi: address type. + :param name: interface name. + :param attrib: attribute name. + :param value: attribute value. + :param opr: operation flag. + :return: generated command. + """ + if not opr: + cmd = "delete interfaces ethernet" + " " + name + " firewall" + else: + cmd = "set interfaces ethernet" + " " + name + " firewall" + if attrib: + cmd += " " + attrib + if afi: + cmd += " " + self._get_fw_type(afi) + if value: + cmd += " '" + str(value) + "'" + return cmd + + def _get_fw_type(self, afi): + """ + This function returns the firewall rule-set type based on IP address. + :param afi: address type + :return: rule-set type. + """ + return "ipv6-name" if afi == "ipv6" else "name" diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index 6e6a82b..ff3d098 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -9,6 +9,7 @@ calls the appropriate facts gathering function from __future__ import absolute_import, division, print_function __metaclass__ = type + from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import ( FactsBase, ) @@ -36,6 +37,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.stati from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_global.firewall_global import ( Firewall_globalFacts, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_interfaces.firewall_interfaces import ( + Firewall_interfacesFacts, +) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import ( Default, Neighbors, @@ -53,6 +57,7 @@ FACT_RESOURCE_SUBSETS = dict( static_routes=Static_routesFacts, firewall_rules=Firewall_rulesFacts, firewall_global=Firewall_globalFacts, + firewall_interfaces=Firewall_interfacesFacts, ) diff --git a/plugins/module_utils/network/vyos/facts/firewall_interfaces/__init__.py b/plugins/module_utils/network/vyos/facts/firewall_interfaces/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/firewall_interfaces/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/firewall_interfaces/firewall_interfaces.py b/plugins/module_utils/network/vyos/facts/firewall_interfaces/firewall_interfaces.py new file mode 100644 index 0000000..4640748 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/firewall_interfaces/firewall_interfaces.py @@ -0,0 +1,196 @@ +# +# -*- 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 firewall_interfaces fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from re import findall, search, M +from copy import deepcopy +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.firewall_interfaces.firewall_interfaces import ( + Firewall_interfacesArgs, +) + + +class Firewall_interfacesFacts(object): + """ The vyos firewall_interfaces fact class + """ + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Firewall_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_device_data(self, connection): + return connection.get_config() + + def populate_facts(self, connection, ansible_facts, data=None): + """ Populate the facts for firewall_interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + if not data: + # typically data is populated from the current device configuration + # data = connection.get('show running-config | section ^interface') + # using mock data instead + data = self.get_device_data(connection) + objs = [] + interfaces = findall( + r"^set interfaces ethernet (?:\'*)(\S+)(?:\'*)", data, M + ) + if interfaces: + objs = self.get_names(data, interfaces) + ansible_facts["ansible_network_resources"].pop( + "firewall_interfaces", None + ) + facts = {} + if objs: + facts["firewall_interfaces"] = [] + params = utils.validate_config( + self.argument_spec, {"config": objs} + ) + for cfg in params["config"]: + facts["firewall_interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def get_names(self, data, interfaces): + """ + This function performs following: + - Form regex to fetch 'interface name' from interfaces firewall data. + - Form the name list. + :param data: configuration. + :param rules: list of interfaces. + :return: generated firewall interfaces configuration. + """ + names = [] + for r in set(interfaces): + int_regex = r" %s .+$" % r.strip("'") + cfg = findall(int_regex, data, M) + fi = self.render_config(cfg) + fi["name"] = r.strip("'") + names.append(fi) + if names: + names = sorted(names, key=lambda i: i["name"]) + return names + + 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 + """ + conf = "\n".join(filter(lambda x: "firewall" in x, conf)) + config = {"access_rules": self.parse_access_rules(conf)} + return config + + def parse_access_rules(self, conf): + """ + This function forms the regex to fetch the 'access-rules' + for specific interface. + :param conf: configuration data. + :return: generated access-rules list configuration. + """ + ar_lst = [] + v4_ar = findall(r"^.*(in|out|local) name .*$", conf, M) + v6_ar = findall(r"^.*(in|out|local) ipv6-name .*$", conf, M) + if v4_ar: + v4_conf = "\n".join(findall(r"(^.*?%s.*?$)" % " name", conf, M)) + config = self.parse_int_rules(v4_conf, "ipv4") + if config: + ar_lst.append(config) + if v6_ar: + v6_conf = "\n".join( + findall(r"(^.*?%s.*?$)" % " ipv6-name", conf, M) + ) + config = self.parse_int_rules(v6_conf, "ipv6") + if config: + ar_lst.append(config) + if ar_lst: + ar_lst = sorted(ar_lst, key=lambda i: i["afi"]) + else: + empty_rules = findall(r"^.*(in|out|local).*", conf, M) + if empty_rules: + ar_lst.append({"afi": "ipv4", "rules": []}) + ar_lst.append({"afi": "ipv6", "rules": []}) + return ar_lst + + def parse_int_rules(self, conf, afi): + """ + This function forms the regex to fetch the 'access-rules' + for specific interface based on ip-type. + :param conf: configuration data. + :param rules: rules configured per interface. + :param afi: ip address type. + :return: generated rule configuration dictionary. + """ + r_lst = [] + config = {} + rules = ["in", "out", "local"] + for r in set(rules): + fr = {} + r_regex = r" %s .+$" % r + cfg = "\n".join(findall(r_regex, conf, M)) + if cfg: + fr = self.parse_rules(cfg, afi) + else: + out = search(r"^.*firewall " + "'" + r + "'" + "(.*)", conf, M) + if out: + fr = {"direction": r} + if fr: + r_lst.append(fr) + if r_lst: + r_lst = sorted(r_lst, key=lambda i: i["direction"]) + config = {"afi": afi, "rules": r_lst} + return config + + def parse_rules(self, conf, afi): + """ + This function triggers the parsing of 'rule' attributes. + a_lst is a list having rule attributes which doesn't + have further sub attributes. + :param conf: configuration. + :param afi: ip address type. + :return: generated rule configuration dictionary. + """ + cfg = {} + out = findall(r"[^\s]+", conf, M) + if out: + cfg["direction"] = out[0].strip("'") + if afi == "ipv6": + out = findall(r"[^\s]+ ipv6-name (?:\'*)(\S+)(?:\'*)", conf, M) + if out: + cfg["name"] = str(out[0]).strip("'") + else: + out = findall(r"[^\s]+ name (?:\'*)(\S+)(?:\'*)", conf, M) + if out: + cfg["name"] = out[-1].strip("'") + return cfg diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py index 402adfc..4635234 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -14,9 +14,10 @@ from ansible_collections.ansible.netcommon.plugins.module_utils.compat import ( def search_obj_in_list(name, lst, key="name"): - for item in lst: - if item[key] == name: - return item + if lst: + for item in lst: + if item[key] == name: + return item return None diff --git a/plugins/modules/vyos_facts.py b/plugins/modules/vyos_facts.py index eec4c3b..4a64066 100644 --- a/plugins/modules/vyos_facts.py +++ b/plugins/modules/vyos_facts.py @@ -47,7 +47,8 @@ options: Can specify a list of values to include a larger subset. Values can also be used with an initial C(M(!)) to specify that a specific subset should not be collected. Valid subsets are 'all', 'interfaces', 'l3_interfaces', 'lag_interfaces', - 'lldp_global', 'lldp_interfaces', 'static_routes', 'firewall_rules', 'firewall_global'. + 'lldp_global', 'lldp_interfaces', 'static_routes', 'firewall_rules', 'firewall_global', + 'firewall_interfaces'. required: false """ diff --git a/plugins/modules/vyos_firewall_interfaces.py b/plugins/modules/vyos_firewall_interfaces.py new file mode 100644 index 0000000..1c2ce98 --- /dev/null +++ b/plugins/modules/vyos_firewall_interfaces.py @@ -0,0 +1,1289 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for vyos_firewall_interfaces +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = { + "metadata_version": "1.1", + "status": ["preview"], + "supported_by": "network", +} + +DOCUMENTATION = """module: vyos_firewall_interfaces +short_description: Manage firewall rules attributes of interfaces on VyOS devices +description: Manage firewall rules of interfaces on VyOS network devices. +author: +- Rohit Thakur (@rohitthakur2590) +options: + config: + description: A list of firewall rules options for interfaces. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier for the interface. + type: str + required: true + access_rules: + description: + - Specifies firewall rules attached to the interfaces. + type: list + elements: dict + suboptions: + afi: + description: + - Specifies the AFI for the Firewall rules to be configured on this interface. + type: str + choices: + - ipv4 + - ipv6 + required: true + rules: + description: + - Specifies the firewall rules for the provided AFI. + type: list + elements: dict + suboptions: + name: + description: + - Specifies the name of the IPv4/IPv6 Firewall rule for the interface. + type: str + direction: + description: + - Specifies the direction of packets that the firewall rule will be + applied on. + type: str + choices: + - in + - local + - out + required: true + running_config: + description: + - The module, by default, will connect to the remote device and retrieve the current + running-config to use as a base for comparing against the contents of source. + There are times when it is not desirable to have the task get the current running-config + for every task in a playbook. The I(running_config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. This + value of this option should be the output received from device by executing + command C(show configuration commands | grep 'firewall' + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - rendered + - gathered + default: merged +""" +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vyos@192# run show configuration commands | grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# +- name: Merge the provided configuration with the existing running configuration + vyos_firewall_interfaces: + config: + - access_rules: + - afi: 'ipv4' + rules: + - name: 'INBOUND' + direction: 'in' + - name: 'OUTBOUND' + direction: 'out' + - name: 'LOCAL' + direction: 'local' + - afi: 'ipv6' + rules: + - name: 'V6-LOCAL' + direction: 'local' + name: 'eth1' + - access_rules: + - afi: 'ipv4' + rules: + - name: 'INBOUND' + direction: 'in' + - name: 'OUTBOUND' + direction: 'out' + - name: 'LOCAL' + direction: 'local' + - afi: 'ipv6' + rules: + - name: 'V6-LOCAL' + direction: 'local' + name: 'eth3' + state: merged +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# before": [ +# { +# "name": "eth0" +# }, +# { +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "name": "eth3" +# } +# ] +# +# "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'" +# ] +# +# "after": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'INBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' + + +# Using merged +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'INBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' +# +- name: Merge the provided configuration with the existing running configuration + vyos_firewall_interfaces: + config: + - access_rules: + - afi: 'ipv4' + rules: + - name: 'OUTBOUND' + direction: 'in' + - name: 'INBOUND' + direction: 'out' + name: 'eth1' + state: merged +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "before": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# "commands": [ +# "set interfaces ethernet eth1 firewall in name 'OUTBOUND'", +# "set interfaces ethernet eth1 firewall out name 'INBOUND'" +# ] +# +# "after": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "OUTBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "INBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'OUTBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'INBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' + + +# Using replaced +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'INBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' +# +- name: Replace device configurations of listed firewall interfaces with provided configurations + vyos_firewall_interfaces: + config: + - name: 'eth1' + access_rules: + - afi: 'ipv4' + rules: + - name: 'OUTBOUND' + direction: 'out' + - afi: 'ipv6' + rules: + - name: 'V6-LOCAL' + direction: 'local' + - name: 'eth3' + access_rules: + - afi: 'ipv4' + rules: + - name: 'INBOUND' + direction: 'in' + state: replaced +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "before": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# "commands": [ +# "delete interfaces ethernet eth1 firewall in name", +# "delete interfaces ethernet eth1 firewall local name", +# "delete interfaces ethernet eth3 firewall local name", +# "delete interfaces ethernet eth3 firewall out name", +# "delete interfaces ethernet eth3 firewall local ipv6-name" +# ] +# +# "after": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall 'in' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall 'local' +# set interfaces ethernet eth3 firewall 'out' + + +# Using overridden +# +# Before state +# -------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall 'in' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall 'local' +# set interfaces ethernet eth3 firewall 'out' +# +- name: Overrides all device configuration with provided configuration + vyos_firewall_interfaces: + config: + - name: 'eth3' + access_rules: + - afi: 'ipv4' + rules: + - name: 'INBOUND' + direction: 'out' + state: overridden +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "before":[ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# "commands": [ +# "delete interfaces ethernet eth1 firewall", +# "delete interfaces ethernet eth3 firewall in name", +# "set interfaces ethernet eth3 firewall out name 'INBOUND'" +# +# +# "after": [ +# { +# "name": "eth0" +# }, +# { +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "out", +# "name": "INBOUND" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# +# After state +# ------------ +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth3 firewall 'in' +# set interfaces ethernet eth3 firewall 'local' +# set interfaces ethernet eth3 firewall out name 'INBOUND' + + +# Using deleted per interface name +# +# Before state +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'INBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' +# +- name: Delete firewall interfaces based on interface name. + vyos_firewall_interfaces: + config: + - name: 'eth1' + - name: 'eth3' + state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# +# "before": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# "commands": [ +# "delete interfaces ethernet eth1 firewall", +# "delete interfaces ethernet eth3 firewall" +# ] +# +# "after": [ +# { +# "name": "eth0" +# }, +# { +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "name": "eth3" +# } +# ] +# After state +# ------------ +# vyos@vyos# run show configuration commands | grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' + + +# Using deleted per afi +# +# Before state +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'INBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' +# +- name: Delete firewall interfaces config per afi. + vyos_firewall_interfaces: + config: + - name: 'eth1' + access_rules: + - afi: 'ipv4' + - afi: 'ipv6' + state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# +# "commands": [ +# "delete interfaces ethernet eth1 firewall in name", +# "delete interfaces ethernet eth1 firewall out name", +# "delete interfaces ethernet eth1 firewall local name", +# "delete interfaces ethernet eth1 firewall local ipv6-name" +# ] +# +# After state +# ------------ +# vyos@vyos# run show configuration commands | grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' + + +# Using deleted without config +# +# Before state +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall in name 'INBOUND' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall local name 'LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth3 firewall local name 'LOCAL' +# set interfaces ethernet eth3 firewall out name 'OUTBOUND' +# +- name: Delete firewall interfaces config when empty config provided. + vyos_firewall_interfaces: + config: + state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# +# "commands": [ +# "delete interfaces ethernet eth1 firewall", +# "delete interfaces ethernet eth1 firewall" +# ] +# +# After state +# ------------ +# vyos@vyos# run show configuration commands | grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' + + +# Using parsed +# +# +- name: Parse the provided configuration + vyos_firewall_interfaces: + running_config: + "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 eth2 firewall in name 'INBOUND' + set interfaces ethernet eth2 firewall out name 'OUTBOUND' + set interfaces ethernet eth2 firewall local name 'LOCAL' + set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'" + state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# }, +# { +# "direction": "local", +# "name": "LOCAL" +# }, +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth2" +# }, +# { +# "name": "eth3" +# } +# ] + + +# Using gathered +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall 'in' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall 'local' +# set interfaces ethernet eth3 firewall 'out' +# +- name: Gather listed firewall interfaces. + vyos_firewall_interfaces: + config: + state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "gathered": [ +# { +# "name": "eth0" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "out", +# "name": "OUTBOUND" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "rules": [ +# { +# "direction": "local", +# "name": "V6-LOCAL" +# } +# ] +# } +# ], +# "name": "eth1" +# }, +# { +# "name": "eth2" +# }, +# { +# "access_rules": [ +# { +# "afi": "ipv4", +# "rules": [ +# { +# "direction": "in", +# "name": "INBOUND" +# } +# ] +# } +# ], +# "name": "eth3" +# } +# ] +# +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall ipv6-name 'V6-LOCAL' +# set firewall name 'INBOUND' +# set firewall name 'LOCAL' +# set firewall name 'OUTBOUND' +# set interfaces ethernet eth1 firewall 'in' +# set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL' +# set interfaces ethernet eth1 firewall out name 'OUTBOUND' +# set interfaces ethernet eth3 firewall in name 'INBOUND' +# set interfaces ethernet eth3 firewall 'local' +# set interfaces ethernet eth3 firewall 'out' + + +# Using rendered +# +# +- name: Render the commands for provided configuration + vyos_firewall_interfaces: + config: + - name: 'eth2' + access_rules: + - afi: 'ipv4' + rules: + - direction: 'in' + name: 'INGRESS' + - direction: 'out' + name: 'OUTGRESS' + - direction: 'local' + name: 'DROP' + state: rendered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +# "set interfaces ethernet eth2 firewall in name 'INGRESS'", +# "set interfaces ethernet eth2 firewall out name 'OUTGRESS'", +# "set interfaces ethernet eth2 firewall local name 'DROP'", +# "set interfaces ethernet eth2 firewall local ipv6-name 'LOCAL'" +# ] + + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The resulting configuration model invocation. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: + - "set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'" + - "set interfaces ethernet eth3 firewall in name 'INBOUND'" +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.firewall_interfaces.firewall_interfaces import ( + Firewall_interfacesArgs, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.firewall_interfaces.firewall_interfaces import ( + Firewall_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Firewall_interfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Firewall_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/vyos_firewall_interfaces/1 b/tests/integration/targets/vyos_firewall_interfaces/1 new file mode 100644 index 0000000..70ae90f --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/1 @@ -0,0 +1,120 @@ +--- +merged: + before: [] + + + 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'" + + after: + - name: 'eth1' + access_rules: + - afi: 'ipv4' + rules: + - name: 'INBOUND' + direction: 'in' + - name: 'OUBOUND' + direction: 'out' + - afi: 'ipv6' + rules: + - name: 'V6-LOCAL' + direction: 'local' + +populate: + - name: 'eth1' + access_rules: + - afi: 'ipv4' + rules: + - name: 'INBOUND' + direction: 'in' + - name: 'OUBOUND' + direction: 'out' + - afi: 'ipv6' + rules: + - name: 'LOCAL' + direction: 'local' + +replaced: + commands: + - "delete service lldp interface eth2 location" + - "set service lldp interface eth2 'disable'" + - "set service lldp interface eth2 location civic-based country-code 'US'" + - "set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'" + - "delete service lldp interface eth1 location" + - "set service lldp interface eth1 'disable'" + - "set service lldp interface eth1 location coordinate-based latitude '33.524449N'" + - "set service lldp interface eth1 location coordinate-based altitude '2200'" + - "set service lldp interface eth1 location coordinate-based datum 'WGS84'" + - "set service lldp interface eth1 location coordinate-based longitude '222.267255W'" + + after: + - name: 'eth2' + enable: false + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth1' + enable: false + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + +populate_intf: + - name: 'eth2' + enable: false + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + +overridden: + commands: + - "delete service lldp interface eth2 location" + - "delete service lldp interface eth2 'disable'" + - "set service lldp interface eth2 location elin '0000000911'" + + after: + - name: 'eth2' + location: + elin: 0000000911 + +deleted: + commands: + - "delete service lldp interface eth1" + - "delete service lldp interface eth2" + + after: [] + +round_trip: + after: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' diff --git a/tests/integration/targets/vyos_firewall_interfaces/defaults/main.yaml b/tests/integration/targets/vyos_firewall_interfaces/defaults/main.yaml new file mode 100644 index 0000000..852a6be --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: '[^_].*' +test_items: [] diff --git a/tests/integration/targets/vyos_firewall_interfaces/meta/main.yaml b/tests/integration/targets/vyos_firewall_interfaces/meta/main.yaml new file mode 100644 index 0000000..7413320 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/meta/main.yaml @@ -0,0 +1,3 @@ +--- +dependencies: + - prepare_vyos_tests diff --git a/tests/integration/targets/vyos_firewall_interfaces/tasks/cli.yaml b/tests/integration/targets/vyos_firewall_interfaces/tasks/cli.yaml new file mode 100644 index 0000000..93eb2fe --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tasks/cli.yaml @@ -0,0 +1,19 @@ +--- +- name: Collect all cli test cases + find: + paths: '{{ role_path }}/tests/cli' + patterns: '{{ testcase }}.yaml' + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=ansible.netcommon.network_cli) + include: '{{ test_case_to_run }}' + vars: + ansible_connection: ansible.netcommon.network_cli + with_items: '{{ test_items }}' + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_firewall_interfaces/tasks/main.yaml b/tests/integration/targets/vyos_firewall_interfaces/tasks/main.yaml new file mode 100644 index 0000000..a3db933 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tasks/main.yaml @@ -0,0 +1,4 @@ +--- +- include: cli.yaml + tags: + - cli diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_parsed_config.cfg new file mode 100644 index 0000000..54696e8 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_parsed_config.cfg @@ -0,0 +1,10 @@ +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 eth2 firewall in name 'INBOUND' +set interfaces ethernet eth2 firewall out name 'OUTBOUND' +set interfaces ethernet eth2 firewall local name 'LOCAL' +set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL' +set interfaces ethernet eth0 + diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_populate.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_populate.yaml new file mode 100644 index 0000000..3e60c41 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_populate.yaml @@ -0,0 +1,12 @@ +--- +- name: Setup + vars: + lines: "set interfaces ethernet eth1 firewall in name 'INBOUND' \nset interfaces\ + \ ethernet eth1 firewall out name 'OUTBOUND' \nset interfaces ethernet eth1\ + \ firewall local name 'LOCAL' \nset interfaces ethernet eth1 firewall local\ + \ ipv6-name 'V6-LOCAL'\nset interfaces ethernet eth2 firewall in name 'INBOUND'\n\ + set interfaces ethernet eth2 firewall out name 'OUTBOUND'\nset interfaces\ + \ ethernet eth2 firewall local name 'LOCAL' \nset interfaces ethernet eth2\ + \ firewall local ipv6-name 'V6-LOCAL'\n" + ansible.netcommon.cli_config: + config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_populate_rule_sets.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_populate_rule_sets.yaml new file mode 100644 index 0000000..40a7f4a --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_populate_rule_sets.yaml @@ -0,0 +1,7 @@ +--- +- name: Setup + vars: + lines: "set firewall name 'INBOUND'\nset firewall name 'OUTBOUND'\nset firewall\ + \ name 'LOCAL'\nset firewall ipv6-name 'V6-LOCAL'\n" + ansible.netcommon.cli_config: + config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_remove_config.yaml new file mode 100644 index 0000000..38a1800 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_remove_config.yaml @@ -0,0 +1,7 @@ +--- +- name: Remove Config + vars: + lines: "delete interfaces ethernet eth1 firewall\ndelete interfaces ethernet\ + \ eth2 firewall\n" + ansible.netcommon.cli_config: + config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_remove_firewall_config.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_remove_firewall_config.yaml new file mode 100644 index 0000000..0844749 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/_remove_firewall_config.yaml @@ -0,0 +1,7 @@ +--- +- name: Remove Config + vars: + lines: "delete firewall name INBOUND\ndelete firewall name OUTBOUND\ndelete\ + \ firewall name LOCAL\ndelete firewall ipv6-name V6-LOCAL\n" + ansible.netcommon.cli_config: + config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted.yaml new file mode 100644 index 0000000..078dd89 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted.yaml @@ -0,0 +1,58 @@ +--- +- debug: + msg: Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ + ansible_connection }} + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Delete attributes of given firewall rules. + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + + - name: eth2 + state: deleted + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that the correct set of commands were generated + assert: + that: + - "{{ deleted['commands'] | symmetric_difference(result['commands']) |length\ + \ == 0 }}" + + - name: Assert that the after dicts were correctly generated + assert: + that: + - "{{ deleted['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Delete attributes of given interfaces (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result.changed == false + - result.commands|length == 0 + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ deleted['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_afi.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_afi.yaml new file mode 100644 index 0000000..f7db06b --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_afi.yaml @@ -0,0 +1,68 @@ +--- +- debug: + msg: Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ + ansible_connection }} + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Delete firewall interfaces based on IP address type provided. + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + + - afi: ipv6 + + - name: eth2 + access_rules: + + - afi: ipv4 + + - afi: ipv6 + state: deleted + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that the correct set of commands were generated + assert: + that: + - "{{ deleted_afi['commands'] | symmetric_difference(result['commands'])\ + \ |length == 0 }}" + + - name: Assert that the after dicts were correctly generated + assert: + that: + - "{{ deleted_afi['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Delete attributes of given interfaces (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result.changed == false + - result.commands|length == 0 + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ deleted_afi['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_all.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_all.yaml new file mode 100644 index 0000000..d85654c --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_all.yaml @@ -0,0 +1,54 @@ +--- +- debug: + msg: Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ + ansible_connection }} + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Delete all the firewall interfaces. + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + state: deleted + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that the correct set of commands were generated + assert: + that: + - "{{ deleted['commands'] | symmetric_difference(result['commands']) |length\ + \ == 0 }}" + + - name: Assert that the after dicts were correctly generated + assert: + that: + - "{{ deleted['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Delete attributes of given interfaces (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result.changed == false + - result.commands|length == 0 + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ deleted['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_single.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_single.yaml new file mode 100644 index 0000000..f7e91f8 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/deleted_single.yaml @@ -0,0 +1,63 @@ +--- +- debug: + msg: Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ + ansible_connection }} + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Delete firewall interface. + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + rules: + + - direction: in + name: INBOUND + state: deleted + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that the correct set of commands were generated + assert: + that: + - "{{ deleted_single['commands'] | symmetric_difference(result['commands'])\ + \ |length == 0 }}" + + - name: Assert that the after dicts were correctly generated + assert: + that: + - "{{ deleted_single['after'] | symmetric_difference(result['after'])\ + \ |length == 0 }}" + + - name: Delete attributes of given interfaces (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result.changed == false + - result.commands|length == 0 + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ deleted_single['after'] | symmetric_difference(result['before'])\ + \ |length == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/empty_config.yaml new file mode 100644 index 0000000..66c49bf --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/empty_config.yaml @@ -0,0 +1,60 @@ +--- +- debug: + msg: START vyos_firewall_interfaces empty_config integration tests on connection={{ + ansible_connection }} + +- name: Merged with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_firewall_interfaces: + config: + state: merged + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_firewall_interfaces: + config: + state: replaced + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Overridden with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_firewall_interfaces: + config: + state: overridden + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state overridden' + +- name: Parsed with empty running_config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_firewall_interfaces: + running_config: + state: parsed + +- assert: + that: + - result.msg == 'value of running_config parameter must not be empty for state + parsed' + +- name: Rendered with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_firewall_interfaces: + config: + state: rendered + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/gathered.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/gathered.yaml new file mode 100644 index 0000000..fd8dd74 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/gathered.yaml @@ -0,0 +1,40 @@ +--- +- debug: + msg: START vyos_firewall_interfaces gathered integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _remove_firewall_config.yaml + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Merge the provided configuration with the exisiting running configuration + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + state: gathered + + - name: Assert that gathered dicts was correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['gathered']) |length == 0\ + \ }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/merged.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/merged.yaml new file mode 100644 index 0000000..0c28eab --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/merged.yaml @@ -0,0 +1,96 @@ +--- +- debug: + msg: START vyos_firewall_interfaces merged integration tests on connection={{ + ansible_connection }} + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _remove_config.yaml + +- block: + + - name: Merge the provided configuration with the exisiting running configuration + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + rules: + + - direction: in + name: INBOUND + + - direction: local + name: LOCAL + + - direction: out + name: OUTBOUND + + - afi: ipv6 + rules: + + - direction: local + name: V6-LOCAL + + - name: eth2 + access_rules: + + - afi: ipv4 + rules: + + - direction: in + name: INBOUND + + - direction: local + name: LOCAL + + - direction: out + name: OUTBOUND + + - afi: ipv6 + rules: + + - direction: local + name: V6-LOCAL + state: merged + + - name: Assert that before dicts were correctly generated + assert: + that: "{{ merged['before'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ merged['commands'] | symmetric_difference(result['commands']) |length\ + \ == 0 }}" + + - name: Assert that after dicts was correctly generated + assert: + that: + - "{{ merged['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Merge the provided configuration with the existing running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ merged['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/merged_edit.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/merged_edit.yaml new file mode 100644 index 0000000..873f4c4 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/merged_edit.yaml @@ -0,0 +1,70 @@ +--- +- debug: + msg: START vyos_firewall_interfaces merged integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _remove_firewall_config.yaml + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Merge the provided configuration with the exisiting running configuration + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + rules: + + - direction: in + name: OUTBOUND + + - direction: out + name: INBOUND + state: merged + + - name: Assert that before dicts were correctly generated + assert: + that: "{{ populate | symmetric_difference(result['before']) |length == 0\ + \ }}" + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ merged_edit['commands'] | symmetric_difference(result['commands'])\ + \ |length == 0 }}" + + - name: Assert that after dicts was correctly generated + assert: + that: + - "{{ merged_edit['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Merge the provided configuration with the existing running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ merged_edit['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/overridden.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/overridden.yaml new file mode 100644 index 0000000..01d30b6 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/overridden.yaml @@ -0,0 +1,66 @@ +--- +- debug: + msg: START vyos_firewall_interfaces overridden integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _remove_firewall_config.yaml + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Overrides all device configuration with provided configuration + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth2 + access_rules: + + - afi: ipv4 + rules: + + - name: INBOUND + direction: out + state: overridden + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that correct commands were generated + assert: + that: + - "{{ overridden['commands'] | symmetric_difference(result['commands'])\ + \ |length == 0 }}" + + - name: Assert that after dicts were correctly generated + assert: + that: + - "{{ overridden['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Overrides all device configuration with provided configurations (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ overridden['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/parsed.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/parsed.yaml new file mode 100644 index 0000000..c7032e1 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/parsed.yaml @@ -0,0 +1,47 @@ +--- +- debug: + msg: START vyos_firewall_interfaces parsed integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _remove_firewall_config.yaml + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Gather firewall_interfaces facts + register: firewall_interfaces_facts + vyos.vyos.vyos_facts: + gather_subset: + - default + gather_network_resources: + - firewall_interfaces + + - name: Provide the running configuration for parsing (config to be parsed) + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + running_config: "{{ lookup('file', '_parsed_config.cfg') }}" + state: parsed + + - name: Assert that correct parsing done + assert: + that: "{{ ansible_facts['network_resources']['firewall_interfaces'] | symmetric_difference(result['parsed'])\ + \ |length == 0 }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/rendered.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/rendered.yaml new file mode 100644 index 0000000..022dd50 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/rendered.yaml @@ -0,0 +1,72 @@ +--- +- debug: + msg: START vyos_firewall_interfaces rendered integration tests on connection={{ + ansible_connection }} + +- block: + + - name: Structure provided configuration into device specific commands + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + rules: + + - name: INBOUND + direction: in + + - name: OUTBOUND + direction: out + + - name: LOCAL + direction: local + + - afi: ipv6 + rules: + + - name: V6-LOCAL + direction: local + + - name: eth2 + access_rules: + + - afi: ipv4 + rules: + + - name: INBOUND + direction: in + + - name: OUTBOUND + direction: out + + - name: LOCAL + direction: local + + - afi: ipv6 + rules: + + - name: V6-LOCAL + direction: local + state: rendered + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ rendered['commands'] | symmetric_difference(result['rendered'])\ + \ |length == 0 }}" + + - name: Structure provided configuration into device specific commands (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/replaced.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/replaced.yaml new file mode 100644 index 0000000..b2b0067 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/replaced.yaml @@ -0,0 +1,83 @@ +--- +- debug: + msg: START vyos_firewall_interfaces replaced integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _remove_firewall_config.yaml + +- include_tasks: _populate_rule_sets.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Replace device configurations of listed firewall rules with provided + configurations + register: result + vyos.vyos.vyos_firewall_interfaces: &id001 + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + rules: + + - name: OUTBOUND + direction: out + + - afi: ipv6 + rules: + + - name: V6-LOCAL + direction: local + + - name: eth2 + access_rules: + + - afi: ipv4 + rules: + + - name: INBOUND + direction: in + state: replaced + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ replaced['commands'] | symmetric_difference(result['commands'])\ + \ |length == 0 }}" + + - name: Assert that before dicts are correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that after dict is correctly generated + assert: + that: + - "{{ replaced['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Replace device configurations of listed firewall rules with provided + configurarions (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_interfaces: *id001 + + - name: Assert that task was idempotent + assert: + that: + - result['changed'] == false + + - name: Assert that before dict is correctly generated + assert: + that: + - "{{ replaced['after'] | symmetric_difference(result['before']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/tests/cli/rtt.yaml b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/rtt.yaml new file mode 100644 index 0000000..9155b7c --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/tests/cli/rtt.yaml @@ -0,0 +1,94 @@ +--- +- debug: + msg: START vyos_firewall_interfaces round trip integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _remove_firewall_config.yaml + +- include_tasks: _populate_rule_sets.yaml + +- block: + + - name: Apply the provided configuration (base config) + register: base_config + vyos.vyos.vyos_firewall_interfaces: + config: + + - name: eth1 + access_rules: + + - afi: ipv4 + rules: + + - name: INBOUND + direction: in + + - name: OUTBOUND + direction: out + + - name: LOCAL + direction: local + + - afi: ipv6 + rules: + + - name: V6-LOCAL + direction: local + state: merged + + - name: Gather firewall_interfaces facts + vyos.vyos.vyos_facts: + gather_subset: + - default + gather_network_resources: + - firewall_interfaces + + - name: Apply the provided configuration (config to be reverted) + register: result + vyos.vyos.vyos_firewall_interfaces: + config: + + - name: eth2 + access_rules: + + - afi: ipv4 + rules: + + - name: INBOUND + direction: in + + - name: OUTBOUND + direction: out + + - name: LOCAL + direction: local + + - afi: ipv6 + rules: + + - name: V6-LOCAL + direction: local + state: merged + + - name: Assert that changes were applied + assert: + that: "{{ round_trip['after'] | symmetric_difference(result['after']) |length\ + \ == 0 }}" + + - name: Revert back to base config using facts round trip + register: revert + vyos.vyos.vyos_firewall_interfaces: + config: "{{ ansible_facts['network_resources']['firewall_interfaces'] }}" + state: overridden + + - name: Assert that config was reverted + assert: + that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length\ + \ == 0 }}" + always: + + - include_tasks: _remove_config.yaml + + - include_tasks: _remove_firewall_config.yaml diff --git a/tests/integration/targets/vyos_firewall_interfaces/vars/main.yaml b/tests/integration/targets/vyos_firewall_interfaces/vars/main.yaml new file mode 100644 index 0000000..45be6db --- /dev/null +++ b/tests/integration/targets/vyos_firewall_interfaces/vars/main.yaml @@ -0,0 +1,279 @@ +--- +merged: + before: + - name: eth0 + - name: eth1 + - name: eth2 + 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 eth2 firewall in name 'INBOUND' + - set interfaces ethernet eth2 firewall out name 'OUTBOUND' + - set interfaces ethernet eth2 firewall local name 'LOCAL' + - set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL' + after: + - name: eth0 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth2 +populate: + - name: eth0 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth2 +merged_edit: + commands: + - set interfaces ethernet eth1 firewall in name 'OUTBOUND' + - set interfaces ethernet eth1 firewall out name 'INBOUND' + after: + - name: eth0 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: OUTBOUND + - direction: local + name: LOCAL + - direction: out + name: INBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth2 +replaced: + commands: + - delete interfaces ethernet eth2 firewall out name + - delete interfaces ethernet eth2 firewall local name + - delete interfaces ethernet eth2 firewall local ipv6-name + - delete interfaces ethernet eth1 firewall local name + - delete interfaces ethernet eth1 firewall in name + after: + - name: eth0 + - access_rules: + - afi: ipv4 + rules: + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + name: eth2 +overridden: + before: + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - access_rules: + - afi: ipv4 + rules: + - name: INBOUND + direction: in + - name: LOCAL + direction: local + - name: OUTBOUND + direction: out + - afi: ipv6 + rules: + - name: V6-LOCAL + direction: local + name: eth2 + commands: + - delete interfaces ethernet eth1 firewall + - delete interfaces ethernet eth2 firewall in name + - delete interfaces ethernet eth2 firewall local name + - delete interfaces ethernet eth2 firewall local ipv6-name + - set interfaces ethernet eth2 firewall out name 'INBOUND' + after: + - name: eth0 + - name: eth1 + - access_rules: + - afi: ipv4 + rules: + - name: INBOUND + direction: out + name: eth2 +deleted: + commands: + - delete interfaces ethernet eth1 firewall + - delete interfaces ethernet eth2 firewall + after: + - name: eth0 + - name: eth1 + - name: eth2 +deleted_afi: + commands: + - delete interfaces ethernet eth1 firewall in name + - delete interfaces ethernet eth1 firewall local name + - delete interfaces ethernet eth1 firewall out name + - delete interfaces ethernet eth1 firewall local ipv6-name + - delete interfaces ethernet eth2 firewall in name + - delete interfaces ethernet eth2 firewall local name + - delete interfaces ethernet eth2 firewall out name + - delete interfaces ethernet eth2 firewall local ipv6-name + after: + - name: eth0 + - access_rules: + - afi: ipv4 + - afi: ipv6 + name: eth1 + - access_rules: + - afi: ipv4 + - afi: ipv6 + name: eth2 +deleted_single: + commands: + - delete interfaces ethernet eth1 firewall in name 'INBOUND' + after: + - name: eth0 + - access_rules: + - afi: ipv4 + rules: + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth2 +rendered: + 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 eth2 firewall in name 'INBOUND' + - set interfaces ethernet eth2 firewall out name 'OUTBOUND' + - set interfaces ethernet eth2 firewall local name 'LOCAL' + - set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL' +round_trip: + after: + - name: eth0 + - access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL + name: eth1 + - name: eth2 + access_rules: + - afi: ipv4 + rules: + - direction: in + name: INBOUND + - direction: local + name: LOCAL + - direction: out + name: OUTBOUND + - afi: ipv6 + rules: + - direction: local + name: V6-LOCAL diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_firewall_interfaces_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_firewall_interfaces_config.cfg new file mode 100644 index 0000000..24704d2 --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_firewall_interfaces_config.cfg @@ -0,0 +1,8 @@ +set interfaces ethernet eth0 firewall in name 'INBOUND' +set interfaces ethernet eth0 firewall local ipv6-name 'V6-LOCAL' +set interfaces ethernet eth0 firewall local name 'LOCAL' +set interfaces ethernet eth0 firewall out name 'OUTBOUND' +set interfaces ethernet eth2 firewall in name 'INBOUND' +set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL' +set interfaces ethernet eth2 firewall local name 'LOCAL' +set interfaces ethernet eth2 firewall out name 'OUTBOUND' diff --git a/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py b/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py new file mode 100644 index 0000000..1ffeae4 --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_firewall_interfaces.py @@ -0,0 +1,432 @@ +# (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 <http://www.gnu.org/licenses/>. + +# 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, + MagicMock, +) +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"),], + ), + 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=[]) |