Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the Capirca and related modules for ACL config generation #50852

Merged
merged 5 commits into from Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
122 changes: 42 additions & 80 deletions salt/modules/capirca_acl.py
Expand Up @@ -19,8 +19,7 @@

.. _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

Expand All @@ -32,15 +31,21 @@
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
Expand Down Expand Up @@ -68,72 +73,13 @@ def __virtual__():
# module globals
# ------------------------------------------------------------------------------


# 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
Expand All @@ -159,15 +105,27 @@ def __virtual__():


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.
'''
def __init__(self):
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.
'''
Expand All @@ -184,10 +142,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))
Expand All @@ -214,7 +172,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:')
Expand Down Expand Up @@ -364,7 +322,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
Expand Down Expand Up @@ -425,7 +387,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 = []
Expand Down Expand Up @@ -512,7 +474,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
Expand All @@ -522,7 +484,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', []):
Expand Down
7 changes: 6 additions & 1 deletion salt/modules/napalm_acl.py
Expand Up @@ -19,6 +19,8 @@

.. _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.
Expand All @@ -34,7 +36,10 @@
# 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:
Expand Down
15 changes: 12 additions & 3 deletions salt/states/netacl.py
Expand Up @@ -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
Expand All @@ -18,7 +18,13 @@
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``.
Expand All @@ -35,7 +41,10 @@
# 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:
Expand Down