Skip to content

Commit

Permalink
Updated Patch for trigger#252
Browse files Browse the repository at this point in the history
* Moved TextFSM vendor mapping functionality into the NetDevices object.
The NetDevices object now has an "os" attribute.

* Added more tests including a test for the template parser.
  • Loading branch information
tcuthbert committed Mar 9, 2016
1 parent fb7db42 commit bc0152c
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 21 deletions.
6 changes: 6 additions & 0 deletions conf/trigger_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@
# Assign NETDEVICES_SOURCE to NETDEVICES_FILE for backwards compatibility
NETDEVICES_FILE = NETDEVICES_SOURCE

# TextFSM Vendor Mappings. Override this if you have defined your own TextFSM templates.
TEXTFSM_VENDOR_MAPPINGS = {
"cisco": [ "ios", "nxos" ],
"arista": [ "eos" ]
}

# TextFSM Template Path. Commando will attempt to match a given show command with a template within this folder.
TEXTFSM_TEMPLATE_DIR = os.getenv('TEXTFSM_TEMPLATE_DIR', os.path.join(PREFIX, 'vendor/ntc_templates'))

Expand Down
8 changes: 8 additions & 0 deletions tests/data/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@
AUTOACL_FILE = os.environ.get('AUTOACL_FILE',
os.path.join(PREFIX, 'autoacl.py'))
BOUNCE_FILE = os.environ.get('BOUNCE_FILE', os.path.join(PREFIX, 'bounce.py'))

TEXTFSM_VENDOR_MAPPINGS = {
"cisco": [ "ios", "nxos" ],
"arista": [ "eos" ]
}


TEXTFSM_TEMPLATE_DIR = os.getenv('TEXTFSM_TEMPLATE_DIR', os.path.join(PREFIX, 'vendor/ntc_templates'))
10 changes: 10 additions & 0 deletions tests/data/vendor/ntc_templates/cisco_ios_show_clock.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Value TIME (\d+:\d+:\d+\.\d+)
Value TIMEZONE (\w+)
Value DAYWEEK (\w+)
Value MONTH (\w+)
Value DAY (\d+)
Value YEAR (\d+)

Start
^[\*]?${TIME}\s${TIMEZONE}\s${DAYWEEK}\s${MONTH}\s${DAY}\s${YEAR} -> Record

15 changes: 15 additions & 0 deletions tests/data/vendor/ntc_templates/cisco_ios_show_version.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Value VERSION (\d+\.\d+(.+).*)
Value HOSTNAME (\S+)
Value UPTIME (.+)
Value RUNNING_IMAGE (\S+)
Value HARDWARE ((WS-C\S+)|(\d+)|(CSR\S+))
Value SERIAL (\S+)
Value CONFIG_REGISTER (\S+)

Start
^.*Software\s.+\),\sVersion\s${VERSION}, RELEASE.*
^${HOSTNAME}\s+uptime\s+is\s+${UPTIME}
^[sS]ystem\s+image\s+file\s+is\s+".*flash:${RUNNING_IMAGE}"
^[Cc]isco\s+${HARDWARE}.+
^[Ss]ystem serial number\s+:\s+${SERIAL}
^[Cc]onfiguration\s+register\s+is\s+${CONFIG_REGISTER} -> Record
9 changes: 8 additions & 1 deletion tests/test_netdevices.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ def test_autoacls(self):
def tearDown(self):
_reset_netdevices()


