VyOS: firewall global module added (#66800)
* firewall global module Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * sanity fixed Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * test updated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * sanity fixes Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * group member handling updated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * comments incorporated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>
This commit is contained in:
parent
b818436c5f
commit
fc05c50b7f
27 changed files with 3338 additions and 2 deletions
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
"""
|
||||
|
|
1185
lib/ansible/modules/network/vyos/vyos_firewall_global.py
Normal file
1185
lib/ansible/modules/network/vyos/vyos_firewall_global.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
testcase: "[^_].*"
|
||||
test_items: []
|
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- prepare_vyos_tests
|
19
test/integration/targets/vyos_firewall_global/tasks/cli.yaml
Normal file
19
test/integration/targets/vyos_firewall_global/tasks/cli.yaml
Normal file
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
- {include: cli.yaml, tags: ['cli']}
|
|
@ -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'
|
|
@ -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'
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
- name: Remove Config
|
||||
cli_config:
|
||||
config: "{{ lines }}"
|
||||
vars:
|
||||
lines: |
|
||||
delete firewall
|
|
@ -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
|
|
@ -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'
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
218
test/integration/targets/vyos_firewall_global/vars/main.yaml
Normal file
218
test/integration/targets/vyos_firewall_global/vars/main.yaml
Normal file
|
@ -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
|
|
@ -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'
|
207
test/units/modules/network/vyos/test_vyos_firewall_global.py
Normal file
207
test/units/modules/network/vyos/test_vyos_firewall_global.py
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# 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)
|
Loading…
Add table
Reference in a new issue