sc-napalm 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sc-napalm might be problematic. Click here for more details.

Files changed (47) hide show
  1. sc_napalm-0.2.0/.gitignore +7 -0
  2. sc_napalm-0.2.0/PKG-INFO +100 -0
  3. sc_napalm-0.2.0/README.md +86 -0
  4. sc_napalm-0.2.0/pyproject.toml +45 -0
  5. sc_napalm-0.2.0/sample_env +2 -0
  6. sc_napalm-0.2.0/src/custom_napalm/__init__.py +28 -0
  7. sc_napalm-0.2.0/src/custom_napalm/base.py +108 -0
  8. sc_napalm-0.2.0/src/custom_napalm/eos/__init__.py +1 -0
  9. sc_napalm-0.2.0/src/custom_napalm/eos/eos.py +94 -0
  10. sc_napalm-0.2.0/src/custom_napalm/get.py +85 -0
  11. sc_napalm-0.2.0/src/custom_napalm/iosxr/__init__.py +1 -0
  12. sc_napalm-0.2.0/src/custom_napalm/iosxr/constants.py +144 -0
  13. sc_napalm-0.2.0/src/custom_napalm/iosxr/iosxr.py +55 -0
  14. sc_napalm-0.2.0/src/custom_napalm/junos/__init__.py +1 -0
  15. sc_napalm-0.2.0/src/custom_napalm/junos/junos.py +201 -0
  16. sc_napalm-0.2.0/src/custom_napalm/junos/junos_views.py +17 -0
  17. sc_napalm-0.2.0/src/custom_napalm/junos/junos_views.yml +228 -0
  18. sc_napalm-0.2.0/src/custom_napalm/models.py +27 -0
  19. sc_napalm-0.2.0/src/custom_napalm/nos/__init__.py +1 -0
  20. sc_napalm-0.2.0/src/custom_napalm/nos/constants.py +112 -0
  21. sc_napalm-0.2.0/src/custom_napalm/nos/nos.py +221 -0
  22. sc_napalm-0.2.0/src/custom_napalm/nxos/__init__.py +1 -0
  23. sc_napalm-0.2.0/src/custom_napalm/nxos/nxos.py +90 -0
  24. sc_napalm-0.2.0/src/custom_napalm/nxos/utils/textfsm_templates/sh_int_transceiver.tpl +27 -0
  25. sc_napalm-0.2.0/src/custom_napalm/nxos/utils/textfsm_templates/sh_inventory.tpl +8 -0
  26. sc_napalm-0.2.0/src/custom_napalm/srl/__init__.py +1 -0
  27. sc_napalm-0.2.0/src/custom_napalm/srl/srl.py +25 -0
  28. sc_napalm-0.2.0/src/custom_napalm/sros/__init__.py +1 -0
  29. sc_napalm-0.2.0/src/custom_napalm/sros/sros.py +6 -0
  30. sc_napalm-0.2.0/src/custom_napalm/utils.py +74 -0
  31. sc_napalm-0.2.0/test/mock_data/eos/get_inventory/um_eos/expected_result.json +324 -0
  32. sc_napalm-0.2.0/test/mock_data/eos/get_inventory/um_eos/show_inventory.json +675 -0
  33. sc_napalm-0.2.0/test/mock_data/iosxr/get_inventory/um_iosxr/expected_result.json +128 -0
  34. sc_napalm-0.2.0/test/mock_data/iosxr/get_inventory/um_iosxr/get-inventory.xml +281 -0
  35. sc_napalm-0.2.0/test/mock_data/junos/get_inventory/um_junos/expected_result.json +86 -0
  36. sc_napalm-0.2.0/test/mock_data/junos/get_inventory/um_junos/get-chassis-inventory.xml +112 -0
  37. sc_napalm-0.2.0/test/mock_data/nxos/get_inventory/um_nxos/expected_result.json +60 -0
  38. sc_napalm-0.2.0/test/mock_data/nxos/get_inventory/um_nxos/show_interface_transceiver.txt +53 -0
  39. sc_napalm-0.2.0/test/mock_data/nxos/get_inventory/um_nxos/show_inventory.txt +23 -0
  40. sc_napalm-0.2.0/test/mock_data/srl/get_facts/clab/interface.txt +1634 -0
  41. sc_napalm-0.2.0/test/mock_data/srl/get_facts/clab/platform_chassis.txt +21 -0
  42. sc_napalm-0.2.0/test/mock_data/srl/get_facts/clab/system_information.txt +21 -0
  43. sc_napalm-0.2.0/test/mock_data/srl/get_facts/clab/system_name_host_name.txt +1 -0
  44. sc_napalm-0.2.0/test/mock_drivers.py +180 -0
  45. sc_napalm-0.2.0/test/mock_get.py +60 -0
  46. sc_napalm-0.2.0/test/test_getters.py +25 -0
  47. sc_napalm-0.2.0/uv.lock +2321 -0
@@ -0,0 +1,7 @@
1
+ .env
2
+ .venv
3
+ __pycache__
4
+ *.egg-info
5
+ *.swp
6
+ *.python-version
7
+ dist/
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.4
2
+ Name: sc-napalm
3
+ Version: 0.2.0
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.8
6
+ Requires-Dist: gitpython>=3.1.45
7
+ Requires-Dist: lxml>=6.0.2
8
+ Requires-Dist: napalm-srl>=1.0.5
9
+ Requires-Dist: napalm-sros>=1.0.2
10
+ Requires-Dist: napalm>=5.1.0
11
+ Requires-Dist: pynautobot>=2.1.1
12
+ Requires-Dist: python-decouple>=3.8
13
+ Description-Content-Type: text/markdown
14
+
15
+ # sc-napalm
16
+
17
+ This repo is for building custom [NAPALM](https://napalm.readthedocs.io/en/latest/) "getters" to pull operational data from network devices, as well as
18
+ override existing NAPALM getters with custom code if needed. At the moment only one custom getter is implemented: `get_inventory`. This getter
19
+ pulls model and serial numbers of device components: fans, psus, and optics.
20
+
21
+ What's cool about NAPALM is that if you nest your custom drivers under `custom_napalm` as is done in this project, you can install your custom drivers
22
+ in the same virtual environment as the main NAPALM package, and they will override NAPALM's core drivers. This allows us to leverage NAPALM in a pretty
23
+ seamless way - by that I mean applications that leverage NAPALM (like Nautobot or Nornir) can be easily altered to use this code instead.
24
+
25
+
26
+ ## Using sc-napalm
27
+ The package comes with a cli script called `sc-napalm-get` that will run a particular getter against a particular device and output the results
28
+ to your terminal.
29
+
30
+ Right now to use this code you must do the following things:
31
+ 1. [Install uv](https://docs.astral.sh/uv/getting-started/installation/)
32
+ 2. Clone the repo onto your local machine, then do a local development install of the repo into a uv virtual environment.
33
+ ```
34
+ git clone https://scinet.supercomputing.org:8443/automation/sc25/sc-napalm.git
35
+ cd sc-napalm
36
+ uv run pip install -e .
37
+ ```
38
+ 3. Copy `sample_env` file into `.env` and fill out `.env` with the credentials you need. Note that you could also specify these credentials
39
+ when you run the script, or in your local environment. The script prefers manual input, then `.env` then environment values.
40
+
41
+ 4. Run the script with `uv run sc-napalm-get`.
42
+ ```
43
+ amylieb@m-n76107kqmh sc-napalm % uv run sc-napalm-get -h
44
+ usage: sc-napalm-get [-h] [-l {DEBUG,INFO,WARNING,ERROR,CRITICAL} | -L {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--logfile LOGFILE] [--username USERNAME]
45
+ [--password PASSWORD]
46
+ device {iosxr,nxos,junos,sros,srl,eos} {get_config,get_facts,get_lldp_neighbors,get_inventory}
47
+
48
+ Run a specific sc_napalm "getter" against a device.
49
+
50
+ positional arguments:
51
+ device device hostname or IP address
52
+ {iosxr,nxos,junos,sros,srl,eos}
53
+ The platform of this device
54
+ {get_config,get_facts,get_lldp_neighbors,get_inventory}
55
+ The getter command to run against this device
56
+
57
+ options:
58
+ -h, --help show this help message and exit
59
+ -l, --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
60
+ Set log level for sc_napalm only
61
+ -L, --LOG-LEVEL {DEBUG,INFO,WARNING,ERROR,CRITICAL}
62
+ set global log level
63
+ --logfile LOGFILE Save logging to a file (specified by name) instead of to stdout
64
+ --username USERNAME Specify credentials
65
+ --password PASSWORD Specify credentials
66
+ aliebowitz@sysauto:~/src/sc-napalm$ uv run sc-napalm-get 2001:468:1f07:ff19::1d eos get_inventory
67
+ [{'name': 'Ethernet45',
68
+ 'part_number': 'QSFP-100G-LR4',
69
+ 'serial_number': 'XYL252206819',
70
+ 'subtype': 'QSFP-100G-LR4',
71
+ 'type': 'optic'},
72
+ {'name': 'Ethernet46',
73
+ 'part_number': 'QSFP-100G-LR4',
74
+ 'serial_number': 'XYL252206822',
75
+ 'subtype': 'QSFP-100G-LR4',
76
+ 'type': 'optic'},
77
+ {'name': 'PSU 1',
78
+ 'part_number': 'PWR-511-AC-RED',
79
+ 'serial_number': 'EEWT2420216960',
80
+ 'subtype': None,
81
+ 'type': 'psu'},
82
+ ...
83
+ .....
84
+
85
+ ```
86
+
87
+ ## Developing sc-napalm
88
+ Currently, the getters that are exposed as options in the `get` script are defined in the [base class](https://scinet.supercomputing.org:8443/automation/sc25/sc-napalm/-/blob/main/src/custom_napalm/base.py?ref_type=heads) of the custom drivers.
89
+ Note that because all the custom classes inherit the NAPALM getters, we could easily define all the other NAPALM getters there, but I've only included ones I think are obviously useful to us.
90
+
91
+ My hope is that instead of just printing out results we can write code that saves data in Nautobot, or some other place.
92
+ This could be done with Nornir or Nautobot jobs.
93
+
94
+ ## To-dos
95
+ * Decide where this code is run and how (periodically? Manually? From Nautobot? if so, how?)
96
+ * Decide what output we want to capture (eg "show version"? "show lldp neighbor"?) and where it should go
97
+ * Fuctions/tasks that transform output and save it appropriately
98
+ * `get_inventory` methods for sros
99
+ * Test/mock classes for custom getters
100
+
@@ -0,0 +1,86 @@
1
+ # sc-napalm
2
+
3
+ This repo is for building custom [NAPALM](https://napalm.readthedocs.io/en/latest/) "getters" to pull operational data from network devices, as well as
4
+ override existing NAPALM getters with custom code if needed. At the moment only one custom getter is implemented: `get_inventory`. This getter
5
+ pulls model and serial numbers of device components: fans, psus, and optics.
6
+
7
+ What's cool about NAPALM is that if you nest your custom drivers under `custom_napalm` as is done in this project, you can install your custom drivers
8
+ in the same virtual environment as the main NAPALM package, and they will override NAPALM's core drivers. This allows us to leverage NAPALM in a pretty
9
+ seamless way - by that I mean applications that leverage NAPALM (like Nautobot or Nornir) can be easily altered to use this code instead.
10
+
11
+
12
+ ## Using sc-napalm
13
+ The package comes with a cli script called `sc-napalm-get` that will run a particular getter against a particular device and output the results
14
+ to your terminal.
15
+
16
+ Right now to use this code you must do the following things:
17
+ 1. [Install uv](https://docs.astral.sh/uv/getting-started/installation/)
18
+ 2. Clone the repo onto your local machine, then do a local development install of the repo into a uv virtual environment.
19
+ ```
20
+ git clone https://scinet.supercomputing.org:8443/automation/sc25/sc-napalm.git
21
+ cd sc-napalm
22
+ uv run pip install -e .
23
+ ```
24
+ 3. Copy `sample_env` file into `.env` and fill out `.env` with the credentials you need. Note that you could also specify these credentials
25
+ when you run the script, or in your local environment. The script prefers manual input, then `.env` then environment values.
26
+
27
+ 4. Run the script with `uv run sc-napalm-get`.
28
+ ```
29
+ amylieb@m-n76107kqmh sc-napalm % uv run sc-napalm-get -h
30
+ usage: sc-napalm-get [-h] [-l {DEBUG,INFO,WARNING,ERROR,CRITICAL} | -L {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--logfile LOGFILE] [--username USERNAME]
31
+ [--password PASSWORD]
32
+ device {iosxr,nxos,junos,sros,srl,eos} {get_config,get_facts,get_lldp_neighbors,get_inventory}
33
+
34
+ Run a specific sc_napalm "getter" against a device.
35
+
36
+ positional arguments:
37
+ device device hostname or IP address
38
+ {iosxr,nxos,junos,sros,srl,eos}
39
+ The platform of this device
40
+ {get_config,get_facts,get_lldp_neighbors,get_inventory}
41
+ The getter command to run against this device
42
+
43
+ options:
44
+ -h, --help show this help message and exit
45
+ -l, --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
46
+ Set log level for sc_napalm only
47
+ -L, --LOG-LEVEL {DEBUG,INFO,WARNING,ERROR,CRITICAL}
48
+ set global log level
49
+ --logfile LOGFILE Save logging to a file (specified by name) instead of to stdout
50
+ --username USERNAME Specify credentials
51
+ --password PASSWORD Specify credentials
52
+ aliebowitz@sysauto:~/src/sc-napalm$ uv run sc-napalm-get 2001:468:1f07:ff19::1d eos get_inventory
53
+ [{'name': 'Ethernet45',
54
+ 'part_number': 'QSFP-100G-LR4',
55
+ 'serial_number': 'XYL252206819',
56
+ 'subtype': 'QSFP-100G-LR4',
57
+ 'type': 'optic'},
58
+ {'name': 'Ethernet46',
59
+ 'part_number': 'QSFP-100G-LR4',
60
+ 'serial_number': 'XYL252206822',
61
+ 'subtype': 'QSFP-100G-LR4',
62
+ 'type': 'optic'},
63
+ {'name': 'PSU 1',
64
+ 'part_number': 'PWR-511-AC-RED',
65
+ 'serial_number': 'EEWT2420216960',
66
+ 'subtype': None,
67
+ 'type': 'psu'},
68
+ ...
69
+ .....
70
+
71
+ ```
72
+
73
+ ## Developing sc-napalm
74
+ Currently, the getters that are exposed as options in the `get` script are defined in the [base class](https://scinet.supercomputing.org:8443/automation/sc25/sc-napalm/-/blob/main/src/custom_napalm/base.py?ref_type=heads) of the custom drivers.
75
+ Note that because all the custom classes inherit the NAPALM getters, we could easily define all the other NAPALM getters there, but I've only included ones I think are obviously useful to us.
76
+
77
+ My hope is that instead of just printing out results we can write code that saves data in Nautobot, or some other place.
78
+ This could be done with Nornir or Nautobot jobs.
79
+
80
+ ## To-dos
81
+ * Decide where this code is run and how (periodically? Manually? From Nautobot? if so, how?)
82
+ * Decide what output we want to capture (eg "show version"? "show lldp neighbor"?) and where it should go
83
+ * Fuctions/tasks that transform output and save it appropriately
84
+ * `get_inventory` methods for sros
85
+ * Test/mock classes for custom getters
86
+
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "sc-napalm"
3
+ version = "0.2.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.8"
7
+ dependencies = [
8
+ "gitpython>=3.1.45",
9
+ "lxml>=6.0.2",
10
+ "napalm>=5.1.0",
11
+ "napalm-srl>=1.0.5",
12
+ "napalm-sros>=1.0.2",
13
+ "pynautobot>=2.1.1",
14
+ "python-decouple>=3.8",
15
+ ]
16
+
17
+
18
+ [build-system]
19
+ requires = ["hatchling"]
20
+ build-backend = "hatchling.build"
21
+
22
+ [project.scripts]
23
+ sc-napalm-get = "custom_napalm.get:main"
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ packages = ["src/custom_napalm"]
27
+
28
+ #[tool.hatch.build]
29
+ #include = [
30
+ # "src/custom_napalm/junos/*.yml",
31
+ # "src/custom_napalm/nxos/*.tpl",
32
+ #]
33
+
34
+ [dependency-groups]
35
+ dev = [
36
+ "pytest>=8.3.5",
37
+ "ruff>=0.14.3",
38
+ ]
39
+
40
+ [tool.pytest.ini_options]
41
+ filterwarnings = [
42
+ "ignore::DeprecationWarning",
43
+ ]
44
+
45
+
@@ -0,0 +1,2 @@
1
+ SC_USERNAME=automaton
2
+ SC_PASSWORD=SCinetisCool
@@ -0,0 +1,28 @@
1
+ from .iosxr import SCIOSXR
2
+ from .junos import SCJunOS
3
+ from .nxos import SCNXOS
4
+ from .sros import SCNokiaSROSDriver
5
+ from .srl import SCNokiaSRLDriver
6
+ from .eos import SCEOSDriver
7
+ from .nos import SCNOSDriver
8
+
9
+ PLATFORM_MAP = {
10
+ "iosxr": SCIOSXR,
11
+ "nxos": SCNXOS,
12
+ "junos": SCJunOS,
13
+ "sros": SCNokiaSROSDriver,
14
+ "srl": SCNokiaSRLDriver,
15
+ "eos": SCEOSDriver,
16
+ "nos": SCNOSDriver,
17
+ }
18
+
19
+
20
+ def get_network_driver(platform: str):
21
+ """
22
+ Returns network driver based on platform string.
23
+ """
24
+ for valid_platform, driver in PLATFORM_MAP.items():
25
+ if valid_platform == platform:
26
+ return driver
27
+
28
+ raise NotImplementedError(f"Unsupported platform {platform}")
@@ -0,0 +1,108 @@
1
+ from typing import Dict, List
2
+ import re
3
+ from napalm.base import models as napalm_models
4
+ from netmiko import ConnectHandler
5
+
6
+ from . import models as sc_models
7
+
8
+
9
+ class SCBaseDriver:
10
+ """
11
+ Base class that all children should inherit
12
+ """
13
+
14
+ # populate in child classes
15
+ INVENTORY_TO_TYPE = {}
16
+
17
+ def _get_inventory_type(self, name: str) -> str:
18
+ """
19
+ Maps the name of the inventory item to its type
20
+ """
21
+ for pattern, inv_type in self.INVENTORY_TO_TYPE.items():
22
+ if inv_type and inv_type not in sc_models.VALID_INVENTORY_TYPES.__args__:
23
+ raise TypeError(f"Invalid Inventory type {inv_type}")
24
+ if re.search(pattern, name):
25
+ return inv_type
26
+
27
+ raise ValueError(f"Unknown inventory item {name}")
28
+
29
+ def get_config(self) -> napalm_models.ConfigDict:
30
+ """napalm get config"""
31
+ raise NotImplementedError
32
+
33
+ def get_facts(self) -> napalm_models.FactsDict:
34
+ """napalm get facts"""
35
+ raise NotImplementedError
36
+
37
+ def get_optics(self) -> Dict[str, napalm_models.OpticsDict]:
38
+ """napalm get optics"""
39
+ raise NotImplementedError
40
+
41
+ def get_lldp_neighbors(self) -> Dict[str, List[napalm_models.LLDPNeighborDict]]:
42
+ """napalm get lldp neighbors"""
43
+ raise NotImplementedError
44
+
45
+ def get_inventory(self) -> List[sc_models.InventoryDict]:
46
+ """sc get inventory"""
47
+ raise NotImplementedError
48
+
49
+
50
+ class SCBaseNetconfDriver(SCBaseDriver):
51
+ """
52
+ Inclues some helper xml functions
53
+ """
54
+
55
+ def ssh_conn(self) -> ConnectHandler:
56
+ """
57
+ Ugly workaround for getting stuff via the cli over ssh.
58
+ Starts a netmiko ssh connection handler and returns it,
59
+ allowing you to interact with the CLI of the device.
60
+ """
61
+
62
+ args = {
63
+ "device_type": "linux",
64
+ "host":self.hostname,
65
+ "username":self.username,
66
+ "password":self.password,
67
+ "ssh_config_file":self.optional_args.get("ssh_config", None),
68
+ }
69
+ return ConnectHandler(**args)
70
+
71
+ def _find_txt(self, xml_tree, path, default=None, namespaces=None):
72
+ """
73
+ Stolen from the napalm iosxr driver
74
+ Extract the text value from a leaf in an XML tree using XPath.
75
+
76
+ Will return a default value if leaf path not matched.
77
+ :param xml_tree:the XML Tree object. <type'lxml.etree._Element'>.
78
+ :param path: XPath to be applied in order to extract the desired data.
79
+ :param default: Value to be returned in case of a no match.
80
+ :param namespaces: namespace dictionary.
81
+ :return: a str value or None if leaf path not matched.
82
+ """
83
+ value = None
84
+ xpath_applied = xml_tree.xpath(path, namespaces=namespaces)
85
+
86
+ if xpath_applied:
87
+ if not len(xpath_applied[0]):
88
+ if xpath_applied[0].text is not None:
89
+ value = xpath_applied[0].text.strip()
90
+ else:
91
+ value = ""
92
+ else:
93
+ value = default
94
+
95
+ return value
96
+
97
+ # Helper xml methods that always pass in our namespaces by default
98
+ def _text(self, xml_tree, path, default=None):
99
+ return self._find_txt(xml_tree, path, default, namespaces=self.NS)
100
+
101
+ def _xpath(self, xml_tree, path):
102
+ return getattr(xml_tree, "xpath")(path, namespaces=self.NS)
103
+
104
+ def _find(self, xml_tree, element):
105
+ return getattr(xml_tree, "find")(element, namespaces=self.NS)
106
+
107
+ def _iterfind(self, xml_tree, element):
108
+ return getattr(xml_tree, "iterfind")(element, namespaces=self.NS)
@@ -0,0 +1 @@
1
+ from .eos import SCEOSDriver
@@ -0,0 +1,94 @@
1
+ from typing import List
2
+ from napalm.eos import EOSDriver
3
+ from ..base import SCBaseDriver
4
+ from ..models import InventoryDict
5
+
6
+
7
+ class SCEOSDriver(EOSDriver, SCBaseDriver):
8
+ ("fabric_module",)
9
+ ("fan",)
10
+ ("linecard",)
11
+ ("optic",)
12
+ ("psu",)
13
+ ("re",)
14
+ ("stack_cable",)
15
+ ("stack_member",)
16
+ ("uplink_module",)
17
+ ("aoc",)
18
+ ("dac",)
19
+
20
+ INVENTORY_TO_TYPE = {
21
+ r"Fabric": "fabric_module",
22
+ r"Linecard": "linecard",
23
+ r"Supervisor": "re",
24
+ }
25
+
26
+ def __init__(self, hostname, username, password, timeout=60, optional_args=None):
27
+ """
28
+ Forcing ssh transport since we don't enable the web interface
29
+ """
30
+ optional_args = optional_args if optional_args else {}
31
+ optional_args["transport"] = "ssh"
32
+
33
+
34
+ super().__init__(
35
+ hostname, username, password, timeout=timeout, optional_args=optional_args
36
+ )
37
+
38
+ def get_inventory(self) -> List[InventoryDict]:
39
+ inventory = self._run_commands(["show inventory"], encoding="json")
40
+
41
+ results = []
42
+
43
+ ### optics
44
+ for slot, optic in inventory[0]["xcvrSlots"].items():
45
+ if optic.get("modelName"):
46
+ results.append(
47
+ {
48
+ "type": "optic",
49
+ "subtype": optic["modelName"],
50
+ "name": f"Ethernet{slot}",
51
+ "part_number": optic["modelName"],
52
+ "serial_number": optic["serialNum"],
53
+ },
54
+ )
55
+
56
+ ### line cards
57
+ for slot, card in inventory[0]["cardSlots"].items():
58
+ if card.get("serialNum"):
59
+ results.append(
60
+ {
61
+ "type": self._get_inventory_type(slot),
62
+ "subtype": card["modelName"],
63
+ "name": f"Ethernet{slot}",
64
+ "part_number": card["modelName"],
65
+ "serial_number": card["serialNum"],
66
+ },
67
+ )
68
+
69
+ ### PSUs
70
+ for slot, psu in inventory[0]["powerSupplySlots"].items():
71
+ if psu.get("serialNum"):
72
+ results.append(
73
+ {
74
+ "type": "psu",
75
+ "subtype": None,
76
+ "name": f"PSU {slot}",
77
+ "part_number": psu["name"],
78
+ "serial_number": psu["serialNum"],
79
+ },
80
+ )
81
+
82
+ ### FANs
83
+ for slot, fan in inventory[0]["fanTraySlots"].items():
84
+ if fan.get("serialNum"):
85
+ results.append(
86
+ {
87
+ "type": "fan",
88
+ "subtype": None,
89
+ "name": f"FAN {slot}",
90
+ "part_number": fan["name"],
91
+ "serial_number": fan["serialNum"],
92
+ },
93
+ )
94
+ return results
@@ -0,0 +1,85 @@
1
+ import argparse
2
+ from pprint import pprint
3
+
4
+ from napalm import get_network_driver
5
+
6
+ from custom_napalm import PLATFORM_MAP
7
+ from custom_napalm.base import SCBaseDriver
8
+ from custom_napalm.utils import configure_logging, LOG_LEVELS, get_from_args_or_env
9
+
10
+ # list of getters to run
11
+ GETTERS = [attr for attr in SCBaseDriver.__dict__ if attr.startswith("get")]
12
+
13
+ cred_args = {"sc_username": True, "sc_password": True}
14
+
15
+
16
+ def main():
17
+ parser = argparse.ArgumentParser(
18
+ description="""
19
+ Run a specific sc_napalm "getter" against a device.
20
+ """
21
+ )
22
+ parser.add_argument("device", help="device hostname or IP address")
23
+ parser.add_argument(
24
+ "sc_napalm_platform",
25
+ choices=PLATFORM_MAP,
26
+ help="The platform of this device",
27
+ )
28
+ parser.add_argument(
29
+ "cmd",
30
+ choices=GETTERS,
31
+ help="The getter command to run against this device",
32
+ )
33
+ parser.add_argument(
34
+ "--ssh-cfg", help="Use SSH config file to connect", type=str
35
+ )
36
+ log_args = parser.add_mutually_exclusive_group()
37
+ log_args.add_argument(
38
+ "-l", "--log-level", help="Set log level for sc_napalm only", choices=LOG_LEVELS
39
+ )
40
+ log_args.add_argument(
41
+ "-L", "--LOG-LEVEL", help="set global log level", choices=LOG_LEVELS
42
+ )
43
+ parser.add_argument(
44
+ "--logfile",
45
+ type=str,
46
+ help="Save logging to a file (specified by name) instead of to stdout",
47
+ )
48
+
49
+ for cred_arg in cred_args:
50
+ parser.add_argument(f"--{cred_arg}", help="Specify credentials")
51
+ args = parser.parse_args()
52
+
53
+ log_level = args.log_level if args.log_level else args.LOG_LEVEL
54
+ if log_level:
55
+ configure_logging(
56
+ log_level,
57
+ log_globally=bool(args.LOG_LEVEL),
58
+ log_file=args.logfile,
59
+ log_to_console=not (bool(args.logfile)),
60
+ )
61
+
62
+ creds = {
63
+ cred: get_from_args_or_env(cred, args, required=reqd)
64
+ for cred, reqd in cred_args.items()
65
+ }
66
+ Driver = get_network_driver(args.sc_napalm_platform)
67
+
68
+ # setting up connection details
69
+ optional_args = {"look_for_keys": False}
70
+ if args.ssh_cfg:
71
+ optional_args = {"ssh_config_file": args.ssh_cfg}
72
+
73
+ with Driver(
74
+ args.device,
75
+ creds["sc_username"],
76
+ creds["sc_password"],
77
+ timeout=60,
78
+ optional_args=optional_args,
79
+ ) as conn:
80
+ result = getattr(conn, args.cmd)()
81
+ pprint(result)
82
+
83
+
84
+ if __name__ == "__main__":
85
+ main()
@@ -0,0 +1 @@
1
+ from .iosxr import SCIOSXR