class TestNetDeviceObject(unittest.TestCase):
"""
Test NetDevice object methods.
Expand Down Expand Up @@ -208,6 +207,14 @@ def test_dump(self):
output = out.getvalue()
self.assertEqual(expected, output)

def test_os(self):
self.nd = NetDevices()
self.device = self.nd[DEVICE_NAME]
self.device.vendor = "cisco"
self.device.operatingSystem = "NXOS"
self.nodename = self.device.nodeName
self.assertEquals("cisco_nxos", self.device.os)

def tearDown(self):
_reset_netdevices()

Expand Down
95 changes: 94 additions & 1 deletion tests/test_templates.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import unittest
import os
import mock
from trigger.netdevices import NetDevices
from trigger.cmds import Commando
from trigger.utils.templates import *
from trigger.conf import settings
from contextlib import contextmanager
from StringIO import StringIO
import cStringIO


# Constants
DEVICE_NAME = 'test1-abc.net.aol.com'
DEVICE2_NAME = 'test2-abc.net.aol.com'

try:
import textfsm
except ImportError:
Expand All @@ -21,6 +26,61 @@


cli_data = """*02:00:42.743 UTC Sat Feb 20 2016"""
big_cli_data = """Cisco IOS XE Software, Version 03.12.00.S - Standard Support Release
Cisco IOS Software, CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 15.4(2)S, RELEASE SOFTWARE (fc2)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2014 by Cisco Systems, Inc.
Compiled Wed 26-Mar-14 21:09 by mcpre
Cisco IOS-XE software, Copyright (c) 2005-2014 by cisco Systems, Inc.
All rights reserved. Certain components of Cisco IOS-XE software are
licensed under the GNU General Public License ("GPL") Version 2.0. The
software code licensed under GPL Version 2.0 is free software that comes
with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such
GPL code under the terms of GPL Version 2.0. For more details, see the
documentation or "License Notice" file accompanying the IOS-XE software,
or the applicable URL provided on the flyer accompanying the IOS-XE
software.
ROM: IOS-XE ROMMON
R1 uptime is 2 hours, 22 minutes
Uptime for this control processor is 2 hours, 23 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: <NULL>
This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.
A summary of U.S. laws governing Cisco cryptographic products may be found at:
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html
If you require further assistance please contact us by sending email to
export@cisco.com.
License Level: limited
License Type: Default. No valid license found.
Next reload license Level: limited
cisco CSR1000V (VXE) processor with 804580K/6147K bytes of memory.
Processor board ID 9G0T83AE5II
4 Gigabit Ethernet interfaces
32768K bytes of non-volatile configuration memory.
2097152K bytes of physical memory.
7774207K bytes of virtual hard disk at bootflash:.
Configuration register is 0x2102"""

text_fsm_data = """Value TIME (\d+:\d+:\d+\.\d+)
Value TIMEZONE (\w+)
Expand All @@ -32,6 +92,13 @@
Start
^[\*]?${TIME}\s${TIMEZONE}\s${DAYWEEK}\s${MONTH}\s${DAY}\s${YEAR} -> Record
"""
no_template_data = "username cisco"


def _reset_netdevices():
"""Reset the Singleton state of NetDevices class."""
NetDevices._Singleton = None


class CheckTemplates(unittest.TestCase):
"""Test structured CLI object data."""
Expand All @@ -41,6 +108,11 @@ def setUp(self):
self.re_table = textfsm.TextFSM(data)
self.assertTrue(isinstance(self.re_table, textfsm.textfsm.TextFSM))

self.nd = NetDevices()
self.device = self.nd[DEVICE_NAME]
self.device.vendor = "cisco"
self.device.operatingSystem = "ios"

def testTemplatePath(self):
"""Test that template path is correct."""
t_path = get_template_path("show clock", dev_type="cisco_ios")
Expand All @@ -54,6 +126,27 @@ def testGetTextFsmObject(self):
for key in keys:
self.assertTrue(data.has_key(key))

def testCommandoResultsGood(self):
commands = ["show version"]
commando = Commando(devices=[self.device.nodeName])
data = commando.parse_template(results=[big_cli_data], device=self.device, commands=commands)
self.assertGreater(len(data), 0)
self.assertTrue(isinstance(data, list))
self.assertTrue(isinstance(data[0], str))
self.assertTrue(isinstance(commando.parsed_results, dict))
self.assertEquals(commando.parsed_results.popitem()[1]["show version"]["hardware"], ['CSR1000V'])

def testCommandoResultsBad(self):
commands = ["show run | in cisco"]
commando = Commando(devices=[self.device.nodeName])
data = commando.parse_template(results=[no_template_data], device=self.device, commands=commands)
self.assertGreater(len(data), 0)
self.assertTrue(isinstance(data, list))
self.assertTrue(isinstance(data[0], str))
self.assertEquals(commando.parsed_results, {})

def tearDown(self):
_reset_netdevices()

if __name__ == "__main__":
unittest.main()
27 changes: 8 additions & 19 deletions trigger/cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,28 +424,17 @@ def parse_template(self, results, device, commands=None):
`~trigger.netdevices.NetDevice`
"""

device_type = ""
device_type = device.os
ret = []
vendor_mapping = {
"cisco": "cisco_ios",
"cisco_nexus": "cisco_nexus",
"arista": "arista_eos"
}
if device.model.lower() == 'nexus':
device_type = "cisco_nxos"
else:
try:
device_type = vendor_mapping[device.vendor]
except:
log.msg("Unable to find template for given device")

for idx, command in enumerate(commands):
try:
re_table = load_cmd_template(command, dev_type=device_type)
fsm = get_textfsm_object(re_table, results[idx])
self.append_parsed_results(device, self.map_parsed_results(command, fsm))
except:
log.msg("Unable to load TextFSM template, updating with unstructured output")
if device_type:
try:
re_table = load_cmd_template(command, dev_type=device_type)
fsm = get_textfsm_object(re_table, results[idx])
self.append_parsed_results(device, self.map_parsed_results(command, fsm))
except:
log.msg("Unable to load TextFSM template, just updating with unstructured output")
ret.append(results[idx])

self.parsed_results = dict(self.parsed_results)
Expand Down
6 changes: 6 additions & 0 deletions trigger/conf/global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,12 @@
# Assign NETDEVICES_SOURCE to NETDEVICES_FILE for backwards compatibility
NETDEVICES_FILE = NETDEVICES_SOURCE

# TextFSM Vendor Mappings. Override this if you have defined your own TextFSM templates.
TEXTFSM_VENDOR_MAPPINGS = {
"cisco": [ "ios", "nxos" ],
"arista": [ "eos" ]
}

# TextFSM Template Path. Commando will attempt to match a given show command with a template within this folder.
TEXTFSM_TEMPLATE_DIR = os.getenv('TEXTFSM_TEMPLATE_DIR', os.path.join(PREFIX, 'vendor/ntc_templates'))

Expand Down
13 changes: 13 additions & 0 deletions trigger/netdevices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,19 @@ def bounce(self):
def shortName(self):
return self.nodeName.split('.', 1)[0]

@property
def os(self):
vendor_mapping = settings.TEXTFSM_VENDOR_MAPPINGS
try:
oss = vendor_mapping[self.vendor]
if self.operatingSystem.lower() in oss:
return "{0}_{1}".format(self.vendor, self.operatingSystem.lower())
except:
log.msg("""Unable to find template for given device.
Check to see if your netdevices object has the 'platform' key.
Otherwise template does not exist.""")
return None

def allowable(self, action, when=None):
"""
Return whether it's okay to perform the specified ``action``.
Expand Down

0 comments on commit bc0152c

Please sign in to comment.