From ec812cb6e0f502cce58b07e78b697031b1d75851 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sat, 2 Jul 2016 11:00:20 -0400 Subject: [PATCH 01/14] Updated test suite for macos --- .cache/v/cache/lastfailed | 1 + test/test_full.sh | 8 +++++++- test/test_queries.sh | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .cache/v/cache/lastfailed diff --git a/.cache/v/cache/lastfailed b/.cache/v/cache/lastfailed new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.cache/v/cache/lastfailed @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/test_full.sh b/test/test_full.sh index 720666e..819dc79 100755 --- a/test/test_full.sh +++ b/test/test_full.sh @@ -1,2 +1,8 @@ #/bin/sh -py.test-3 --resultlog=/tmp/pytest.log ngtest.py +export pytestcmd="py.test" + +if ! type "$pytestcmd" 2> /dev/null; then + export pytestcmd="py.test-3" +fi + +$pytestcmd --resultlog=/tmp/pytest.log ngtest.py diff --git a/test/test_queries.sh b/test/test_queries.sh index e8bdadd..7989218 100755 --- a/test/test_queries.sh +++ b/test/test_queries.sh @@ -1,2 +1,9 @@ #/bin/sh -py.test-3 --resultlog=/tmp/pytest.log ngtest.py::test_queries + +export pytestcmd="py.test-3" + +if ! type "$pytestcmd" 2> /dev/null; then + export pytestcmd="py.test" +fi + +$pytestcmd --resultlog=/tmp/pytest.log ngtest.py::test_queries From 821a41b466047a1850b05c46226a7da5848b8036 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sat, 2 Jul 2016 11:03:07 -0400 Subject: [PATCH 02/14] Fixed pytest-3 glitch --- test/test_full.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_full.sh b/test/test_full.sh index 819dc79..d18460a 100755 --- a/test/test_full.sh +++ b/test/test_full.sh @@ -1,8 +1,8 @@ #/bin/sh -export pytestcmd="py.test" +export pytestcmd="py.test-3" if ! type "$pytestcmd" 2> /dev/null; then - export pytestcmd="py.test-3" + export pytestcmd="py.test" fi $pytestcmd --resultlog=/tmp/pytest.log ngtest.py From e56cb1de9fea4a381fce5435675350aa9c80718f Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sat, 2 Jul 2016 11:19:55 -0400 Subject: [PATCH 03/14] Local commit test with VSC --- test/test_full.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_full.sh b/test/test_full.sh index d18460a..c39472e 100755 --- a/test/test_full.sh +++ b/test/test_full.sh @@ -1,6 +1,9 @@ #/bin/sh + +# Check for Ubuntu Python3 export pytestcmd="py.test-3" +# Revert to default pytest if ! type "$pytestcmd" 2> /dev/null; then export pytestcmd="py.test" fi From 767cc9fc4a2fc228d51bc313cb74f5f7554abeb8 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sat, 2 Jul 2016 13:29:42 -0400 Subject: [PATCH 04/14] Added -dev report to reporting module --- nglib/__init__.py | 1 - nglib/query/dev.py | 5 +++-- nglib/report/__init__.py | 41 +++++++++++++++++++++++++++++++++++++++- ngreport.py | 10 ++++++++-- ngtest.py | 3 ++- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/nglib/__init__.py b/nglib/__init__.py index bf4d991..f29f1dc 100644 --- a/nglib/__init__.py +++ b/nglib/__init__.py @@ -65,7 +65,6 @@ import nglib.query.nNode - logger = logging.getLogger(__name__) # Global variables diff --git a/nglib/query/dev.py b/nglib/query/dev.py index 1e7f43d..a61965b 100644 --- a/nglib/query/dev.py +++ b/nglib/query/dev.py @@ -42,7 +42,7 @@ verbose = 0 -def get_device(dev, rtype="TREE", vrange=None): +def get_device(dev, rtype="NGTREE", vrange=None): """Get Switch perspective (neighbors, vlans, routed networks)""" rtypes = ('TREE', 'JSON', 'YAML', 'NGTREE') @@ -52,7 +52,8 @@ def get_device(dev, rtype="TREE", vrange=None): ngtree = nglib.ngtree.get_ngtree(dev, tree_type="Device") - logger.info("Query: Device %s for %s", dev, nglib.user) + if rtype != "NGTREE": + logger.info("Query: Device %s for %s", dev, nglib.user) switch = nglib.bolt_ses.run( diff --git a/nglib/report/__init__.py b/nglib/report/__init__.py index 4b54f4b..9a5d533 100644 --- a/nglib/report/__init__.py +++ b/nglib/report/__init__.py @@ -82,6 +82,7 @@ def get_vlan_report(vrange, report="all", rtype="TREE"): if '_ccount' in etree.keys(): etree['Empty VLAN Count'] = etree['_ccount'] nglib.query.exp_ngtree(etree, rtype) + return etree else: print("No Empty Vlans in Range", vrange) @@ -133,9 +134,47 @@ def get_vlan_data(vrange, rtype): for v in vlans: vtree = nglib.query.vlan.search_vlan_id(v['vid'], allSwitches=allSwitches) nglib.ngtree.add_child_ngtree(pngtree, vtree) - return pngtree + +def get_dev_report(dev, rtype="NGTREE"): + """ + Get all devices on a regex + + Note: Only returns devices in a mgmt group + """ + + rtypes = ('TREE', 'JSON', 'YAML', 'NGTREE') + + if rtype in rtypes: + logger.info("Query: Generating Device Report (%s) for %s", dev, nglib.user) + + devices = nglib.bolt_ses.run( + 'MATCH(s:Switch) WHERE s.name =~ {dev} ' + + 'RETURN s.name AS name, s.mgmt AS mgmt ORDER BY name', + {"dev": dev}) + + ngtree = nglib.ngtree.get_ngtree("Report", tree_type="DEVs") + ngtree['Device Regex'] = dev + + for d in devices: + if d["mgmt"]: + cngtree = nglib.query.dev.get_device(d["name"]) + if cngtree: + nglib.ngtree.add_child_ngtree(ngtree, cngtree) + + # Found Devices, count and print + if '_ccount' in ngtree.keys(): + ngtree['Device Count'] = ngtree['_ccount'] + nglib.query.exp_ngtree(ngtree, rtype) + return ngtree + else: + print("No Devices found on regex:", dev) + + else: + raise Exception("RType Not Supported, use:" + str(rtypes)) + + def get_children(ngtree): """Return list of children and count in ngtree""" diff --git a/ngreport.py b/ngreport.py index d9cd342..01be309 100755 --- a/ngreport.py +++ b/ngreport.py @@ -69,7 +69,7 @@ action="store_true") parser.add_argument("--conf", metavar='file', help="Alternate Config File", type=str) parser.add_argument("--debug", help="Set debugging level", type=int) -parser.add_argument("--verbose", help="Verbose Output", action="store_true") +parser.add_argument("-v", help="Verbose Output", action="store_true") args = parser.parse_args() @@ -78,7 +78,7 @@ config_file = args.conf verbose = 0 -if args.verbose: +if args.v: verbose = 1 if args.debug: verbose = args.debug @@ -108,6 +108,12 @@ nglib.report.get_vlan_report(args.vrange, report=report, rtype=rtype) +elif args.dev: + rtype = "TREE" + if args.output: + rtype = args.output + + nglib.report.get_dev_report(args.dev, rtype=rtype) else: parser.print_help() diff --git a/ngtest.py b/ngtest.py index f5a25fd..197a2bc 100755 --- a/ngtest.py +++ b/ngtest.py @@ -73,7 +73,8 @@ # qtest['-rp 10.33.1.100 10.26.76.1'] = 'core1' rtest = dict() #rtest['-vlans -empty -vra 200'] = 'v6test' - +rtest['-vlans -vrange 120 -o yaml'] = 'Root: abc4mdf' +rtest['-v -dev "xyz.*" -o json'] = '"parent_switch": "core1"' # Update Tests (check for errors) utest = ('-ivrf', '-id', '-ind', '-inet', '-isnet', '-iasa', '-ivlan', '-uvlan') From 630c9158affc485a7bdf59d03d012a4a56a8b2aa Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 07:22:54 -0400 Subject: [PATCH 05/14] Skeleton code for VRF report, documentation update --- CONTRIBUTING.md | 2 +- nglib/report/__init__.py | 7 +++++++ ngreport.py | 12 +++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a7ce59..5c10ec9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ These are the early days of NetGrph, but I fully plan to support this program going forward and am looking for contributors. I am also the primary maintainer of the [Network Tracking Database (NetDB)](http://netdbtracking.sourceforge.net/), which is in production on some -extremely large network. NetGrph is currently serving as our internal model for +extremely large networks. NetGrph is currently serving as our internal model for network automation tasks, and we hope others find it useful as well. It's primary purpose is to do work at this time, from automation to troubleshooting tasks. diff --git a/nglib/report/__init__.py b/nglib/report/__init__.py index 9a5d533..2554d5e 100644 --- a/nglib/report/__init__.py +++ b/nglib/report/__init__.py @@ -137,6 +137,13 @@ def get_vlan_data(vrange, rtype): return pngtree +def get_vrf_report(vrf, rtype="NGTREE"): + """ + Get a report on vrfs that match regex + """ + return vrf + + def get_dev_report(dev, rtype="NGTREE"): """ Get all devices on a regex diff --git a/ngreport.py b/ngreport.py index 01be309..8a974bb 100755 --- a/ngreport.py +++ b/ngreport.py @@ -51,10 +51,9 @@ parser = argparse.ArgumentParser(prog='ngreport', description='Generate Reports from NetGrph') -parser.add_argument("-vrf", metavar='name', help="Generate a Report on a VRF", +parser.add_argument("-vrf", metavar='name', + help="Generate a Report on a VRF (.* for all)", type=str) -parser.add_argument("-vrfs", help="VRF Report on all VRFs", - action="store_true") parser.add_argument("-vlans", help="VLAN ID Report (combine with -vra and -e)", action="store_true") @@ -108,6 +107,13 @@ nglib.report.get_vlan_report(args.vrange, report=report, rtype=rtype) +elif args.vrf: + rtype = "TREE" + if args.output: + rtype = args.output + + nglib.report.get_vrf_report(args.vrf, rtype=rtype) + elif args.dev: rtype = "TREE" if args.output: From 3b5d5e079073dcbf722e3a904ff5a8a1dbf35f16 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 08:03:35 -0400 Subject: [PATCH 06/14] VRF Checkpoint --- .gitignore | 1 + nglib/report/__init__.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f2cf3e2..79df73a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ netgrphdev.ini netgrphtest.ini neo4j-queries.txt build-commands +.vscode/ diff --git a/nglib/report/__init__.py b/nglib/report/__init__.py index 2554d5e..93abf68 100644 --- a/nglib/report/__init__.py +++ b/nglib/report/__init__.py @@ -141,7 +141,21 @@ def get_vrf_report(vrf, rtype="NGTREE"): """ Get a report on vrfs that match regex """ - return vrf + rtypes = ('TREE', 'JSON', 'YAML', 'NGTREE') + + if rtype in rtypes: + logger.info("Query: Generating VRF Report (%s) for %s", vrf, nglib.user) + + vrfs = nglib.bolt_ses.run( + 'MATCH(v:VRF) WHERE v.name =~ {vrf} ' + + 'RETURN v.name AS name ORDER BY name', + {"vrf": vrf}) + + ngtree = nglib.ngtree.get_ngtree("Report", tree_type="VRFs") + ngtree['VRF Regex'] = vrf + + for v in vrfs: + print(v["name"]) def get_dev_report(dev, rtype="NGTREE"): From 52f9c1126f800b5c2ce25f8923c4b1960ed50e29 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 08:40:45 -0400 Subject: [PATCH 07/14] Refactored get_networks_on_group to get_networks_on_filter to handle stored config filters or dynamic filters. Completed ngreport on VRFs. --- netgrph.py | 6 +++++- nglib/__init__.py | 1 + nglib/query/__init__.py | 25 +++++++++++++++++-------- nglib/query/net.py | 36 ++++++++++++++++++++++-------------- nglib/report/__init__.py | 18 +++++++++++++++++- 5 files changed, 62 insertions(+), 24 deletions(-) diff --git a/netgrph.py b/netgrph.py index 37420ab..cbcc0cb 100755 --- a/netgrph.py +++ b/netgrph.py @@ -39,6 +39,7 @@ import argparse import nglib + # Default Config File Location config_file = '/etc/netgrph.ini' alt_config = './docs/netgrph.ini' @@ -134,16 +135,19 @@ if args.fpath: nglib.query.path.get_fw_path(args.fpath, args.search) + elif args.spath: rtype = "TREE" if args.output: rtype = args.output nglib.query.path.get_switch_path(args.spath, args.search, rtype=rtype) + elif args.rpath: rtype = "TREE" if args.output: rtype = args.output nglib.query.path.get_routed_path(args.rpath, args.search, rtype=rtype) + elif args.dev: rtype = "TREE" if args.output: @@ -167,7 +171,7 @@ rtype = "CSV" if args.output: rtype = args.output - nglib.query.net.get_networks_on_group(args.search, rtype=rtype) + nglib.query.net.get_networks_on_filter(args.search, rtype=rtype) elif args.group: nglib.query.vlan.get_vlans_on_group(args.search, args.vrange) diff --git a/nglib/__init__.py b/nglib/__init__.py index f29f1dc..bf4d991 100644 --- a/nglib/__init__.py +++ b/nglib/__init__.py @@ -65,6 +65,7 @@ import nglib.query.nNode + logger = logging.getLogger(__name__) # Global variables diff --git a/nglib/query/__init__.py b/nglib/query/__init__.py index dd6109e..752be1c 100644 --- a/nglib/query/__init__.py +++ b/nglib/query/__init__.py @@ -114,11 +114,11 @@ def get_net_filter(group): raise Exception("No Group Filter Found", group) -def check_net_filter(netDict, group): +def check_net_filter(netDict, group=None, nFilter=None): """ Filters Networks based on vrf:role (from supernets) - Needs optimization + Pass in a group filter to read from config, or a custom nFilter Examples: nst = all (all networks) @@ -136,7 +136,10 @@ def check_net_filter(netDict, group): com = default:printer """ - vDict = get_filter_dict(group) + if group: + vDict = get_filter_dict(group=group) + elif nFilter: + vDict = get_filter_dict(nFilter=nFilter) # Check filter against vDict for vrf in vDict.keys(): @@ -164,13 +167,19 @@ def check_net_filter(netDict, group): @functools.lru_cache(maxsize=1) -def get_filter_dict(group): - """Process config for group and cache it for each call""" +def get_filter_dict(group=None, nFilter=None): + """Process config for group or custom filter and cache it for each call""" vDict = dict() + gFilter = None - gFilter = config['NetAlertFilter'][group] - + if group: + gFilter = config['NetAlertFilter'][group] + elif nFilter: + gFilter = nFilter + else: + raise Exception("Must pass in group or filter") + # Split all VRFs by spaces vrfFilters = gFilter.rsplit() @@ -213,7 +222,7 @@ def universal_text_search(text, vrange, rtype="TREE"): #Look for group filter first try: get_net_filter(text) - nglib.query.net.get_networks_on_group(text, rtype=rtype) + nglib.query.net.get_networks_on_filter(text, rtype=rtype) found = True except: pass diff --git a/nglib/query/net.py b/nglib/query/net.py index 48d8564..5723891 100644 --- a/nglib/query/net.py +++ b/nglib/query/net.py @@ -129,32 +129,40 @@ def get_net_extended_tree(net, ip=None, ngtree=None, ngname="Networks"): return ngtree -def get_networks_on_group(group, rtype="CSV"): +def get_networks_on_filter(group=None, nFilter=None, rtype="NGTREE"): """ Get list of networks as CSV for a group in netgraph.ini """ - rtypes = ('CSV', 'TREE', 'JSON', 'YAML') + rtypes = ('CSV', 'TREE', 'JSON', 'YAML', 'NGTREE') if rtype in rtypes: - logger.info("Query: Network List %s for %s", group, nglib.user) + if rtype != "NGTREE": + logger.info("Query: Network List %s for %s", group, nglib.user) netList = [] ngtree = nglib.ngtree.get_ngtree("Networks", tree_type="NET") - ngtree['Group'] = group - try: - ngtree['Filter'] = nglib.query.get_net_filter(group) - except KeyError: - print("Error: No Group Found in Config", group) - return - except: - raise + if group: + ngtree['Group'] = group + + try: + ngtree['Filter'] = nglib.query.get_net_filter(group) + except KeyError: + print("Error: No Group Found in Config", group) + return + except: + raise + + # Custom Filter + elif nFilter: + ngtree['Filter'] = nFilter + else: + raise Exception("Must pass in group or nFilter") - # Get all networks - #networks = nglib.bolt_ses.run('MATCH (n:Network) RETURN n.vrfcidr as vrfcidr') + # Get all networks networks = nglib.bolt_ses.run( 'MATCH(n:Network), (n)--(v:VRF), (n)-[:ROUTED_BY]->(r:Switch:Router) ' + 'OPTIONAL MATCH (n)--(s:Supernet) OPTIONAL MATCH (n)-[:ROUTED_STANDBY]->(rs:Switch:Router) ' @@ -172,7 +180,7 @@ def get_networks_on_group(group, rtype="CSV"): netDict[key] = net[key] # Matches Filter - if len(netDict) and nglib.query.check_net_filter(netDict, group): + if len(netDict) and nglib.query.check_net_filter(netDict, group=group, nFilter=nFilter): netList.append(netDict) netDict['_type'] = "CIDR" diff --git a/nglib/report/__init__.py b/nglib/report/__init__.py index 93abf68..cd34fd9 100644 --- a/nglib/report/__init__.py +++ b/nglib/report/__init__.py @@ -154,8 +154,24 @@ def get_vrf_report(vrf, rtype="NGTREE"): ngtree = nglib.ngtree.get_ngtree("Report", tree_type="VRFs") ngtree['VRF Regex'] = vrf + # Process VRFs + tree_count = 0 for v in vrfs: - print(v["name"]) + tree_count += 1 + cngtree = nglib.query.net.get_networks_on_filter(nFilter=v["name"], rtype="NGTREE") + nglib.ngtree.add_child_ngtree(ngtree, cngtree) + + # Return output + if not tree_count: + print("No VRFs found on regex:", vrf) + elif tree_count == 1: + nglib.query.exp_ngtree(cngtree, rtype) + return ngtree + else: + nglib.query.exp_ngtree(ngtree, rtype) + return ngtree + else: + raise Exception("RType Not Supported, use:" + str(rtypes)) def get_dev_report(dev, rtype="NGTREE"): From 53b5d6510814c606526637034366c34d1ddc4bfc Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 08:44:32 -0400 Subject: [PATCH 08/14] Added -nfilter to netgrph to search on custom filters at runtime --- netgrph.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/netgrph.py b/netgrph.py index cbcc0cb..b6d980a 100755 --- a/netgrph.py +++ b/netgrph.py @@ -71,6 +71,8 @@ action="store_true") parser.add_argument("-nlist", help="Get all networks in an alert group", action="store_true") +parser.add_argument("-nfilter", help="Get all networks on a filter (see netgrph.ini)", + action="store_true") parser.add_argument("-dev", help="Get the Details for a Device (Switch/Router/FW)", action="store_true") parser.add_argument("-fpath", metavar="src", @@ -173,6 +175,12 @@ rtype = args.output nglib.query.net.get_networks_on_filter(args.search, rtype=rtype) +elif args.nfilter: + rtype = "CSV" + if args.output: + rtype = args.output + nglib.query.net.get_networks_on_filter(nFilter=args.search, rtype=rtype) + elif args.group: nglib.query.vlan.get_vlans_on_group(args.search, args.vrange) From 7df8c4fbff233fe2dd69d89b2764b6c938faf0a5 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 09:04:08 -0400 Subject: [PATCH 09/14] Updated test/dev config_file locations, base directory config overrides all others --- docs/TODO | 4 +-- docs/VERSION | 2 +- netgrph.ini | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ netgrph.py | 4 +-- ngreport.py | 12 +++++-- ngupdate.py | 4 +-- 6 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 netgrph.ini diff --git a/docs/TODO b/docs/TODO index a17f3ad..a445196 100644 --- a/docs/TODO +++ b/docs/TODO @@ -1,12 +1,10 @@ NetDB: -- Add CIDR usage for scope usage reporting +- Add CIDR scope usage reporting - Add more extensive device reporting Reporting: - - VRF Report - - Switch Report - No name, no root, no router report Other: diff --git a/docs/VERSION b/docs/VERSION index 63f2359..3d105a6 100644 --- a/docs/VERSION +++ b/docs/VERSION @@ -1 +1 @@ -v0.7.1 +v0.7.3 diff --git a/netgrph.ini b/netgrph.ini new file mode 100644 index 0000000..b85c562 --- /dev/null +++ b/netgrph.ini @@ -0,0 +1,98 @@ +# NetGrph INI File + +[Global] +enabled = 1 + +[nglib] +dbuser = neo4j +dbpass = your_passwd +dbhost = 128.23.185.119 +logfile = ./log/nglib.log + +# debuglib, infolib, info, warning, critical +loglevel = info +#loglevel = debuglib + +logcmd = /scripts/splunkalert/splunkalert.pl -m 15 -fs -cs +logurl = https://splunk.musc.edu/en-US/app/search/search?q=search%%20 + +#[netdb] +#host = localhost +#user = netdbadmin +#pass = nyet.sup4u + +[topology] +max_distance = 100 +seeds = core1,core2 +dist_exclude = (voip|hvt10\-mwavesw1) + + +[ngfiles] +#vrfs = /home/yantisj/csv/vrfs.csv +#devices = /home/yantisj/csv/devices.csv +#device_info = /home/yantisj/csv/devinfo.csv +#neighbors = /home/yantisj/csv/nd.csv +#networks = /home/yantisj/csv/allnets.csv +#vlans = /home/yantisj/csv/allvlans.csv +#supernets = /home/yantisj/csv/supernets.csv +#firewalls = /home/yantisj/csv/firewalls.csv + +vrfs = ./csv/vrfs.csv +devices = ./csv/devices.csv +device_info = ./csv/devinfo.csv +neighbors = ./csv/nd.csv +networks = ./csv/allnets.csv +vlans = ./csv/allvlans.csv +supernets = ./csv/supernets.csv +firewalls = ./csv/firewalls.csv + +[ngfw] +fwdir = /tftpboot/asafw/ + +[default_vrf] +usb-perim = perim +art-perim = perim +usb-border = outside +art-border = outside + +## NetAlert Section + +[Network] +seeds = core1,core2 + +[NetAlert] +from = nst@musc.edu +subject = New Network Alert +mailServer = mailhost.musc.edu + +[NetAlertGroups] +security = security@musc.edu +nst = nst@musc.edu +#jon = yantisj@musc.edu +#radonc = pacs-help@musc.edu +#mdt = mdt@musc.edu + + +# Filters Networks based on vrf:role (from supernets) +# Examples: +# nst = all (all networks) +# radonc = default:none|access-private|access-wan (default VRF only with no supernet role or roles in the new access layer supernets 10.177 etc) +# est = default:none|access-private|access-wan pci:all (EST wants all access layer networks plus all PCI networks) +# jci = fwutil:all (JCI Wants all fwutil networks) +# com = default:printer (COM wants only printer networks) + +[NetAlertFilter] +nst = all +security = all +access = default:none|access-private|access-private-wan +jon = all +perim = perim:none +#jon = default:none|access-private|access-private-wan +radonc = default:none|access-private|access-private-wan +mdt = default:none|access-private|access-wan pci:pci +flex = flex:all +jci = utility:utility +pci = pci:pci +dcaccess = default:dc-access +guest = wireless-guest:all guest:all +test_group = all diff --git a/netgrph.py b/netgrph.py index b6d980a..c78890a 100755 --- a/netgrph.py +++ b/netgrph.py @@ -47,9 +47,9 @@ # Test/Dev Config dirname = os.path.dirname(os.path.realpath(__file__)) if re.search(r'\/dev$', dirname): - config_file = 'netgrphdev.ini' + config_file = 'netgrph.ini' elif re.search(r'\/test$', dirname): - config_file = "netgrphtest.ini" + config_file = "netgrph.ini" parser = argparse.ArgumentParser() diff --git a/ngreport.py b/ngreport.py index 8a974bb..103c3bc 100755 --- a/ngreport.py +++ b/ngreport.py @@ -38,13 +38,14 @@ # Default Config File Location config_file = '/etc/netgrph.ini' +alt_config = './docs/netgrph.ini' # Test/Dev Config dirname = os.path.dirname(os.path.realpath(__file__)) if re.search(r'\/dev$', dirname): - config_file = 'netgrphdev.ini' + config_file = 'netgrph.ini' elif re.search(r'\/test$', dirname): - config_file = "netgrphtest.ini" + config_file = "netgrph.ini" parser = argparse.ArgumentParser() @@ -76,6 +77,13 @@ if args.conf: config_file = args.conf +# Test configuration exists +if not os.path.exists(config_file): + if not os.path.exists(alt_config): + raise Exception("Configuration File not found", config_file) + else: + config_file = alt_config + verbose = 0 if args.v: verbose = 1 diff --git a/ngupdate.py b/ngupdate.py index eb0ef6d..9c06739 100755 --- a/ngupdate.py +++ b/ngupdate.py @@ -50,9 +50,9 @@ # Test/Dev Config File dirname = os.path.dirname(os.path.realpath(__file__)) if re.search(r'\/dev$', dirname): - config_file = 'netgrphdev.ini' + config_file = 'netgrph.ini' elif re.search(r'\/test$', dirname): - config_file = "netgrphtest.ini" + config_file = "netgrph.ini" #print("Config:",config_file,dirname) From faa8408504adac963f7947c40bd83780b0e64f8c Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 09:20:39 -0400 Subject: [PATCH 10/14] Reverted to using netgrphdev.ini for testing --- netgrph.ini | 98 ----------------------------------------------------- netgrph.py | 4 +-- ngreport.py | 4 +-- ngupdate.py | 5 ++- 4 files changed, 6 insertions(+), 105 deletions(-) delete mode 100644 netgrph.ini diff --git a/netgrph.ini b/netgrph.ini deleted file mode 100644 index b85c562..0000000 --- a/netgrph.ini +++ /dev/null @@ -1,98 +0,0 @@ -# NetGrph INI File - -[Global] -enabled = 1 - -[nglib] -dbuser = neo4j -dbpass = your_passwd -dbhost = 128.23.185.119 -logfile = ./log/nglib.log - -# debuglib, infolib, info, warning, critical -loglevel = info -#loglevel = debuglib - -logcmd = /scripts/splunkalert/splunkalert.pl -m 15 -fs -cs -logurl = https://splunk.musc.edu/en-US/app/search/search?q=search%%20 - -#[netdb] -#host = localhost -#user = netdbadmin -#pass = nyet.sup4u - -[topology] -max_distance = 100 -seeds = core1,core2 -dist_exclude = (voip|hvt10\-mwavesw1) - - -[ngfiles] -#vrfs = /home/yantisj/csv/vrfs.csv -#devices = /home/yantisj/csv/devices.csv -#device_info = /home/yantisj/csv/devinfo.csv -#neighbors = /home/yantisj/csv/nd.csv -#networks = /home/yantisj/csv/allnets.csv -#vlans = /home/yantisj/csv/allvlans.csv -#supernets = /home/yantisj/csv/supernets.csv -#firewalls = /home/yantisj/csv/firewalls.csv - -vrfs = ./csv/vrfs.csv -devices = ./csv/devices.csv -device_info = ./csv/devinfo.csv -neighbors = ./csv/nd.csv -networks = ./csv/allnets.csv -vlans = ./csv/allvlans.csv -supernets = ./csv/supernets.csv -firewalls = ./csv/firewalls.csv - -[ngfw] -fwdir = /tftpboot/asafw/ - -[default_vrf] -usb-perim = perim -art-perim = perim -usb-border = outside -art-border = outside - -## NetAlert Section - -[Network] -seeds = core1,core2 - -[NetAlert] -from = nst@musc.edu -subject = New Network Alert -mailServer = mailhost.musc.edu - -[NetAlertGroups] -security = security@musc.edu -nst = nst@musc.edu -#jon = yantisj@musc.edu -#radonc = pacs-help@musc.edu -#mdt = mdt@musc.edu - - -# Filters Networks based on vrf:role (from supernets) -# Examples: -# nst = all (all networks) -# radonc = default:none|access-private|access-wan (default VRF only with no supernet role or roles in the new access layer supernets 10.177 etc) -# est = default:none|access-private|access-wan pci:all (EST wants all access layer networks plus all PCI networks) -# jci = fwutil:all (JCI Wants all fwutil networks) -# com = default:printer (COM wants only printer networks) - -[NetAlertFilter] -nst = all -security = all -access = default:none|access-private|access-private-wan -jon = all -perim = perim:none -#jon = default:none|access-private|access-private-wan -radonc = default:none|access-private|access-private-wan -mdt = default:none|access-private|access-wan pci:pci -flex = flex:all -jci = utility:utility -pci = pci:pci -dcaccess = default:dc-access -guest = wireless-guest:all guest:all -test_group = all diff --git a/netgrph.py b/netgrph.py index c78890a..156411f 100755 --- a/netgrph.py +++ b/netgrph.py @@ -47,9 +47,9 @@ # Test/Dev Config dirname = os.path.dirname(os.path.realpath(__file__)) if re.search(r'\/dev$', dirname): - config_file = 'netgrph.ini' + config_file = 'netgrphdev.ini' elif re.search(r'\/test$', dirname): - config_file = "netgrph.ini" + config_file = "netgrphdev.ini" parser = argparse.ArgumentParser() diff --git a/ngreport.py b/ngreport.py index 103c3bc..dcc39c9 100755 --- a/ngreport.py +++ b/ngreport.py @@ -43,9 +43,9 @@ # Test/Dev Config dirname = os.path.dirname(os.path.realpath(__file__)) if re.search(r'\/dev$', dirname): - config_file = 'netgrph.ini' + config_file = 'netgrphdev.ini' elif re.search(r'\/test$', dirname): - config_file = "netgrph.ini" + config_file = "netgrphdev.ini" parser = argparse.ArgumentParser() diff --git a/ngupdate.py b/ngupdate.py index 9c06739..76662b5 100755 --- a/ngupdate.py +++ b/ngupdate.py @@ -50,9 +50,9 @@ # Test/Dev Config File dirname = os.path.dirname(os.path.realpath(__file__)) if re.search(r'\/dev$', dirname): - config_file = 'netgrph.ini' + config_file = 'netgrphdev.ini' elif re.search(r'\/test$', dirname): - config_file = "netgrph.ini" + config_file = "netgrphdev.ini" #print("Config:",config_file,dirname) @@ -107,7 +107,6 @@ if args.conf: config_file = args.conf - # Test configuration exists if not os.path.exists(config_file): if not os.path.exists(alt_config): From a521ffe18bfbf2b090183b7f7d62767cff2a7b84 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 10:12:22 -0400 Subject: [PATCH 11/14] Fixed error handling for empty VRFs --- csv/vrfs.csv | 1 + docs/CHANGES.md | 6 +++++- nglib/query/net.py | 8 ++++---- nglib/report/__init__.py | 6 ++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/csv/vrfs.csv b/csv/vrfs.csv index c1a8345..fe52f2f 100644 --- a/csv/vrfs.csv +++ b/csv/vrfs.csv @@ -3,3 +3,4 @@ guest,10,Guest Network outside,1,External Networks perim,25,Perimeter DMZ Network utility,150,Utility Network +test,1,Test Empty VRF diff --git a/docs/CHANGES.md b/docs/CHANGES.md index f8387b7..d119245 100644 --- a/docs/CHANGES.md +++ b/docs/CHANGES.md @@ -1,6 +1,10 @@ +### v0.7.3 +- Added vrf and dev to ngreport +- Added nfilter to netgrph to pass in custom filters at runtime +- Cleaned up debug netgrph.ini handling -### 7/1/16 +### v0.7.0 - Created public repo - Added lots of documentation - Cleaned up config files diff --git a/nglib/query/net.py b/nglib/query/net.py index 5723891..ac7f967 100644 --- a/nglib/query/net.py +++ b/nglib/query/net.py @@ -30,7 +30,7 @@ """ NetGrph Query Network data """ - +import sys import ipaddress import logging import nglib @@ -65,7 +65,7 @@ def get_net(ip, rtype="TREE", days=7): return ngtree else: - print("Unsupport RType, try", str(rtypes)) + print("Unsupport RType, try", str(rtypes), file=sys.stderr) def get_net_extended_tree(net, ip=None, ngtree=None, ngname="Networks"): @@ -205,7 +205,7 @@ def get_networks_on_filter(group=None, nFilter=None, rtype="NGTREE"): ngtree = nglib.query.exp_ngtree(ngtree, rtype) return ngtree else: - print("No results found for filter:", ngtree['Filter']) + print("No results found for filter:", ngtree['Filter'], file=sys.stderr) else: raise Exception("RType Not Allowed, try: ", str(rtypes)) @@ -271,7 +271,7 @@ def get_networks_on_cidr(cidr, rtype="CSV"): print("No Results for", cidr) else: - raise Exception("RType Not Allowed, try: ", str(rtypes)) + raise Exception("RType Not Allowed, try: ", str(rtypes), file=sys.stderr) diff --git a/nglib/report/__init__.py b/nglib/report/__init__.py index cd34fd9..5385a33 100644 --- a/nglib/report/__init__.py +++ b/nglib/report/__init__.py @@ -159,11 +159,13 @@ def get_vrf_report(vrf, rtype="NGTREE"): for v in vrfs: tree_count += 1 cngtree = nglib.query.net.get_networks_on_filter(nFilter=v["name"], rtype="NGTREE") - nglib.ngtree.add_child_ngtree(ngtree, cngtree) + if cngtree: + tree_count += 1 + nglib.ngtree.add_child_ngtree(ngtree, cngtree) # Return output if not tree_count: - print("No VRFs found on regex:", vrf) + print("No VRFs found on regex:", vrf, file=sys.stderr) elif tree_count == 1: nglib.query.exp_ngtree(cngtree, rtype) return ngtree From 4171f462836dda4d49dab07cc058d19b94b2356d Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 17:55:59 -0400 Subject: [PATCH 12/14] Updated path output and error handling for default CIDR match --- cypher/constraints.cyp | 1 - docs/TODO | 1 + nglib/query/dev.py | 10 ++++++++-- nglib/query/net.py | 14 +++++++++++--- nglib/query/path.py | 27 +++++++++++++++++---------- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/cypher/constraints.cyp b/cypher/constraints.cyp index 653feae..9b49299 100644 --- a/cypher/constraints.cyp +++ b/cypher/constraints.cyp @@ -1,7 +1,6 @@ -- Create constraints on DB for consistency and performance --CREATE Garbage CREATE CONSTRAINT ON (n:Network) ASSERT n.vrfcidr IS UNIQUE -CREATE CONSTRAINT ON (m:MgmtGroup) ASSERT m.name IS UNIQUE CREATE CONSTRAINT ON (s:Switch) ASSERT s.name IS UNIQUE CREATE CONSTRAINT ON (v:VRF) ASSERT v.name IS UNIQUE CREATE CONSTRAINT ON (v:VLAN) ASSERT v.name IS UNIQUE diff --git a/docs/TODO b/docs/TODO index a445196..dfdeaa3 100644 --- a/docs/TODO +++ b/docs/TODO @@ -10,6 +10,7 @@ Reporting: Other: - Add VRF to -rpath - Add master -path to netgrph +- Add tabular output option Maintenance: - Add switch skip on certain neighbors diff --git a/nglib/query/dev.py b/nglib/query/dev.py index a61965b..4cdca2b 100644 --- a/nglib/query/dev.py +++ b/nglib/query/dev.py @@ -34,6 +34,7 @@ """ import logging import re +import sys import nglib import nglib.ngtree import nglib.ngtree.export @@ -63,7 +64,12 @@ def get_device(dev, rtype="NGTREE", vrange=None): for sw in switch: - ngtree['Distance'] = int(sw['distance']) + try: + ngtree['Distance'] = int(sw['distance']) + except TypeError: + print("Error, device not part of the topology:", dev, file=sys.stderr) + return + ngtree['MGMT Group'] = sw['mgmt'] if vrange: ngtree['VLAN Range'] = vrange @@ -132,7 +138,7 @@ def get_device(dev, rtype="NGTREE", vrange=None): nglib.query.exp_ngtree(ngtree, rtype) return ngtree - print("No results found for device:", dev) + print("No results found for device:", dev, file=sys.stderr) def get_neighbors(dev): """ diff --git a/nglib/query/net.py b/nglib/query/net.py index ac7f967..0e018d7 100644 --- a/nglib/query/net.py +++ b/nglib/query/net.py @@ -54,15 +54,20 @@ def get_net(ip, rtype="TREE", days=7): if rtype in rtypes: net = nglib.query.net.find_cidr(ip) ngtree = get_net_extended_tree(net, ip=ip, ngname="IP Object") + print(ngtree) if nglib.use_netdb: hours = days * 24 netdbtree = nglib.netdb.ip.get_netdb_ip(ip, hours=hours) if netdbtree: nglib.ngtree.add_child_ngtree(ngtree, netdbtree) + # Export NGTree - ngtree = nglib.query.exp_ngtree(ngtree, rtype) - return ngtree + if ngtree: + ngtree = nglib.query.exp_ngtree(ngtree, rtype) + return ngtree + else: + print("No CIDR results for IP search:", ip, file=sys.stderr) else: print("Unsupport RType, try", str(rtypes), file=sys.stderr) @@ -93,7 +98,7 @@ def get_net_extended_tree(net, ip=None, ngtree=None, ngname="Networks"): if n.sr: standby = getJSONProperties(n.sr)['name'] - # Not already found + # Cache: Not already found if nProp['vrfcidr'] not in matches.keys(): matches[nProp['vrfcidr']] = 1 cngt = nglib.ngtree.get_ngtree(nProp['cidr'], tree_type="CIDR") @@ -125,6 +130,8 @@ def get_net_extended_tree(net, ip=None, ngtree=None, ngname="Networks"): elif verbose > 3: print("Existing Matches", nProp['vrfcidr']) + else: + return return ngtree @@ -291,6 +298,7 @@ def find_cidr(ip): print(ip + " in " + r.cidr) mostSpecific = compare_cidr(mostSpecific, r.cidr) + return mostSpecific diff --git a/nglib/query/path.py b/nglib/query/path.py index a5a9e8a..28b7b31 100644 --- a/nglib/query/path.py +++ b/nglib/query/path.py @@ -32,6 +32,7 @@ """ import re +import sys import logging import subprocess import nglib @@ -64,7 +65,9 @@ def get_switch_path(switch1, switch2, rtype="NGTREE"): switch1, switch2, nglib.user) pathList = [] - ngtree = nglib.ngtree.get_ngtree("Switched Paths", tree_type="SPATHS") + ngtree = nglib.ngtree.get_ngtree("Switched Paths", tree_type="SPATHs") + ngtree["Path"] = switch1 + " -> " + switch2 + dist = dict() swp = nglib.py2neo_ses.cypher.execute( @@ -117,7 +120,7 @@ def get_switch_path(switch1, switch2, rtype="NGTREE"): def get_routed_path(net1, net2, rtype="NGTREE"): """ Find the routed path between two CIDRs and return all interfaces and - devices between the two. This query is currently highly unoptimized. + devices between the two. This query need optimization. - net1 and net2 can be IPs, and it will find the CIDR - Uses Neo4j All Shortest Paths on ROUTED Relationships @@ -140,14 +143,18 @@ def get_routed_path(net1, net2, rtype="NGTREE"): if re.search(r'^\d+\.\d+\.\d+\.\d+$', net2): n2tree = nglib.query.net.get_net(net2, rtype="NGTREE") - net2 = n2tree['_child001']['Name'] + if n2tree: + net2 = n2tree['_child001']['Name'] + + + ngtree = nglib.ngtree.get_ngtree("Routed Paths", tree_type="RPATHs") + ngtree["Path"] = net1 + " -> " + net2 pathList = [] pathRec = [] - ngtree = nglib.ngtree.get_ngtree("Routed Paths", tree_type="RPATHS") - + # Finds all paths, then finds the relationships rtrp = nglib.py2neo_ses.cypher.execute( 'MATCH (sn:Network), (dn:Network), rp = allShortestPaths ' + '((sn)-[:ROUTED|ROUTED_BY|ROUTED_STANDBY*0..12]-(dn)) ' @@ -221,7 +228,7 @@ def get_routed_path(net1, net2, rtype="NGTREE"): ngtree = nglib.query.exp_ngtree(ngtree, rtype) return ngtree else: - print("No results found for path between {:} and {:}".format(net1, net2)) + print("No results found for path between {:} and {:}".format(net1, net2), file=sys.stderr) return @@ -231,7 +238,7 @@ def get_fw_path(src, dst): srcnet = nglib.query.net.find_cidr(src) dstnet = nglib.query.net.find_cidr(dst) - logger.info("Query: Tracing %s --> %s for %s", src, dst, nglib.user) + logger.info("Query: Tracing %s -> %s for %s", src, dst, nglib.user) if verbose: print("\nFinding security path from {:} -> {:}:\n".format(srcnet, dstnet)) @@ -253,7 +260,7 @@ def get_fw_path(src, dst): dn = r.d dnp = nglib.query.nNode.getJSONProperties(dn) - path = snp['cidr'] + " --> " + path = snp['cidr'] + " -> " # Path nodes = r.p.nodes @@ -261,10 +268,10 @@ def get_fw_path(src, dst): nProp = nglib.query.nNode.getJSONProperties(node) label = nglib.query.nNode.getLabel(node) if re.search('VRF', label): - path = path + "VRF:" + nProp['name'] + " --> " + path = path + "VRF:" + nProp['name'] + " -> " if re.search('FW', label): - path = path + nProp['name'] + " --> " + path = path + nProp['name'] + " -> " fwsearch[nProp['name']] = nProp['hostname'] + "," + nProp['logIndex'] path = path + dnp['cidr'] From 0c35fbe9491d7378d202c06034d081c17908e0cb Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Sun, 3 Jul 2016 18:35:07 -0400 Subject: [PATCH 13/14] Added terminal size awareness to VLAN group printing --- docs/CHANGES.md | 1 + docs/TODO | 5 +++-- nglib/query/net.py | 1 - nglib/query/vlan.py | 15 +++++++++++++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/CHANGES.md b/docs/CHANGES.md index d119245..ec0e59a 100644 --- a/docs/CHANGES.md +++ b/docs/CHANGES.md @@ -3,6 +3,7 @@ - Added vrf and dev to ngreport - Added nfilter to netgrph to pass in custom filters at runtime - Cleaned up debug netgrph.ini handling +- VLAN Group printing follows terminal size ### v0.7.0 - Created public repo diff --git a/docs/TODO b/docs/TODO index dfdeaa3..e52db7b 100644 --- a/docs/TODO +++ b/docs/TODO @@ -11,10 +11,11 @@ Other: - Add VRF to -rpath - Add master -path to netgrph - Add tabular output option +- built-in paging support +- Group report takes up entire console Maintenance: - Add switch skip on certain neighbors - Rewrite nglib.net_update using Bolt as Pythonic - Emulate dict with ngtree -- built-in paging support -- Group report takes up entire console + diff --git a/nglib/query/net.py b/nglib/query/net.py index 0e018d7..48f0445 100644 --- a/nglib/query/net.py +++ b/nglib/query/net.py @@ -54,7 +54,6 @@ def get_net(ip, rtype="TREE", days=7): if rtype in rtypes: net = nglib.query.net.find_cidr(ip) ngtree = get_net_extended_tree(net, ip=ip, ngname="IP Object") - print(ngtree) if nglib.use_netdb: hours = days * 24 diff --git a/nglib/query/vlan.py b/nglib/query/vlan.py index e1c0286..ed0decd 100644 --- a/nglib/query/vlan.py +++ b/nglib/query/vlan.py @@ -32,6 +32,7 @@ """ import sys +import os import logging import nglib from nglib.query.nNode import getJSONProperties @@ -421,13 +422,23 @@ def get_vlans_on_group(group, vrange): print("Total: " + str(vtotal)) print() print(" VID Name Sw/Macs/Ports Root Switches") - print("------------------------------------------------------------------------------------------------") + + # Header Size + try: + tsize = os.get_terminal_size() + tsize = tsize.columns + except OSError: + tsize = 80 + print("-" * tsize) + for en in sortedList: + slen = tsize - 65 + swl = '' for sw in en['switches']: swl = swl + " " + sw - swlt = (swl[:36] + '..') if len(swl) > 36 else swl + swlt = (swl[:slen] + '..') if len(swl) > slen else swl counts = "{:3>}/{:4>}/{:<4}".format( str(en['scount']), str(en['mcount']), str(en['pcount'])) From f110aa9369ab15ed1c3e76f2381b21f9696b5ea3 Mon Sep 17 00:00:00 2001 From: Jonathan Yantis Date: Mon, 4 Jul 2016 06:52:14 -0400 Subject: [PATCH 14/14] Added router list to ngreport vrf --- docs/INSTALL.md | 8 +++++--- nglib/query/dev.py | 17 +++++++++++++++++ nglib/report/__init__.py | 2 ++ test/first_import.sh | 3 +++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index b7a0a07..e0594f9 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -51,14 +51,16 @@ sudo pip3 install -r requirements.txt - Browse to the database web interface and run `MATCH (s:Switch) RETURN s` - Try out some sample commands -## Sample netgrph for use with test data +## Sample commands for use with test data ``` +./netgrph.py -nf all +./netgrph.py -nf all -o tree +./ngreport.py -dev ".*" ./netgrph.py abc4mdf -./netgrph.py abc4mdf -o csv ./netgrph.py abc4mdf -o json ./netgrph.py abc4mdf -o yaml ./netgrph.py -sp abc2sw1 xyz2sw1 -./netgrph.py -sp abc.* xyz.* +./netgrph.py -sp abc.* xyz.* -o csv ./netgrph.py 120 ./netgrph.py 1246 ./netgrph.py -fp 10.1.120.50 8.8.8.8 diff --git a/nglib/query/dev.py b/nglib/query/dev.py index 4cdca2b..7835ce6 100644 --- a/nglib/query/dev.py +++ b/nglib/query/dev.py @@ -259,4 +259,21 @@ def get_vlans(dev, vrange=None): if vlan['mcount']: vt['MAC Count'] = vlan['mcount'] return vtree + + +def get_devlist_vrf(vrf): + """Returns a list of devices that route a VRF""" + + devices = nglib.bolt_ses.run( + 'MATCH(v:VRF)-[e:VRF_ON]-(r:Router) WHERE v.name = {vrf} ' + + 'RETURN r.name AS name ORDER BY name', + {"vrf": vrf}) + + devlist = [] + + for r in devices: + devlist.append(r["name"]) + + return devlist + #END diff --git a/nglib/report/__init__.py b/nglib/report/__init__.py index 5385a33..4133a3c 100644 --- a/nglib/report/__init__.py +++ b/nglib/report/__init__.py @@ -160,6 +160,8 @@ def get_vrf_report(vrf, rtype="NGTREE"): tree_count += 1 cngtree = nglib.query.net.get_networks_on_filter(nFilter=v["name"], rtype="NGTREE") if cngtree: + devlist = nglib.query.dev.get_devlist_vrf(v["name"]) + cngtree["Routers"] = devlist tree_count += 1 nglib.ngtree.add_child_ngtree(ngtree, cngtree) diff --git a/test/first_import.sh b/test/first_import.sh index 7681090..95f9b97 100755 --- a/test/first_import.sh +++ b/test/first_import.sh @@ -1,4 +1,5 @@ #!/bin/sh +./ngupdate.py -v --dropDatabase ./ngupdate.py -ivrf -v ./ngupdate.py -id -v ./ngupdate.py -ind -v @@ -9,3 +10,5 @@ ./ngupdate.py -ifw -v ./ngupdate.py -v -ifile ./cypher/buildfw.cyp ./ngupdate.py -v -ifile ./cypher/constraints.cyp +./ngupdate.py -full -v +./test/test_full.sh