Skip to content

Commit

Permalink
Merge pull request #203 from coxley/develop
Browse files Browse the repository at this point in the history
Support for Cisco's ASA
  • Loading branch information
jathanism committed Jan 20, 2015
2 parents b084435 + 7ea91cb commit c1a7851
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ _build

# Gerrit
.gitreview

# PyCharm
.idea
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ lifetime:
- `Mike Biancaniello <https://github.com/chepazzo>`_
- `Murat Ezbiderli <https://github.com/mezbiderli>`_
- `Johannes Erdfelt <https://github.com/jerdfelt>`_
- `Codey Oxley <https://github.com/coxley>`_
27 changes: 27 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@
Changelog
=========

.. _v1.4.8:

1.4.8
=====

New Features
------------

+ Cisco ASA firewall now supported as a NetDevice. To begin using, ensure
that ``FIREWALL`` is added in your settings.py as a supported cisco platform.o

For it to enable properly, either the netdevice attribute ``enablePW`` needs
to be set or the environment variable ``TRIGGER_ENABLEPW`` does. For now, I
typically accomplish this via::

>>> from trigger.conf import settings
>>> from trigger import tacacsrc
>>> settings.DEFAULT_REALM = 'MyRealm'
>>> os.environ['TRIGGER_ENABLEPW'] = \
tacacsrc.get_device_password(settings.DEFAULT_REALM).password
>>> # Then the rest of my program

ACL parsing for ASA is not implemented yet. NetACLInfo will generate the
proper command, but will currently just add a message warning about future
support


.. _v1.4.7:

1.4.7
Expand Down
2 changes: 1 addition & 1 deletion trigger/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = (1, 4, 7)
__version__ = (1, 4, 8)

full_version = '.'.join(map(str, __version__[0:3])) + ''.join(__version__[3:])
release = full_version
Expand Down
20 changes: 17 additions & 3 deletions trigger/cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ def _lookup_method(self, device, method):
from_juniper
to_foundry
and defaults to ``self.from_base`` and ``self.to_base`` methods if
customized methods not found.
:param device:
A `~trigger.netdevices.NetDevice` object
Expand Down Expand Up @@ -360,13 +363,16 @@ class constructor.

def parse(self, results, device):
"""
Parse output from a device.
Parse output from a device. Calls to ``self._lookup_method`` to find
specific ``from`` method.
Define a 'from_{vendor_name}' method to customize the behavior for each
platform.
:param results:
The results of the commands executed on the device
:type results:
list
:param device:
A `~trigger.netdevices.NetDevice` object
Expand Down Expand Up @@ -679,7 +685,10 @@ def IPhost(self, addr):
def to_cisco(self, dev, commands=None, extra=None):
"""This is the "show me all interface information" command we pass to
IOS devices"""
return ['show configuration | include ^(interface | ip address | ip access-group | description|!)']
if dev.is_cisco_asa():
return ['show running-config | include ^(interface | ip address | nameif | description |access-group|!)']
else:
return ['show configuration | include ^(interface | ip address | ip access-group | description|!)']

def to_arista(self, dev, commands=None, extra=None):
"""
Expand Down Expand Up @@ -712,7 +721,12 @@ def from_cisco(self, data, device):
alld = data[0]

log.msg('Parsing interface data (%d bytes)' % len(alld))
self.config[device] = _parse_ios_interfaces(alld, skip_disabled=self.skip_disabled)
if not device.is_cisco_asa():
self.config[device] = _parse_ios_interfaces(alld, skip_disabled=self.skip_disabled)
else:
self.config[device] = {
"unsupported": "ASA ACL parsing unsupported this release"
}

return True

Expand Down
2 changes: 1 addition & 1 deletion trigger/conf/global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
'arista': ['SWITCH'], # Your "Cloud" network vendor
'aruba': ['SWITCH'], # Aruba Wi-Fi controllers
'brocade': ['ROUTER', 'SWITCH'],
'cisco': ['ROUTER', 'SWITCH'],
'cisco': ['ROUTER', 'SWITCH', 'FIREWALL'],
'citrix': ['SWITCH'], # Assumed to be NetScalers
'dell': ['SWITCH'],
'f5': ['LOAD BALANCING', 'SWITCH'],
Expand Down
38 changes: 37 additions & 1 deletion trigger/netdevices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,14 +343,21 @@ def disable_paging_brocade():
else:
return ['skip-page-display']

def disable_paging_cisco():
"""Cisco ASA commands differ from IOS"""
if self.is_cisco_asa():
return ['terminal pager 0']
else:
return default

# Commands used to disable paging.
default = ['terminal length 0']
paging_map = {
'a10': default,
'arista': default,
'aruba': ['no paging'], # v6.2.x this is not necessary
'brocade': disable_paging_brocade(), # See comments above
'cisco': default,
'cisco': disable_paging_cisco(),
'dell': ['terminal datadump'],
'f5': ['modify cli preference pager disabled'],
'force10': default,
Expand Down Expand Up @@ -559,6 +566,35 @@ def is_brocade_vdx(self):
self._is_brocade_vdx = 'vdx' in self.make.lower()
return self._is_brocade_vdx

def is_cisco_asa(self):
"""
Am I a Cisco ASA Firewall?
This is used to account for slight differences in the commands that
may be used between Cisco's ASA and IOS platforms. Cisco ASA is still
very IOS-like, but there are still several gotcha's between the
platforms.
Will return True if vendor is Cisco and platform is Firewall. This
is to allow operability if using .csv NetDevices and pretty safe to
assume considering ASA (was PIX) are Cisco's flagship(if not only)
Firewalls.
"""
if hasattr(self, '_is_cisco_asa'):
return self._is_cisco_asa

if not (self.vendor == 'cisco' and self.is_firewall()):
self._is_cisco_asa = False
return False

if self.make is not None:
self._is_cisco_asa = 'asa' in self.make.lower()

self._is_cisco_asa = self.vendor == 'cisco' and self.is_firewall()

return self._is_cisco_asa


def _ssh_enabled(self, disabled_mapping):
"""Check whether vendor/type is enabled against the given mapping."""
disabled_types = disabled_mapping.get(self.vendor.name, [])
Expand Down
6 changes: 6 additions & 0 deletions trigger/twister.py
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,12 @@ def loseConnection(self):

def dataReceived(self, data):
"""And write data to the terminal."""
# -- Left during debugging. Enable on ASA not fixed here yet -- #
# log.msg('[%s] DATA: %r' % (self.device, data))
# if requires_enable(self, data):
# log.msg('[%s] Device Requires Enable: %s' % (self.device, requires_enable(self, data)))
# log.msg('[%s] Is Device Currently Enabled: %s' % (self.device, self.enabled))

# Check whether we need to send an enable password.
if not self.enabled and requires_enable(self, data):
log.msg('[%s] Interactive PTY requires enable commands' % self.device)
Expand Down

0 comments on commit c1a7851

Please sign in to comment.