mirror of https://github.com/ansible/ansible.git
VyOS: firewall_interfaces module added (#67254)
* firewall_interfaces module added Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * sanity fixes Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * sanity fixes Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * delete opr updated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * tests updated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * comments incorporated Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com> * ci failure fix Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>pull/67895/head
parent
7765870421
commit
8f9f8ec594
@ -0,0 +1,85 @@
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Red Hat
|
||||
# GNU General Public License v3.0+
|
||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#############################################
|
||||
# WARNING #
|
||||
#############################################
|
||||
#
|
||||
# This file is auto generated by the resource
|
||||
# module builder playbook.
|
||||
#
|
||||
# Do not edit this file manually.
|
||||
#
|
||||
# Changes to this file will be over written
|
||||
# by the resource module builder.
|
||||
#
|
||||
# Changes should be made in the model used to
|
||||
# generate this file or in the resource module
|
||||
# builder template.
|
||||
#
|
||||
#############################################
|
||||
"""
|
||||
The arg spec for the vyos_firewall_interfaces module
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class Firewall_interfacesArgs(object): # pylint: disable=R0903
|
||||
"""The arg spec for the vyos_firewall_interfaces module
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
argument_spec = {
|
||||
'config': {
|
||||
'elements': 'dict',
|
||||
'options': {
|
||||
'access_rules': {
|
||||
'elements': 'dict',
|
||||
'options': {
|
||||
'afi': {
|
||||
'choices': ['ipv4', 'ipv6'],
|
||||
'required': True,
|
||||
'type': 'str'
|
||||
},
|
||||
'rules': {
|
||||
'elements': 'dict',
|
||||
'options': {
|
||||
'direction': {
|
||||
'choices': ['in', 'local', 'out'],
|
||||
'required': True,
|
||||
'type': 'str'
|
||||
},
|
||||
'name': {
|
||||
'type': 'str'
|
||||
}
|
||||
},
|
||||
'type': 'list'
|
||||
}
|
||||
},
|
||||
'type': 'list'
|
||||
},
|
||||
'name': {
|
||||
'required': True,
|
||||
'type': 'str'
|
||||
}
|
||||
},
|
||||
'type': 'list'
|
||||
},
|
||||
'running_config': {'type': 'str'},
|
||||
'state': {
|
||||
'choices': [
|
||||
'merged', 'replaced', 'overridden', 'deleted', 'parsed',
|
||||
'rendered', 'gathered'
|
||||
],
|
||||
'default':
|
||||
'merged',
|
||||
'type':
|
||||
'str'
|
||||
}
|
||||
} # pylint: disable=C0301
|
@ -0,0 +1,364 @@
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Red Hat
|
||||
# GNU General Public License v3.0+
|
||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
"""
|
||||
The vyos_firewall_interfaces class
|
||||
It is in this file where the current configuration (as dict)
|
||||
is compared to the provided configuration (as dict) and the command set
|
||||
necessary to bring the current configuration to it's desired end-state is
|
||||
created
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
from copy import deepcopy
|
||||
from ansible.module_utils.network.common.cfg.base import ConfigBase
|
||||
from ansible.module_utils.network.common.utils import to_list, dict_diff, remove_empties, search_obj_in_list
|
||||
from ansible.module_utils.network.vyos.facts.facts import Facts
|
||||
|
||||
|
||||
class Firewall_interfaces(ConfigBase):
|
||||
"""
|
||||
The vyos_firewall_interfaces class
|
||||
"""
|
||||
|
||||
gather_subset = [
|
||||
'!all',
|
||||
'!min',
|
||||
]
|
||||
|
||||
gather_network_resources = [
|
||||
'firewall_interfaces',
|
||||
]
|
||||
|
||||
def __init__(self, module):
|
||||
super(Firewall_interfaces, self).__init__(module)
|
||||
|
||||
def get_firewall_interfaces_facts(self, data=None):
|
||||
""" Get the 'facts' (the current configuration)
|
||||
|
||||
:rtype: A dictionary
|
||||
:returns: The current configuration as a dictionary
|
||||
"""
|
||||
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data)
|
||||
firewall_interfaces_facts = facts['ansible_network_resources'].get('firewall_interfaces')
|
||||
if not firewall_interfaces_facts:
|
||||
return []
|
||||
return firewall_interfaces_facts
|
||||
|
||||
def execute_module(self):
|
||||
""" Execute the module
|
||||
|
||||
:rtype: A dictionary
|
||||
:returns: The result from module execution
|
||||
"""
|
||||
result = {'changed': False}
|
||||
warnings = list()
|
||||
commands = list()
|
||||
|
||||
if self.state in self.ACTION_STATES:
|
||||
existing_firewall_interfaces_facts = self.get_firewall_interfaces_facts()
|
||||
else:
|
||||
existing_firewall_interfaces_facts = []
|
||||
|
||||
if self.state in self.ACTION_STATES or self.state == 'rendered':
|
||||
commands.extend(self.set_config(existing_firewall_interfaces_facts))
|
||||
|
||||
if commands and self.state in self.ACTION_STATES:
|
||||
if not self._module.check_mode:
|
||||
self._connection.edit_config(commands)
|
||||
result['changed'] = True
|
||||
|
||||
if self.state in self.ACTION_STATES:
|
||||
result['commands'] = commands
|
||||
|
||||
if self.state in self.ACTION_STATES or self.state == 'gathered':
|
||||
changed_firewall_interfaces_facts = self.get_firewall_interfaces_facts()
|
||||
elif self.state == 'rendered':
|
||||
result['rendered'] = commands
|
||||
elif self.state == 'parsed':
|
||||
running_config = self._module.params['running_config']
|
||||
if not running_config:
|
||||
self._module.fail_json(
|
||||
msg="value of running_config parameter must not be empty for state parsed"
|
||||
)
|
||||
result['parsed'] = self.get_firewall_interfaces_facts(data=running_config)
|
||||
else:
|
||||
changed_firewall_interfaces_facts = []
|
||||
|
||||
if self.state in self.ACTION_STATES:
|
||||
result['before'] = existing_firewall_interfaces_facts
|
||||
if result['changed']:
|
||||
result['after'] = changed_firewall_interfaces_facts
|
||||
elif self.state == 'gathered':
|
||||
result['gathered'] = changed_firewall_interfaces_facts
|
||||
|
||||
result['warnings'] = warnings
|
||||
return result
|
||||
|
||||
def set_config(self, existing_firewall_interfaces_facts):
|
||||
""" Collect the configuration from the args passed to the module,
|
||||
collect the current configuration (as a dict from facts)
|
||||
|
||||
:rtype: A list
|
||||
:returns: the commands necessary to migrate the current configuration
|
||||
to the desired configuration
|
||||
"""
|
||||
want = self._module.params['config']
|
||||
have = existing_firewall_interfaces_facts
|
||||
resp = self.set_state(want, have)
|
||||
return to_list(resp)
|
||||
|
||||
def set_state(self, w, h):
|
||||
""" Select the appropriate function based on the state provided
|
||||
|
||||
:param want: the desired configuration as a dictionary
|
||||
:param have: the current configuration as a dictionary
|
||||
:rtype: A list
|
||||
:returns: the commands necessary to migrate the current configuration
|
||||
to the desired configuration
|
||||
"""
|
||||
commands = []
|
||||
if self.state in ('merged', 'replaced', 'overridden', 'rendered') and not w:
|
||||
self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(self.state))
|
||||
if self.state == 'overridden':
|
||||
commands.extend(self._state_overridden(w, h))
|
||||
elif self.state == 'deleted':
|
||||
commands.extend(self._state_deleted(w, h))
|
||||
elif w:
|
||||
if self.state == 'merged' or self.state == 'rendered':
|
||||
commands.extend(self._state_merged(w, h))
|
||||
elif self.state == 'replaced':
|
||||
commands.extend(self._state_replaced(w, h))
|
||||
return commands
|
||||
|
||||
def _state_replaced(self, want, have):
|
||||
""" The command generator when state is replaced
|
||||
|
||||
:rtype: A list
|
||||
:returns: the commands necessary to migrate the current configuration
|
||||
to the desired configuration
|
||||
"""
|
||||
commands = []
|
||||
if have:
|
||||
for h in have:
|
||||
w = search_obj_in_list(h['name'], want)
|
||||
commands.extend(self._render_access_rules(h, w, opr=False))
|
||||
commands.extend(self._state_merged(want, have))
|
||||
return commands
|
||||
|
||||
def _state_overridden(self, want, have):
|
||||
""" The command generator when state is overridden
|
||||
|
||||
:rtype: A list
|
||||
:returns: the commands necessary to migrate the current configuration
|
||||
to the desired configuration
|
||||
"""
|
||||
commands = []
|
||||
if have:
|
||||
for h_ar in have:
|
||||
w_ar = search_obj_in_list(h_ar['name'], want)
|
||||
if not w_ar and 'access_rules' in h_ar:
|
||||
commands.append(self._compute_command(name=h_ar['name'], opr=False))
|
||||
else:
|
||||
h_rules = h_ar.get('access_rules') or []
|
||||
key = 'direction'
|
||||
if w_ar:
|
||||
w_rules = w_ar.get('access_rules') or []
|
||||
if not w_rules and h_rules:
|
||||
commands.append(self._compute_command(name=h_ar['name'], opr=False))
|
||||
if h_rules:
|
||||
for h_rule in h_rules:
|
||||
w_rule = search_obj_in_list(h_rule['afi'], w_rules, key='afi')
|
||||
have_rules = h_rule.get('rules') or []
|
||||
if w_rule:
|
||||
want_rules = w_rule.get('rules') or []
|
||||
for h in have_rules:
|
||||
if key in h:
|
||||
w = search_obj_in_list(h[key], want_rules, key=key)
|
||||
if not w or key not in w or ('name' in h and w and 'name' not in w):
|
||||
commands.append(
|
||||
self._compute_command(
|
||||
afi=h_rule['afi'], name=h_ar['name'], attrib=h[key], opr=False
|
||||
)
|
||||
)
|
||||
|
||||
commands.extend(self._state_merged(want, have))
|
||||
return commands
|
||||
|
||||
def _state_merged(self, want, have):
|
||||
""" The command generator when state is merged
|
||||
|
||||
:rtype: A list
|
||||
:returns: the commands necessary to merge the provided into
|
||||
the current configuration
|
||||
"""
|
||||
commands = []
|
||||
for w in want:
|
||||
h = search_obj_in_list(w['name'], have)
|
||||
commands.extend(self._render_access_rules(w, h))
|
||||
return commands
|
||||
|
||||
def _state_deleted(self, want, have):
|
||||
""" The command generator when state is deleted
|
||||
|
||||
:rtype: A list
|
||||
:returns: the commands necessary to remove the current configuration
|
||||
of the provided objects
|
||||
"""
|
||||
commands = []
|
||||
|
||||
if want:
|
||||
for w in want:
|
||||
h = search_obj_in_list(w['name'], have)
|
||||
if h and 'access_rules' in h:
|
||||
commands.extend(self._delete_access_rules(w, h, opr=False))
|
||||
elif have:
|
||||
for h in have:
|
||||
if 'access_rules' in h:
|
||||
commands.append(self._compute_command(name=h['name'], opr=False))
|
||||
return commands
|
||||
|
||||
def _delete_access_rules(self, want, have, opr=False):
|
||||
"""
|
||||
This function forms the delete commands based on the 'opr' type
|
||||
for 'access_rules' attributes.
|
||||
:param want: desired config.
|
||||
:param have: target config.
|
||||
:param opr: True/False.
|
||||
:return: generated commands list.
|
||||
"""
|
||||
commands = []
|
||||
h_rules = {}
|
||||
w_rs = deepcopy(remove_empties(want))
|
||||
w_rules = w_rs.get('access_rules') or []
|
||||
if have:
|
||||
h_rs = deepcopy(remove_empties(have))
|
||||
h_rules = h_rs.get('access_rules') or []
|
||||
|
||||
# if all firewall config needed to be deleted for specific interface
|
||||
# when operation is delete.
|
||||
if not w_rules and h_rules:
|
||||
commands.append(self._compute_command(name=want['name'], opr=opr))
|
||||
if w_rules:
|
||||
for w in w_rules:
|
||||
h = search_obj_in_list(w['afi'], h_rules, key='afi')
|
||||
commands.extend(self._delete_rules(want['name'], w, h))
|
||||
return commands
|
||||
|
||||
def _delete_rules(self, name, want, have, opr=False):
|
||||
"""
|
||||
This function forms the delete commands based on the 'opr' type
|
||||
for rules attributes.
|
||||
:param name: interface id/name.
|
||||
:param want: desired config.
|
||||
:param have: target config.
|
||||
:param opr: True/False.
|
||||
:return: generated commands list.
|
||||
"""
|
||||
commands = []
|
||||
h_rules = []
|
||||
key = 'direction'
|
||||
w_rules = want.get('rules') or []
|
||||
if have:
|
||||
h_rules = have.get('rules') or []
|
||||
# when rule set needed to be removed on
|
||||
# (inbound|outbound|local interface)
|
||||
if h_rules and not w_rules:
|
||||
for h in h_rules:
|
||||
if key in h:
|
||||
commands.append(self._compute_command(afi=want['afi'], name=name, attrib=h[key], opr=opr))
|
||||
for w in w_rules:
|
||||
h = search_obj_in_list(w[key], h_rules, key=key)
|
||||
if key in w and h and key in h and 'name' in w and 'name' in h and w['name'] == h['name']:
|
||||
commands.append(self._compute_command(
|
||||
afi=want['afi'],
|
||||
name=name,
|
||||
attrib=w[key],
|
||||
value=w['name'],
|
||||
opr=opr)
|
||||
)
|
||||
return commands
|
||||
|
||||
def _render_access_rules(self, want, have, opr=True):
|
||||
"""
|
||||
This function forms the set/delete commands based on the 'opr' type
|
||||
for 'access_rules' attributes.
|
||||
:param want: desired config.
|
||||
:param have: target config.
|
||||
:param opr: True/False.
|
||||
:return: generated commands list.
|
||||
"""
|
||||
commands = []
|
||||
h_rules = {}
|
||||
w_rs = deepcopy(remove_empties(want))
|
||||
w_rules = w_rs.get('access_rules') or []
|
||||
if have:
|
||||
h_rs = deepcopy(remove_empties(have))
|
||||
h_rules = h_rs.get('access_rules') or []
|
||||
if w_rules:
|
||||
for w in w_rules:
|
||||
h = search_obj_in_list(w['afi'], h_rules, key='afi')
|
||||
commands.extend(self._render_rules(want['name'], w, h, opr))
|
||||
return commands
|
||||
|
||||
def _render_rules(self, name, want, have, opr=True):
|
||||
"""
|
||||
This function forms the set/delete commands based on the 'opr' type
|
||||
for rules attributes.
|
||||
:param name: interface id/name.
|
||||
:param want: desired config.
|
||||
:param have: target config.
|
||||
:param opr: True/False.
|
||||
:return: generated commands list.
|
||||
"""
|
||||
commands = []
|
||||
h_rules = []
|
||||
key = 'direction'
|
||||
w_rules = want.get('rules') or []
|
||||
if have:
|
||||
h_rules = have.get('rules') or []
|
||||
for w in w_rules:
|
||||
h = search_obj_in_list(w[key], h_rules, key=key)
|
||||
if key in w:
|
||||
if opr:
|
||||
if 'name' in w and not (h and h[key] == w[key] and h['name'] == w['name']):
|
||||
commands.append(self._compute_command(afi=want['afi'], name=name, attrib=w[key], value=w['name']))
|
||||
elif not (h and key in h):
|
||||
commands.append(self._compute_command(afi=want['afi'], name=name, attrib=w[key]))
|
||||
elif not opr:
|
||||
if not h or key not in h or ('name' in w and h and 'name' not in h):
|
||||
commands.append(self._compute_command(afi=want['afi'], name=name, attrib=w[key], opr=opr))
|
||||
return commands
|
||||
|
||||
def _compute_command(self, afi=None, name=None, attrib=None, value=None, opr=True):
|
||||
"""
|
||||
This function construct the add/delete command based on passed attributes.
|
||||
:param afi: address type.
|
||||
:param name: interface name.
|
||||
:param attrib: attribute name.
|
||||
:param value: attribute value.
|
||||
:param opr: operation flag.
|
||||
:return: generated command.
|
||||
"""
|
||||
if not opr:
|
||||
cmd = 'delete interfaces ethernet' + ' ' + name + ' firewall'
|
||||
else:
|
||||
cmd = 'set interfaces ethernet' + ' ' + name + ' firewall'
|
||||
if attrib:
|
||||
cmd += (' ' + attrib)
|
||||
if afi:
|
||||
cmd += ' ' + self._get_fw_type(afi)
|
||||
if value:
|
||||
cmd += (" '" + str(value) + "'")
|
||||
return cmd
|
||||
|
||||
def _get_fw_type(self, afi):
|
||||
"""
|
||||
This function returns the firewall rule-set type based on IP address.
|
||||
:param afi: address type
|
||||
:return: rule-set type.
|
||||
"""
|
||||
return 'ipv6-name' if afi == 'ipv6' else 'name'
|
@ -0,0 +1,183 @@
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Red Hat
|
||||
# GNU General Public License v3.0+
|
||||
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
"""
|
||||
The vyos firewall_interfaces fact class
|
||||
It is in this file the configuration is collected from the device
|
||||
for a given resource, parsed, and the facts tree is populated
|
||||
based on the configuration.
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
from re import findall, search, M
|
||||
from copy import deepcopy
|
||||
from ansible.module_utils.network.common import utils
|
||||
from ansible.module_utils.network.vyos.argspec.firewall_interfaces.firewall_interfaces import Firewall_interfacesArgs
|
||||
|
||||
|
||||
class Firewall_interfacesFacts(object):
|
||||
""" The vyos firewall_interfaces fact class
|
||||
"""
|
||||
|
||||
def __init__(self, module, subspec='config', options='options'):
|
||||
self._module = module
|
||||
self.argument_spec = Firewall_interfacesArgs.argument_spec
|
||||
spec = deepcopy(self.argument_spec)
|
||||
if subspec:
|
||||
if options:
|
||||
facts_argument_spec = spec[subspec][options]
|
||||
else:
|
||||
facts_argument_spec = spec[subspec]
|
||||
else:
|
||||
facts_argument_spec = spec
|
||||
|
||||
self.generated_spec = utils.generate_dict(facts_argument_spec)
|
||||
|
||||
def get_device_data(self, connection):
|
||||
return connection.get_config()
|
||||
|
||||
def populate_facts(self, connection, ansible_facts, data=None):
|
||||
""" Populate the facts for firewall_interfaces
|
||||
:param connection: the device connection
|
||||
:param ansible_facts: Facts dictionary
|
||||
:param data: previously collected conf
|
||||
:rtype: dictionary
|
||||
:returns: facts
|
||||
"""
|
||||
if not data:
|
||||
# typically data is populated from the current device configuration
|
||||
# data = connection.get('show running-config | section ^interface')
|
||||
# using mock data instead
|
||||
data = self.get_device_data(connection)
|
||||
objs = []
|
||||
interfaces = findall(r'^set interfaces ethernet (?:\'*)(\S+)(?:\'*)', data, M)
|
||||
if interfaces:
|
||||
objs = self.get_names(data, interfaces)
|
||||
ansible_facts['ansible_network_resources'].pop('firewall_interfaces', None)
|
||||
facts = {}
|
||||
if objs:
|
||||
facts['firewall_interfaces'] = []
|
||||
params = utils.validate_config(self.argument_spec, {'config': objs})
|
||||
for cfg in params['config']:
|
||||
facts['firewall_interfaces'].append(utils.remove_empties(cfg))
|
||||
|
||||
ansible_facts['ansible_network_resources'].update(facts)
|
||||
return ansible_facts
|
||||
|
||||
def get_names(self, data, interfaces):
|
||||
"""
|
||||
This function performs following:
|
||||
- Form regex to fetch 'interface name' from interfaces firewall data.
|
||||
- Form the name list.
|
||||
:param data: configuration.
|
||||
:param rules: list of interfaces.
|
||||
:return: generated firewall interfaces configuration.
|
||||
"""
|
||||
names = []
|
||||
for r in set(interfaces):
|
||||
int_regex = r' %s .+$' % r.strip("'")
|
||||
cfg = findall(int_regex, data, M)
|
||||
fi = self.render_config(cfg)
|
||||
fi['name'] = r.strip("'")
|
||||
names.append(fi)
|
||||
if names:
|
||||
names = sorted(names, key=lambda i: i['name'])
|
||||
return names
|
||||
|
||||
def render_config(self, conf):
|
||||
"""
|
||||
Render config as dictionary structure and delete keys
|
||||
from spec for null values
|
||||
|
||||
:param spec: The facts tree, generated from the argspec
|
||||
:param conf: The configuration
|
||||
:rtype: dictionary
|
||||
:returns: The generated config
|
||||
"""
|
||||
conf = '\n'.join(filter(lambda x: 'firewall' in x, conf))
|
||||
config = {'access_rules': self.parse_access_rules(conf)}
|
||||
return config
|
||||
|
||||
def parse_access_rules(self, conf):
|
||||
"""
|
||||
This function forms the regex to fetch the 'access-rules'
|
||||
for specific interface.
|
||||
:param conf: configuration data.
|
||||
:return: generated access-rules list configuration.
|
||||
"""
|
||||
ar_lst = []
|
||||
v4_ar = findall(r'^.*(in|out|local) name .*$', conf, M)
|
||||
v6_ar = findall(r'^.*(in|out|local) ipv6-name .*$', conf, M)
|
||||
if v4_ar:
|
||||
v4_conf = "\n".join(findall(r"(^.*?%s.*?$)" % ' name', conf, M))
|
||||
config = self.parse_int_rules(v4_conf, 'ipv4')
|
||||
if config:
|
||||
ar_lst.append(config)
|
||||
if v6_ar:
|
||||
v6_conf = "\n".join(findall(r"(^.*?%s.*?$)" % ' ipv6-name', conf, M))
|
||||
config = self.parse_int_rules(v6_conf, 'ipv6')
|
||||
if config:
|
||||
ar_lst.append(config)
|
||||
if ar_lst:
|
||||
ar_lst = sorted(ar_lst, key=lambda i: i['afi'])
|
||||
else:
|
||||
empty_rules = findall(r'^.*(in|out|local).*', conf, M)
|
||||
if empty_rules:
|
||||
ar_lst.append({'afi': 'ipv4', 'rules': []})
|
||||
ar_lst.append({'afi': 'ipv6', 'rules': []})
|
||||
return ar_lst
|
||||
|
||||
def parse_int_rules(self, conf, afi):
|
||||
"""
|
||||
This function forms the regex to fetch the 'access-rules'
|
||||
for specific interface based on ip-type.
|
||||
:param conf: configuration data.
|
||||
:param rules: rules configured per interface.
|
||||
:param afi: ip address type.
|
||||
:return: generated rule configuration dictionary.
|
||||
"""
|
||||
r_lst = []
|
||||
config = {}
|
||||
rules = ['in', 'out', 'local']
|
||||
for r in set(rules):
|
||||
fr = {}
|
||||
r_regex = r' %s .+$' % r
|
||||
cfg = '\n'.join(findall(r_regex, conf, M))
|
||||
if cfg:
|
||||
fr = self.parse_rules(cfg, afi)
|
||||
else:
|
||||
out = search(r'^.*firewall ' + "'" + r + "'" + '(.*)', conf, M)
|
||||
if out:
|
||||
fr = {'direction': r}
|
||||
if fr:
|
||||
r_lst.append(fr)
|
||||
if r_lst:
|
||||
r_lst = sorted(r_lst, key=lambda i: i['direction'])
|
||||
config = {'afi': afi, 'rules': r_lst}
|
||||
return config
|
||||
|
||||
def parse_rules(self, conf, afi):
|
||||
"""
|
||||
This function triggers the parsing of 'rule' attributes.
|
||||
a_lst is a list having rule attributes which doesn't
|
||||
have further sub attributes.
|
||||
:param conf: configuration.
|
||||
:param afi: ip address type.
|
||||
:return: generated rule configuration dictionary.
|
||||
"""
|
||||
cfg = {}
|
||||
out = findall(r'[^\s]+', conf, M)
|
||||
if out:
|
||||
cfg['direction'] = out[0].strip("'")
|
||||
if afi == 'ipv6':
|
||||
out = findall(r'[^\s]+ ipv6-name (?:\'*)(\S+)(?:\'*)', conf, M)
|
||||
if out:
|
||||
cfg['name'] = str(out[0]).strip("'")
|
||||
else:
|
||||
out = findall(r'[^\s]+ name (?:\'*)(\S+)(?:\'*)', conf, M)
|
||||
if out:
|
||||
cfg['name'] = out[-1].strip("'")
|
||||
return cfg
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,120 @@
|
||||
---
|
||||
merged:
|
||||
before: []
|
||||
|
||||
|
||||
commands:
|
||||
- "set interfaces ethernet eth1 firewall in name 'INBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall out name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall local name 'LOCAL'"
|
||||
- "set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'"
|
||||
- "set interfaces ethernet eth3 firewall in name 'INBOUND'"
|
||||
- "set interfaces ethernet eth3 firewall out name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth3 firewall local name 'LOCAL'"
|
||||
- "set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL'"
|
||||
|
||||
after:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
- name: 'OUBOUND'
|
||||
direction: 'out'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'V6-LOCAL'
|
||||
direction: 'local'
|
||||
|
||||
populate:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
- name: 'OUBOUND'
|
||||
direction: 'out'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'LOCAL'
|
||||
direction: 'local'
|
||||
|
||||
replaced:
|
||||
commands:
|
||||
- "delete service lldp interface eth2 location"
|
||||
- "set service lldp interface eth2 'disable'"
|
||||
- "set service lldp interface eth2 location civic-based country-code 'US'"
|
||||
- "set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'"
|
||||
- "delete service lldp interface eth1 location"
|
||||
- "set service lldp interface eth1 'disable'"
|
||||
- "set service lldp interface eth1 location coordinate-based latitude '33.524449N'"
|
||||
- "set service lldp interface eth1 location coordinate-based altitude '2200'"
|
||||
- "set service lldp interface eth1 location coordinate-based datum 'WGS84'"
|
||||
- "set service lldp interface eth1 location coordinate-based longitude '222.267255W'"
|
||||
|
||||
after:
|
||||
- name: 'eth2'
|
||||
enable: false
|
||||
location:
|
||||
civic_based:
|
||||
country_code: 'US'
|
||||
ca_info:
|
||||
- ca_type: 0
|
||||
ca_value: 'ENGLISH'
|
||||
|
||||
- name: 'eth1'
|
||||
enable: false
|
||||
location:
|
||||
coordinate_based:
|
||||
altitude: 2200
|
||||
datum: 'WGS84'
|
||||
longitude: '222.267255W'
|
||||
latitude: '33.524449N'
|
||||
|
||||
populate_intf:
|
||||
- name: 'eth2'
|
||||
enable: false
|
||||
location:
|
||||
civic_based:
|
||||
country_code: 'US'
|
||||
ca_info:
|
||||
- ca_type: 0
|
||||
ca_value: 'ENGLISH'
|
||||
|
||||
overridden:
|
||||
commands:
|
||||
- "delete service lldp interface eth2 location"
|
||||
- "delete service lldp interface eth2 'disable'"
|
||||
- "set service lldp interface eth2 location elin '0000000911'"
|
||||
|
||||
after:
|
||||
- name: 'eth2'
|
||||
location:
|
||||
elin: 0000000911
|
||||
|
||||
deleted:
|
||||
commands:
|
||||
- "delete service lldp interface eth1"
|
||||
- "delete service lldp interface eth2"
|
||||
|
||||
after: []
|
||||
|
||||
round_trip:
|
||||
after:
|
||||
- name: 'eth1'
|
||||
location:
|
||||
civic_based:
|
||||
country_code: 'US'
|
||||
ca_info:
|
||||
- ca_type: 0
|
||||
ca_value: 'ENGLISH'
|
||||
|
||||
- name: 'eth2'
|
||||
location:
|
||||
coordinate_based:
|
||||
altitude: 2200
|
||||
datum: 'WGS84'
|
||||
longitude: '222.267255W'
|
||||
latitude: '33.524449N'
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
testcase: "[^_].*"
|
||||
test_items: []
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
dependencies:
|
||||
- prepare_vyos_tests
|
@ -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,10 @@
|
||||
set interfaces ethernet eth1 firewall in name 'INBOUND'
|
||||
set interfaces ethernet eth1 firewall out name 'OUTBOUND'
|
||||
set interfaces ethernet eth1 firewall local name 'LOCAL'
|
||||
set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'
|
||||
set interfaces ethernet eth2 firewall in name 'INBOUND'
|
||||
set interfaces ethernet eth2 firewall out name 'OUTBOUND'
|
||||
set interfaces ethernet eth2 firewall local name 'LOCAL'
|
||||
set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'
|
||||
set interfaces ethernet eth0
|
||||
|
@ -0,0 +1,15 @@
|
||||
---
|
||||
- name: Setup
|
||||
cli_config:
|
||||
config: "{{ lines }}"
|
||||
vars:
|
||||
lines: |
|
||||
set interfaces ethernet eth1 firewall in name 'INBOUND'
|
||||
set interfaces ethernet eth1 firewall out name 'OUTBOUND'
|
||||
set interfaces ethernet eth1 firewall local name 'LOCAL'
|
||||
set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'
|
||||
set interfaces ethernet eth2 firewall in name 'INBOUND'
|
||||
set interfaces ethernet eth2 firewall out name 'OUTBOUND'
|
||||
set interfaces ethernet eth2 firewall local name 'LOCAL'
|
||||
set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Setup
|
||||
cli_config:
|
||||
config: "{{ lines }}"
|
||||
vars:
|
||||
lines: |
|
||||
set firewall name 'INBOUND'
|
||||
set firewall name 'OUTBOUND'
|
||||
set firewall name 'LOCAL'
|
||||
set firewall ipv6-name 'V6-LOCAL'
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Remove Config
|
||||
cli_config:
|
||||
config: "{{ lines }}"
|
||||
vars:
|
||||
lines: |
|
||||
delete interfaces ethernet eth1 firewall
|
||||
delete interfaces ethernet eth2 firewall
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Remove Config
|
||||
cli_config:
|
||||
config: "{{ lines }}"
|
||||
vars:
|
||||
lines: |
|
||||
delete firewall name INBOUND
|
||||
delete firewall name OUTBOUND
|
||||
delete firewall name LOCAL
|
||||
delete firewall ipv6-name V6-LOCAL
|
@ -0,0 +1,50 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Delete attributes of given firewall rules.
|
||||
vyos_firewall_interfaces: &deleted
|
||||
config:
|
||||
- name: 'eth1'
|
||||
- name: 'eth2'
|
||||
state: deleted
|
||||
register: result
|
||||
|
||||
- name: Assert that the before dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the correct set of commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the after dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Delete attributes of given interfaces (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *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'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,56 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Delete firewall interfaces based on IP address type provided.
|
||||
vyos_firewall_interfaces: &deleted_afi
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
- afi: 'ipv6'
|
||||
- name: 'eth2'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
- afi: 'ipv6'
|
||||
state: deleted
|
||||
register: result
|
||||
|
||||
- name: Assert that the before dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the correct set of commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted_afi['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the after dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted_afi['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Delete attributes of given interfaces (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *deleted_afi
|
||||
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_afi['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,48 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Delete all the firewall interfaces.
|
||||
vyos_firewall_interfaces: &deleted_all
|
||||
config:
|
||||
state: deleted
|
||||
register: result
|
||||
|
||||
- name: Assert that the before dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the correct set of commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the after dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Delete attributes of given interfaces (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *deleted_all
|
||||
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'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,54 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "Start vyos_firewall_interfaces deleted integration tests ansible_connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Delete firewall interface.
|
||||
vyos_firewall_interfaces: &deleted_single
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- direction: 'in'
|
||||
name: 'INBOUND'
|
||||
state: deleted
|
||||
register: result
|
||||
|
||||
- name: Assert that the before dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the correct set of commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted_single['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that the after dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ deleted_single['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Delete attributes of given interfaces (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *deleted_single
|
||||
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_single['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,58 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces empty_config integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- name: Merged with empty config should give appropriate error message
|
||||
vyos_firewall_interfaces:
|
||||
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_interfaces:
|
||||
config:
|
||||
state: replaced
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result.msg == 'value of config parameter must not be empty for state replaced'
|
||||
|
||||
- name: Overridden with empty config should give appropriate error message
|
||||
vyos_firewall_interfaces:
|
||||
config:
|
||||
state: overridden
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result.msg == 'value of config parameter must not be empty for state overridden'
|
||||
|
||||
- name: Parsed with empty running_config should give appropriate error message
|
||||
vyos_firewall_interfaces:
|
||||
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_interfaces:
|
||||
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,37 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces gathered integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Merge the provided configuration with the exisiting running configuration
|
||||
vyos_firewall_interfaces: &gathered
|
||||
config:
|
||||
state: gathered
|
||||
register: result
|
||||
|
||||
- name: Assert that gathered dicts was correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ populate | symmetric_difference(result['gathered']) |length == 0 }}"
|
||||
|
||||
- name: Gather the existing running configuration (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *gathered
|
||||
register: result
|
||||
|
||||
- name: Assert that the previous task was idempotent
|
||||
assert:
|
||||
that:
|
||||
- "result['changed'] == false"
|
||||
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,75 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces merged integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- block:
|
||||
- name: Merge the provided configuration with the exisiting running configuration
|
||||
vyos_firewall_interfaces: &merged
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- direction: 'in'
|
||||
name: 'INBOUND'
|
||||
- direction: 'local'
|
||||
name: 'LOCAL'
|
||||
- direction: 'out'
|
||||
name: 'OUTBOUND'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- direction: 'local'
|
||||
name: 'V6-LOCAL'
|
||||
- name: 'eth2'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- direction: 'in'
|
||||
name: 'INBOUND'
|
||||
- direction: 'local'
|
||||
name: 'LOCAL'
|
||||
- direction: 'out'
|
||||
name: 'OUTBOUND'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- direction: 'local'
|
||||
name: 'V6-LOCAL'
|
||||
state: merged
|
||||
register: result
|
||||
|
||||
- name: Assert that before dicts were correctly generated
|
||||
assert:
|
||||
that: "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that correct set of commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ merged['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that after dicts was correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ merged['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *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'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,59 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces merged integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Merge the provided configuration with the exisiting running configuration
|
||||
vyos_firewall_interfaces: &merged_edit
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- direction: 'in'
|
||||
name: 'OUTBOUND'
|
||||
- direction: 'out'
|
||||
name: 'INBOUND'
|
||||
state: merged
|
||||
register: result
|
||||
|
||||
- name: Assert that before dicts were correctly generated
|
||||
assert:
|
||||
that: "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that correct set of commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ merged_edit['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that after dicts was correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ merged_edit['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *merged_edit
|
||||
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_edit['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,58 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces overridden integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Overrides all device configuration with provided configuration
|
||||
vyos_firewall_interfaces: &overridden
|
||||
config:
|
||||
- name: 'eth2'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'out'
|
||||
state: overridden
|
||||
register: result
|
||||
|
||||
- name: Assert that before dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ populate | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that correct commands were generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ overridden['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
|
||||
|
||||
- name: Assert that after dicts were correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ overridden['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Overrides all device configuration with provided configurations (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *overridden
|
||||
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:
|
||||
- "{{ overridden['after'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,44 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces parsed integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Gather firewall_interfaces facts
|
||||
vyos_facts:
|
||||
gather_subset:
|
||||
- default
|
||||
gather_network_resources:
|
||||
- firewall_interfaces
|
||||
register: firewall_interfaces_facts
|
||||
|
||||
- name: Provide the running configuration for parsing (config to be parsed)
|
||||
vyos_firewall_interfaces: &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_interfaces'] | symmetric_difference(result['parsed']) |length == 0 }}"
|
||||
|
||||
- name: Gather the existing running configuration (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *parsed
|
||||
register: result
|
||||
|
||||
- name: Assert that the previous task was idempotent
|
||||
assert:
|
||||
that:
|
||||
- "result['changed'] == false"
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,55 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces rendered integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- block:
|
||||
- name: Structure provided configuration into device specific commands
|
||||
vyos_firewall_interfaces: &rendered
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
- name: 'OUTBOUND'
|
||||
direction: 'out'
|
||||
- name: 'LOCAL'
|
||||
direction: 'local'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'V6-LOCAL'
|
||||
direction: 'local'
|
||||
- name: 'eth2'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
- name: 'OUTBOUND'
|
||||
direction: 'out'
|
||||
- name: 'LOCAL'
|
||||
direction: 'local'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'V6-LOCAL'
|
||||
direction: 'local'
|
||||
state: rendered
|
||||
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_interfaces: *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,68 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces replaced integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- include_tasks: _populate.yaml
|
||||
|
||||
- block:
|
||||
- name: Replace device configurations of listed firewall rules with provided configurations
|
||||
vyos_firewall_interfaces: &replaced
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'OUTBOUND'
|
||||
direction: 'out'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'V6-LOCAL'
|
||||
direction: 'local'
|
||||
- name: 'eth2'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
state: replaced
|
||||
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 | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
- name: Assert that after dict is correctly generated
|
||||
assert:
|
||||
that:
|
||||
- "{{ replaced['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Replace device configurations of listed firewall rules with provided configurarions (IDEMPOTENT)
|
||||
vyos_firewall_interfaces: *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'] | symmetric_difference(result['before']) |length == 0 }}"
|
||||
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,76 @@
|
||||
---
|
||||
- debug:
|
||||
msg: "START vyos_firewall_interfaces round trip integration tests on connection={{ ansible_connection }}"
|
||||
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
||||
|
||||
- include_tasks: _populate_rule_sets.yaml
|
||||
|
||||
- block:
|
||||
- name: Apply the provided configuration (base config)
|
||||
vyos_firewall_interfaces:
|
||||
config:
|
||||
- name: 'eth1'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
- name: 'OUTBOUND'
|
||||
direction: 'out'
|
||||
- name: 'LOCAL'
|
||||
direction: 'local'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'V6-LOCAL'
|
||||
direction: 'local'
|
||||
state: merged
|
||||
register: base_config
|
||||
|
||||
- name: Gather firewall_interfaces facts
|
||||
vyos_facts:
|
||||
gather_subset:
|
||||
- default
|
||||
gather_network_resources:
|
||||
- firewall_interfaces
|
||||
|
||||
- name: Apply the provided configuration (config to be reverted)
|
||||
vyos_firewall_interfaces:
|
||||
config:
|
||||
- name: 'eth2'
|
||||
access_rules:
|
||||
- afi: 'ipv4'
|
||||
rules:
|
||||
- name: 'INBOUND'
|
||||
direction: 'in'
|
||||
- name: 'OUTBOUND'
|
||||
direction: 'out'
|
||||
- name: 'LOCAL'
|
||||
direction: 'local'
|
||||
- afi: 'ipv6'
|
||||
rules:
|
||||
- name: 'V6-LOCAL'
|
||||
direction: 'local'
|
||||
state: merged
|
||||
register: result
|
||||
|
||||
- name: Assert that changes were applied
|
||||
assert:
|
||||
that: "{{ round_trip['after'] | symmetric_difference(result['after']) |length == 0 }}"
|
||||
|
||||
- name: Revert back to base config using facts round trip
|
||||
vyos_firewall_interfaces:
|
||||
config: "{{ ansible_facts['network_resources']['firewall_interfaces'] }}"
|
||||
state: overridden
|
||||
register: revert
|
||||
|
||||
- name: Assert that config was reverted
|
||||
assert:
|
||||
that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length == 0 }}"
|
||||
|
||||
always:
|
||||
- include_tasks: _remove_config.yaml
|
||||
|
||||
- include_tasks: _remove_firewall_config.yaml
|
@ -0,0 +1,294 @@
|
||||
---
|
||||
merged:
|
||||
before:
|
||||
- name: eth0
|
||||
- name: eth1
|
||||
- name: eth2
|
||||
|
||||
commands:
|
||||
- "set interfaces ethernet eth1 firewall in name 'INBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall out name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall local name 'LOCAL'"
|
||||
- "set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'"
|
||||
- "set interfaces ethernet eth2 firewall in name 'INBOUND'"
|
||||
- "set interfaces ethernet eth2 firewall out name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth2 firewall local name 'LOCAL'"
|
||||
- "set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'"
|
||||
|
||||
after:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth2
|
||||
|
||||
populate:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth2
|
||||
|
||||
merged_edit:
|
||||
commands:
|
||||
- "set interfaces ethernet eth1 firewall in name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall out name 'INBOUND'"
|
||||
|
||||
after:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: OUTBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: INBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth2
|
||||
replaced:
|
||||
commands:
|
||||
- "delete interfaces ethernet eth2 firewall out name"
|
||||
- "delete interfaces ethernet eth2 firewall local name"
|
||||
- "delete interfaces ethernet eth2 firewall local ipv6-name"
|
||||
- "delete interfaces ethernet eth1 firewall local name"
|
||||
- "delete interfaces ethernet eth1 firewall in name"
|
||||
|
||||
after:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
name: eth2
|
||||
|
||||
overridden:
|
||||
before:
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- name: INBOUND
|
||||
direction: in
|
||||
- name: LOCAL
|
||||
direction: local
|
||||
- name: OUTBOUND
|
||||
direction: out
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- name: V6-LOCAL
|
||||
direction: local
|
||||
name: eth2
|
||||
commands:
|
||||
- "delete interfaces ethernet eth1 firewall"
|
||||
- "delete interfaces ethernet eth2 firewall in name"
|
||||
- "delete interfaces ethernet eth2 firewall local name"
|
||||
- "delete interfaces ethernet eth2 firewall local ipv6-name"
|
||||
- "set interfaces ethernet eth2 firewall out name 'INBOUND'"
|
||||
|
||||
after:
|
||||
- name: eth0
|
||||
- name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- name: INBOUND
|
||||
direction: out
|
||||
name: eth2
|
||||
|
||||
deleted:
|
||||
commands:
|
||||
- "delete interfaces ethernet eth1 firewall"
|
||||
- "delete interfaces ethernet eth2 firewall"
|
||||
|
||||
after:
|
||||
- name: eth0
|
||||
- name: eth1
|
||||
- name: eth2
|
||||
|
||||
deleted_afi:
|
||||
commands:
|
||||
- "delete interfaces ethernet eth1 firewall in name"
|
||||
- "delete interfaces ethernet eth1 firewall local name"
|
||||
- "delete interfaces ethernet eth1 firewall out name"
|
||||
- "delete interfaces ethernet eth1 firewall local ipv6-name"
|
||||
- "delete interfaces ethernet eth2 firewall in name"
|
||||
- "delete interfaces ethernet eth2 firewall local name"
|
||||
- "delete interfaces ethernet eth2 firewall out name"
|
||||
- "delete interfaces ethernet eth2 firewall local ipv6-name"
|
||||
|
||||
after:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
- afi: ipv6
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
- afi: ipv6
|
||||
name: eth2
|
||||
|
||||
deleted_single:
|
||||
commands:
|
||||
- "delete interfaces ethernet eth1 firewall in name 'INBOUND'"
|
||||
after:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth2
|
||||
|
||||
rendered:
|
||||
commands:
|
||||
- "set interfaces ethernet eth1 firewall in name 'INBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall out name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth1 firewall local name 'LOCAL'"
|
||||
- "set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'"
|
||||
- "set interfaces ethernet eth2 firewall in name 'INBOUND'"
|
||||
- "set interfaces ethernet eth2 firewall out name 'OUTBOUND'"
|
||||
- "set interfaces ethernet eth2 firewall local name 'LOCAL'"
|
||||
- "set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'"
|
||||
|
||||
round_trip:
|
||||
after:
|
||||
- name: eth0
|
||||
- access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
||||
name: eth1
|
||||
- name: eth2
|
||||
access_rules:
|
||||
- afi: ipv4
|
||||
rules:
|
||||
- direction: in
|
||||
name: INBOUND
|
||||
- direction: local
|
||||
name: LOCAL
|
||||
- direction: out
|
||||
name: OUTBOUND
|
||||
- afi: ipv6
|
||||
rules:
|
||||
- direction: local
|
||||
name: V6-LOCAL
|
@ -0,0 +1,8 @@
|
||||
set interfaces ethernet eth0 firewall in name 'INBOUND'
|
||||
set interfaces ethernet eth0 firewall local ipv6-name 'V6-LOCAL'
|
||||
set interfaces ethernet eth0 firewall local name 'LOCAL'
|
||||
set interfaces ethernet eth0 firewall out name 'OUTBOUND'
|
||||
set interfaces ethernet eth2 firewall in name 'INBOUND'
|
||||
set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'
|
||||
set interfaces ethernet eth2 firewall local name 'LOCAL'
|
||||
set interfaces ethernet eth2 firewall out name 'OUTBOUND'
|
@ -0,0 +1,305 @@
|
||||
# (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_interfaces
|
||||
from units.modules.utils import set_module_args
|
||||
from .vyos_module import TestVyosModule, load_fixture
|
||||
|
||||
|
||||
class TestVyosFirewallInterfacesModule(TestVyosModule):
|
||||
|
||||
module = vyos_firewall_interfaces
|
||||
|
||||
def setUp(self):
|
||||
super(TestVyosFirewallInterfacesModule, self).setUp()
|
||||
self.mock_get_config = patch(
|
||||
'ansible.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_interfaces.firewall_interfaces.Firewall_interfacesFacts.get_device_data'
|
||||
)
|
||||
self.execute_show_command = self.mock_execute_show_command.start()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestVyosFirewallInterfacesModule, self).tearDown()
|
||||
self.mock_get_resource_connection_config.stop()
|
||||
self.mock_get_resource_connection_facts.stop()
|
||||
self.mock_get_config.stop()
|
||||
self.mock_load_config.stop()
|
||||
self.mock_execute_show_command.stop()
|
||||
|
||||
def load_fixtures(self, commands=None):
|
||||
def load_from_file(*args, **kwargs):
|
||||
return load_fixture('vyos_firewall_interfaces_config.cfg')
|
||||
|
||||
self.execute_show_command.side_effect = load_from_file
|
||||
|
||||
def test_vyos_firewall_rule_set_01_merged(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth1',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
]),
|
||||
dict(name='eth3',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
])
|
||||
],
|
||||
state="merged"))
|
||||
commands = [
|
||||
"set interfaces ethernet eth1 firewall in name 'INBOUND'",
|
||||
"set interfaces ethernet eth1 firewall out name 'OUTBOUND'",
|
||||
"set interfaces ethernet eth1 firewall local name 'LOCAL'",
|
||||
"set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'",
|
||||
"set interfaces ethernet eth3 firewall in name 'INBOUND'",
|
||||
"set interfaces ethernet eth3 firewall out name 'OUTBOUND'",
|
||||
"set interfaces ethernet eth3 firewall local name 'LOCAL'",
|
||||
"set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL'"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_02_merged_idem(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth0',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
]),
|
||||
dict(name='eth2',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
])
|
||||
],
|
||||
state="merged"))
|
||||
self.execute_module(changed=False, commands=[])
|
||||
|
||||
def test_vyos_firewall_rule_set_01_deleted_per_afi(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth0',
|
||||
access_rules=[dict(afi='ipv4'),
|
||||
dict(afi='ipv6')])
|
||||
],
|
||||
state="deleted"))
|
||||
commands = [
|
||||
"delete interfaces ethernet eth0 firewall in name",
|
||||
"delete interfaces ethernet eth0 firewall local name",
|
||||
"delete interfaces ethernet eth0 firewall out name",
|
||||
"delete interfaces ethernet eth0 firewall local ipv6-name"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_03_deleted_per_interface(self):
|
||||
set_module_args(
|
||||
dict(config=[dict(name='eth0'),
|
||||
dict(name='eth2')],
|
||||
state="deleted"))
|
||||
commands = [
|
||||
"delete interfaces ethernet eth0 firewall",
|
||||
"delete interfaces ethernet eth2 firewall"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_03_deleted_all(self):
|
||||
set_module_args(dict(config=[], state="deleted"))
|
||||
commands = [
|
||||
"delete interfaces ethernet eth0 firewall",
|
||||
"delete interfaces ethernet eth2 firewall"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_03_deleted(self):
|
||||
set_module_args(
|
||||
dict(config=[dict(name='eth0'),
|
||||
dict(name='eth2')],
|
||||
state="deleted"))
|
||||
commands = [
|
||||
"delete interfaces ethernet eth0 firewall",
|
||||
"delete interfaces ethernet eth2 firewall"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_04_deleted_interface_idem(self):
|
||||
set_module_args(
|
||||
dict(config=[dict(name='eth1'),
|
||||
dict(name='eth3')],
|
||||
state="deleted"))
|
||||
self.execute_module(changed=False, commands=[])
|
||||
|
||||
def test_vyos_firewall_rule_set_02_replaced_idem(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth0',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
]),
|
||||
dict(name='eth2',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
])
|
||||
],
|
||||
state="replaced"))
|
||||
self.execute_module(changed=False, commands=[])
|
||||
|
||||
def test_vyos_firewall_rule_set_01_replaced(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth0',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
]),
|
||||
dict(name='eth2',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[dict(name='LOCAL', direction='local')]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
]),
|
||||
dict(name='eth3',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[dict(name='LOCAL', direction='local')]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
])
|
||||
],
|
||||
state="replaced"))
|
||||
commands = [
|
||||
"delete interfaces ethernet eth0 firewall out name",
|
||||
"delete interfaces ethernet eth0 firewall local name",
|
||||
"delete interfaces ethernet eth2 firewall in name",
|
||||
"delete interfaces ethernet eth2 firewall out name",
|
||||
"set interfaces ethernet eth3 firewall local name 'LOCAL'",
|
||||
"set interfaces ethernet eth3 firewall local ipv6-name 'V6-LOCAL'"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_01_overridden(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth1',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[dict(name='INBOUND', direction='in')])
|
||||
])
|
||||
],
|
||||
state="overridden"))
|
||||
commands = [
|
||||
"delete interfaces ethernet eth0 firewall",
|
||||
"delete interfaces ethernet eth2 firewall",
|
||||
"set interfaces ethernet eth1 firewall in name 'INBOUND'"
|
||||
]
|
||||
self.execute_module(changed=True, commands=commands)
|
||||
|
||||
def test_vyos_firewall_rule_set_02_overridden_idem(self):
|
||||
set_module_args(
|
||||
dict(config=[
|
||||
dict(name='eth0',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
]),
|
||||
dict(name='eth2',
|
||||
access_rules=[
|
||||
dict(afi='ipv4',
|
||||
rules=[
|
||||
dict(name='INBOUND', direction='in'),
|
||||
dict(name='OUTBOUND', direction='out'),
|
||||
dict(name='LOCAL', direction='local')
|
||||
]),
|
||||
dict(afi='ipv6',
|
||||
rules=[dict(name='V6-LOCAL', direction='local')])
|
||||
])
|
||||
],
|
||||
state="overridden"))
|
||||
self.execute_module(changed=False, commands=[])
|
Loading…
Reference in New Issue