From fc05c50b7fe93c9dbb887eed93e2eeed60e17e38 Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 24 Feb 2020 09:03:02 -0500 Subject: [PATCH] VyOS: firewall global module added (#66800) * firewall global module Signed-off-by: rohitthakur2590 * sanity fixed Signed-off-by: rohitthakur2590 * test updated Signed-off-by: rohitthakur2590 * sanity fixes Signed-off-by: rohitthakur2590 * group member handling updated Signed-off-by: rohitthakur2590 * comments incorporated Signed-off-by: rohitthakur2590 --- .../vyos/argspec/firewall_global/__init__.py | 0 .../firewall_global/firewall_global.py | 197 +++ .../vyos/config/firewall_global/__init__.py | 0 .../config/firewall_global/firewall_global.py | 611 +++++++++ .../module_utils/network/vyos/facts/facts.py | 4 +- .../vyos/facts/firewall_global/__init__.py | 0 .../facts/firewall_global/firewall_global.py | 360 +++++ .../modules/network/vyos/vyos_facts.py | 2 +- .../network/vyos/vyos_firewall_global.py | 1185 +++++++++++++++++ .../vyos_firewall_global/defaults/main.yaml | 3 + .../vyos_firewall_global/meta/main.yaml | 2 + .../vyos_firewall_global/tasks/cli.yaml | 19 + .../vyos_firewall_global/tasks/main.yaml | 2 + .../tests/cli/_parsed_config.cfg | 19 + .../tests/cli/_populate.yaml | 25 + .../tests/cli/_remove_config.yaml | 7 + .../tests/cli/deleted.yaml | 44 + .../tests/cli/empty_config.yaml | 47 + .../tests/cli/gathered.yaml | 31 + .../tests/cli/merged.yaml | 76 ++ .../tests/cli/parsed.yaml | 39 + .../tests/cli/rendered.yaml | 69 + .../tests/cli/replaced.yaml | 84 ++ .../vyos_firewall_global/tests/cli/rtt.yaml | 83 ++ .../vyos_firewall_global/vars/main.yaml | 218 +++ .../fixtures/vyos_firewall_global_config.cfg | 6 + .../network/vyos/test_vyos_firewall_global.py | 207 +++ 27 files changed, 3338 insertions(+), 2 deletions(-) create mode 100644 lib/ansible/module_utils/network/vyos/argspec/firewall_global/__init__.py create mode 100644 lib/ansible/module_utils/network/vyos/argspec/firewall_global/firewall_global.py create mode 100644 lib/ansible/module_utils/network/vyos/config/firewall_global/__init__.py create mode 100644 lib/ansible/module_utils/network/vyos/config/firewall_global/firewall_global.py create mode 100644 lib/ansible/module_utils/network/vyos/facts/firewall_global/__init__.py create mode 100644 lib/ansible/module_utils/network/vyos/facts/firewall_global/firewall_global.py create mode 100644 lib/ansible/modules/network/vyos/vyos_firewall_global.py create mode 100644 test/integration/targets/vyos_firewall_global/defaults/main.yaml create mode 100644 test/integration/targets/vyos_firewall_global/meta/main.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tasks/cli.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tasks/main.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/_parsed_config.cfg create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/gathered.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/merged.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/rendered.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/replaced.yaml create mode 100644 test/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml create mode 100644 test/integration/targets/vyos_firewall_global/vars/main.yaml create mode 100644 test/units/modules/network/vyos/fixtures/vyos_firewall_global_config.cfg create mode 100644 test/units/modules/network/vyos/test_vyos_firewall_global.py diff --git a/lib/ansible/module_utils/network/vyos/argspec/firewall_global/__init__.py b/lib/ansible/module_utils/network/vyos/argspec/firewall_global/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/vyos/argspec/firewall_global/firewall_global.py b/lib/ansible/module_utils/network/vyos/argspec/firewall_global/firewall_global.py new file mode 100644 index 00000000000..bea4d61a2a8 --- /dev/null +++ b/lib/ansible/module_utils/network/vyos/argspec/firewall_global/firewall_global.py @@ -0,0 +1,197 @@ +# +# -*- 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/lib/ansible/module_utils/network/vyos/config/firewall_global/__init__.py b/lib/ansible/module_utils/network/vyos/config/firewall_global/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/vyos/config/firewall_global/firewall_global.py b/lib/ansible/module_utils/network/vyos/config/firewall_global/firewall_global.py new file mode 100644 index 00000000000..fc5962466b0 --- /dev/null +++ b/lib/ansible/module_utils/network/vyos/config/firewall_global/firewall_global.py @@ -0,0 +1,611 @@ +# +# -*- 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.module_utils.network.common.cfg.base import ConfigBase +from ansible.module_utils.network.common.utils import to_list, dict_diff, remove_empties +from ansible.module_utils.network.vyos.facts.facts import Facts +from ansible.module_utils.six import iteritems +from ansible.module_utils.network.vyos.utils.utils import list_diff_want_only, list_diff_have_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/lib/ansible/module_utils/network/vyos/facts/facts.py b/lib/ansible/module_utils/network/vyos/facts/facts.py index 8b191f0df49..802c4c88964 100644 --- a/lib/ansible/module_utils/network/vyos/facts/facts.py +++ b/lib/ansible/module_utils/network/vyos/facts/facts.py @@ -16,6 +16,7 @@ from ansible.module_utils.network.vyos.facts.lldp_global.lldp_global import Lldp from ansible.module_utils.network.vyos.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts from ansible.module_utils.network.vyos.facts.firewall_rules.firewall_rules import Firewall_rulesFacts from ansible.module_utils.network.vyos.facts.static_routes.static_routes import Static_routesFacts +from ansible.module_utils.network.vyos.facts.firewall_global.firewall_global import Firewall_globalFacts from ansible.module_utils.network.vyos.facts.legacy.base import Default, Neighbors, Config @@ -31,7 +32,8 @@ FACT_RESOURCE_SUBSETS = dict( lldp_global=Lldp_globalFacts, lldp_interfaces=Lldp_interfacesFacts, static_routes=Static_routesFacts, - firewall_rules=Firewall_rulesFacts + firewall_rules=Firewall_rulesFacts, + firewall_global=Firewall_globalFacts ) diff --git a/lib/ansible/module_utils/network/vyos/facts/firewall_global/__init__.py b/lib/ansible/module_utils/network/vyos/facts/firewall_global/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/vyos/facts/firewall_global/firewall_global.py b/lib/ansible/module_utils/network/vyos/facts/firewall_global/firewall_global.py new file mode 100644 index 00000000000..de517501ee9 --- /dev/null +++ b/lib/ansible/module_utils/network/vyos/facts/firewall_global/firewall_global.py @@ -0,0 +1,360 @@ +# +# -*- 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.module_utils.network.common import utils +from ansible.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/lib/ansible/modules/network/vyos/vyos_facts.py b/lib/ansible/modules/network/vyos/vyos_facts.py index bfb12f24f3c..82a207d11e6 100644 --- a/lib/ansible/modules/network/vyos/vyos_facts.py +++ b/lib/ansible/modules/network/vyos/vyos_facts.py @@ -52,7 +52,7 @@ options: 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 version_added: "2.9" """ diff --git a/lib/ansible/modules/network/vyos/vyos_firewall_global.py b/lib/ansible/modules/network/vyos/vyos_firewall_global.py new file mode 100644 index 00000000000..96267a6fa20 --- /dev/null +++ b/lib/ansible/modules/network/vyos/vyos_firewall_global.py @@ -0,0 +1,1185 @@ +#!/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 +version_added: '2.10' +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.module_utils.network.vyos.argspec.firewall_global.firewall_global import Firewall_globalArgs +from ansible.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/test/integration/targets/vyos_firewall_global/defaults/main.yaml b/test/integration/targets/vyos_firewall_global/defaults/main.yaml new file mode 100644 index 00000000000..164afead284 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/test/integration/targets/vyos_firewall_global/meta/main.yaml b/test/integration/targets/vyos_firewall_global/meta/main.yaml new file mode 100644 index 00000000000..f88bce55675 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/meta/main.yaml @@ -0,0 +1,2 @@ +dependencies: + - prepare_vyos_tests diff --git a/test/integration/targets/vyos_firewall_global/tasks/cli.yaml b/test/integration/targets/vyos_firewall_global/tasks/cli.yaml new file mode 100644 index 00000000000..655e51ee63d --- /dev/null +++ b/test/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=network_cli) + include: "{{ test_case_to_run }}" + vars: + ansible_connection: network_cli + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/vyos_firewall_global/tasks/main.yaml b/test/integration/targets/vyos_firewall_global/tasks/main.yaml new file mode 100644 index 00000000000..d4cf26fc4a1 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tasks/main.yaml @@ -0,0 +1,2 @@ +--- +- {include: cli.yaml, tags: ['cli']} diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/_parsed_config.cfg b/test/integration/targets/vyos_firewall_global/tests/cli/_parsed_config.cfg new file mode 100644 index 00000000000..45446bdb08c --- /dev/null +++ b/test/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/test/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml new file mode 100644 index 00000000000..5417bad9ac2 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/_populate.yaml @@ -0,0 +1,25 @@ +--- +- name: Setup + cli_config: + config: "{{ lines }}" + vars: + lines: | + 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/test/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml new file mode 100644 index 00000000000..e56093b3891 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/_remove_config.yaml @@ -0,0 +1,7 @@ +--- +- name: Remove Config + cli_config: + config: "{{ lines }}" + vars: + lines: | + delete firewall diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml new file mode 100644 index 00000000000..8cce6c94d90 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/deleted.yaml @@ -0,0 +1,44 @@ +--- +- debug: + msg: "Start vyos_firewall_global deleted integration tests ansible_connection={{ ansible_connection }}" + +- include_tasks: _populate.yaml + +- block: + - name: Delete attributes of firewall. + vyos_firewall_global: &deleted + config: + state: deleted + register: result + + - 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) + vyos_firewall_global: *deleted + register: result + + - 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/test/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml new file mode 100644 index 00000000000..0edd88083eb --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/empty_config.yaml @@ -0,0 +1,47 @@ +--- +- debug: + msg: "START vyos_firewall_global empty_config integration tests on connection={{ ansible_connection }}" + +- name: Merged with empty config should give appropriate error message + vyos_firewall_global: + config: + state: merged + register: result + ignore_errors: true + +- 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 + vyos_firewall_global: + config: + state: replaced + register: result + ignore_errors: true + +- 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 + vyos_firewall_global: + running_config: + state: parsed + register: result + ignore_errors: true + +- 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 + vyos_firewall_global: + config: + state: rendered + register: result + ignore_errors: true + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/gathered.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/gathered.yaml new file mode 100644 index 00000000000..0aca48bbeda --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/gathered.yaml @@ -0,0 +1,31 @@ +--- +- 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 + vyos_firewall_global: &gathered + config: + state: gathered + register: result + + - name: Assert that gathered dicts was correctly generated + assert: + that: + - "{{ populate == result['gathered'] }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + vyos_firewall_global: *gathered + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result['changed'] == false" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/merged.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/merged.yaml new file mode 100644 index 00000000000..3bd433aae02 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/merged.yaml @@ -0,0 +1,76 @@ +--- +- 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 + vyos_firewall_global: &merged + 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 + register: result + + - 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) + vyos_firewall_global: *merged + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result['changed'] == false" + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ merged['after'] == result['before'] }}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml new file mode 100644 index 00000000000..24e77fa7cab --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/parsed.yaml @@ -0,0 +1,39 @@ +--- +- 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 + vyos_facts: + gather_subset: + - default + gather_network_resources: + - firewall_global + register: firewall_global_facts + + - name: Provide the running configuration for parsing (config to be parsed) + vyos_firewall_global: &parsed + running_config: + "{{ lookup('file', '_parsed_config.cfg') }}" + state: parsed + register: result + + - name: Assert that correct parsing done + assert: + that: "{{ ansible_facts['network_resources']['firewall_global'] == result['parsed'] }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + vyos_firewall_global: *parsed + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result['changed'] == false" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/rendered.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/rendered.yaml new file mode 100644 index 00000000000..7a92bb314c1 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/rendered.yaml @@ -0,0 +1,69 @@ +--- +- 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 + vyos_firewall_global: &rendered + 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 + register: result + + - 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) + vyos_firewall_global: *rendered + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result['changed'] == false" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/replaced.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/replaced.yaml new file mode 100644 index 00000000000..57a4f71b3a3 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/replaced.yaml @@ -0,0 +1,84 @@ +--- +- 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 + vyos_firewall_global: &replaced + 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 + register: result + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ replaced['commands'] | symmetric_difference(result['commands']) |length == 0 }}" + + - name: Assert that before dicts are correctly generated + assert: + that: + - "{{ populate == 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) + vyos_firewall_global: *replaced + register: result + + - name: Assert that task was idempotent + assert: + that: + - "result['changed'] == false" + + - name: Assert that before dict is correctly generated + assert: + that: + - "{{ replaced['after'] == result['before'] }}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml b/test/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml new file mode 100644 index 00000000000..e092afd784d --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/tests/cli/rtt.yaml @@ -0,0 +1,83 @@ +--- +- 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) + 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 + register: base_config + + - name: Gather firewall_global facts + vyos_facts: + gather_subset: + - default + gather_network_resources: + - firewall_global + + - name: Apply the provided configuration (config to be reverted) + 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 + register: result + + - name: Assert that changes were applied + assert: + that: "{{ round_trip['after'] == result['after'] }}" + + - name: Revert back to base config using facts round trip + vyos_firewall_global: + config: "{{ ansible_facts['network_resources']['firewall_global'] }}" + state: replaced + register: revert + + - name: Assert that config was reverted + assert: + that: "{{ base_config['after'] == revert['after']}}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_firewall_global/vars/main.yaml b/test/integration/targets/vyos_firewall_global/vars/main.yaml new file mode 100644 index 00000000000..409104ebcb5 --- /dev/null +++ b/test/integration/targets/vyos_firewall_global/vars/main.yaml @@ -0,0 +1,218 @@ +--- +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/test/units/modules/network/vyos/fixtures/vyos_firewall_global_config.cfg b/test/units/modules/network/vyos/fixtures/vyos_firewall_global_config.cfg new file mode 100644 index 00000000000..2a2a8e8bd85 --- /dev/null +++ b/test/units/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/test/units/modules/network/vyos/test_vyos_firewall_global.py b/test/units/modules/network/vyos/test_vyos_firewall_global.py new file mode 100644 index 00000000000..d1bff887191 --- /dev/null +++ b/test/units/modules/network/vyos/test_vyos_firewall_global.py @@ -0,0 +1,207 @@ +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from units.compat.mock import patch, MagicMock +from ansible.modules.network.vyos import vyos_firewall_global +from units.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.module_utils.network.common.network.Config.get_config') + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + 'ansible.module_utils.network.common.network.Config.load_config') + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + 'ansible.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.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.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)