mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Improve the Capirca and related modules for ACL config generation
Since I added these modules in 2017.7.0, Capirca has been released on PyPI, now available to be installed as a regular Python library. Besides that, in the past there were various issues due to the way the modules are interacting with the underlying library, solved by adding a hardcoded list for the policy term fields. This has caused some issues in the past, and had to be patches, e.g.,db255d3702
or1e74141cc0
. While the changes referenced above are not particularly big, it's tedious to always keep an eye on Capirca and be aware of what's newly added or changed. Besides, this may have caused issues for users in the past when using other Capirca versions.
This commit is contained in:
parent
32dfabab50
commit
5176cd8798
3 changed files with 57 additions and 84 deletions
|
@ -19,8 +19,7 @@ The firewall configuration is generated by Capirca_.
|
|||
|
||||
.. _Capirca: https://github.com/google/capirca
|
||||
|
||||
Capirca is not yet available on PyPI threrefore it has to be installed
|
||||
directly form Git: ``pip install -e git+git@github.com:google/capirca.git#egg=aclgen``.
|
||||
To install Capirca, execute: ``pip install capirca``.
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
@ -32,15 +31,21 @@ import datetime
|
|||
log = logging.getLogger(__file__)
|
||||
|
||||
# Import third party libs
|
||||
from salt.ext import six
|
||||
try:
|
||||
import aclgen
|
||||
import capirca
|
||||
import capirca.aclgen
|
||||
import capirca.lib.policy
|
||||
import capirca.lib.aclgenerator
|
||||
HAS_CAPIRCA = True
|
||||
except ImportError:
|
||||
HAS_CAPIRCA = False
|
||||
|
||||
# Import Salt modules
|
||||
import salt.utils
|
||||
from salt.ext import six
|
||||
# Import Salt libs
|
||||
try:
|
||||
from salt.utils import fopen
|
||||
except ImportError:
|
||||
from salt.utils.files import fopen
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# module properties
|
||||
|
@ -69,71 +74,9 @@ def __virtual__():
|
|||
# ------------------------------------------------------------------------------
|
||||
|
||||
# define the default values for all possible term fields
|
||||
# we could also extract them from the `policy` module, inspecting the `Policy`
|
||||
# class, but that might be overkill & it would make the code less obvious.
|
||||
# we can revisit this later if necessary.
|
||||
_TERM_FIELDS = {
|
||||
'action': [],
|
||||
'address': [],
|
||||
'address_exclude': [],
|
||||
'comment': [],
|
||||
'counter': None,
|
||||
'expiration': None,
|
||||
'destination_address': [],
|
||||
'destination_address_exclude': [],
|
||||
'destination_port': [],
|
||||
'destination_prefix': [],
|
||||
'forwarding_class': [],
|
||||
'forwarding_class_except': [],
|
||||
'logging': [],
|
||||
'log_name': None,
|
||||
'loss_priority': None,
|
||||
'option': [],
|
||||
'owner': None,
|
||||
'policer': None,
|
||||
'port': [],
|
||||
'precedence': [],
|
||||
'principals': [],
|
||||
'protocol': [],
|
||||
'protocol_except': [],
|
||||
'qos': None,
|
||||
'pan_application': [],
|
||||
'routing_instance': None,
|
||||
'source_address': [],
|
||||
'source_address_exclude': [],
|
||||
'source_port': [],
|
||||
'source_prefix': [],
|
||||
'verbatim': [],
|
||||
'packet_length': None,
|
||||
'fragment_offset': None,
|
||||
'hop_limit': None,
|
||||
'icmp_type': [],
|
||||
'icmp_code': None,
|
||||
'ether_type': [],
|
||||
'traffic_class_count': None,
|
||||
'traffic_type': [],
|
||||
'translated': False,
|
||||
'dscp_set': None,
|
||||
'dscp_match': [],
|
||||
'dscp_except': [],
|
||||
'next_ip': None,
|
||||
'flexible_match_range': [],
|
||||
'source_prefix_except': [],
|
||||
'destination_prefix_except': [],
|
||||
'vpn': None,
|
||||
'source_tag': [],
|
||||
'destination_tag': [],
|
||||
'source_interface': None,
|
||||
'destination_interface': None,
|
||||
'platform': [],
|
||||
'platform_exclude': [],
|
||||
'timeout': None,
|
||||
'flattened': False,
|
||||
'flattened_addr': None,
|
||||
'flattened_saddr': None,
|
||||
'flattened_daddr': None,
|
||||
'priority': None
|
||||
}
|
||||
# This mapping is currently built dynamically using the Term class from the
|
||||
# underlying library, Capirca
|
||||
_TERM_FIELDS = {}
|
||||
|
||||
# IP-type fields
|
||||
# when it comes to IP fields, Capirca does not ingest raw text
|
||||
|
@ -159,7 +102,19 @@ _SERVICES = {}
|
|||
|
||||
|
||||
if HAS_CAPIRCA:
|
||||
class _Policy(aclgen.policy.Policy):
|
||||
_TempTerm = capirca.lib.policy.Term
|
||||
|
||||
def _add_object(self, obj):
|
||||
return
|
||||
|
||||
setattr(_TempTerm, 'AddObject', _add_object)
|
||||
dumy_term = _TempTerm(None)
|
||||
for item in dir(dumy_term):
|
||||
if hasattr(item, '__func__') or item.startswith('_') or item != item.lower():
|
||||
continue
|
||||
_TERM_FIELDS[item] = getattr(dumy_term, item)
|
||||
|
||||
class _Policy(capirca.lib.policy.Policy):
|
||||
'''
|
||||
Extending the Capirca Policy class to allow inserting custom filters.
|
||||
'''
|
||||
|
@ -167,7 +122,7 @@ if HAS_CAPIRCA:
|
|||
self.filters = []
|
||||
self.filename = ''
|
||||
|
||||
class _Term(aclgen.policy.Term):
|
||||
class _Term(capirca.lib.policy.Term):
|
||||
'''
|
||||
Extending the Capirca Term class to allow setting field valued on the fly.
|
||||
'''
|
||||
|
@ -184,10 +139,10 @@ def _import_platform_generator(platform):
|
|||
for a class inheriting the `ACLGenerator` class.
|
||||
'''
|
||||
log.debug('Using platform: {plat}'.format(plat=platform))
|
||||
for mod_name, mod_obj in inspect.getmembers(aclgen):
|
||||
for mod_name, mod_obj in inspect.getmembers(capirca.aclgen):
|
||||
if mod_name == platform and inspect.ismodule(mod_obj):
|
||||
for plat_obj_name, plat_obj in inspect.getmembers(mod_obj): # pylint: disable=unused-variable
|
||||
if inspect.isclass(plat_obj) and issubclass(plat_obj, aclgen.aclgenerator.ACLGenerator):
|
||||
if inspect.isclass(plat_obj) and issubclass(plat_obj, capirca.lib.aclgenerator.ACLGenerator):
|
||||
log.debug('Identified Capirca class {cls} for {plat}'.format(
|
||||
cls=plat_obj,
|
||||
plat=platform))
|
||||
|
@ -214,7 +169,7 @@ def _get_services_mapping():
|
|||
return _SERVICES
|
||||
services_txt = ''
|
||||
try:
|
||||
with salt.utils.fopen('/etc/services', 'r') as srv_f:
|
||||
with fopen('/etc/services', 'r') as srv_f:
|
||||
services_txt = srv_f.read()
|
||||
except IOError as ioe:
|
||||
log.error('Unable to read from /etc/services:')
|
||||
|
@ -364,7 +319,11 @@ def _clean_term_opts(term_opts):
|
|||
# IP-type fields need to be transformed
|
||||
ip_values = []
|
||||
for addr in value:
|
||||
ip_values.append(aclgen.policy.nacaddr.IP(addr))
|
||||
if six.PY2:
|
||||
addr = six.text_type(addr)
|
||||
# Adding this, as ipaddress would complain about valid
|
||||
# addresses not being valid. #pythonIsFun
|
||||
ip_values.append(capirca.lib.policy.nacaddr.IP(addr))
|
||||
value = ip_values[:]
|
||||
clean_opts[field] = value
|
||||
return clean_opts
|
||||
|
@ -425,7 +384,7 @@ def _merge_list_of_dict(first, second, prepend=True):
|
|||
if first and not second:
|
||||
return first
|
||||
# Determine overlaps
|
||||
# So we don't change the position of the existing terms/filters
|
||||
# So we dont change the position of the existing terms/filters
|
||||
overlaps = []
|
||||
merged = []
|
||||
appended = []
|
||||
|
@ -512,7 +471,7 @@ def _get_policy_object(platform,
|
|||
continue # go to the next filter
|
||||
filter_name = filter_.keys()[0]
|
||||
filter_config = filter_.values()[0]
|
||||
header = aclgen.policy.Header() # same header everywhere
|
||||
header = capirca.lib.policy.Header() # same header everywhere
|
||||
target_opts = [
|
||||
platform,
|
||||
filter_name
|
||||
|
@ -522,7 +481,7 @@ def _get_policy_object(platform,
|
|||
filter_options = _make_it_list({}, filter_name, filter_options)
|
||||
# make sure the filter options are sent as list
|
||||
target_opts.extend(filter_options)
|
||||
target = aclgen.policy.Target(target_opts)
|
||||
target = capirca.lib.policy.Target(target_opts)
|
||||
header.AddObject(target)
|
||||
filter_terms = []
|
||||
for term_ in filter_config.get('terms', []):
|
||||
|
|
|
@ -19,6 +19,8 @@ The firewall configuration is generated by Capirca_.
|
|||
|
||||
.. _Capirca: https://github.com/google/capirca
|
||||
|
||||
To install Capirca, execute: ``pip install capirca``.
|
||||
|
||||
To be able to load configuration on network devices,
|
||||
it requires NAPALM_ library to be installed: ``pip install napalm``.
|
||||
Please check Installation_ for complete details.
|
||||
|
@ -34,7 +36,10 @@ log = logging.getLogger(__file__)
|
|||
# Import third party libs
|
||||
try:
|
||||
# pylint: disable=W0611
|
||||
import aclgen
|
||||
import capirca
|
||||
import capirca.aclgen
|
||||
import capirca.lib.policy
|
||||
import capirca.lib.aclgenerator
|
||||
HAS_CAPIRCA = True
|
||||
# pylint: enable=W0611
|
||||
except ImportError:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Network ACL
|
||||
===========
|
||||
|
||||
Manage the firewall configuration on the network device namaged through NAPALM.
|
||||
Manage the firewall configuration on the network device managed through NAPALM.
|
||||
The firewall configuration is generated by Capirca_.
|
||||
|
||||
.. _Capirca: https://github.com/google/capirca
|
||||
|
@ -18,7 +18,13 @@ The firewall configuration is generated by Capirca_.
|
|||
Dependencies
|
||||
------------
|
||||
|
||||
Capirca: ``pip install -e git+git@github.com:google/capirca.git#egg=aclgen``
|
||||
Capirca
|
||||
~~~~~~~
|
||||
|
||||
To install Capirca, execute: ``pip install capirca``.
|
||||
|
||||
NAPALM
|
||||
~~~~~~
|
||||
|
||||
To be able to load configuration on network devices,
|
||||
it requires NAPALM_ library to be installed: ``pip install napalm``.
|
||||
|
@ -35,7 +41,10 @@ log = logging.getLogger(__file__)
|
|||
# Import third party libs
|
||||
try:
|
||||
# pylint: disable=W0611
|
||||
import aclgen
|
||||
import capirca
|
||||
import capirca.aclgen
|
||||
import capirca.lib.policy
|
||||
import capirca.lib.aclgenerator
|
||||
HAS_CAPIRCA = True
|
||||
# pylint: enable=W0611
|
||||
except ImportError:
|
||||
|
|
Loading…
Add table
Reference in a new issue