From a13c62f4f7f7a91a4b7de81ce0f0d5a5daf93140 Mon Sep 17 00:00:00 2001 From: Thomas Scott Date: Fri, 10 Nov 2023 14:39:21 -0500 Subject: [PATCH 1/8] allow multiple sites --- README.md | 12 +++++----- docs/CONFIGURATION.md | 4 ++-- jupyter/ntopex.ipynb | 14 ++++++------ nrx.conf | 4 ++-- nrx/nrx.py | 51 ++++++++++++++++++++++++------------------- tests/colo/nrx.conf | 4 ++-- tests/dc1/nrx.conf | 4 ++-- tests/dc2/nrx.conf | 4 ++-- tests/h88/nrx.conf | 4 ++-- tests/lrg/nrx.conf | 4 ++-- tests/site1/nrx.conf | 4 ++-- 11 files changed, 58 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index c1ff11f..e6de12e 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ optional arguments: -i, --input INPUT input source: netbox (default) | cyjs -o, --output OUTPUT output format: cyjs | gml | clab | cml | graphite | d2 -a, --api API netbox API URL - -s, --site SITE netbox site to export + -s, --sites SITES netbox site(s) to export, for multiple sites use a comma-separated list: site1,site2,site3 (uses OR logic) -t, --tags TAGS netbox tags to export, for multiple tags use a comma-separated list: tag1,tag2,tag3 (uses AND logic) -n, --noconfigs disable device configuration export (enabled by default) -k, --insecure allow insecure server connections when using TLS @@ -194,7 +194,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --templates templates --output clab --dir demo --site DM-Albany + ./nrx.py --api https://demo.netbox.dev --templates templates --output clab --dir demo --sites DM-Albany ``` 2. Now you're ready to start the Containerlab topology. Here is the example for "DM-Albany" site @@ -207,7 +207,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --site DM-Albany --dir demo + ./nrx.py --api https://demo.netbox.dev --sites DM-Albany --dir demo ``` 5. If you have a CYJS file, run `./nrx.py --input cyjs --file .cyjs --output clab` to create a Containerlab topology file from the CYJS graph you exported in the previous step. For example, run: @@ -222,7 +222,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --templates templates --output cml --dir demo --site DM-Akron + ./nrx.py --api https://demo.netbox.dev --templates templates --output cml --dir demo --sites DM-Akron ``` 2. Now you're ready to start the "DM-Akron" topology in CML. @@ -237,7 +237,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --dir demo --site DM-Akron + ./nrx.py --api https://demo.netbox.dev --dir demo --sites DM-Akron ``` 4. If you have a CYJS file, run `./nrx.py --input cyjs --file .cyjs --output cml` to create a topology file from the CYJS graph you exported in the previous step. For example, run: @@ -256,7 +256,7 @@ Follow a two-step process: ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --site DM-Akron --templates templates --output graphite + ./nrx.py --api https://demo.netbox.dev --sites DM-Akron --templates templates --output graphite ``` 2. Start Graphite to visualize "DM-Akron" site: diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index a32c689..032cc11 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -29,8 +29,8 @@ TEMPLATES_PATH = ['templates'] # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['router', 'core-switch', 'distribution-switch', 'access-switch', 'tor-switch', 'server'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'DM-Akron' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['DM-Akron'] # NetBox tags to export. Alternatively, use --tags argument EXPORT_TAGS = [] # Export device configurations, when available diff --git a/jupyter/ntopex.ipynb b/jupyter/ntopex.ipynb index 0d578fa..f7480d8 100644 --- a/jupyter/ntopex.ipynb +++ b/jupyter/ntopex.ipynb @@ -24,7 +24,7 @@ "metadata": {}, "outputs": [], "source": [ - "export_site = \"nr-1\"\n", + "export_sites = [\"nr-1\"]\n", "nb_api_url = 'https://demo.netbox.dev'\n", "nb_api_token = 'd2fa978199167d24f75aa477fc24a1a59eba9db7'\n", "export_device_roles = [\"router\", \"core-switch\", \"access-switch\", \"distribution-switch\", \"tor-switch\"]" @@ -107,7 +107,7 @@ } ], "source": [ - "s = nb.dcim.sites.get(name=export_site)\n", + "s = nb.dcim.sites.get(name=export_sites)\n", "nodes, devices, interfaces = [], [], []\n", "device_ids, interface_ids, cable_ids = [], [], []\n", "for device in list(nb.dcim.devices.filter(site_id=s.id,role=export_device_roles)):\n", @@ -167,7 +167,7 @@ ], "source": [ "import networkx as nx\n", - "G = nx.Graph(name=export_site)\n", + "G = nx.Graph(name=export_sites)\n", "\n", "for cable in list(nb.dcim.cables.filter(id=cable_ids)):\n", " if len(cable.a_terminations) == 1 and len(cable.b_terminations) == 1:\n", @@ -235,7 +235,7 @@ "id": "2a78d1be", "metadata": {}, "source": [ - "Serialize the graph into GML format and save it as `.gml`" + "Serialize the graph into GML format and save it as `.gml`" ] }, { @@ -400,7 +400,7 @@ ], "source": [ "print(\"\\n\".join(nx.generate_gml(G)))\n", - "nx.write_gml(G, export_site+\".gml\")\n" + "nx.write_gml(G, export_sites+\".gml\")\n" ] }, { @@ -409,7 +409,7 @@ "id": "9cd785d6", "metadata": {}, "source": [ - "Also export in Cytoscape JSON format `.cyjs`" + "Also export in Cytoscape JSON format `.cyjs`" ] }, { @@ -634,7 +634,7 @@ "import json\n", "cyjs = nx.cytoscape_data(G)\n", "print(json.dumps(cyjs, indent=4))\n", - "with open(export_site + \".cyjs\", 'w', encoding='utf-8') as f:\n", + "with open(export_sites + \".cyjs\", 'w', encoding='utf-8') as f:\n", " json.dump(cyjs, f, indent=4)" ] } diff --git a/nrx.conf b/nrx.conf index fd712ff..401b608 100644 --- a/nrx.conf +++ b/nrx.conf @@ -12,8 +12,8 @@ OUTPUT_FORMAT = 'clab' OUTPUT_DIR = 'demo' # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['router', 'core-switch', 'distribution-switch', 'access-switch', 'tor-switch', 'server'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'DM-Akron' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['DM-Akron'] # NetBox tags to export. Alternatively, use --tags argument EXPORT_TAGS = [] # Export device configurations, when available diff --git a/nrx/nrx.py b/nrx/nrx.py index 276fad8..13505d7 100755 --- a/nrx/nrx.py +++ b/nrx/nrx.py @@ -123,15 +123,17 @@ class NBFactory: def __init__(self, config): self.config = config self.nb_net = NBNetwork() - if len(config['export_site']) > 0: - self.topology_name = config['export_site'] + if len(config['export_sites']) > 1: + self.topology_name = "__".join(config['export_sites']) + elif len(config['export_sites']) > 0: + self.topology_name = config['export_sites'][0] elif len(config['export_tags']) > 0: self.topology_name = "-".join(config['export_tags']) self.G = nx.Graph(name=self.topology_name) self.nb_session = pynetbox.api(self.config['nb_api_url'], token=self.config['nb_api_token'], threading=True) - self.nb_site = None + self.nb_sites = None if not config['tls_validate']: self.nb_session.http_session.verify = False urllib3.disable_warnings() @@ -140,16 +142,16 @@ def __init__(self, config): self.nb_session.http_session.mount("http://", adapter) self.nb_session.http_session.mount("https://", adapter) print(f"Connecting to NetBox at: {config['nb_api_url']}") - if len(config['export_site']) > 0: - debug(f"Fetching site: {config['export_site']}") + if len(config['export_sites']) > 0: + debug(f"Fetching sites: {config['export_sites']}") try: - self.nb_site = self.nb_session.dcim.sites.get(name=config['export_site']) + self.nb_sites = self.nb_session.dcim.sites.filter(name=config['export_sites']) except (pynetbox.core.query.RequestError, pynetbox.core.query.ContentError) as e: error("NetBox API failure at get site:", e) - if self.nb_site is None: - error(f"Site not found: {config['export_site']}") + if self.nb_sites is None: + error(f"One of these site not found: {config['export_site']}") else: - print(f"Fetching devices from site: {config['export_site']}") + print(f"Fetching devices from sites: {config['export_sites']}") else: print(f"Fetching devices with tags: {','.join(config['export_tags'])}") @@ -189,15 +191,20 @@ def _get_nb_objects(self, kind, block_size): def _get_nb_devices(self): """Get device list from NetBox filtered by site, tags and device roles""" - devices = None - if self.nb_site is None: - devices = self.nb_session.dcim.devices.filter(tag=self.config['export_tags'], + devices = [] + if len(self.nb_sites) == 0: + devices.append(self.nb_session.dcim.devices.filter(tag=self.config['export_tags'], role=self.config['export_device_roles']) + ) else: - devices = self.nb_session.dcim.devices.filter(site_id=self.nb_site.id, - tag=self.config['export_tags'], - role=self.config['export_device_roles']) - for device in list(devices): + site_ids = [] + for site in self.nb_sites: + debug(f'Site ID: {site.id} - Site Name: {site.name}') + site_ids.append(str(site.id)) + devices = self.nb_session.dcim.devices.filter(site_id=site_ids, + tag=self.config['export_tags'], + role=self.config['export_device_roles']) + for device in devices: d = self._init_device(device) self.nb_net.nodes.append(d) d["node_id"] = len(self.nb_net.nodes) - 1 @@ -766,7 +773,7 @@ def parse_args(): parser.add_argument('-o', '--output', required=False, help='output format: cyjs | gml | clab | cml | graphite | d2', type=arg_output_check, ) parser.add_argument('-a', '--api', required=False, help='netbox API URL') - parser.add_argument('-s', '--site', required=False, help='netbox site to export') + parser.add_argument('-s', '--sites', required=False, help='netbox site to export') parser.add_argument('-t', '--tags', required=False, help='netbox tags to export, for multiple tags use a comma-separated list: tag1,tag2,tag3 (uses AND logic)') parser.add_argument('-n', '--noconfigs', required=False, help='disable device configuration export (enabled by default)', action=argparse.BooleanOptionalAction) @@ -810,7 +817,7 @@ def load_toml_config(filename): 'super-spine': 3, 'router': 4, }, - 'export_site': '', + 'export_sites': [], 'export_tags': [], 'export_configs': True, 'templates_path': ['.'], @@ -846,13 +853,13 @@ def config_apply_netbox_args(config, args): error("Need an API URL to connect to NetBox.\nUse --api argument, NB_API_URL environment variable or key in --config file") if len(config['nb_api_token']) == 0: error("Need an API token to connect to NetBox.\nUse NB_API_TOKEN environment variable or key in --config file") - if args.site is not None and len(args.site) > 0: - config['export_site'] = args.site + if args.sites is not None and len(args.sites) > 0: + config['export_sites'] = args.sites.split(',') if args.tags is not None and len(args.tags) > 0: config['export_tags'] = args.tags.split(',') debug(f"List of tags to filter devices for export: {config['export_tags']}") - if len(config['export_site']) == 0 and len(config['export_tags']) == 0: - error("Need a Site name or Tags to export. Use --site/--tags arguments, or EXPORT_SITE/EXPORT_TAGS key in --config file") + if len(config['export_sites']) == 0 and len(config['export_tags']) == 0: + error("Need a Site name or Tags to export. Use --sites/--tags arguments, or EXPORT_SITE/EXPORT_TAGS key in --config file") if args.noconfigs is not None: if args.noconfigs: config['export_configs'] = False diff --git a/tests/colo/nrx.conf b/tests/colo/nrx.conf index 4bb5b01..4a9be38 100644 --- a/tests/colo/nrx.conf +++ b/tests/colo/nrx.conf @@ -4,7 +4,7 @@ OUTPUT_FORMAT = 'cyjs' TEMPLATES_PATH = ['../../../templates'] # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['access-switch'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'colo' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['colo'] # Output directory. Alternatively, use --dir argument OUTPUT_DIR = '.' \ No newline at end of file diff --git a/tests/dc1/nrx.conf b/tests/dc1/nrx.conf index 6316b32..f094366 100644 --- a/tests/dc1/nrx.conf +++ b/tests/dc1/nrx.conf @@ -4,7 +4,7 @@ OUTPUT_FORMAT = 'clab' TEMPLATES_PATH = ['../../../templates'] # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['server','access-switch','leaf','spine','tor-switch'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'dc1' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['dc1'] # Output directory. Alternatively, use --dir argument OUTPUT_DIR = '.' \ No newline at end of file diff --git a/tests/dc2/nrx.conf b/tests/dc2/nrx.conf index 1cd1b04..3c38c0f 100644 --- a/tests/dc2/nrx.conf +++ b/tests/dc2/nrx.conf @@ -6,7 +6,7 @@ TEMPLATES_PATH = ['../../../templates'] TLS_VALIDATE = false # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['tor-switch', 'spine', 'server'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'dc2' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['dc2'] # Output directory. Alternatively, use --dir argument OUTPUT_DIR = '.' \ No newline at end of file diff --git a/tests/h88/nrx.conf b/tests/h88/nrx.conf index 0ef436a..faa8d8a 100644 --- a/tests/h88/nrx.conf +++ b/tests/h88/nrx.conf @@ -4,8 +4,8 @@ TLS_VALIDATE = true OUTPUT_FORMAT = 'clab' # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['router', 'core-switch', 'distribution-switch', 'access-switch', 'tor-switch'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'HQ' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['HQ'] # Templates path TEMPLATES_PATH = ['../../../templates'] # Output directory. Alternatively, use --dir argument diff --git a/tests/lrg/nrx.conf b/tests/lrg/nrx.conf index f41d56a..053ed3f 100644 --- a/tests/lrg/nrx.conf +++ b/tests/lrg/nrx.conf @@ -4,8 +4,8 @@ OUTPUT_FORMAT = 'clab' TEMPLATES_PATH = ['../../../templates'] # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['server','leaf','spine','core'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'lrg' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['lrg'] # Output directory. Alternatively, use --dir argument OUTPUT_DIR = '.' # Netbox API bulk queries optimization diff --git a/tests/site1/nrx.conf b/tests/site1/nrx.conf index 502d7de..c74d5b9 100644 --- a/tests/site1/nrx.conf +++ b/tests/site1/nrx.conf @@ -4,7 +4,7 @@ OUTPUT_FORMAT = 'cyjs' TEMPLATES_PATH = ['../../../templates'] # List of NetBox Device Roles to export EXPORT_DEVICE_ROLES = ['router','server'] -# NetBox Site to export. Alternatively, use --site argument -EXPORT_SITE = 'site1' +# NetBox Site to export. Alternatively, use --sites argument +EXPORT_SITES = ['site1'] # Output directory. Alternatively, use --dir argument OUTPUT_DIR = '.' \ No newline at end of file From 812a7b5dd11acb7b0f1abaeb3f937edbdcdf342f Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:31:06 -0800 Subject: [PATCH 2/8] equal --site and --sites --- Makefile | 32 ++++++++++++++++++-- nrx/nrx.py | 61 +++++++++++++++++++++----------------- tests/dc1/nrx-no-site.conf | 10 +++++++ 3 files changed, 74 insertions(+), 29 deletions(-) create mode 100644 tests/dc1/nrx-no-site.conf diff --git a/Makefile b/Makefile index 8006724..cf244fa 100644 --- a/Makefile +++ b/Makefile @@ -2,15 +2,23 @@ lint: pylint nrx/*.py test-local: test-dc1 test-dc2 test-colo test-site1 test-h88 test-lrg -test: test-dc1-cyjs-2-clab test-dc2-cyjs-2-cml test-site1-cyjs-2-clab test-site1-cyjs-2-clab-rename test-dc1-cyjs-2-graphite test-dc2-cyjs-2-graphite test-h88-cyjs-2-clab test-dc1-cyjs-2-d2 test-lrg-cyjs-2-graphite +test: test-args test-dc1-cyjs-2-clab test-dc2-cyjs-2-cml test-site1-cyjs-2-clab test-site1-cyjs-2-clab-rename test-dc1-cyjs-2-graphite test-dc2-cyjs-2-graphite test-h88-cyjs-2-clab test-dc1-cyjs-2-d2 test-lrg-cyjs-2-graphite -test-dc1: test-dc1-nb-2-cyjs-current test-dc1-nb-2-cyjs-latest test-dc1-cyjs-2-clab test-dc1-cyjs-2-graphite test-dc1-cyjs-2-d2 +test-args: test-args-site-and-sites +test-dc1: test-dc1-nb-2-cyjs-current test-dc1-nb-2-cyjs-latest test-dc1-nb-2-cyjs-single-site test-dc1-nb-2-cyjs-single-sites test-dc1-cyjs-2-clab test-dc1-cyjs-2-graphite test-dc1-cyjs-2-d2 test-dc2: test-dc2-nb-2-cyjs-current test-dc2-nb-2-cyjs-latest test-dc2-cyjs-2-cml test-dc2-cyjs-2-graphite test-colo: test-colo-nb-2-cyjs-current test-colo-nb-2-cyjs-latest test-site1: test-site1-nb-2-cyjs-current test-site1-nb-2-cyjs-latest test-site1-cyjs-2-clab test-site1-cyjs-2-clab-rename test-h88: test-h88-nb-2-cyjs-current test-h88-nb-2-cyjs-latest test-h88-nb-2-cyjs-latest-noconfigs test-h88-cyjs-2-clab test-lrg: test-lrg-nb-2-cyjs-latest test-lrg-cyjs-2-graphite +test-args-site-and-sites: + @echo "#################################################################" + @echo "# Simulteneous use of site and sites should fail" + @echo "#################################################################" + ! ./nrx.py --site dc1 --sites dc1,dc2 -d + @echo + test-dc1-nb-2-cyjs-current: @echo "#################################################################" @echo "# DC1: read from NetBox current version and export as CYJS" @@ -31,6 +39,26 @@ test-dc1-nb-2-cyjs-latest: diff dc1.cyjs ../data/dc1.cyjs @echo +test-dc1-nb-2-cyjs-single-site: + @echo "#################################################################" + @echo "# Single site DC1: read from NetBox current version and export as CYJS" + @echo "#################################################################" + mkdir -p tests/dc1/test && cd tests/dc1/test && rm -rf * && \ + source ../../.env_current && \ + ../../../nrx.py -c ../nrx-no-site.conf -o cyjs --site dc1 -d && \ + diff dc1.cyjs ../data/dc1.cyjs + @echo + +test-dc1-nb-2-cyjs-single-sites: + @echo "#################################################################" + @echo "# Single site DC1: read from NetBox current version and export as CYJS" + @echo "#################################################################" + mkdir -p tests/dc1/test && cd tests/dc1/test && rm -rf * && \ + source ../../.env_current && \ + ../../../nrx.py -c ../nrx-no-site.conf -o cyjs --sites dc1 -d && \ + diff dc1.cyjs ../data/dc1.cyjs + @echo + test-dc1-cyjs-2-clab: @echo "#################################################################" @echo "# DC1: read from CYJS and export as Containerlab" diff --git a/nrx/nrx.py b/nrx/nrx.py index f565d00..e6f927b 100755 --- a/nrx/nrx.py +++ b/nrx/nrx.py @@ -127,7 +127,7 @@ def __init__(self, config): if len(config['topology_name']) > 0: self.topology_name = config['topology_name'] elif len(config['export_sites']) > 1: - self.topology_name = "__".join(config['export_sites']) + self.topology_name = "-".join(config['export_sites']) elif len(config['export_sites']) > 0: self.topology_name = config['export_sites'][0] elif len(config['export_tags']) > 0: @@ -768,31 +768,36 @@ def arg_output_check(s): def parse_args(): """CLI arguments parser""" - parser = argparse.ArgumentParser(prog='nrx', description="nrx - network topology exporter by netreplica") - parser.add_argument('-c', '--config', required=False, help='configuration file') - parser.add_argument('-i', '--input', required=False, help='input source: netbox (default) | cyjs', - default='netbox', type=arg_input_check,) - parser.add_argument('-o', '--output', required=False, help='output format: cyjs | gml | clab | cml | graphite | d2', - type=arg_output_check, ) - parser.add_argument('-a', '--api', required=False, help='netbox API URL') - parser.add_argument('-s', '--sites', required=False, help='netbox site to export') - parser.add_argument('-t', '--tags', required=False, help='netbox tags to export, for multiple tags use a comma-separated list: tag1,tag2,tag3 (uses AND logic)') - parser.add_argument('-n', '--name', required=False, help='name of the exported topology (site name or tags by default)') - parser.add_argument('--noconfigs', required=False, help='disable device configuration export (enabled by default)', - action=argparse.BooleanOptionalAction) - parser.add_argument('-k', '--insecure', required=False, help='allow insecure server connections when using TLS', - action=argparse.BooleanOptionalAction) - parser.add_argument('-d', '--debug', required=False, help='enable debug output', - action=argparse.BooleanOptionalAction) - parser.add_argument('-f', '--file', required=False, help='file with the network graph to import') - parser.add_argument('-T', '--templates', required=False, help='directory with template files, \ - will be prepended to TEMPLATES_PATH list \ - in the configuration file') - parser.add_argument('-D', '--dir', required=False, help='save files into specified directory. \ - nested relative and absolute paths are OK \ - (topology name is used by default)') - - args = parser.parse_args() + args_parser = argparse.ArgumentParser(prog='nrx', description="nrx - network topology exporter by netreplica") + + sites_group = args_parser.add_mutually_exclusive_group() + + args_parser.add_argument('-c', '--config', required=False, help='configuration file') + args_parser.add_argument('-i', '--input', required=False, help='input source: netbox (default) | cyjs', + default='netbox', type=arg_input_check,) + args_parser.add_argument('-o', '--output', required=False, help='output format: cyjs | gml | clab | cml | graphite | d2', + type=arg_output_check, ) + args_parser.add_argument('-a', '--api', required=False, help='netbox API URL') + sites_group.add_argument('-s', '--site', required=False, help='netbox site to export') + sites_group.add_argument( '--sites', required=False, help='comma-separated list of netbox sites to export') + args_parser.add_argument('-t', '--tags', required=False, help='netbox tags to export, for multiple tags use a comma-separated list: \ + tag1,tag2,tag3 (uses AND logic)') + args_parser.add_argument('-n', '--name', required=False, help='name of the exported topology (site name or tags by default)') + args_parser.add_argument( '--noconfigs', required=False, help='disable device configuration export (enabled by default)', + action=argparse.BooleanOptionalAction) + args_parser.add_argument('-k', '--insecure', required=False, help='allow insecure server connections when using TLS', + action=argparse.BooleanOptionalAction) + args_parser.add_argument('-d', '--debug', required=False, help='enable debug output', + action=argparse.BooleanOptionalAction) + args_parser.add_argument('-f', '--file', required=False, help='file with the network graph to import') + args_parser.add_argument('-T', '--templates', required=False, help='directory with template files, \ + will be prepended to TEMPLATES_PATH list \ + in the configuration file') + args_parser.add_argument('-D', '--dir', required=False, help='save files into specified directory. \ + nested relative and absolute paths are OK \ + (topology name is used by default)') + + args = args_parser.parse_args() global DEBUG_ON DEBUG_ON = args.debug is True debug(f"arguments {args}") @@ -857,7 +862,9 @@ def config_apply_netbox_args(config, args): error("Need an API URL to connect to NetBox.\nUse --api argument, NB_API_URL environment variable or key in --config file") if len(config['nb_api_token']) == 0: error("Need an API token to connect to NetBox.\nUse NB_API_TOKEN environment variable or key in --config file") - if args.sites is not None and len(args.sites) > 0: + if args.site is not None and len(args.site) > 0: + config['export_sites'] = args.site.split(',') # --site and --sites can be used interchangeably but not at the same time + elif args.sites is not None and len(args.sites) > 0: config['export_sites'] = args.sites.split(',') if args.tags is not None and len(args.tags) > 0: config['export_tags'] = args.tags.split(',') diff --git a/tests/dc1/nrx-no-site.conf b/tests/dc1/nrx-no-site.conf new file mode 100644 index 0000000..ac8c6f4 --- /dev/null +++ b/tests/dc1/nrx-no-site.conf @@ -0,0 +1,10 @@ +# Output format to use for export: 'gml' | 'cyjs' | 'clab'. Alternatively, use --output argument +OUTPUT_FORMAT = 'clab' +# Templates path +TEMPLATES_PATH = ['../../../templates'] +# List of NetBox Device Roles to export +EXPORT_DEVICE_ROLES = ['server','access-switch','leaf','spine','tor-switch'] +# NetBox Site to export. Alternatively, use --sites argument +;EXPORT_SITES = ['dc1'] +# Output directory. Alternatively, use --dir argument +OUTPUT_DIR = '.' \ No newline at end of file From 6b534e0330e63b782c3616157fdf42e75160bd5d Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:41:52 -0800 Subject: [PATCH 3/8] tests for multisite --- Makefile | 22 +- tests/dc1/data/dc1-dc2.cyjs | 1776 ++++++++++++++++++++++++++ tests/dc1/data/dc1-dc2.graphite.json | 578 +++++++++ 3 files changed, 2375 insertions(+), 1 deletion(-) create mode 100644 tests/dc1/data/dc1-dc2.cyjs create mode 100644 tests/dc1/data/dc1-dc2.graphite.json diff --git a/Makefile b/Makefile index cf244fa..803061a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ test-local: test-dc1 test-dc2 test-colo test-site1 test-h88 test-lrg test: test-args test-dc1-cyjs-2-clab test-dc2-cyjs-2-cml test-site1-cyjs-2-clab test-site1-cyjs-2-clab-rename test-dc1-cyjs-2-graphite test-dc2-cyjs-2-graphite test-h88-cyjs-2-clab test-dc1-cyjs-2-d2 test-lrg-cyjs-2-graphite test-args: test-args-site-and-sites -test-dc1: test-dc1-nb-2-cyjs-current test-dc1-nb-2-cyjs-latest test-dc1-nb-2-cyjs-single-site test-dc1-nb-2-cyjs-single-sites test-dc1-cyjs-2-clab test-dc1-cyjs-2-graphite test-dc1-cyjs-2-d2 +test-dc1: test-dc1-nb-2-cyjs-current test-dc1-nb-2-cyjs-latest test-dc1-nb-2-cyjs-single-site test-dc1-nb-2-cyjs-single-sites test-dc1-cyjs-2-clab test-dc1-cyjs-2-graphite test-dc1-cyjs-2-d2 test-dc1-dc2-nb-2-cyjs-sites test-dc1-dc2-cyjs-2-graphite + test-dc2: test-dc2-nb-2-cyjs-current test-dc2-nb-2-cyjs-latest test-dc2-cyjs-2-cml test-dc2-cyjs-2-graphite test-colo: test-colo-nb-2-cyjs-current test-colo-nb-2-cyjs-latest test-site1: test-site1-nb-2-cyjs-current test-site1-nb-2-cyjs-latest test-site1-cyjs-2-clab test-site1-cyjs-2-clab-rename @@ -59,6 +60,16 @@ test-dc1-nb-2-cyjs-single-sites: diff dc1.cyjs ../data/dc1.cyjs @echo +test-dc1-dc2-nb-2-cyjs-sites: + @echo "#################################################################" + @echo "# Two site DC1 and DC2: read from NetBox current version and export as CYJS" + @echo "#################################################################" + mkdir -p tests/dc1/test && cd tests/dc1/test && rm -rf * && \ + source ../../.env_current && \ + ../../../nrx.py -c ../nrx-no-site.conf -o cyjs --sites dc1,dc2 -d && \ + diff dc1-dc2.cyjs ../data/dc1-dc2.cyjs + @echo + test-dc1-cyjs-2-clab: @echo "#################################################################" @echo "# DC1: read from CYJS and export as Containerlab" @@ -77,6 +88,15 @@ test-dc1-cyjs-2-graphite: for f in *; do echo Comparing file $$f ...; diff $$f ../data/$$f || exit 1; done @echo +test-dc1-dc2-cyjs-2-graphite: + @echo "#################################################################" + @echo "# DC1 and DC2: read from CYJS and export as graphite" + @echo "#################################################################" + mkdir -p tests/dc1/graphite && cd tests/dc1/graphite && rm -rf * && \ + ../../../nrx.py -c ../nrx-no-site.conf -i cyjs -f ../data/dc1-dc2.cyjs -o graphite -d && \ + for f in *; do echo Comparing file $$f ...; diff $$f ../data/$$f || exit 1; done + @echo + test-dc1-cyjs-2-d2: @echo "#################################################################" @echo "# DC1: read from CYJS and export as d2" diff --git a/tests/dc1/data/dc1-dc2.cyjs b/tests/dc1/data/dc1-dc2.cyjs new file mode 100644 index 0000000..3e2b811 --- /dev/null +++ b/tests/dc1/data/dc1-dc2.cyjs @@ -0,0 +1,1776 @@ +{ + "data": [ + [ + "name", + "dc1-dc2" + ] + ], + "directed": false, + "multigraph": false, + "elements": { + "nodes": [ + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 15, + "type": "device", + "name": "dc1-leaf-1", + "node_id": 0, + "site": "dc1", + "platform": "sr-linux", + "platform_name": "Nokia SR-Linux", + "vendor": "nokia", + "vendor_name": "Nokia", + "model": "7220-ixr-d2", + "model_name": "7220 IXR-D2", + "role": "leaf", + "role_name": "Leaf", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 0 + }, + "id": "0", + "value": 0, + "name": "0" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 13, + "type": "device", + "name": "dc1-spine-1", + "node_id": 4, + "site": "dc1", + "platform": "eos", + "platform_name": "Arista EOS", + "vendor": "arista", + "vendor_name": "Arista", + "model": "dcs-7280cr3-32p4", + "model_name": "DCS-7280CR3-32P4", + "role": "spine", + "role_name": "Spine", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 4 + }, + "id": "4", + "value": 4, + "name": "4" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 671, + "type": "interface", + "name": "ethernet-1/49", + "node_id": 21, + "interface_index": 1 + }, + "id": "21", + "value": 21, + "name": "21" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 549, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 32, + "interface_index": 12 + }, + "id": "32", + "value": 32, + "name": "32" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 14, + "type": "device", + "name": "dc1-spine-2", + "node_id": 5, + "site": "dc1", + "platform": "eos", + "platform_name": "Arista EOS", + "vendor": "arista", + "vendor_name": "Arista", + "model": "dcs-7280cr3-32p4", + "model_name": "DCS-7280CR3-32P4", + "role": "spine", + "role_name": "Spine", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 5 + }, + "id": "5", + "value": 5, + "name": "5" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 672, + "type": "interface", + "name": "ethernet-1/50", + "node_id": 22, + "interface_index": 2 + }, + "id": "22", + "value": 22, + "name": "22" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 586, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 37, + "interface_index": 17 + }, + "id": "37", + "value": 37, + "name": "37" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 16, + "type": "device", + "name": "dc1-leaf-2", + "node_id": 1, + "site": "dc1", + "platform": "sr-linux", + "platform_name": "Nokia SR-Linux", + "vendor": "nokia", + "vendor_name": "Nokia", + "model": "7220-ixr-d2", + "model_name": "7220 IXR-D2", + "role": "leaf", + "role_name": "Leaf", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 1 + }, + "id": "1", + "value": 1, + "name": "1" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 727, + "type": "interface", + "name": "ethernet-1/49", + "node_id": 24, + "interface_index": 4 + }, + "id": "24", + "value": 24, + "name": "24" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 550, + "type": "interface", + "name": "Ethernet2/1", + "node_id": 33, + "interface_index": 13 + }, + "id": "33", + "value": 33, + "name": "33" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 728, + "type": "interface", + "name": "ethernet-1/50", + "node_id": 25, + "interface_index": 5 + }, + "id": "25", + "value": 25, + "name": "25" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 587, + "type": "interface", + "name": "Ethernet2/1", + "node_id": 38, + "interface_index": 18 + }, + "id": "38", + "value": 38, + "name": "38" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 17, + "type": "device", + "name": "dc1-leaf-3", + "node_id": 2, + "site": "dc1", + "platform": "sr-linux", + "platform_name": "Nokia SR-Linux", + "vendor": "nokia", + "vendor_name": "Nokia", + "model": "7220-ixr-d2", + "model_name": "7220 IXR-D2", + "role": "leaf", + "role_name": "Leaf", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 2 + }, + "id": "2", + "value": 2, + "name": "2" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 783, + "type": "interface", + "name": "ethernet-1/49", + "node_id": 27, + "interface_index": 7 + }, + "id": "27", + "value": 27, + "name": "27" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 551, + "type": "interface", + "name": "Ethernet3/1", + "node_id": 34, + "interface_index": 14 + }, + "id": "34", + "value": 34, + "name": "34" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 784, + "type": "interface", + "name": "ethernet-1/50", + "node_id": 28, + "interface_index": 8 + }, + "id": "28", + "value": 28, + "name": "28" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 588, + "type": "interface", + "name": "Ethernet3/1", + "node_id": 39, + "interface_index": 19 + }, + "id": "39", + "value": 39, + "name": "39" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 18, + "type": "device", + "name": "dc1-leaf-4", + "node_id": 3, + "site": "dc1", + "platform": "sr-linux", + "platform_name": "Nokia SR-Linux", + "vendor": "nokia", + "vendor_name": "Nokia", + "model": "7220-ixr-d2", + "model_name": "7220 IXR-D2", + "role": "leaf", + "role_name": "Leaf", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 3 + }, + "id": "3", + "value": 3, + "name": "3" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 839, + "type": "interface", + "name": "ethernet-1/49", + "node_id": 30, + "interface_index": 10 + }, + "id": "30", + "value": 30, + "name": "30" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 552, + "type": "interface", + "name": "Ethernet4/1", + "node_id": 35, + "interface_index": 15 + }, + "id": "35", + "value": 35, + "name": "35" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 840, + "type": "interface", + "name": "ethernet-1/50", + "node_id": 31, + "interface_index": 11 + }, + "id": "31", + "value": 31, + "name": "31" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 589, + "type": "interface", + "name": "Ethernet4/1", + "node_id": 40, + "interface_index": 20 + }, + "id": "40", + "value": 40, + "name": "40" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 21, + "type": "device", + "name": "dc2-tor-1", + "node_id": 16, + "site": "dc2", + "platform": "cisco-nxos-9000", + "platform_name": "Cisco NX-OS 9000", + "vendor": "cisco", + "vendor_name": "Cisco", + "model": "n9k-c93108tc-ex", + "model_name": "Nexus 93108TC-EX", + "role": "tor-switch", + "role_name": "TOR Switch", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 16 + }, + "id": "16", + "value": 16, + "name": "16" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 19, + "type": "device", + "name": "dc2-spine-1", + "node_id": 10, + "site": "dc2", + "platform": "cisco-nxos-9000", + "platform_name": "Cisco NX-OS 9000", + "vendor": "cisco", + "vendor_name": "Cisco", + "model": "n9k-c9336c-fx2", + "model_name": "Nexus 9336C-FX2", + "role": "spine", + "role_name": "Spine", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 10 + }, + "id": "10", + "value": 10, + "name": "10" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 969, + "type": "interface", + "name": "Ethernet1/49", + "node_id": 58, + "interface_index": 38 + }, + "id": "58", + "value": 58, + "name": "58" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 847, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 45, + "interface_index": 25 + }, + "id": "45", + "value": 45, + "name": "45" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 20, + "type": "device", + "name": "dc2-spine-2", + "node_id": 11, + "site": "dc2", + "platform": "cisco-nxos-9000", + "platform_name": "Cisco NX-OS 9000", + "vendor": "cisco", + "vendor_name": "Cisco", + "model": "n9k-c9336c-fx2", + "model_name": "Nexus 9336C-FX2", + "role": "spine", + "role_name": "Spine", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 11 + }, + "id": "11", + "value": 11, + "name": "11" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 970, + "type": "interface", + "name": "Ethernet1/50", + "node_id": 59, + "interface_index": 39 + }, + "id": "59", + "value": 59, + "name": "59" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 884, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 49, + "interface_index": 29 + }, + "id": "49", + "value": 49, + "name": "49" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 22, + "type": "device", + "name": "dc2-tor-2", + "node_id": 17, + "site": "dc2", + "platform": "cisco-nxos-9000", + "platform_name": "Cisco NX-OS 9000", + "vendor": "cisco", + "vendor_name": "Cisco", + "model": "n9k-c93108tc-ex", + "model_name": "Nexus 93108TC-EX", + "role": "tor-switch", + "role_name": "TOR Switch", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 17 + }, + "id": "17", + "value": 17, + "name": "17" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1024, + "type": "interface", + "name": "Ethernet1/49", + "node_id": 61, + "interface_index": 41 + }, + "id": "61", + "value": 61, + "name": "61" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 848, + "type": "interface", + "name": "Ethernet1/2", + "node_id": 46, + "interface_index": 26 + }, + "id": "46", + "value": 46, + "name": "46" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1025, + "type": "interface", + "name": "Ethernet1/50", + "node_id": 62, + "interface_index": 42 + }, + "id": "62", + "value": 62, + "name": "62" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 885, + "type": "interface", + "name": "Ethernet1/2", + "node_id": 50, + "interface_index": 30 + }, + "id": "50", + "value": 50, + "name": "50" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 23, + "type": "device", + "name": "dc2-tor-3", + "node_id": 18, + "site": "dc2", + "platform": "cisco-nxos-9000", + "platform_name": "Cisco NX-OS 9000", + "vendor": "cisco", + "vendor_name": "Cisco", + "model": "n9k-c93108tc-ex", + "model_name": "Nexus 93108TC-EX", + "role": "tor-switch", + "role_name": "TOR Switch", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 18 + }, + "id": "18", + "value": 18, + "name": "18" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1079, + "type": "interface", + "name": "Ethernet1/49", + "node_id": 64, + "interface_index": 44 + }, + "id": "64", + "value": 64, + "name": "64" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 849, + "type": "interface", + "name": "Ethernet1/3", + "node_id": 47, + "interface_index": 27 + }, + "id": "47", + "value": 47, + "name": "47" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1080, + "type": "interface", + "name": "Ethernet1/50", + "node_id": 65, + "interface_index": 45 + }, + "id": "65", + "value": 65, + "name": "65" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 886, + "type": "interface", + "name": "Ethernet1/3", + "node_id": 51, + "interface_index": 31 + }, + "id": "51", + "value": 51, + "name": "51" + } + }, + { + "data": { + "side": "a", + "type": "device", + "device": { + "id": 24, + "type": "device", + "name": "dc2-tor-4", + "node_id": 19, + "site": "dc2", + "platform": "cisco-nxos-9000", + "platform_name": "Cisco NX-OS 9000", + "vendor": "cisco", + "vendor_name": "Cisco", + "model": "n9k-c93108tc-ex", + "model_name": "Nexus 93108TC-EX", + "role": "tor-switch", + "role_name": "TOR Switch", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 19 + }, + "id": "19", + "value": 19, + "name": "19" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1134, + "type": "interface", + "name": "Ethernet1/49", + "node_id": 67, + "interface_index": 47 + }, + "id": "67", + "value": 67, + "name": "67" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 850, + "type": "interface", + "name": "Ethernet1/4", + "node_id": 48, + "interface_index": 28 + }, + "id": "48", + "value": 48, + "name": "48" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1135, + "type": "interface", + "name": "Ethernet1/50", + "node_id": 68, + "interface_index": 48 + }, + "id": "68", + "value": 68, + "name": "68" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 887, + "type": "interface", + "name": "Ethernet1/4", + "node_id": 52, + "interface_index": 32 + }, + "id": "52", + "value": 52, + "name": "52" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 25, + "type": "device", + "name": "dc2-srv-1", + "node_id": 12, + "site": "dc2", + "platform": "ubuntu", + "platform_name": "Ubuntu", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 12 + }, + "id": "12", + "value": 12, + "name": "12" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 921, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 57, + "interface_index": 37 + }, + "id": "57", + "value": 57, + "name": "57" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1141, + "type": "interface", + "name": "Gig-E 1", + "node_id": 53, + "interface_index": 33 + }, + "id": "53", + "value": 53, + "name": "53" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 26, + "type": "device", + "name": "dc2-srv-2", + "node_id": 13, + "site": "dc2", + "platform": "ubuntu", + "platform_name": "Ubuntu", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 13 + }, + "id": "13", + "value": 13, + "name": "13" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 976, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 60, + "interface_index": 40 + }, + "id": "60", + "value": 60, + "name": "60" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1146, + "type": "interface", + "name": "Gig-E 1", + "node_id": 54, + "interface_index": 34 + }, + "id": "54", + "value": 54, + "name": "54" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 27, + "type": "device", + "name": "dc2-srv-3", + "node_id": 14, + "site": "dc2", + "platform": "ubuntu", + "platform_name": "Ubuntu", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 14 + }, + "id": "14", + "value": 14, + "name": "14" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1031, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 63, + "interface_index": 43 + }, + "id": "63", + "value": 63, + "name": "63" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1151, + "type": "interface", + "name": "Gig-E 1", + "node_id": 55, + "interface_index": 35 + }, + "id": "55", + "value": 55, + "name": "55" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 28, + "type": "device", + "name": "dc2-srv-4", + "node_id": 15, + "site": "dc2", + "platform": "ubuntu", + "platform_name": "Ubuntu", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 15 + }, + "id": "15", + "value": 15, + "name": "15" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 1086, + "type": "interface", + "name": "Ethernet1/1", + "node_id": 66, + "interface_index": 46 + }, + "id": "66", + "value": 66, + "name": "66" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1156, + "type": "interface", + "name": "Gig-E 1", + "node_id": 56, + "interface_index": 36 + }, + "id": "56", + "value": 56, + "name": "56" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 29, + "type": "device", + "name": "dc1-srv-1", + "node_id": 6, + "site": "dc1", + "platform": "linux", + "platform_name": "Linux", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 6 + }, + "id": "6", + "value": 6, + "name": "6" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 623, + "type": "interface", + "name": "ethernet-1/1", + "node_id": 20, + "interface_index": 0 + }, + "id": "20", + "value": 20, + "name": "20" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1161, + "type": "interface", + "name": "Gig-E 1", + "node_id": 41, + "interface_index": 21 + }, + "id": "41", + "value": 41, + "name": "41" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 30, + "type": "device", + "name": "dc1-srv-2", + "node_id": 7, + "site": "dc1", + "platform": "linux", + "platform_name": "Linux", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 7 + }, + "id": "7", + "value": 7, + "name": "7" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 679, + "type": "interface", + "name": "ethernet-1/1", + "node_id": 23, + "interface_index": 3 + }, + "id": "23", + "value": 23, + "name": "23" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1166, + "type": "interface", + "name": "Gig-E 1", + "node_id": 42, + "interface_index": 22 + }, + "id": "42", + "value": 42, + "name": "42" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 31, + "type": "device", + "name": "dc1-srv-3", + "node_id": 8, + "site": "dc1", + "platform": "linux", + "platform_name": "Linux", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 8 + }, + "id": "8", + "value": 8, + "name": "8" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 735, + "type": "interface", + "name": "ethernet-1/1", + "node_id": 26, + "interface_index": 6 + }, + "id": "26", + "value": 26, + "name": "26" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1171, + "type": "interface", + "name": "Gig-E 1", + "node_id": 43, + "interface_index": 23 + }, + "id": "43", + "value": 43, + "name": "43" + } + }, + { + "data": { + "side": "b", + "type": "device", + "device": { + "id": 32, + "type": "device", + "name": "dc1-srv-4", + "node_id": 9, + "site": "dc1", + "platform": "linux", + "platform_name": "Linux", + "vendor": "dell", + "vendor_name": "Dell", + "model": "dell_poweredge_r640", + "model_name": "PowerEdge R640", + "role": "server", + "role_name": "server", + "primary_ip4": "", + "primary_ip6": "", + "config": "", + "device_index": 9 + }, + "id": "9", + "value": 9, + "name": "9" + } + }, + { + "data": { + "side": "a", + "type": "interface", + "interface": { + "id": 791, + "type": "interface", + "name": "ethernet-1/1", + "node_id": 29, + "interface_index": 9 + }, + "id": "29", + "value": 29, + "name": "29" + } + }, + { + "data": { + "side": "b", + "type": "interface", + "interface": { + "id": 1176, + "type": "interface", + "name": "Gig-E 1", + "node_id": 44, + "interface_index": 24 + }, + "id": "44", + "value": 44, + "name": "44" + } + } + ], + "edges": [ + { + "data": { + "source": 0, + "target": 21 + } + }, + { + "data": { + "source": 0, + "target": 22 + } + }, + { + "data": { + "source": 0, + "target": 20 + } + }, + { + "data": { + "source": 4, + "target": 32 + } + }, + { + "data": { + "source": 4, + "target": 33 + } + }, + { + "data": { + "source": 4, + "target": 34 + } + }, + { + "data": { + "source": 4, + "target": 35 + } + }, + { + "data": { + "source": 21, + "target": 32 + } + }, + { + "data": { + "source": 5, + "target": 37 + } + }, + { + "data": { + "source": 5, + "target": 38 + } + }, + { + "data": { + "source": 5, + "target": 39 + } + }, + { + "data": { + "source": 5, + "target": 40 + } + }, + { + "data": { + "source": 22, + "target": 37 + } + }, + { + "data": { + "source": 1, + "target": 24 + } + }, + { + "data": { + "source": 1, + "target": 25 + } + }, + { + "data": { + "source": 1, + "target": 23 + } + }, + { + "data": { + "source": 24, + "target": 33 + } + }, + { + "data": { + "source": 25, + "target": 38 + } + }, + { + "data": { + "source": 2, + "target": 27 + } + }, + { + "data": { + "source": 2, + "target": 28 + } + }, + { + "data": { + "source": 2, + "target": 26 + } + }, + { + "data": { + "source": 27, + "target": 34 + } + }, + { + "data": { + "source": 28, + "target": 39 + } + }, + { + "data": { + "source": 3, + "target": 30 + } + }, + { + "data": { + "source": 3, + "target": 31 + } + }, + { + "data": { + "source": 3, + "target": 29 + } + }, + { + "data": { + "source": 30, + "target": 35 + } + }, + { + "data": { + "source": 31, + "target": 40 + } + }, + { + "data": { + "source": 16, + "target": 58 + } + }, + { + "data": { + "source": 16, + "target": 59 + } + }, + { + "data": { + "source": 16, + "target": 57 + } + }, + { + "data": { + "source": 10, + "target": 45 + } + }, + { + "data": { + "source": 10, + "target": 46 + } + }, + { + "data": { + "source": 10, + "target": 47 + } + }, + { + "data": { + "source": 10, + "target": 48 + } + }, + { + "data": { + "source": 58, + "target": 45 + } + }, + { + "data": { + "source": 11, + "target": 49 + } + }, + { + "data": { + "source": 11, + "target": 50 + } + }, + { + "data": { + "source": 11, + "target": 51 + } + }, + { + "data": { + "source": 11, + "target": 52 + } + }, + { + "data": { + "source": 59, + "target": 49 + } + }, + { + "data": { + "source": 17, + "target": 61 + } + }, + { + "data": { + "source": 17, + "target": 62 + } + }, + { + "data": { + "source": 17, + "target": 60 + } + }, + { + "data": { + "source": 61, + "target": 46 + } + }, + { + "data": { + "source": 62, + "target": 50 + } + }, + { + "data": { + "source": 18, + "target": 64 + } + }, + { + "data": { + "source": 18, + "target": 65 + } + }, + { + "data": { + "source": 18, + "target": 63 + } + }, + { + "data": { + "source": 64, + "target": 47 + } + }, + { + "data": { + "source": 65, + "target": 51 + } + }, + { + "data": { + "source": 19, + "target": 67 + } + }, + { + "data": { + "source": 19, + "target": 68 + } + }, + { + "data": { + "source": 19, + "target": 66 + } + }, + { + "data": { + "source": 67, + "target": 48 + } + }, + { + "data": { + "source": 68, + "target": 52 + } + }, + { + "data": { + "source": 12, + "target": 53 + } + }, + { + "data": { + "source": 57, + "target": 53 + } + }, + { + "data": { + "source": 13, + "target": 54 + } + }, + { + "data": { + "source": 60, + "target": 54 + } + }, + { + "data": { + "source": 14, + "target": 55 + } + }, + { + "data": { + "source": 63, + "target": 55 + } + }, + { + "data": { + "source": 15, + "target": 56 + } + }, + { + "data": { + "source": 66, + "target": 56 + } + }, + { + "data": { + "source": 6, + "target": 41 + } + }, + { + "data": { + "source": 20, + "target": 41 + } + }, + { + "data": { + "source": 7, + "target": 42 + } + }, + { + "data": { + "source": 23, + "target": 42 + } + }, + { + "data": { + "source": 8, + "target": 43 + } + }, + { + "data": { + "source": 26, + "target": 43 + } + }, + { + "data": { + "source": 9, + "target": 44 + } + }, + { + "data": { + "source": 29, + "target": 44 + } + } + ] + } +} \ No newline at end of file diff --git a/tests/dc1/data/dc1-dc2.graphite.json b/tests/dc1/data/dc1-dc2.graphite.json new file mode 100644 index 0000000..c7f522e --- /dev/null +++ b/tests/dc1/data/dc1-dc2.graphite.json @@ -0,0 +1,578 @@ +{ + "name": "dc1-dc2", + "type": "graphite", + "source": "netbox", + "motd": "Start Graphite and open http://localhost:8080/graphite to upload and view the topology: docker run -dt --rm -p 8080:80 --name graphite netreplica/graphite:latest", + "nodes": { + "dc1-leaf-1": { + "index": "0", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "leaf", + "graph-level": 9, + "role": "Leaf", + "group": "dc1", + "platform": "Nokia SR-Linux", + "vendor": "Nokia", + "model": "7220 IXR-D2" + } + }, + "dc1-spine-1": { + "index": "4", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "spine", + "graph-level": 8, + "role": "Spine", + "group": "dc1", + "platform": "Arista EOS", + "vendor": "Arista", + "model": "DCS-7280CR3-32P4" + } + }, + "dc1-spine-2": { + "index": "5", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "spine", + "graph-level": 8, + "role": "Spine", + "group": "dc1", + "platform": "Arista EOS", + "vendor": "Arista", + "model": "DCS-7280CR3-32P4" + } + }, + "dc1-leaf-2": { + "index": "1", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "leaf", + "graph-level": 9, + "role": "Leaf", + "group": "dc1", + "platform": "Nokia SR-Linux", + "vendor": "Nokia", + "model": "7220 IXR-D2" + } + }, + "dc1-leaf-3": { + "index": "2", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "leaf", + "graph-level": 9, + "role": "Leaf", + "group": "dc1", + "platform": "Nokia SR-Linux", + "vendor": "Nokia", + "model": "7220 IXR-D2" + } + }, + "dc1-leaf-4": { + "index": "3", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "leaf", + "graph-level": 9, + "role": "Leaf", + "group": "dc1", + "platform": "Nokia SR-Linux", + "vendor": "Nokia", + "model": "7220 IXR-D2" + } + }, + "dc2-tor-1": { + "index": "16", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "tor-switch", + "graph-level": 9, + "role": "TOR Switch", + "group": "dc2", + "platform": "Cisco NX-OS 9000", + "vendor": "Cisco", + "model": "Nexus 93108TC-EX" + } + }, + "dc2-spine-1": { + "index": "10", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "spine", + "graph-level": 8, + "role": "Spine", + "group": "dc2", + "platform": "Cisco NX-OS 9000", + "vendor": "Cisco", + "model": "Nexus 9336C-FX2" + } + }, + "dc2-spine-2": { + "index": "11", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "spine", + "graph-level": 8, + "role": "Spine", + "group": "dc2", + "platform": "Cisco NX-OS 9000", + "vendor": "Cisco", + "model": "Nexus 9336C-FX2" + } + }, + "dc2-tor-2": { + "index": "17", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "tor-switch", + "graph-level": 9, + "role": "TOR Switch", + "group": "dc2", + "platform": "Cisco NX-OS 9000", + "vendor": "Cisco", + "model": "Nexus 93108TC-EX" + } + }, + "dc2-tor-3": { + "index": "18", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "tor-switch", + "graph-level": 9, + "role": "TOR Switch", + "group": "dc2", + "platform": "Cisco NX-OS 9000", + "vendor": "Cisco", + "model": "Nexus 93108TC-EX" + } + }, + "dc2-tor-4": { + "index": "19", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "tor-switch", + "graph-level": 9, + "role": "TOR Switch", + "group": "dc2", + "platform": "Cisco NX-OS 9000", + "vendor": "Cisco", + "model": "Nexus 93108TC-EX" + } + }, + "dc2-srv-1": { + "index": "12", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc2", + "platform": "Ubuntu", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc2-srv-2": { + "index": "13", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc2", + "platform": "Ubuntu", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc2-srv-3": { + "index": "14", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc2", + "platform": "Ubuntu", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc2-srv-4": { + "index": "15", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc2", + "platform": "Ubuntu", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc1-srv-1": { + "index": "6", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc1", + "platform": "Linux", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc1-srv-2": { + "index": "7", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc1", + "platform": "Linux", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc1-srv-3": { + "index": "8", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc1", + "platform": "Linux", + "vendor": "Dell", + "model": "PowerEdge R640" + } + }, + "dc1-srv-4": { + "index": "9", + "mgmt-ipv4-address": "", + "mgmt-ipv6-address": "", + "labels": { + "graph-icon": "server", + "graph-level": 10, + "role": "server", + "group": "dc1", + "platform": "Linux", + "vendor": "Dell", + "model": "PowerEdge R640" + } + } + }, + "links": [ + { + "a": { + "node": "dc1-leaf-1", + "interface": "ethernet-1/49", + "peer": "z" + }, + "z": { + "node": "dc1-spine-1", + "interface": "Ethernet1/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-1", + "interface": "ethernet-1/50", + "peer": "z" + }, + "z": { + "node": "dc1-spine-2", + "interface": "Ethernet1/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-2", + "interface": "ethernet-1/49", + "peer": "z" + }, + "z": { + "node": "dc1-spine-1", + "interface": "Ethernet2/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-2", + "interface": "ethernet-1/50", + "peer": "z" + }, + "z": { + "node": "dc1-spine-2", + "interface": "Ethernet2/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-3", + "interface": "ethernet-1/49", + "peer": "z" + }, + "z": { + "node": "dc1-spine-1", + "interface": "Ethernet3/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-3", + "interface": "ethernet-1/50", + "peer": "z" + }, + "z": { + "node": "dc1-spine-2", + "interface": "Ethernet3/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-4", + "interface": "ethernet-1/49", + "peer": "z" + }, + "z": { + "node": "dc1-spine-1", + "interface": "Ethernet4/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-4", + "interface": "ethernet-1/50", + "peer": "z" + }, + "z": { + "node": "dc1-spine-2", + "interface": "Ethernet4/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-1", + "interface": "Ethernet1/49", + "peer": "z" + }, + "z": { + "node": "dc2-spine-1", + "interface": "Ethernet1/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-1", + "interface": "Ethernet1/50", + "peer": "z" + }, + "z": { + "node": "dc2-spine-2", + "interface": "Ethernet1/1", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-2", + "interface": "Ethernet1/49", + "peer": "z" + }, + "z": { + "node": "dc2-spine-1", + "interface": "Ethernet1/2", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-2", + "interface": "Ethernet1/50", + "peer": "z" + }, + "z": { + "node": "dc2-spine-2", + "interface": "Ethernet1/2", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-3", + "interface": "Ethernet1/49", + "peer": "z" + }, + "z": { + "node": "dc2-spine-1", + "interface": "Ethernet1/3", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-3", + "interface": "Ethernet1/50", + "peer": "z" + }, + "z": { + "node": "dc2-spine-2", + "interface": "Ethernet1/3", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-4", + "interface": "Ethernet1/49", + "peer": "z" + }, + "z": { + "node": "dc2-spine-1", + "interface": "Ethernet1/4", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-4", + "interface": "Ethernet1/50", + "peer": "z" + }, + "z": { + "node": "dc2-spine-2", + "interface": "Ethernet1/4", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-1", + "interface": "Ethernet1/1", + "peer": "z" + }, + "z": { + "node": "dc2-srv-1", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-2", + "interface": "Ethernet1/1", + "peer": "z" + }, + "z": { + "node": "dc2-srv-2", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-3", + "interface": "Ethernet1/1", + "peer": "z" + }, + "z": { + "node": "dc2-srv-3", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc2-tor-4", + "interface": "Ethernet1/1", + "peer": "z" + }, + "z": { + "node": "dc2-srv-4", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-1", + "interface": "ethernet-1/1", + "peer": "z" + }, + "z": { + "node": "dc1-srv-1", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-2", + "interface": "ethernet-1/1", + "peer": "z" + }, + "z": { + "node": "dc1-srv-2", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-3", + "interface": "ethernet-1/1", + "peer": "z" + }, + "z": { + "node": "dc1-srv-3", + "interface": "Gig-E 1", + "peer": "a" + } + }, + { + "a": { + "node": "dc1-leaf-4", + "interface": "ethernet-1/1", + "peer": "z" + }, + "z": { + "node": "dc1-srv-4", + "interface": "Gig-E 1", + "peer": "a" + } + } + ] +} \ No newline at end of file From 8f1324b7345a55002398881720c75dddc4db6b1c Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:47:00 -0800 Subject: [PATCH 4/8] readme update with --site and --sites --- README.md | 3 ++- nrx/nrx.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c35aa17..9f24483 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,8 @@ optional arguments: -i, --input INPUT input source: netbox (default) | cyjs -o, --output OUTPUT output format: cyjs | gml | clab | cml | graphite | d2 -a, --api API netbox API URL - -s, --sites SITES netbox site(s) to export, for multiple sites use a comma-separated list: site1,site2,site3 (uses OR logic) + -s SITE, --site SITE netbox site to export, cannot be combined with --sites + --sites SITES netbox sites to export, for multiple tags use a comma-separated list: site1,site2,site3 (uses OR logic) -t, --tags TAGS netbox tags to export, for multiple tags use a comma-separated list: tag1,tag2,tag3 (uses AND logic) -n, --name NAME name of the exported topology (site name or tags by default) --noconfigs disable device configuration export (enabled by default) diff --git a/nrx/nrx.py b/nrx/nrx.py index e6f927b..0f823ec 100755 --- a/nrx/nrx.py +++ b/nrx/nrx.py @@ -778,8 +778,9 @@ def parse_args(): args_parser.add_argument('-o', '--output', required=False, help='output format: cyjs | gml | clab | cml | graphite | d2', type=arg_output_check, ) args_parser.add_argument('-a', '--api', required=False, help='netbox API URL') - sites_group.add_argument('-s', '--site', required=False, help='netbox site to export') - sites_group.add_argument( '--sites', required=False, help='comma-separated list of netbox sites to export') + sites_group.add_argument('-s', '--site', required=False, help='netbox site to export, cannot be combined with --sites') + sites_group.add_argument( '--sites', required=False, help='netbox sites to export, for multiple tags use a comma-separated list: \ + site1,site2,site3 (uses OR logic)') args_parser.add_argument('-t', '--tags', required=False, help='netbox tags to export, for multiple tags use a comma-separated list: \ tag1,tag2,tag3 (uses AND logic)') args_parser.add_argument('-n', '--name', required=False, help='name of the exported topology (site name or tags by default)') From 6addcf9eb9f579e7ebdc977964dcea6c346b40ad Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Tue, 26 Dec 2023 21:39:58 -0800 Subject: [PATCH 5/8] readme cli help update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edff67b..84bb101 100644 --- a/README.md +++ b/README.md @@ -145,8 +145,8 @@ optional arguments: -i, --input INPUT input source: netbox (default) | cyjs -o, --output OUTPUT output format: cyjs | clab | cml | graphite | d2 or any other format supported by provided templates -a, --api API netbox API URL - -s SITE, --site SITE netbox site to export, cannot be combined with --sites - --sites SITES netbox sites to export, for multiple tags use a comma-separated list: site1,site2,site3 (uses OR logic) + -s, --site SITE netbox site to export, cannot be combined with --sites + --sites SITES netbox sites to export, for multiple tags use a comma-separated list: site1,site2,site3 (uses OR logic) -t, --tags TAGS netbox tags to export, for multiple tags use a comma-separated list: tag1,tag2,tag3 (uses AND logic) -n, --name NAME name of the exported topology (site name or tags by default) --noconfigs disable device configuration export (enabled by default) From 15d54bd9a0419b7297d9084c978cab3918406066 Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Tue, 26 Dec 2023 21:42:07 -0800 Subject: [PATCH 6/8] use --site in the examples --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 84bb101..bbe2a85 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --templates templates --output clab --dir demo --sites DM-Albany + ./nrx.py --api https://demo.netbox.dev --templates templates --output clab --dir demo --site DM-Albany ``` 2. Now you're ready to start the Containerlab topology. Here is the example for "DM-Albany" site @@ -233,7 +233,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --sites DM-Albany --dir demo + ./nrx.py --api https://demo.netbox.dev --site DM-Albany --dir demo ``` 5. If you have a CYJS file, run `./nrx.py --input cyjs --file .cyjs --output clab` to create a Containerlab topology file from the CYJS graph you exported in the previous step. For example, run: @@ -248,7 +248,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --templates templates --output cml --dir demo --sites DM-Akron + ./nrx.py --api https://demo.netbox.dev --templates templates --output cml --dir demo --site DM-Akron ``` 2. Now you're ready to start the "DM-Akron" topology in CML. @@ -263,7 +263,7 @@ source nrx39/bin/activate ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --dir demo --sites DM-Akron + ./nrx.py --api https://demo.netbox.dev --dir demo --site DM-Akron ``` 4. If you have a CYJS file, run `./nrx.py --input cyjs --file .cyjs --output cml` to create a topology file from the CYJS graph you exported in the previous step. For example, run: @@ -282,7 +282,7 @@ Follow a two-step process: ```Shell export NB_API_TOKEN='replace_with_valid_API_token' - ./nrx.py --api https://demo.netbox.dev --sites DM-Akron --templates templates --output graphite + ./nrx.py --api https://demo.netbox.dev --site DM-Akron --templates templates --output graphite ``` 2. Start Graphite to visualize "DM-Akron" site: From 7576cf4145569e24d23200b3a7911f4c8f6add91 Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:05:56 -0800 Subject: [PATCH 7/8] simplify naming topo from sites --- nrx/nrx.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nrx/nrx.py b/nrx/nrx.py index 9e7d3e1..350d1ef 100755 --- a/nrx/nrx.py +++ b/nrx/nrx.py @@ -201,10 +201,8 @@ def __init__(self, config): # Determine the name of the topology if not provided in the configuration if len(config['topology_name']) > 0: self.topology_name = config['topology_name'] - elif len(config['export_sites']) > 1: - self.topology_name = "-".join(config['export_sites']) elif len(config['export_sites']) > 0: - self.topology_name = config['export_sites'][0] + self.topology_name = "-".join(config['export_sites']) elif len(config['export_tags']) > 0: self.topology_name = "-".join(config['export_tags']) self.G = nx.Graph(name=self.topology_name) From cd49143eab38cccd899b2f1cbd0b0292a4950484 Mon Sep 17 00:00:00 2001 From: Alex Bortok <431965+bortok@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:17:27 -0800 Subject: [PATCH 8/8] improve no sites found handling --- nrx/nrx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nrx/nrx.py b/nrx/nrx.py index 350d1ef..5224859 100755 --- a/nrx/nrx.py +++ b/nrx/nrx.py @@ -224,8 +224,8 @@ def __init__(self, config): self.nb_sites = self.nb_session.dcim.sites.filter(name=config['export_sites']) except (pynetbox.core.query.RequestError, pynetbox.core.query.ContentError) as e: error("NetBox API failure at get site:", e) - if self.nb_sites is None: - error(f"One of these site not found: {config['export_site']}") + if self.nb_sites is None or len(self.nb_sites) == 0: + error(f"No sites from the list were found: {config['export_sites']}") else: print(f"Fetching devices from sites: {config['export_sites']}") else: