diff options
42 files changed, 3659 insertions, 7 deletions
diff --git a/tests/integration/targets/vyos_interface/aliases b/plugins/module_utils/network/vyos/argspec/firewall_global/__init__.py index e69de29..e69de29 100644 --- a/tests/integration/targets/vyos_interface/aliases +++ b/plugins/module_utils/network/vyos/argspec/firewall_global/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/firewall_global/firewall_global.py b/plugins/module_utils/network/vyos/argspec/firewall_global/firewall_global.py new file mode 100644 index 0000000..4c26773 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/firewall_global/firewall_global.py @@ -0,0 +1,152 @@ +# +# -*- 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_global module +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +class Firewall_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the vyos_firewall_global module + """ + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "options": { + "config_trap": {"type": "bool"}, + "group": { + "options": { + "address_group": { + "elements": "dict", + "options": { + "description": {"type": "str"}, + "members": { + "elements": "dict", + "options": {"address": {"type": "str"}}, + "type": "list", + }, + "name": {"required": True, "type": "str"}, + }, + "type": "list", + }, + "network_group": { + "elements": "dict", + "options": { + "description": {"type": "str"}, + "members": { + "elements": "dict", + "options": {"address": {"type": "str"}}, + "type": "list", + }, + "name": {"required": True, "type": "str"}, + }, + "type": "list", + }, + "port_group": { + "elements": "dict", + "options": { + "description": {"type": "str"}, + "members": { + "elements": "dict", + "options": {"port": {"type": "str"}}, + "type": "list", + }, + "name": {"required": True, "type": "str"}, + }, + "type": "list", + }, + }, + "type": "dict", + }, + "log_martians": {"type": "bool"}, + "ping": { + "options": { + "all": {"type": "bool"}, + "broadcast": {"type": "bool"}, + }, + "type": "dict", + }, + "route_redirects": { + "elements": "dict", + "options": { + "afi": { + "choices": ["ipv4", "ipv6"], + "required": True, + "type": "str", + }, + "icmp_redirects": { + "options": { + "receive": {"type": "bool"}, + "send": {"type": "bool"}, + }, + "type": "dict", + }, + "ip_src_route": {"type": "bool"}, + }, + "type": "list", + }, + "state_policy": { + "elements": "dict", + "options": { + "action": { + "choices": ["accept", "drop", "reject"], + "type": "str", + }, + "connection_type": { + "choices": ["established", "invalid", "related"], + "type": "str", + }, + "log": {"type": "bool"}, + }, + "type": "list", + }, + "syn_cookies": {"type": "bool"}, + "twa_hazards_protection": {"type": "bool"}, + "validation": { + "choices": ["strict", "loose", "disable"], + "type": "str", + }, + }, + "type": "dict", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/tests/integration/targets/vyos_l3_interface/aliases b/plugins/module_utils/network/vyos/config/firewall_global/__init__.py index e69de29..e69de29 100644 --- a/tests/integration/targets/vyos_l3_interface/aliases +++ b/plugins/module_utils/network/vyos/config/firewall_global/__init__.py diff --git a/plugins/module_utils/network/vyos/config/firewall_global/firewall_global.py b/plugins/module_utils/network/vyos/config/firewall_global/firewall_global.py new file mode 100644 index 0000000..afc9853 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/firewall_global/firewall_global.py @@ -0,0 +1,810 @@ +# +# -*- 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_global 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, + remove_empties, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( + Facts, +) +from ansible.module_utils.six import iteritems +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import ( + list_diff_want_only, +) + + +class Firewall_global(ConfigBase): + """ + The vyos_firewall_global class + """ + + gather_subset = [ + "!all", + "!min", + ] + + gather_network_resources = [ + "firewall_global", + ] + + def __init__(self, module): + super(Firewall_global, self).__init__(module) + + def get_firewall_global_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_global_facts = facts["ansible_network_resources"].get( + "firewall_global" + ) + if not firewall_global_facts: + return [] + return firewall_global_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_global_facts = self.get_firewall_global_facts() + else: + existing_firewall_global_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_firewall_global_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_global_facts = self.get_firewall_global_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_global_facts( + data=running_config + ) + else: + changed_firewall_global_facts = [] + + if self.state in self.ACTION_STATES: + result["before"] = existing_firewall_global_facts + if result["changed"]: + result["after"] = changed_firewall_global_facts + elif self.state == "gathered": + result["gathered"] = changed_firewall_global_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_firewall_global_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_global_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", "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 == "deleted": + commands.extend(self._state_deleted(want=None, have=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: + commands.extend(self._state_deleted(have, want)) + 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 = [] + commands.extend(self._add_global_attr(want, have)) + 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 = [] + b_set = ( + "config_trap", + "validation", + "log_martians", + "syn_cookies", + "twa_hazards_protection", + ) + if want: + for key, val in iteritems(want): + if val and key in b_set and not have: + commands.append(self._form_attr_cmd(attr=key, opr=False)) + elif ( + val + and key in b_set + and have + and key in have + and have[key] != val + ): + commands.append(self._form_attr_cmd(attr=key, opr=False)) + else: + commands.extend(self._render_attr_config(want, have, key)) + elif not want and have: + commands.append(self._compute_command(opr=False)) + elif have: + for key, val in iteritems(have): + if val and key in b_set: + commands.append(self._form_attr_cmd(attr=key, opr=False)) + else: + commands.extend(self._render_attr_config(want, have, key)) + return commands + + def _render_attr_config(self, w, h, key, opr=False): + """ + This function invoke the function to extend commands + based on the key. + :param w: the desired configuration. + :param h: the current configuration. + :param key: attribute name + :param opr: operation + :return: list of commands + """ + commands = [] + if key == "ping": + commands.extend(self._render_ping(key, w, h, opr=opr)) + elif key == "group": + commands.extend(self._render_group(key, w, h, opr=opr)) + elif key == "state_policy": + commands.extend(self._render_state_policy(key, w, h, opr=opr)) + elif key == "route_redirects": + commands.extend(self._render_route_redirects(key, w, h, opr=opr)) + return commands + + def _add_global_attr(self, w, h, opr=True): + """ + This function forms the set/delete commands based on the 'opr' type + for firewall_global attributes. + :param w: the desired config. + :param h: the target config. + :param opr: True/False. + :return: generated commands list. + """ + commands = [] + w_fg = deepcopy(remove_empties(w)) + l_set = ( + "config_trap", + "validation", + "log_martians", + "syn_cookies", + "twa_hazards_protection", + ) + if w_fg: + for key, val in iteritems(w_fg): + if ( + opr + and key in l_set + and not (h and self._is_w_same(w_fg, h, key)) + ): + commands.append( + self._form_attr_cmd( + attr=key, val=self._bool_to_str(val), opr=opr + ) + ) + elif not opr: + if key and self._is_del(l_set, h): + commands.append( + self._form_attr_cmd( + attr=key, key=self._bool_to_str(val), opr=opr + ) + ) + continue + elif ( + key in l_set + and not (h and self._in_target(h, key)) + and not self._is_del(l_set, h) + ): + commands.append( + self._form_attr_cmd( + attr=key, val=self._bool_to_str(val), opr=opr + ) + ) + else: + commands.extend( + self._render_attr_config(w_fg, h, key, opr) + ) + return commands + + def _render_ping(self, attr, w, h, opr): + """ + This function forms the commands for 'ping' attributes based on the 'opr'. + :param attr: attribute name. + :param w: the desired configuration. + :param h: the target config. + :param opr: True/False. + :return: generated list of commands. + """ + commands = [] + h_ping = {} + l_set = ("all", "broadcast") + if h: + h_ping = h.get(attr) or {} + if self._is_root_del(w[attr], h_ping, attr): + for item, value in iteritems(h[attr]): + if not opr and item in l_set: + commands.append(self._form_attr_cmd(attr=item, opr=opr)) + elif w[attr]: + if h and attr in h.keys(): + h_ping = h.get(attr) or {} + for item, value in iteritems(w[attr]): + if ( + opr + and item in l_set + and not (h_ping and self._is_w_same(w[attr], h_ping, item)) + ): + commands.append( + self._form_attr_cmd( + attr=item, val=self._bool_to_str(value), opr=opr + ) + ) + elif ( + not opr + and item in l_set + and not (h_ping and self._is_w_same(w[attr], h_ping, item)) + ): + commands.append(self._form_attr_cmd(attr=item, opr=opr)) + return commands + + def _render_group(self, attr, w, h, opr): + """ + This function forms the commands for 'group' attribute based on the 'opr'. + :param attr: attribute name. + :param w: base config. + :param h: target config. + :param opr: True/False. + :return: generated list of commands. + """ + commands = [] + h_grp = {} + if not opr and self._is_root_del(h, w, attr): + commands.append(self._form_attr_cmd(attr=attr, opr=opr)) + else: + if h: + h_grp = h.get("group") or {} + if w: + commands.extend( + self._render_grp_mem("port-group", w["group"], h_grp, opr) + ) + commands.extend( + self._render_grp_mem( + "address_group", w["group"], h_grp, opr + ) + ) + commands.extend( + self._render_grp_mem( + "network_group", w["group"], h_grp, opr + ) + ) + return commands + + def _render_grp_mem(self, attr, w, h, opr): + """ + This function forms the commands for group list/members attributes based on the 'opr'. + :param attr: attribute name. + :param w: the desired config. + :param h: the target config. + :param opr: True/False. + :return: generated list of commands. + """ + commands = [] + h_grp = [] + w_grp = [] + l_set = ("name", "description") + if w: + w_grp = w.get(attr) or [] + if h: + h_grp = h.get(attr) or [] + + if w_grp: + for want in w_grp: + cmd = self._compute_command(key="group", attr=attr, opr=opr) + h = self.search_attrib_in_have(h_grp, want, "name") + for key, val in iteritems(want): + if val: + if ( + opr + and key in l_set + and not (h and self._is_w_same(want, h, key)) + ): + if key == "name": + commands.append(cmd + " " + str(val)) + else: + commands.append( + cmd + + " " + + want["name"] + + " " + + key + + " '" + + str(want[key]) + + "'" + ) + elif not opr and key in l_set: + if key == "name" and self._is_grp_del( + h, want, key + ): + commands.append(cmd + " " + want["name"]) + continue + elif not ( + h and self._in_target(h, key) + ) and not self._is_grp_del(h, want, key): + commands.append( + cmd + " " + want["name"] + " " + key + ) + elif key == "members": + commands.extend( + self._render_ports_addrs( + key, want, h, opr, cmd, want["name"], attr + ) + ) + return commands + + def _render_ports_addrs(self, attr, w, h, opr, cmd, name, type): + """ + This function forms the commands for port/address/network group members + based on the 'opr'. + :param attr: attribute name. + :param w: the desired config. + :param h: the target config. + :param cmd: commands to be prepend. + :param name: name of group. + :param type: group type. + :return: generated list of commands. + """ + commands = [] + have = [] + if w: + want = w.get(attr) or [] + if h: + have = h.get(attr) or [] + + if want: + if opr: + members = list_diff_want_only(want, have) + for member in members: + commands.append( + cmd + + " " + + name + + " " + + self._grp_type(type) + + " " + + member[self._get_mem_type(type)] + ) + elif not opr and have: + members = list_diff_want_only(want, have) + for member in members: + commands.append( + cmd + + " " + + name + + " " + + self._grp_type(type) + + " " + + member[self._get_mem_type(type)] + ) + return commands + + def _get_mem_type(self, group): + """ + This function returns the member type + based on the type of group. + """ + return "port" if group == "port_group" else "address" + + def _render_state_policy(self, attr, w, h, opr): + """ + This function forms the commands for 'state-policy' attributes + based on the 'opr'. + :param attr: attribute name. + :param w: the desired config. + :param h: the target config. + :param opr: True/False. + :return: generated list of commands. + """ + commands = [] + have = [] + l_set = ("log", "action", "connection_type") + if not opr and self._is_root_del(h, w, attr): + commands.append(self._form_attr_cmd(attr=attr, opr=opr)) + else: + w_sp = deepcopy(remove_empties(w)) + want = w_sp.get(attr) or [] + if h: + have = h.get(attr) or [] + if want: + for w in want: + h = self.search_attrib_in_have(have, w, "connection_type") + for key, val in iteritems(w): + if val and key != "connection_type": + if ( + opr + and key in l_set + and not (h and self._is_w_same(w, h, key)) + ): + commands.append( + self._form_attr_cmd( + key=attr + " " + w["connection_type"], + attr=key, + val=self._bool_to_str(val), + opr=opr, + ) + ) + elif not opr and key in l_set: + if not ( + h and self._in_target(h, key) + ) and not self._is_del(l_set, h): + if key == "action": + commands.append( + self._form_attr_cmd( + attr=attr + + " " + + w["connection_type"], + opr=opr, + ) + ) + else: + commands.append( + self._form_attr_cmd( + attr=attr + + " " + + w["connection_type"], + val=self._bool_to_str(val), + opr=opr, + ) + ) + return commands + + def _render_route_redirects(self, attr, w, h, opr): + """ + This function forms the commands for 'route_redirects' attributes based on the 'opr'. + :param attr: attribute name. + :param w: the desired config. + :param h: the target config. + :param opr: True/False. + :return: generated list of commands. + """ + commands = [] + have = [] + l_set = ("afi", "ip_src_route") + + if w: + want = w.get(attr) or [] + if h: + have = h.get(attr) or [] + + if want: + for w in want: + h = self.search_attrib_in_have(have, w, "afi") + for key, val in iteritems(w): + if val and key != "afi": + if ( + opr + and key in l_set + and not (h and self._is_w_same(w, h, key)) + ): + commands.append( + self._form_attr_cmd( + attr=key, + val=self._bool_to_str(val), + opr=opr, + ) + ) + elif not opr and key in l_set: + if self._is_del(l_set, h): + commands.append( + self._form_attr_cmd( + attr=key, + val=self._bool_to_str(val), + opr=opr, + ) + ) + continue + elif not ( + h and self._in_target(h, key) + ) and not self._is_del(l_set, h): + commands.append( + self._form_attr_cmd( + attr=key, + val=self._bool_to_str(val), + opr=opr, + ) + ) + elif key == "icmp_redirects": + commands.extend( + self._render_icmp_redirects(key, w, h, opr) + ) + return commands + + def _render_icmp_redirects(self, attr, w, h, opr): + """ + This function forms the commands for 'icmp_redirects' attributes + based on the 'opr'. + :param attr: attribute name. + :param w: the desired config. + :param h: the target config. + :param opr: True/False. + :return: generated list of commands. + """ + commands = [] + h_red = {} + l_set = ("send", "receive") + if w[attr]: + if h and attr in h.keys(): + h_red = h.get(attr) or {} + for item, value in iteritems(w[attr]): + if ( + opr + and item in l_set + and not (h_red and self._is_w_same(w[attr], h_red, item)) + ): + commands.append( + self._form_attr_cmd( + attr=item, val=self._bool_to_str(value), opr=opr + ) + ) + elif ( + not opr + and item in l_set + and not (h_red and self._is_w_same(w[attr], h_red, item)) + ): + commands.append(self._form_attr_cmd(attr=item, opr=opr)) + return commands + + def search_attrib_in_have(self, have, want, attr): + """ + This function returns the attribute if it is present in target config. + :param have: the target config. + :param want: the desired config. + :param attr: attribute name . + :return: attribute/None + """ + if have: + for h in have: + if h[attr] == want[attr]: + return h + return None + + def _form_attr_cmd(self, key=None, attr=None, val=None, opr=True): + """ + This function forms the command for leaf attribute. + :param key: parent key. + :param attr: attribute name + :param value: value + :param opr: True/False. + :return: generated command. + """ + command = self._compute_command( + key=key, attr=self._map_attrib(attr), val=val, opr=opr + ) + return command + + def _compute_command( + self, key=None, attr=None, val=None, remove=False, opr=True + ): + """ + This function construct the add/delete command based on passed attributes. + :param key: parent key. + :param attr: attribute name + :param value: value + :param remove: True/False. + :param opr: True/False. + :return: generated command. + """ + if remove or not opr: + cmd = "delete firewall " + else: + cmd = "set firewall " + if key: + cmd += key.replace("_", "-") + " " + if attr: + cmd += attr.replace("_", "-") + if val and opr: + cmd += " '" + str(val) + "'" + return cmd + + def _bool_to_str(self, val): + """ + This function converts the bool value into string. + :param val: bool value. + :return: enable/disable. + """ + return ( + "enable" + if str(val) == "True" + else "disable" + if str(val) == "False" + else val + ) + + def _grp_type(self, val): + """ + This function returns the group member type based on value argument. + :param val: value. + :return: member type. + """ + return ( + "address" + if val == "address_group" + else "network" + if val == "network_group" + else "port" + ) + + def _is_w_same(self, w, h, key): + """ + This function checks whether the key value is same in desired and + target config dictionary. + :param w: base config. + :param h: target config. + :param key:attribute name. + :return: True/False. + """ + return True if h and key in h and h[key] == w[key] else False + + def _in_target(self, h, key): + """ + This function checks whether the target exist and key present in target config. + :param h: target config. + :param key: attribute name. + :return: True/False. + """ + return True if h and key in h else False + + def _is_grp_del(self, w, h, key): + """ + This function checks whether group needed to be deleted based on + desired and target configs. + :param w: the desired config. + :param h: the target config. + :param key: group name. + :return: True/False. + """ + return ( + True + if h and key in h and (not w or key not in w or not w[key]) + else False + ) + + def _is_root_del(self, w, h, key): + """ + This function checks whether a root attribute which can have + further child attributes needed to be deleted. + :param w: the desired config. + :param h: the target config. + :param key: attribute name. + :return: True/False. + """ + return ( + True + if h and key in h and (not w or key not in w or not w[key]) + else False + ) + + def _is_del(self, b_set, h, key="number"): + """ + This function checks whether attribute needs to be deleted + when operation is false and attribute present in present target config. + :param b_set: attribute set. + :param h: target config. + :param key: number. + :return: True/False. + """ + return key in b_set and not (h and self._in_target(h, key)) + + def _map_attrib(self, attrib, type=None): + """ + - This function construct the regex string. + - replace the underscore with hyphen. + :param attrib: attribute + :return: regex string + """ + regex = attrib.replace("_", "-") + if attrib == "send": + if type == "ipv6": + regex = "ipv6-send-redirects" + else: + regex = "send-redirects" + elif attrib == "ip_src_route": + if type == "ipv6": + regex = "ipv6-src-route" + elif attrib == "receive": + if type == "ipv6": + regex = "ipv6-receive-redirects" + else: + regex = "receive-redirects" + elif attrib == "disabled": + regex = "disable" + elif attrib == "all": + regex = "all-ping" + elif attrib == "broadcast": + regex = "broadcast-ping" + elif attrib == "validation": + regex = "source-validation" + return regex diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index 8f0a3bb..6e6a82b 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -33,6 +33,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firew from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.static_routes.static_routes import ( Static_routesFacts, ) +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.legacy.base import ( Default, Neighbors, @@ -49,6 +52,7 @@ FACT_RESOURCE_SUBSETS = dict( lldp_interfaces=Lldp_interfacesFacts, static_routes=Static_routesFacts, firewall_rules=Firewall_rulesFacts, + firewall_global=Firewall_globalFacts, ) diff --git a/tests/integration/targets/vyos_linkagg/aliases b/plugins/module_utils/network/vyos/facts/firewall_global/__init__.py index e69de29..e69de29 100644 --- a/tests/integration/targets/vyos_linkagg/aliases +++ b/plugins/module_utils/network/vyos/facts/firewall_global/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/firewall_global/firewall_global.py b/plugins/module_utils/network/vyos/facts/firewall_global/firewall_global.py new file mode 100644 index 0000000..0823259 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/firewall_global/firewall_global.py @@ -0,0 +1,388 @@ +# +# -*- 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_global fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from copy import deepcopy +from re import findall, search, M +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.firewall_global.firewall_global import ( + Firewall_globalArgs, +) + + +class Firewall_globalFacts(object): + """ The vyos firewall_global fact class + """ + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Firewall_globalArgs.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_global + :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 = {} + firewalls = findall(r"^set firewall .*$", data, M) + if firewalls: + objs = self.render_config(firewalls) + facts = {} + params = utils.validate_config(self.argument_spec, {"config": objs}) + facts["firewall_global"] = utils.remove_empties(params["config"]) + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + conf = "\n".join( + filter( + lambda x: ("firewall ipv6-name" and "firewall name" not in x), + conf, + ) + ) + + a_lst = [ + "config_trap", + "validation", + "log_martians", + "syn_cookies", + "twa_hazards_protection", + ] + firewall = self.parse_attr(conf, a_lst) + f_sub = { + "ping": self.parse_ping(conf), + "group": self.parse_group(conf), + "route_redirects": self.route_redirects(conf), + "state_policy": self.parse_state_policy(conf), + } + firewall.update(f_sub) + return firewall + + def route_redirects(self, conf): + """ + This function forms the regex to fetch the afi and invoke + functions to fetch route redirects and source routes + :param conf: configuration data. + :return: generated rule list configuration. + """ + rr_lst = [] + + v6_attr = findall( + r"^set firewall (?:ipv6-src-route|ipv6-receive-redirects) (\S+)", + conf, + M, + ) + if v6_attr: + obj = self.parse_rr_attrib(conf, "ipv6") + if obj: + rr_lst.append(obj) + + v4_attr = findall( + r"^set firewall (?:ip-src-route|receive-redirects|send-redirects) (\S+)", + conf, + M, + ) + if v4_attr: + obj = self.parse_rr_attrib(conf, "ipv4") + if obj: + rr_lst.append(obj) + return rr_lst + + def parse_rr_attrib(self, conf, attrib=None): + """ + This function fetches the 'ip_src_route' + invoke function to parse icmp redirects. + :param conf: configuration to be parsed. + :param attrib: 'ipv4/ipv6'. + :return: generated config dictionary. + """ + + cfg_dict = self.parse_attr(conf, ["ip_src_route"], type=attrib) + cfg_dict["icmp_redirects"] = self.parse_icmp_redirects(conf, attrib) + cfg_dict["afi"] = attrib + return cfg_dict + + def parse_icmp_redirects(self, conf, attrib=None): + """ + This function triggers the parsing of 'icmp_redirects' attributes. + :param conf: configuration to be parsed. + :param attrib: 'ipv4/ipv6'. + :return: generated config dictionary. + """ + a_lst = ["send", "receive"] + cfg_dict = self.parse_attr(conf, a_lst, type=attrib) + return cfg_dict + + def parse_ping(self, conf): + """ + This function triggers the parsing of 'ping' attributes. + :param conf: configuration to be parsed. + :return: generated config dictionary. + """ + a_lst = ["all", "broadcast"] + cfg_dict = self.parse_attr(conf, a_lst) + return cfg_dict + + def parse_state_policy(self, conf): + """ + This function fetched the connecton type and invoke + function to parse other state-policy attributes. + :param conf: configuration data. + :return: generated rule list configuration. + """ + sp_lst = [] + attrib = "state-policy" + policies = findall(r"^set firewall " + attrib + " (\\S+)", conf, M) + + if policies: + rules_lst = [] + for sp in set(policies): + sp_regex = r" %s .+$" % sp + cfg = "\n".join(findall(sp_regex, conf, M)) + obj = self.parse_policies(cfg, sp) + obj["connection_type"] = sp + if obj: + rules_lst.append(obj) + sp_lst = sorted(rules_lst, key=lambda i: i["connection_type"]) + return sp_lst + + def parse_policies(self, conf, attrib=None): + """ + This function triggers the parsing of policy attributes + action and log. + :param conf: configuration + :param attrib: connection type. + :return: generated rule configuration dictionary. + """ + a_lst = ["action", "log"] + cfg_dict = self.parse_attr(conf, a_lst, match=attrib) + return cfg_dict + + def parse_group(self, conf): + """ + This function triggers the parsing of 'group' attributes. + :param conf: configuration. + :return: generated config dictionary. + """ + cfg_dict = {} + cfg_dict["port_group"] = self.parse_group_lst(conf, "port-group") + cfg_dict["address_group"] = self.parse_group_lst(conf, "address-group") + cfg_dict["network_group"] = self.parse_group_lst(conf, "network-group") + return cfg_dict + + def parse_group_lst(self, conf, type): + """ + This function fetches the name of group and invoke function to + parse group attributes'. + :param conf: configuration data. + :param type: type of group. + :return: generated group list configuration. + """ + g_lst = [] + + groups = findall(r"^set firewall group " + type + " (\\S+)", conf, M) + if groups: + rules_lst = [] + for gr in set(groups): + gr_regex = r" %s .+$" % gr + cfg = "\n".join(findall(gr_regex, conf, M)) + obj = self.parse_groups(cfg, type, gr) + obj["name"] = gr.strip("'") + if obj: + rules_lst.append(obj) + g_lst = sorted(rules_lst, key=lambda i: i["name"]) + return g_lst + + def parse_groups(self, conf, type, name): + """ + This function fetches the description and invoke + the parsing of group members. + :param conf: configuration. + :param type: type of group. + :param name: name of group. + :return: generated configuration dictionary. + """ + a_lst = ["name", "description"] + group = self.parse_attr(conf, a_lst) + key = self.get_key(type) + r_sub = {key[0]: self.parse_address_port_lst(conf, name, key[1])} + group.update(r_sub) + return group + + def parse_address_port_lst(self, conf, name, key): + """ + This function forms the regex to fetch the + group members attributes. + :param conf: configuration data. + :param name: name of group. + :param key: key value. + :return: generated member list configuration. + """ + l_lst = [] + attribs = findall(r"^.*" + name + " " + key + " (\\S+)", conf, M) + if attribs: + for attr in attribs: + if key == "port": + l_lst.append({"port": attr.strip("'")}) + else: + l_lst.append({"address": attr.strip("'")}) + return l_lst + + def parse_attr(self, conf, attr_list, match=None, type=None): + """ + This function peforms the following: + - Form the regex to fetch the required attribute config. + - Type cast the output in desired format. + :param conf: configuration. + :param attr_list: list of attributes. + :param match: parent node/attribute name. + :return: generated config dictionary. + """ + config = {} + for attrib in attr_list: + regex = self.map_regex(attrib, type) + if match: + regex = match + " " + regex + if conf: + if self.is_bool(attrib): + attr = self.map_regex(attrib, type) + out = conf.find(attr.replace("_", "-")) + dis = conf.find(attr.replace("_", "-") + " 'disable'") + if out >= 1: + if dis >= 1: + config[attrib] = False + else: + config[attrib] = True + else: + out = search(r"^.*" + regex + " (.+)", conf, M) + if out: + val = out.group(1).strip("'") + if self.is_num(attrib): + val = int(val) + config[attrib] = val + return config + + def get_key(self, type): + """ + This function map the group type to + member type + :param type: + :return: + """ + key = () + if type == "port-group": + key = ("members", "port") + elif type == "address-group": + key = ("members", "address") + elif type == "network-group": + key = ("members", "network") + return key + + def map_regex(self, attrib, type=None): + """ + - This function construct the regex string. + - replace the underscore with hyphen. + :param attrib: attribute + :return: regex string + """ + regex = attrib.replace("_", "-") + if attrib == "all": + regex = "all-ping" + elif attrib == "disabled": + regex = "disable" + elif attrib == "broadcast": + regex = "broadcast-ping" + elif attrib == "send": + if type == "ipv6": + regex = "ipv6-send-redirects" + else: + regex = "send-redirects" + elif attrib == "ip_src_route": + if type == "ipv6": + regex = "ipv6-src-route" + elif attrib == "receive": + if type == "ipv6": + regex = "ipv6-receive-redirects" + else: + regex = "receive-redirects" + return regex + + def is_num(self, attrib): + """ + This function looks for the attribute in predefined integer type set. + :param attrib: attribute. + :return: True/false. + """ + num_set = ("time", "code", "type", "count", "burst", "number") + return True if attrib in num_set else False + + def get_src_route(self, attrib): + """ + This function looks for the attribute in predefined integer type set. + :param attrib: attribute. + :return: True/false. + """ + return "ipv6_src_route" if attrib == "ipv6" else "ip_src_route" + + def is_bool(self, attrib): + """ + This function looks for the attribute in predefined bool type set. + :param attrib: attribute. + :return: True/False + """ + bool_set = ( + "all", + "log", + "send", + "receive", + "broadcast", + "config_trap", + "log_martians", + "syn_cookies", + "ip_src_route", + "twa_hazards_protection", + ) + return True if attrib in bool_set else False diff --git a/plugins/modules/vyos_facts.py b/plugins/modules/vyos_facts.py index 19fb727..eec4c3b 100644 --- a/plugins/modules/vyos_facts.py +++ b/plugins/modules/vyos_facts.py @@ -47,7 +47,7 @@ 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'. + 'lldp_global', 'lldp_interfaces', 'static_routes', 'firewall_rules', 'firewall_global'. required: false """ diff --git a/plugins/modules/vyos_firewall_global.py b/plugins/modules/vyos_firewall_global.py new file mode 100644 index 0000000..519725a --- /dev/null +++ b/plugins/modules/vyos_firewall_global.py @@ -0,0 +1,1204 @@ +#!/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_global +""" + +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_global +short_description: Manage global policies or configurations for firewall on VyOS devices. +description: This module manage global policies or configurations for firewall on + VyOS devices. +notes: +- Tested against VyOS 1.1.8 (helium). +- This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html). +author: +- Rohit Thakur (@rohitthakur2590) +options: + config: + description: + - A dictionary of Firewall global configuration options. + type: dict + suboptions: + route_redirects: + description: -A dictionary of Firewall icmp redirect and source route global + configuration options. + type: list + elements: dict + suboptions: + afi: + description: + - Specifies IP address type + type: str + choices: + - ipv4 + - ipv6 + required: true + icmp_redirects: + description: + - Specifies whether to allow sending/receiving of IPv4/v6 ICMP redirect + messages. + type: dict + suboptions: + send: + description: + - Permits or denies transmitting packets ICMP redirect messages. + type: bool + receive: + description: + - Permits or denies receiving packets ICMP redirect messages. + type: bool + ip_src_route: + description: + - Specifies whether or not to process source route IP options. + type: bool + ping: + description: + - Policy for handling of all IPv4 ICMP echo requests. + type: dict + suboptions: + all: + description: + - Enables or disables response to all IPv4 ICMP Echo Request (ping) messages. + - The system responds to IPv4 ICMP Echo Request messages. + type: bool + broadcast: + description: + - Enables or disables response to broadcast IPv4 ICMP Echo Request and + Timestamp Request messages. + - IPv4 ICMP Echo and Timestamp Request messages are not processed. + type: bool + config_trap: + description: + - SNMP trap generation on firewall configuration changes. + type: bool + validation: + description: + - Specifies a policy for source validation by reversed path, as defined in + RFC 3704. + - (disable) No source validation is performed. + - (loose) Enable Loose Reverse Path Forwarding as defined in RFC3704. + - (strict) Enable Strict Reverse Path Forwarding as defined in RFC3704. + type: str + choices: + - strict + - loose + - disable + group: + description: + - Defines a group of objects for referencing in firewall rules. + type: dict + suboptions: + address_group: + description: + - Defines a group of IP addresses for referencing in firewall rules. + type: list + elements: dict + suboptions: + name: + description: + - Name of the firewall address group. + type: str + required: true + description: + description: + - Allows you to specify a brief description for the address group. + type: str + members: + description: + - Address-group members. + - IPv4 address to match. + - IPv4 range to match. + type: list + elements: dict + suboptions: + address: + description: IP address. + type: str + network_group: + description: + - Defines a group of networks for referencing in firewall rules. + type: list + elements: dict + suboptions: + name: + description: + - Name of the firewall network group. + type: str + required: true + description: + description: + - Allows you to specify a brief description for the network group. + type: str + members: + description: + - Adds an IPv4 network to the specified network group. + - The format is ip-address/prefix. + type: list + elements: dict + suboptions: + address: + description: IP address. + type: str + port_group: + description: + - Defines a group of ports for referencing in firewall rules. + type: list + elements: dict + suboptions: + name: + description: + - Name of the firewall port group. + type: str + required: true + description: + description: + - Allows you to specify a brief description for the port group. + type: str + members: + description: + - Port-group member. + type: list + elements: dict + suboptions: + port: + description: Defines the number. + type: str + log_martians: + description: + - Specifies whether or not to record packets with invalid addresses in the + log. + - (True) Logs packets with invalid addresses. + - (False) Does not log packets with invalid addresses. + type: bool + syn_cookies: + description: + - Specifies policy for using TCP SYN cookies with IPv4. + - (True) Enables TCP SYN cookies with IPv4. + - (False) Disables TCP SYN cookies with IPv4. + type: bool + twa_hazards_protection: + description: + - RFC1337 TCP TIME-WAIT assasination hazards protection. + type: bool + state_policy: + description: + - Specifies global firewall state-policy. + type: list + elements: dict + suboptions: + connection_type: + description: Specifies connection type. + type: str + choices: + - established + - invalid + - related + action: + description: + - Action for packets part of an established connection. + type: str + choices: + - accept + - drop + - reject + log: + description: + - Enable logging of packets part of an established connection. + type: bool + 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 + - deleted + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vyos@vyos# run show configuration commands | grep firewall +# +# +- name: Merge the provided configuration with the exisiting running configuration + vyos_firewall_global: + config: + validation: strict + config_trap: True + log_martians: True + syn_cookies: True + twa_hazards_protection: True + ping: + all: True + broadcast: True + state_policy: + - connection_type: 'established' + action: 'accept' + log: True + - connection_type: 'invalid' + action: 'reject' + route_redirects: + - afi: 'ipv4' + ip_src_route: True + icmp_redirects: + send: True + receive: False + group: + address_group: + - name: 'MGMT-HOSTS' + description: 'This group has the Management hosts address list' + members: + - address: 192.0.1.1 + - address: 192.0.1.3 + - address: 192.0.1.5 + network_group: + - name: 'MGMT' + description: 'This group has the Management network addresses' + members: + - address: 192.0.1.0/24 + state: merged +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# before": [] +# +# "commands": [ +# "set firewall group address-group MGMT-HOSTS address 192.0.1.1", +# "set firewall group address-group MGMT-HOSTS address 192.0.1.3", +# "set firewall group address-group MGMT-HOSTS address 192.0.1.5", +# "set firewall group address-group MGMT-HOSTS description 'This group has the Management hosts address list'", +# "set firewall group address-group MGMT-HOSTS", +# "set firewall group network-group MGMT network 192.0.1.0/24", +# "set firewall group network-group MGMT description 'This group has the Management network addresses'", +# "set firewall group network-group MGMT", +# "set firewall ip-src-route 'enable'", +# "set firewall receive-redirects 'disable'", +# "set firewall send-redirects 'enable'", +# "set firewall config-trap 'enable'", +# "set firewall state-policy established action 'accept'", +# "set firewall state-policy established log 'enable'", +# "set firewall state-policy invalid action 'reject'", +# "set firewall broadcast-ping 'enable'", +# "set firewall all-ping 'enable'", +# "set firewall log-martians 'enable'", +# "set firewall twa-hazards-protection 'enable'", +# "set firewall syn-cookies 'enable'", +# "set firewall source-validation 'strict'" +# ] +# +# "after": { +# "config_trap": true, +# "group": { +# "address_group": [ +# { +# "description": "This group has the Management hosts address list", +# "members": [ +# { +# "address": "192.0.1.1" +# }, +# { +# "address": "192.0.1.3" +# }, +# { +# "address": "192.0.1.5" +# } +# ], +# "name": "MGMT-HOSTS" +# } +# ], +# "network_group": [ +# { +# "description": "This group has the Management network addresses", +# "members": [ +# { +# "address": "192.0.1.0/24" +# } +# ], +# "name": "MGMT" +# } +# ] +# }, +# "log_martians": true, +# "ping": { +# "all": true, +# "broadcast": true +# }, +# "route_redirects": [ +# { +# "afi": "ipv4", +# "icmp_redirects": { +# "receive": false, +# "send": true +# }, +# "ip_src_route": true +# } +# ], +# "state_policy": [ +# { +# "action": "accept", +# "connection_type": "established", +# "log": true +# }, +# { +# "action": "reject", +# "connection_type": "invalid" +# } +# ], +# "syn_cookies": true, +# "twa_hazards_protection": true, +# "validation": "strict" +# } +# +# After state: +# ------------- +# +# vyos@192# run show configuration commands | grep firewall +# set firewall all-ping 'enable' +# set firewall broadcast-ping 'enable' +# set firewall config-trap 'enable' +# set firewall group address-group MGMT-HOSTS address '192.0.1.1' +# set firewall group address-group MGMT-HOSTS address '192.0.1.3' +# set firewall group address-group MGMT-HOSTS address '192.0.1.5' +# set firewall group address-group MGMT-HOSTS description 'This group has the Management hosts address list' +# set firewall group network-group MGMT description 'This group has the Management network addresses' +# set firewall group network-group MGMT network '192.0.1.0/24' +# set firewall ip-src-route 'enable' +# set firewall log-martians 'enable' +# set firewall receive-redirects 'disable' +# set firewall send-redirects 'enable' +# set firewall source-validation 'strict' +# set firewall state-policy established action 'accept' +# set firewall state-policy established log 'enable' +# set firewall state-policy invalid action 'reject' +# set firewall syn-cookies 'enable' +# set firewall twa-hazards-protection 'enable' +# +# +# Using parsed +# +# +- name: Render the commands for provided configuration + vyos_firewall_global: + running_config: + "set firewall all-ping 'enable' + set firewall broadcast-ping 'enable' + set firewall config-trap 'enable' + set firewall group address-group ENG-HOSTS address '192.0.3.1' + set firewall group address-group ENG-HOSTS address '192.0.3.2' + set firewall group address-group ENG-HOSTS description 'Sales office hosts address list' + set firewall group address-group SALES-HOSTS address '192.0.2.1' + set firewall group address-group SALES-HOSTS address '192.0.2.2' + set firewall group address-group SALES-HOSTS address '192.0.2.3' + set firewall group address-group SALES-HOSTS description 'Sales office hosts address list' + set firewall group network-group MGMT description 'This group has the Management network addresses' + set firewall group network-group MGMT network '192.0.1.0/24' + set firewall ip-src-route 'enable' + set firewall log-martians 'enable' + set firewall receive-redirects 'disable' + set firewall send-redirects 'enable' + set firewall source-validation 'strict' + set firewall state-policy established action 'accept' + set firewall state-policy established log 'enable' + set firewall state-policy invalid action 'reject' + set firewall syn-cookies 'enable' + set firewall twa-hazards-protection 'enable'" + state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": { +# "config_trap": true, +# "group": { +# "address_group": [ +# { +# "description": "Sales office hosts address list", +# "members": [ +# { +# "address": "192.0.3.1" +# }, +# { +# "address": "192.0.3.2" +# } +# ], +# "name": "ENG-HOSTS" +# }, +# { +# "description": "Sales office hosts address list", +# "members": [ +# { +# "address": "192.0.2.1" +# }, +# { +# "address": "192.0.2.2" +# }, +# { +# "address": "192.0.2.3" +# } +# ], +# "name": "SALES-HOSTS" +# } +# ], +# "network_group": [ +# { +# "description": "This group has the Management network addresses", +# "members": [ +# { +# "address": "192.0.1.0/24" +# } +# ], +# "name": "MGMT" +# } +# ] +# }, +# "log_martians": true, +# "ping": { +# "all": true, +# "broadcast": true +# }, +# "route_redirects": [ +# { +# "afi": "ipv4", +# "icmp_redirects": { +# "receive": false, +# "send": true +# }, +# "ip_src_route": true +# } +# ], +# "state_policy": [ +# { +# "action": "accept", +# "connection_type": "established", +# "log": true +# }, +# { +# "action": "reject", +# "connection_type": "invalid" +# } +# ], +# "syn_cookies": true, +# "twa_hazards_protection": true, +# "validation": "strict" +# } +# } +# +# +# Using deleted +# +# Before state +# ------------- +# +# vyos@192# run show configuration commands | grep firewall +# set firewall all-ping 'enable' +# set firewall broadcast-ping 'enable' +# set firewall config-trap 'enable' +# set firewall group address-group MGMT-HOSTS address '192.0.1.1' +# set firewall group address-group MGMT-HOSTS address '192.0.1.3' +# set firewall group address-group MGMT-HOSTS address '192.0.1.5' +# set firewall group address-group MGMT-HOSTS description 'This group has the Management hosts address list' +# set firewall group network-group MGMT description 'This group has the Management network addresses' +# set firewall group network-group MGMT network '192.0.1.0/24' +# set firewall ip-src-route 'enable' +# set firewall log-martians 'enable' +# set firewall receive-redirects 'disable' +# set firewall send-redirects 'enable' +# set firewall source-validation 'strict' +# set firewall state-policy established action 'accept' +# set firewall state-policy established log 'enable' +# set firewall state-policy invalid action 'reject' +# set firewall syn-cookies 'enable' +# set firewall twa-hazards-protection 'enable' +- name: Delete attributes of firewall. + vyos_firewall_global: + config: + state_policy: + config_trap: + log_martians: + syn_cookies: + twa_hazards_protection: + route_redirects: + ping: + group: + state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# +# "before": { +# "config_trap": true, +# "group": { +# "address_group": [ +# { +# "description": "This group has the Management hosts address list", +# "members": [ +# { +# "address": "192.0.1.1" +# }, +# { +# "address": "192.0.1.3" +# }, +# { +# "address": "192.0.1.5" +# } +# ], +# "name": "MGMT-HOSTS" +# } +# ], +# "network_group": [ +# { +# "description": "This group has the Management network addresses", +# "members": [ +# { +# "address": "192.0.1.0/24" +# } +# ], +# "name": "MGMT" +# } +# ] +# }, +# "log_martians": true, +# "ping": { +# "all": true, +# "broadcast": true +# }, +# "route_redirects": [ +# { +# "afi": "ipv4", +# "icmp_redirects": { +# "receive": false, +# "send": true +# }, +# "ip_src_route": true +# } +# ], +# "state_policy": [ +# { +# "action": "accept", +# "connection_type": "established", +# "log": true +# }, +# { +# "action": "reject", +# "connection_type": "invalid" +# } +# ], +# "syn_cookies": true, +# "twa_hazards_protection": true, +# "validation": "strict" +# } +# "commands": [ +# "delete firewall source-validation", +# "delete firewall group", +# "delete firewall log-martians", +# "delete firewall ip-src-route", +# "delete firewall receive-redirects", +# "delete firewall send-redirects", +# "delete firewall config-trap", +# "delete firewall state-policy", +# "delete firewall syn-cookies", +# "delete firewall broadcast-ping", +# "delete firewall all-ping", +# "delete firewall twa-hazards-protection" +# ] +# +# "after": [] +# After state +# ------------ +# vyos@192# run show configuration commands | grep firewall +# set 'firewall' +# +# +# Using replaced +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration commands| grep firewall +# set firewall all-ping 'enable' +# set firewall broadcast-ping 'enable' +# set firewall config-trap 'enable' +# set firewall group address-group MGMT-HOSTS address '192.0.1.1' +# set firewall group address-group MGMT-HOSTS address '192.0.1.3' +# set firewall group address-group MGMT-HOSTS address '192.0.1.5' +# set firewall group address-group MGMT-HOSTS description 'This group has the Management hosts address list' +# set firewall group network-group MGMT description 'This group has the Management network addresses' +# set firewall group network-group MGMT network '192.0.1.0/24' +# set firewall ip-src-route 'enable' +# set firewall log-martians 'enable' +# set firewall receive-redirects 'disable' +# set firewall send-redirects 'enable' +# set firewall source-validation 'strict' +# set firewall state-policy established action 'accept' +# set firewall state-policy established log 'enable' +# set firewall state-policy invalid action 'reject' +# set firewall syn-cookies 'enable' +# set firewall twa-hazards-protection 'enable' +# +- name: Replace firewall global attributes configuration. + vyos_firewall_global: + config: + validation: strict + config_trap: True + log_martians: True + syn_cookies: True + twa_hazards_protection: True + ping: + all: True + broadcast: True + state_policy: + - connection_type: 'established' + action: 'accept' + log: True + - connection_type: 'invalid' + action: 'reject' + route_redirects: + - afi: 'ipv4' + ip_src_route: True + icmp_redirects: + send: True + receive: False + group: + address_group: + - name: 'SALES-HOSTS' + description: 'Sales office hosts address list' + members: + - address: 192.0.2.1 + - address: 192.0.2.2 + - address: 192.0.2.3 + - name: 'ENG-HOSTS' + description: 'Sales office hosts address list' + members: + - address: 192.0.3.1 + - address: 192.0.3.2 + network_group: + - name: 'MGMT' + description: 'This group has the Management network addresses' + members: + - address: 192.0.1.0/24 + state: replaced +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "before": { +# "config_trap": true, +# "group": { +# "address_group": [ +# { +# "description": "This group has the Management hosts address list", +# "members": [ +# { +# "address": "192.0.1.1" +# }, +# { +# "address": "192.0.1.3" +# }, +# { +# "address": "192.0.1.5" +# } +# ], +# "name": "MGMT-HOSTS" +# } +# ], +# "network_group": [ +# { +# "description": "This group has the Management network addresses", +# "members": [ +# { +# "address": "192.0.1.0/24" +# } +# ], +# "name": "MGMT" +# } +# ] +# }, +# "log_martians": true, +# "ping": { +# "all": true, +# "broadcast": true +# }, +# "route_redirects": [ +# { +# "afi": "ipv4", +# "icmp_redirects": { +# "receive": false, +# "send": true +# }, +# "ip_src_route": true +# } +# ], +# "state_policy": [ +# { +# "action": "accept", +# "connection_type": "established", +# "log": true +# }, +# { +# "action": "reject", +# "connection_type": "invalid" +# } +# ], +# "syn_cookies": true, +# "twa_hazards_protection": true, +# "validation": "strict" +# } +# +# "commands": [ +# "delete firewall group address-group MGMT-HOSTS", +# "set firewall group address-group SALES-HOSTS address 192.0.2.1", +# "set firewall group address-group SALES-HOSTS address 192.0.2.2", +# "set firewall group address-group SALES-HOSTS address 192.0.2.3", +# "set firewall group address-group SALES-HOSTS description 'Sales office hosts address list'", +# "set firewall group address-group SALES-HOSTS", +# "set firewall group address-group ENG-HOSTS address 192.0.3.1", +# "set firewall group address-group ENG-HOSTS address 192.0.3.2", +# "set firewall group address-group ENG-HOSTS description 'Sales office hosts address list'", +# "set firewall group address-group ENG-HOSTS" +# ] +# +# "after": { +# "config_trap": true, +# "group": { +# "address_group": [ +# { +# "description": "Sales office hosts address list", +# "members": [ +# { +# "address": "192.0.3.1" +# }, +# { +# "address": "192.0.3.2" +# } +# ], +# "name": "ENG-HOSTS" +# }, +# { +# "description": "Sales office hosts address list", +# "members": [ +# { +# "address": "192.0.2.1" +# }, +# { +# "address": "192.0.2.2" +# }, +# { +# "address": "192.0.2.3" +# } +# ], +# "name": "SALES-HOSTS" +# } +# ], +# "network_group": [ +# { +# "description": "This group has the Management network addresses", +# "members": [ +# { +# "address": "192.0.1.0/24" +# } +# ], +# "name": "MGMT" +# } +# ] +# }, +# "log_martians": true, +# "ping": { +# "all": true, +# "broadcast": true +# }, +# "route_redirects": [ +# { +# "afi": "ipv4", +# "icmp_redirects": { +# "receive": false, +# "send": true +# }, +# "ip_src_route": true +# } +# ], +# "state_policy": [ +# { +# "action": "accept", +# "connection_type": "established", +# "log": true +# }, +# { +# "action": "reject", +# "connection_type": "invalid" +# } +# ], +# "syn_cookies": true, +# "twa_hazards_protection": true, +# "validation": "strict" +# } +# +# After state: +# ------------- +# +# vyos@192# run show configuration commands | grep firewall +# set firewall all-ping 'enable' +# set firewall broadcast-ping 'enable' +# set firewall config-trap 'enable' +# set firewall group address-group ENG-HOSTS address '192.0.3.1' +# set firewall group address-group ENG-HOSTS address '192.0.3.2' +# set firewall group address-group ENG-HOSTS description 'Sales office hosts address list' +# set firewall group address-group SALES-HOSTS address '192.0.2.1' +# set firewall group address-group SALES-HOSTS address '192.0.2.2' +# set firewall group address-group SALES-HOSTS address '192.0.2.3' +# set firewall group address-group SALES-HOSTS description 'Sales office hosts address list' +# set firewall group network-group MGMT description 'This group has the Management network addresses' +# set firewall group network-group MGMT network '192.0.1.0/24' +# set firewall ip-src-route 'enable' +# set firewall log-martians 'enable' +# set firewall receive-redirects 'disable' +# set firewall send-redirects 'enable' +# set firewall source-validation 'strict' +# set firewall state-policy established action 'accept' +# set firewall state-policy established log 'enable' +# set firewall state-policy invalid action 'reject' +# set firewall syn-cookies 'enable' +# set firewall twa-hazards-protection 'enable' +# +# +# Using gathered +# +# Before state: +# ------------- +# +# vyos@192# run show configuration commands | grep firewall +# set firewall all-ping 'enable' +# set firewall broadcast-ping 'enable' +# set firewall config-trap 'enable' +# set firewall group address-group ENG-HOSTS address '192.0.3.1' +# set firewall group address-group ENG-HOSTS address '192.0.3.2' +# set firewall group address-group ENG-HOSTS description 'Sales office hosts address list' +# set firewall group address-group SALES-HOSTS address '192.0.2.1' +# set firewall group address-group SALES-HOSTS address '192.0.2.2' +# set firewall group address-group SALES-HOSTS address '192.0.2.3' +# set firewall group address-group SALES-HOSTS description 'Sales office hosts address list' +# set firewall group network-group MGMT description 'This group has the Management network addresses' +# set firewall group network-group MGMT network '192.0.1.0/24' +# set firewall ip-src-route 'enable' +# set firewall log-martians 'enable' +# set firewall receive-redirects 'disable' +# set firewall send-redirects 'enable' +# set firewall source-validation 'strict' +# set firewall state-policy established action 'accept' +# set firewall state-policy established log 'enable' +# set firewall state-policy invalid action 'reject' +# set firewall syn-cookies 'enable' +# set firewall twa-hazards-protection 'enable' +# +- name: Gather firewall global config with provided configurations + vyos_firewall_global: + config: + state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "gathered": [ +# { +# "config_trap": true, +# "group": { +# "address_group": [ +# { +# "description": "Sales office hosts address list", +# "members": [ +# { +# "address": "192.0.3.1" +# }, +# { +# "address": "192.0.3.2" +# } +# ], +# "name": "ENG-HOSTS" +# }, +# { +# "description": "Sales office hosts address list", +# "members": [ +# { +# "address": "192.0.2.1" +# }, +# { +# "address": "192.0.2.2" +# }, +# { +# "address": "192.0.2.3" +# } +# ], +# "name": "SALES-HOSTS" +# } +# ], +# "network_group": [ +# { +# "description": "This group has the Management network addresses", +# "members": [ +# { +# "address": "192.0.1.0/24" +# } +# ], +# "name": "MGMT" +# } +# ] +# }, +# "log_martians": true, +# "ping": { +# "all": true, +# "broadcast": true +# }, +# "route_redirects": [ +# { +# "afi": "ipv4", +# "icmp_redirects": { +# "receive": false, +# "send": true +# }, +# "ip_src_route": true +# } +# ], +# "state_policy": [ +# { +# "action": "accept", +# "connection_type": "established", +# "log": true +# }, +# { +# "action": "reject", +# "connection_type": "invalid" +# } +# ], +# "syn_cookies": true, +# "twa_hazards_protection": true, +# "validation": "strict" +# } +# +# After state: +# ------------- +# +# vyos@192# run show configuration commands | grep firewall +# set firewall all-ping 'enable' +# set firewall broadcast-ping 'enable' +# set firewall config-trap 'enable' +# set firewall group address-group ENG-HOSTS address '192.0.3.1' +# set firewall group address-group ENG-HOSTS address '192.0.3.2' +# set firewall group address-group ENG-HOSTS description 'Sales office hosts address list' +# set firewall group address-group SALES-HOSTS address '192.0.2.1' +# set firewall group address-group SALES-HOSTS address '192.0.2.2' +# set firewall group address-group SALES-HOSTS address '192.0.2.3' +# set firewall group address-group SALES-HOSTS description 'Sales office hosts address list' +# set firewall group network-group MGMT description 'This group has the Management network addresses' +# set firewall group network-group MGMT network '192.0.1.0/24' +# set firewall ip-src-route 'enable' +# set firewall log-martians 'enable' +# set firewall receive-redirects 'disable' +# set firewall send-redirects 'enable' +# set firewall source-validation 'strict' +# set firewall state-policy established action 'accept' +# set firewall state-policy established log 'enable' +# set firewall state-policy invalid action 'reject' +# set firewall syn-cookies 'enable' +# set firewall twa-hazards-protection 'enable' + + +# Using rendered +# +# +- name: Render the commands for provided configuration + vyos_firewall_global: + config: + validation: strict + config_trap: True + log_martians: True + syn_cookies: True + twa_hazards_protection: True + ping: + all: True + broadcast: True + state_policy: + - connection_type: 'established' + action: 'accept' + log: True + - connection_type: 'invalid' + action: 'reject' + route_redirects: + - afi: 'ipv4' + ip_src_route: True + icmp_redirects: + send: True + receive: False + group: + address_group: + - name: 'SALES-HOSTS' + description: 'Sales office hosts address list' + members: + - address: 192.0.2.1 + - address: 192.0.2.2 + - address: 192.0.2.3 + - name: 'ENG-HOSTS' + description: 'Sales office hosts address list' + members: + - address: 192.0.3.1 + - address: 192.0.3.2 + network_group: + - name: 'MGMT' + description: 'This group has the Management network addresses' + members: + - address: 192.0.1.0/24 + state: rendered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +# "set firewall group address-group SALES-HOSTS address 192.0.2.1", +# "set firewall group address-group SALES-HOSTS address 192.0.2.2", +# "set firewall group address-group SALES-HOSTS address 192.0.2.3", +# "set firewall group address-group SALES-HOSTS description 'Sales office hosts address list'", +# "set firewall group address-group SALES-HOSTS", +# "set firewall group address-group ENG-HOSTS address 192.0.3.1", +# "set firewall group address-group ENG-HOSTS address 192.0.3.2", +# "set firewall group address-group ENG-HOSTS description 'Sales office hosts address list'", +# "set firewall group address-group ENG-HOSTS", +# "set firewall group network-group MGMT network 192.0.1.0/24", +# "set firewall group network-group MGMT description 'This group has the Management network addresses'", +# "set firewall group network-group MGMT", +# "set firewall ip-src-route 'enable'", +# "set firewall receive-redirects 'disable'", +# "set firewall send-redirects 'enable'", +# "set firewall config-trap 'enable'", +# "set firewall state-policy established action 'accept'", +# "set firewall state-policy established log 'enable'", +# "set firewall state-policy invalid action 'reject'", +# "set firewall broadcast-ping 'enable'", +# "set firewall all-ping 'enable'", +# "set firewall log-martians 'enable'", +# "set firewall twa-hazards-protection 'enable'", +# "set firewall syn-cookies 'enable'", +# "set firewall source-validation 'strict'" +# ] +# +# +""" +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 firewall group address-group ENG-HOSTS', + 'set firewall group address-group ENG-HOSTS address 192.0.3.1'] +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.firewall_global.firewall_global import ( + Firewall_globalArgs, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.firewall_global.firewall_global import ( + Firewall_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Firewall_globalArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Firewall_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/vyos_banner/aliases b/tests/integration/targets/vyos_banner/aliases index 539d957..8071e1f 100644 --- a/tests/integration/targets/vyos_banner/aliases +++ b/tests/integration/targets/vyos_banner/aliases @@ -1 +1 @@ -shippable/network +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_command/aliases b/tests/integration/targets/vyos_command/aliases index 539d957..8071e1f 100644 --- a/tests/integration/targets/vyos_command/aliases +++ b/tests/integration/targets/vyos_command/aliases @@ -1 +1 @@ -shippable/network +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_config/aliases b/tests/integration/targets/vyos_config/aliases index 539d957..8071e1f 100644 --- a/tests/integration/targets/vyos_config/aliases +++ b/tests/integration/targets/vyos_config/aliases @@ -1 +1 @@ -shippable/network +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_facts/aliases b/tests/integration/targets/vyos_facts/aliases index 539d957..8071e1f 100644 --- a/tests/integration/targets/vyos_facts/aliases +++ b/tests/integration/targets/vyos_facts/aliases @@ -1 +1 @@ -shippable/network +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_firewall_global/defaults/main.yaml b/tests/integration/targets/vyos_firewall_global/defaults/main.yaml new file mode 100644 index 0000000..852a6be --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: '[^_].*' +test_items: [] diff --git a/tests/integration/targets/vyos_firewall_global/meta/main.yaml b/tests/integration/targets/vyos_firewall_global/meta/main.yaml new file mode 100644 index 0000000..7413320 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/meta/main.yaml @@ -0,0 +1,3 @@ +--- +dependencies: + - prepare_vyos_tests diff --git a/tests/integration/targets/vyos_firewall_global/tasks/cli.yaml b/tests/integration/targets/vyos_firewall_global/tasks/cli.yaml new file mode 100644 index 0000000..93eb2fe --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/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_global/tasks/main.yaml b/tests/integration/targets/vyos_firewall_global/tasks/main.yaml new file mode 100644 index 0000000..a3db933 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tasks/main.yaml @@ -0,0 +1,4 @@ +--- +- include: cli.yaml + tags: + - cli diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_firewall_global/tests/cli/_parsed_config.cfg new file mode 100644 index 0000000..45446bd --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/_parsed_config.cfg @@ -0,0 +1,19 @@ +set firewall all-ping 'enable' +set firewall broadcast-ping 'enable' +set firewall config-trap 'enable' +set firewall group address-group MGMT-HOSTS address '192.0.1.1' +set firewall group address-group MGMT-HOSTS address '192.0.1.3' +set firewall group address-group MGMT-HOSTS address '192.0.1.5' +set firewall group address-group MGMT-HOSTS description 'This group has the Management hosts address list' +set firewall group network-group MGMT description 'This group has the Management network addresses' +set firewall group network-group MGMT network '192.0.1.0/24' +set firewall ip-src-route 'enable' +set firewall log-martians 'enable' +set firewall receive-redirects 'disable' +set firewall send-redirects 'enable' +set firewall source-validation 'strict' +set firewall state-policy established action 'accept' +set firewall state-policy established log 'enable' +set firewall state-policy invalid action 'reject' +set firewall syn-cookies 'enable' +set firewall twa-hazards-protection 'enable' diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml new file mode 100644 index 0000000..f79bb9a --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml @@ -0,0 +1,18 @@ +--- +- name: Setup + vars: + lines: "set firewall all-ping 'enable'\nset firewall broadcast-ping 'enable'\n\ + set firewall config-trap 'enable'\nset firewall group address-group MGMT-HOSTS\ + \ address '192.0.1.1'\nset firewall group address-group MGMT-HOSTS address\ + \ '192.0.1.3'\nset firewall group address-group MGMT-HOSTS address '192.0.1.5'\n\ + set firewall group address-group MGMT-HOSTS description 'This group has the\ + \ Management hosts address list'\nset firewall group network-group MGMT description\ + \ 'This group has the Management network addresses'\nset firewall group network-group\ + \ MGMT network '192.0.1.0/24'\nset firewall ip-src-route 'enable'\nset firewall\ + \ log-martians 'enable'\nset firewall receive-redirects 'disable'\nset firewall\ + \ send-redirects 'enable'\nset firewall source-validation 'strict'\nset firewall\ + \ state-policy established action 'accept'\nset firewall state-policy established\ + \ log 'enable'\nset firewall state-policy invalid action 'reject'\nset firewall\ + \ syn-cookies 'enable'\nset firewall twa-hazards-protection 'enable'\n" + ansible.netcommon.cli_config: + config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml new file mode 100644 index 0000000..5c86924 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml @@ -0,0 +1,6 @@ +--- +- name: Remove Config + vars: + lines: "delete firewall\n" + ansible.netcommon.cli_config: + config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml new file mode 100644 index 0000000..44df47c --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml @@ -0,0 +1,48 @@ +--- +- debug: + msg: Start vyos_firewall_global deleted integration tests ansible_connection={{ + ansible_connection }} + +- include_tasks: _populate.yaml + +- block: + + - name: Delete attributes of firewall. + register: result + vyos.vyos.vyos_firewall_global: &id001 + config: + state: deleted + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ populate == result['before'] }}" + + - 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'] == result['after'] }}" + + - name: Delete attributes of given interfaces (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_global: *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'] == result['before'] }}" + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml new file mode 100644 index 0000000..3910952 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml @@ -0,0 +1,49 @@ +--- +- debug: + msg: START vyos_firewall_global 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_global: + 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_global: + config: + state: replaced + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Parsed with empty running_config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_firewall_global: + 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_global: + 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_global/tests/cli/gathered.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/gathered.yaml new file mode 100644 index 0000000..eda24fd --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/gathered.yaml @@ -0,0 +1,33 @@ +--- +- debug: + msg: START vyos_firewall_global gathered integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Merge the provided configuration with the exisiting running configuration + register: result + vyos.vyos.vyos_firewall_global: &id001 + config: + state: gathered + + - name: Assert that gathered dicts was correctly generated + assert: + that: + - "{{ populate == result['gathered'] }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_global: *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_global/tests/cli/merged.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/merged.yaml new file mode 100644 index 0000000..4f22660 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/merged.yaml @@ -0,0 +1,89 @@ +--- +- debug: + msg: START vyos_firewall_global merged integration tests on connection={{ ansible_connection + }} + +- include_tasks: _remove_config.yaml + +- block: + + - name: Merge the provided configuration with the exisiting running configuration + register: result + vyos.vyos.vyos_firewall_global: &id001 + config: + validation: strict + config_trap: true + log_martians: true + syn_cookies: true + twa_hazards_protection: true + ping: + all: true + broadcast: true + state_policy: + + - connection_type: established + action: accept + log: true + + - connection_type: invalid + action: reject + route_redirects: + + - afi: ipv4 + ip_src_route: true + icmp_redirects: + send: true + receive: false + group: + address_group: + + - name: MGMT-HOSTS + description: This group has the Management hosts address list + members: + + - address: 192.0.1.1 + + - address: 192.0.1.3 + + - address: 192.0.1.5 + network_group: + + - name: MGMT + description: This group has the Management network addresses + members: + + - address: 192.0.1.0/24 + state: merged + + - name: Assert that before dicts were correctly generated + assert: + that: "{{ merged['before'] == result['before'] }}" + + - 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'] == result['after'] }}" + + - name: Merge the provided configuration with the existing running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_global: *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'] == result['before'] }}" + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml new file mode 100644 index 0000000..b94d95e --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml @@ -0,0 +1,41 @@ +--- +- debug: + msg: START vyos_firewall_global parsed integration tests on connection={{ ansible_connection + }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Gather firewall_global facts + register: firewall_global_facts + vyos.vyos.vyos_facts: + gather_subset: + - default + gather_network_resources: + - firewall_global + + - name: Provide the running configuration for parsing (config to be parsed) + register: result + vyos.vyos.vyos_firewall_global: &id001 + running_config: "{{ lookup('file', '_parsed_config.cfg') }}" + state: parsed + + - name: Assert that correct parsing done + assert: + that: "{{ ansible_facts['network_resources']['firewall_global'] == result['parsed']\ + \ }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_global: *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_global/tests/cli/rendered.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/rendered.yaml new file mode 100644 index 0000000..528563e --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/rendered.yaml @@ -0,0 +1,84 @@ +--- +- debug: + msg: START vyos_firewall_global rendered integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Structure provided configuration into device specific commands + register: result + vyos.vyos.vyos_firewall_global: &id001 + config: + validation: strict + config_trap: true + log_martians: true + syn_cookies: true + twa_hazards_protection: true + ping: + all: true + broadcast: true + state_policy: + + - connection_type: established + action: accept + log: true + + - connection_type: invalid + action: reject + route_redirects: + + - afi: ipv4 + ip_src_route: true + icmp_redirects: + send: true + receive: false + group: + address_group: + + - name: SALES-HOSTS + description: Sales office hosts address list + members: + + - address: 192.0.2.1 + + - address: 192.0.2.2 + + - address: 192.0.2.3 + + - name: ENG-HOSTS + description: Sales office hosts address list + members: + + - address: 192.0.3.1 + + - address: 192.0.3.2 + network_group: + + - name: MGMT + description: This group has the Management network addresses + members: + + - address: 192.0.1.0/24 + 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_global: *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_global/tests/cli/replaced.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/replaced.yaml new file mode 100644 index 0000000..31a7644 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/replaced.yaml @@ -0,0 +1,100 @@ +--- +- debug: + msg: START vyos_firewall_global replaced integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Replace device configurations of listed firewall with provided configurations + register: result + vyos.vyos.vyos_firewall_global: &id001 + config: + validation: strict + config_trap: true + log_martians: true + syn_cookies: true + twa_hazards_protection: true + ping: + all: true + broadcast: true + state_policy: + + - connection_type: established + action: accept + log: true + + - connection_type: invalid + action: reject + route_redirects: + + - afi: ipv4 + ip_src_route: true + icmp_redirects: + send: true + receive: false + group: + address_group: + + - name: SALES-HOSTS + description: Sales office hosts address list + members: + + - address: 192.0.2.1 + + - address: 192.0.2.2 + + - address: 192.0.2.3 + + - name: ENG-HOSTS + description: Sales office hosts address list + members: + + - address: 192.0.3.1 + + - address: 192.0.3.2 + network_group: + + - name: MGMT + description: This group has the Management network addresses + members: + + - address: 192.0.1.0/24 + 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 == result['before'] }}" + + - name: Assert that after dict is correctly generated + assert: + that: + - "{{ replaced['after'] == result['after'] }}" + + - name: Replace device configurations of listed firewall with provided configurarions + (IDEMPOTENT) + register: result + vyos.vyos.vyos_firewall_global: *id001 + + - name: Assert that task was idempotent + assert: + that: + - result['changed'] == false + + - name: Assert that before dict is correctly generated + assert: + that: + - "{{ replaced['after'] == result['before'] }}" + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml b/tests/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml new file mode 100644 index 0000000..00c5635 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml @@ -0,0 +1,94 @@ +--- +- debug: + msg: START vyos_firewall_global round trip integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + + - name: Apply the provided configuration (base config) + register: base_config + vyos.vyos.vyos_firewall_global: + config: + validation: strict + config_trap: true + log_martians: true + syn_cookies: true + twa_hazards_protection: true + ping: + all: true + broadcast: true + state_policy: + + - connection_type: established + action: accept + log: true + + - connection_type: invalid + action: reject + route_redirects: + + - afi: ipv4 + ip_src_route: true + icmp_redirects: + send: true + receive: false + group: + address_group: + + - name: MGMT-HOSTS + description: This group has the Management hosts address list + members: + + - address: 192.0.1.1 + + - address: 192.0.1.3 + + - address: 192.0.1.5 + network_group: + + - name: MGMT + description: This group has the Management network addresses + members: + + - address: 192.0.1.0/24 + state: merged + + - name: Gather firewall_global facts + vyos.vyos.vyos_facts: + gather_subset: + - default + gather_network_resources: + - firewall_global + + - name: Apply the provided configuration (config to be reverted) + register: result + vyos.vyos.vyos_firewall_global: + config: + validation: strict + config_trap: false + log_martians: false + syn_cookies: false + twa_hazards_protection: false + ping: + all: false + broadcast: false + state: merged + + - name: Assert that changes were applied + assert: + that: "{{ round_trip['after'] == result['after'] }}" + + - name: Revert back to base config using facts round trip + register: revert + vyos.vyos.vyos_firewall_global: + config: "{{ ansible_facts['network_resources']['firewall_global'] }}" + state: replaced + + - name: Assert that config was reverted + assert: + that: "{{ base_config['after'] == revert['after']}}" + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_firewall_global/vars/main.yaml b/tests/integration/targets/vyos_firewall_global/vars/main.yaml new file mode 100644 index 0000000..4a1e7a8 --- /dev/null +++ b/tests/integration/targets/vyos_firewall_global/vars/main.yaml @@ -0,0 +1,217 @@ +--- +merged: + before: [] + commands: + - set firewall group address-group MGMT-HOSTS address 192.0.1.1 + - set firewall group address-group MGMT-HOSTS address 192.0.1.3 + - set firewall group address-group MGMT-HOSTS address 192.0.1.5 + - set firewall group address-group MGMT-HOSTS description 'This group has the + Management hosts address list' + - set firewall group address-group MGMT-HOSTS + - set firewall group network-group MGMT network 192.0.1.0/24 + - set firewall group network-group MGMT description 'This group has the Management + network addresses' + - set firewall group network-group MGMT + - set firewall ip-src-route 'enable' + - set firewall receive-redirects 'disable' + - set firewall send-redirects 'enable' + - set firewall config-trap 'enable' + - set firewall state-policy established action 'accept' + - set firewall state-policy established log 'enable' + - set firewall state-policy invalid action 'reject' + - set firewall broadcast-ping 'enable' + - set firewall all-ping 'enable' + - set firewall log-martians 'enable' + - set firewall twa-hazards-protection 'enable' + - set firewall syn-cookies 'enable' + - set firewall source-validation 'strict' + after: + config_trap: true + group: + address_group: + - members: + - address: 192.0.1.1 + - address: 192.0.1.3 + - address: 192.0.1.5 + description: This group has the Management hosts address list + name: MGMT-HOSTS + network_group: + - members: + - address: 192.0.1.0/24 + description: This group has the Management network addresses + name: MGMT + log_martians: true + ping: + all: true + broadcast: true + route_redirects: + - afi: ipv4 + icmp_redirects: + receive: false + send: true + ip_src_route: true + syn_cookies: true + state_policy: + - action: accept + connection_type: established + log: true + - action: reject + connection_type: invalid + twa_hazards_protection: true + validation: strict +populate: + validation: strict + config_trap: true + log_martians: true + syn_cookies: true + twa_hazards_protection: true + ping: + all: true + broadcast: true + state_policy: + - connection_type: established + action: accept + log: true + - connection_type: invalid + action: reject + route_redirects: + - afi: ipv4 + ip_src_route: true + icmp_redirects: + send: true + receive: false + group: + address_group: + - name: MGMT-HOSTS + description: This group has the Management hosts address list + members: + - address: 192.0.1.1 + - address: 192.0.1.3 + - address: 192.0.1.5 + network_group: + - name: MGMT + description: This group has the Management network addresses + members: + - address: 192.0.1.0/24 +replaced: + commands: + - delete firewall group address-group MGMT-HOSTS + - set firewall group address-group SALES-HOSTS address 192.0.2.1 + - set firewall group address-group SALES-HOSTS address 192.0.2.2 + - set firewall group address-group SALES-HOSTS address 192.0.2.3 + - set firewall group address-group SALES-HOSTS description 'Sales office hosts + address list' + - set firewall group address-group SALES-HOSTS + - set firewall group address-group ENG-HOSTS address 192.0.3.1 + - set firewall group address-group ENG-HOSTS address 192.0.3.2 + - set firewall group address-group ENG-HOSTS description 'Sales office hosts address + list' + - set firewall group address-group ENG-HOSTS + after: + config_trap: true + group: + address_group: + - members: + - address: 192.0.3.1 + - address: 192.0.3.2 + description: Sales office hosts address list + name: ENG-HOSTS + - members: + - address: 192.0.2.1 + - address: 192.0.2.2 + - address: 192.0.2.3 + description: Sales office hosts address list + name: SALES-HOSTS + network_group: + - members: + - address: 192.0.1.0/24 + description: This group has the Management network addresses + name: MGMT + log_martians: true + ping: + all: true + broadcast: true + route_redirects: + - afi: ipv4 + icmp_redirects: + receive: false + send: true + ip_src_route: true + state_policy: + - action: accept + connection_type: established + log: true + - action: reject + connection_type: invalid + syn_cookies: true + twa_hazards_protection: true + validation: strict +rendered: + commands: + - set firewall group address-group SALES-HOSTS address 192.0.2.1 + - set firewall group address-group SALES-HOSTS address 192.0.2.2 + - set firewall group address-group SALES-HOSTS address 192.0.2.3 + - set firewall group address-group SALES-HOSTS description 'Sales office hosts + address list' + - set firewall group address-group SALES-HOSTS + - set firewall group address-group ENG-HOSTS address 192.0.3.1 + - set firewall group address-group ENG-HOSTS address 192.0.3.2 + - set firewall group address-group ENG-HOSTS description 'Sales office hosts address + list' + - set firewall group address-group ENG-HOSTS + - set firewall group network-group MGMT network 192.0.1.0/24 + - set firewall group network-group MGMT description 'This group has the Management + network addresses' + - set firewall group network-group MGMT + - set firewall ip-src-route 'enable' + - set firewall receive-redirects 'disable' + - set firewall send-redirects 'enable' + - set firewall config-trap 'enable' + - set firewall state-policy established action 'accept' + - set firewall state-policy established log 'enable' + - set firewall state-policy invalid action 'reject' + - set firewall broadcast-ping 'enable' + - set firewall all-ping 'enable' + - set firewall log-martians 'enable' + - set firewall twa-hazards-protection 'enable' + - set firewall syn-cookies 'enable' + - set firewall source-validation 'strict' +deleted: + commands: + - 'delete firewall ' + after: [] +round_trip: + after: + validation: strict + config_trap: false + log_martians: false + syn_cookies: false + twa_hazards_protection: false + ping: + all: false + broadcast: false + state_policy: + - connection_type: established + action: accept + log: true + - connection_type: invalid + action: reject + route_redirects: + - afi: ipv4 + ip_src_route: true + icmp_redirects: + send: true + receive: false + group: + address_group: + - name: MGMT-HOSTS + description: This group has the Management hosts address list + members: + - address: 192.0.1.1 + - address: 192.0.1.3 + - address: 192.0.1.5 + network_group: + - name: MGMT + description: This group has the Management network addresses + members: + - address: 192.0.1.0/24 diff --git a/tests/integration/targets/vyos_firewall_rules/aliases b/tests/integration/targets/vyos_firewall_rules/aliases new file mode 100644 index 0000000..8071e1f --- /dev/null +++ b/tests/integration/targets/vyos_firewall_rules/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_lldp/aliases b/tests/integration/targets/vyos_lldp/aliases index 539d957..8071e1f 100644 --- a/tests/integration/targets/vyos_lldp/aliases +++ b/tests/integration/targets/vyos_lldp/aliases @@ -1 +1 @@ -shippable/network +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_lldp_global/aliases b/tests/integration/targets/vyos_lldp_global/aliases new file mode 100644 index 0000000..8071e1f --- /dev/null +++ b/tests/integration/targets/vyos_lldp_global/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_lldp_interface/aliases b/tests/integration/targets/vyos_lldp_interface/aliases index e69de29..8071e1f 100644 --- a/tests/integration/targets/vyos_lldp_interface/aliases +++ b/tests/integration/targets/vyos_lldp_interface/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_lldp_interfaces/aliases b/tests/integration/targets/vyos_lldp_interfaces/aliases new file mode 100644 index 0000000..8071e1f --- /dev/null +++ b/tests/integration/targets/vyos_lldp_interfaces/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_logging/aliases b/tests/integration/targets/vyos_logging/aliases index e69de29..8071e1f 100644 --- a/tests/integration/targets/vyos_logging/aliases +++ b/tests/integration/targets/vyos_logging/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_static_route/aliases b/tests/integration/targets/vyos_static_route/aliases index 539d957..8071e1f 100644 --- a/tests/integration/targets/vyos_static_route/aliases +++ b/tests/integration/targets/vyos_static_route/aliases @@ -1 +1 @@ -shippable/network +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_static_routes/aliases b/tests/integration/targets/vyos_static_routes/aliases new file mode 100644 index 0000000..8071e1f --- /dev/null +++ b/tests/integration/targets/vyos_static_routes/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_system/aliases b/tests/integration/targets/vyos_system/aliases new file mode 100644 index 0000000..8071e1f --- /dev/null +++ b/tests/integration/targets/vyos_system/aliases @@ -0,0 +1 @@ +shippable/vyos/group1 diff --git a/tests/integration/targets/vyos_user/aliases b/tests/integration/targets/vyos_user/aliases deleted file mode 100644 index e69de29..0000000 --- a/tests/integration/targets/vyos_user/aliases +++ /dev/null diff --git a/tests/integration/targets/vyos_vlan/aliases b/tests/integration/targets/vyos_vlan/aliases deleted file mode 100644 index e69de29..0000000 --- a/tests/integration/targets/vyos_vlan/aliases +++ /dev/null diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_firewall_global_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_firewall_global_config.cfg new file mode 100644 index 0000000..2a2a8e8 --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_firewall_global_config.cfg @@ -0,0 +1,6 @@ +set firewall group address-group RND-HOSTS address 192.0.2.1 +set firewall group address-group RND-HOSTS address 192.0.2.3 +set firewall group address-group RND-HOSTS address 192.0.2.5 +set firewall group address-group RND-HOSTS description 'This group has the Management hosts address lists' +set firewall group network-group RND network 192.0.2.0/24 +set firewall group network-group RND description 'This group has the Management network addresses' diff --git a/tests/unit/modules/network/vyos/test_vyos_firewall_global.py b/tests/unit/modules/network/vyos/test_vyos_firewall_global.py new file mode 100644 index 0000000..0697f6e --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_firewall_global.py @@ -0,0 +1,254 @@ +# (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 +from ansible_collections.vyos.vyos.plugins.modules import vyos_firewall_global +from ansible_collections.vyos.vyos.tests.unit.modules.utils import ( + set_module_args, +) +from .vyos_module import TestVyosModule, load_fixture + + +class TestVyosFirewallRulesModule(TestVyosModule): + + module = vyos_firewall_global + + def setUp(self): + super(TestVyosFirewallRulesModule, self).setUp() + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config" + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config" + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection" + ) + self.get_resource_connection_config = ( + self.mock_get_resource_connection_config.start() + ) + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection" + ) + self.get_resource_connection_facts = ( + self.mock_get_resource_connection_facts.start() + ) + + self.mock_execute_show_command = patch( + "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_global.firewall_global.Firewall_globalFacts.get_device_data" + ) + + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestVyosFirewallRulesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + return load_fixture("vyos_firewall_global_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_vyos_firewall_global_set_01_merged(self): + set_module_args( + dict( + config=dict( + validation="strict", + config_trap=True, + log_martians=True, + syn_cookies=True, + twa_hazards_protection=True, + ping=dict(all=True, broadcast=True), + state_policy=[ + dict( + connection_type="established", + action="accept", + log=True, + ), + dict(connection_type="invalid", action="reject"), + ], + route_redirects=[ + dict( + afi="ipv4", + ip_src_route=True, + icmp_redirects=dict(send=True, receive=False), + ) + ], + group=dict( + address_group=[ + dict( + name="MGMT-HOSTS", + description="This group has the Management hosts address lists", + members=[ + dict(address="192.0.1.1"), + dict(address="192.0.1.3"), + dict(address="192.0.1.5"), + ], + ) + ], + network_group=[ + dict( + name="MGMT", + description="This group has the Management network addresses", + members=[dict(address="192.0.1.0/24")], + ) + ], + ), + ), + state="merged", + ) + ) + commands = [ + "set firewall group address-group MGMT-HOSTS address 192.0.1.1", + "set firewall group address-group MGMT-HOSTS address 192.0.1.3", + "set firewall group address-group MGMT-HOSTS address 192.0.1.5", + "set firewall group address-group MGMT-HOSTS description 'This group has the Management hosts address lists'", + "set firewall group address-group MGMT-HOSTS", + "set firewall group network-group MGMT network 192.0.1.0/24", + "set firewall group network-group MGMT description 'This group has the Management network addresses'", + "set firewall group network-group MGMT", + "set firewall ip-src-route 'enable'", + "set firewall receive-redirects 'disable'", + "set firewall send-redirects 'enable'", + "set firewall config-trap 'enable'", + "set firewall state-policy established action 'accept'", + "set firewall state-policy established log 'enable'", + "set firewall state-policy invalid action 'reject'", + "set firewall broadcast-ping 'enable'", + "set firewall all-ping 'enable'", + "set firewall log-martians 'enable'", + "set firewall twa-hazards-protection 'enable'", + "set firewall syn-cookies 'enable'", + "set firewall source-validation 'strict'", + ] + self.execute_module(changed=True, commands=commands) + + def test_vyos_firewall_global_set_01_merged_idem(self): + set_module_args( + dict( + config=dict( + group=dict( + address_group=[ + dict( + name="RND-HOSTS", + description="This group has the Management hosts address lists", + members=[ + dict(address="192.0.2.1"), + dict(address="192.0.2.3"), + dict(address="192.0.2.5"), + ], + ) + ], + network_group=[ + dict( + name="RND", + description="This group has the Management network addresses", + members=[dict(address="192.0.2.0/24")], + ) + ], + ) + ), + state="merged", + ) + ) + self.execute_module(changed=False, commands=[]) + + def test_vyos_firewall_global_set_01_replaced(self): + set_module_args( + dict( + config=dict( + group=dict( + address_group=[ + dict( + name="RND-HOSTS", + description="This group has the Management hosts address lists", + members=[ + dict(address="192.0.2.1"), + dict(address="192.0.2.7"), + dict(address="192.0.2.9"), + ], + ) + ], + network_group=[ + dict( + name="RND", + description="This group has the Management network addresses", + members=[dict(address="192.0.2.0/24")], + ) + ], + ) + ), + state="replaced", + ) + ) + commands = [ + "delete firewall group address-group RND-HOSTS address 192.0.2.3", + "delete firewall group address-group RND-HOSTS address 192.0.2.5", + "set firewall group address-group RND-HOSTS address 192.0.2.7", + "set firewall group address-group RND-HOSTS address 192.0.2.9", + ] + self.execute_module(changed=True, commands=commands) + + def test_vyos_firewall_global_set_01_replaced_idem(self): + set_module_args( + dict( + config=dict( + group=dict( + address_group=[ + dict( + name="RND-HOSTS", + description="This group has the Management hosts address lists", + members=[ + dict(address="192.0.2.1"), + dict(address="192.0.2.3"), + dict(address="192.0.2.5"), + ], + ) + ], + network_group=[ + dict( + name="RND", + description="This group has the Management network addresses", + members=[dict(address="192.0.2.0/24")], + ) + ], + ) + ), + state="replaced", + ) + ) + self.execute_module(changed=False, commands=[]) + + def test_vyos_firewall_global_set_01_deleted(self): + set_module_args(dict(config=dict(), state="deleted")) + commands = ["delete firewall "] + self.execute_module(changed=True, commands=commands) |