From 2c5c8eddc17104401ef9f44f0f037b62e965056f Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Wed, 29 Dec 2021 11:58:34 -0600 Subject: [PATCH 01/57] add extra for connections --- development/nautobot_config.py | 7 ++++++- .../plugins/inventory/nautobot_orm.py | 19 ++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 6dc7d02..b6624d5 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -7,7 +7,6 @@ from nautobot.core.settings import * # noqa: F403 from nautobot.core.settings_funcs import parse_redis_connection - # # Misc. settings # @@ -132,6 +131,12 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { + "napalm_extras": {"global_delay_factor": 5}, + "netmiko_extras": { + "global_delay_factor": 5, + "banner_timeout": 40, + "conn_timeout": 30, + }, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c544a22..c7a73fb 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -5,18 +5,9 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string -from nornir.core.inventory import ( - Inventory, - ConnectionOptions, - Defaults, - Groups, - Host, - Hosts, - Group, - ParentGroups, -) - from nautobot.dcim.models import Device +from nautobot_plugin_nornir.constants import PLUGIN_CFG +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -148,8 +139,10 @@ def create_host(self, device, cred, params: Dict): host = { "data": { "connection_options": { - "netmiko": {"extras": {}}, - "napalm": {"extras": {"optional_args": {}}}, + # "netmiko": {"extras": {}}, + "netmiko": {"extras": PLUGIN_CFG.get("napalm_extras", {})}, + # "napalm": {"extras": {"optional_args": {}}}, + "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("netmiko_extras", {})}}, }, }, } From 38faad837edbe484316b1254d9198a30ef932a9c Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 09:34:07 -0600 Subject: [PATCH 02/57] add debugs --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c7a73fb..fa396e0 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -7,7 +7,8 @@ from django.utils.module_loading import import_string from nautobot.dcim.models import Device from nautobot_plugin_nornir.constants import PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -136,6 +137,7 @@ def create_host(self, device, cred, params: Dict): Returns: dict: Nornir Host dictionnary """ + print(f"============={PLUGIN_CFG}\n=============") host = { "data": { "connection_options": { @@ -146,6 +148,7 @@ def create_host(self, device, cred, params: Dict): }, }, } + print(f"=============\nhost\n{host}\n=============") if "use_fqdn" in params and params.get("use_fqdn"): host["hostname"] = f"{device.name}.{params.get('fqdn')}" else: From a52e0bbbf40f6363dd4321c0d097a2303dd5d904 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 09:55:03 -0600 Subject: [PATCH 03/57] cleanups --- .../plugins/inventory/nautobot_orm.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index fa396e0..85c81c4 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -7,8 +7,7 @@ from django.utils.module_loading import import_string from nautobot.dcim.models import Device from nautobot_plugin_nornir.constants import PLUGIN_CFG -from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, - Host, Hosts, Inventory, ParentGroups) +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -137,18 +136,14 @@ def create_host(self, device, cred, params: Dict): Returns: dict: Nornir Host dictionnary """ - print(f"============={PLUGIN_CFG}\n=============") host = { "data": { "connection_options": { - # "netmiko": {"extras": {}}, - "netmiko": {"extras": PLUGIN_CFG.get("napalm_extras", {})}, - # "napalm": {"extras": {"optional_args": {}}}, - "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("netmiko_extras", {})}}, + "netmiko": {"extras": PLUGIN_CFG.get("netmiko_extras", {})}, + "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("napalm_extras", {})}}, }, }, } - print(f"=============\nhost\n{host}\n=============") if "use_fqdn" in params and params.get("use_fqdn"): host["hostname"] = f"{device.name}.{params.get('fqdn')}" else: From cccefb73c5020fcf282c0111dc1c233290810aba Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 10:46:44 -0600 Subject: [PATCH 04/57] add defaults to plugin config for example --- development/nautobot_config.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index b6624d5..5446ee5 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -131,12 +131,8 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "napalm_extras": {"global_delay_factor": 5}, - "netmiko_extras": { - "global_delay_factor": 5, - "banner_timeout": 40, - "conn_timeout": 30, - }, + "napalm_extras": {"global_delay_factor": 1}, + "netmiko_extras": {"global_delay_factor": 1}, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { From 9acbcfe316fdfc61dc831ae93ba9efe6a0164894 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 11:28:54 -0600 Subject: [PATCH 05/57] cleanups add to readme, fix spelling --- README.md | 10 ++++++++-- .../tests/inventory/test_nautobot_orm.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 170e3dc..738b96a 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { + "napalm_extras": {}, + "netmiko_extras": {}, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { @@ -59,6 +61,8 @@ Alternatively you can use the `CredentialsSettingsVars` class to set the usernam PLUGINS_CONFIG = { "nautobot_plugin_nornir": { "nornir_settings": { + "napalm_extras": {}, + "netmiko_extras": {}, "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", "runner": { "plugin": "threaded", @@ -83,6 +87,8 @@ The plugin behavior can be controlled with the following list of settings. | username | ntc | N/A | The username when leveraging the `CredentialsSettingsVars` credential provider. | | password | password123 | N/A | The password when leveraging the `CredentialsSettingsVars` credential provider. | | secret | password123 | N/A | The secret password when leveraging the `CredentialsSettingsVars` credential provider, **placeholder only, not currently functioning**. | +| netmiko_extras | {"global_delay_factor": 2} | N/A | Netmiko Extras can be used to control Netmiko settings for the connection. E.g. banner_timeout, conn_timeout. | +| napalm_extras | {"global_delay_factor": 2} | N/A | Napalm `optional_args` can be used to control Napalm settings. Options are listed [here](https://napalm.readthedocs.io/en/latest/support/#list-of-supported-optional-arguments). | Finally, as root, restart Nautobot and the Nautobot worker. @@ -108,7 +114,7 @@ The `dispatcher_mapping` configuration option can be set to extend or map the pl The above example demonstrates the following use cases. * Creating a custom only local dispatcher -* Mapping a user defined and preffered platform slug name to expected driver (e.g. ios -> cisco_ios) +* Mapping a user defined and preferred platform slug name to expected driver (e.g. ios -> cisco_ios) * Overloading platform slug keys, by mapping ios and ios_xe to the same class * Leveraging the existing "default" Netmiko driver @@ -117,7 +123,7 @@ allow users to define their own mappings as described above. # Inventory -The Nautobot ORM inventory is rather static in nature at this point. The user has the ability to define the `default` data. The native capabilites +The Nautobot ORM inventory is rather static in nature at this point. The user has the ability to define the `default` data. The native capabilities include. * Providing an object called within the `obj` key that is a Nautobot `Device` object instance. diff --git a/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py b/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py index fc2b830..8e4bd1c 100644 --- a/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py +++ b/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py @@ -2,7 +2,7 @@ from unittest import skip from django.test import TestCase -from nautobot.dcim.models import Device, Manufacturer, Site, DeviceType, DeviceRole +from nautobot.dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site from nautobot_plugin_nornir.plugins.inventory.nautobot_orm import NautobotORMInventory From a92d2cd87fa567cadb907ff88db11d4cfd324737 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 6 Jan 2022 12:04:11 -0600 Subject: [PATCH 06/57] fix incorrect default values --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 738b96a..e4a3880 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ The plugin behavior can be controlled with the following list of settings. | username | ntc | N/A | The username when leveraging the `CredentialsSettingsVars` credential provider. | | password | password123 | N/A | The password when leveraging the `CredentialsSettingsVars` credential provider. | | secret | password123 | N/A | The secret password when leveraging the `CredentialsSettingsVars` credential provider, **placeholder only, not currently functioning**. | -| netmiko_extras | {"global_delay_factor": 2} | N/A | Netmiko Extras can be used to control Netmiko settings for the connection. E.g. banner_timeout, conn_timeout. | -| napalm_extras | {"global_delay_factor": 2} | N/A | Napalm `optional_args` can be used to control Napalm settings. Options are listed [here](https://napalm.readthedocs.io/en/latest/support/#list-of-supported-optional-arguments). | +| netmiko_extras | {"global_delay_factor": 1} | N/A | Netmiko Extras can be used to control Netmiko settings for the connection. E.g. banner_timeout, conn_timeout. | +| napalm_extras | {"global_delay_factor": 1} | N/A | Napalm `optional_args` can be used to control Napalm settings. Options are listed [here](https://napalm.readthedocs.io/en/latest/support/#list-of-supported-optional-arguments). | Finally, as root, restart Nautobot and the Nautobot worker. From d4a201685b59d6e34e1d10ca8df31f1bd2356367 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 7 Jan 2022 14:02:51 -0600 Subject: [PATCH 07/57] rework to support generic connection_options --- development/nautobot_config.py | 16 +++++- nautobot_plugin_nornir/constants.py | 6 +++ .../plugins/inventory/nautobot_orm.py | 51 ++++++++++++------- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 5446ee5..776a5fb 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -131,8 +131,20 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "napalm_extras": {"global_delay_factor": 1}, - "netmiko_extras": {"global_delay_factor": 1}, + "connection_options": { + "napalm": { + "extras": { + "optional_args": { + "global_delay_factor": 1 + }, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { diff --git a/nautobot_plugin_nornir/constants.py b/nautobot_plugin_nornir/constants.py index 085b7a6..866efde 100644 --- a/nautobot_plugin_nornir/constants.py +++ b/nautobot_plugin_nornir/constants.py @@ -12,3 +12,9 @@ NORNIR_SETTINGS = PLUGIN_CFG.get("nornir_settings", _NORNIR_SETTINGS) DEFAULT_DRIVERS_MAPPING = PLUGIN_CFG.get("dispatcher_mapping", _DEFAULT_DRIVERS_MAPPING) + +CONNECTION_SECRETS_PATHS = { + "netmiko": "netmiko.extras.secret", + "napalm": "napalm.extras.optional_args.secret", + "scrapli": "scrapli.extras.auth_secondary", +} diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 85c81c4..2c41943 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,11 +6,20 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import PLUGIN_CFG +from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException +def _set_dict_key_path(dictionary, key_path, value): + *keys, last_key = key_path.split(".") + pointer = dictionary + for key in keys: + + pointer = pointer.setdefault(key, {}) + pointer[last_key] = value + + def _set_host(data: Dict[str, Any], name: str, groups, host, defaults) -> Host: connection_option = {} for key, value in data.get("connection_options", {}).items(): @@ -136,14 +145,7 @@ def create_host(self, device, cred, params: Dict): Returns: dict: Nornir Host dictionnary """ - host = { - "data": { - "connection_options": { - "netmiko": {"extras": PLUGIN_CFG.get("netmiko_extras", {})}, - "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("napalm_extras", {})}}, - }, - }, - } + host = {"data": {}} if "use_fqdn" in params and params.get("use_fqdn"): host["hostname"] = f"{device.name}.{params.get('fqdn')}" else: @@ -156,9 +158,6 @@ def create_host(self, device, cred, params: Dict): if not device.platform: raise NornirNautobotException(f"Platform missing from device {device.name}") host["platform"] = device.platform.slug - if device.platform.napalm_driver: - host["data"]["connection_options"]["napalm"]["platform"] = device.platform.napalm_driver - host["data"]["id"] = device.id host["data"]["type"] = device.device_type.slug host["data"]["site"] = device.site.slug @@ -174,14 +173,30 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - # Use secret if specified. - # Netmiko - host["data"]["connection_options"]["netmiko"]["extras"]["secret"] = secret - - # Napalm - host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret + if PLUGIN_CFG.get("connection_options"): + for nornir_provider, nornir_options in PLUGIN_CFG["connection_options"].items(): + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + else: + secret_path = CONNECTION_SECRETS_PATHS.get(nornir_provider) + _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + else: + # Still support current pattern + host["data"]["connection_options"] = { + "netmiko": {"extras": {}}, + "napalm": {"extras": {"optional_args": {}}}, + } + # Use secret if specified. + # Netmiko + host["data"]["connection_options"]["netmiko"]["extras"]["secret"] = secret + + # Napalm + host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret host["groups"] = self.get_host_groups(device=device) + + if device.platform.napalm_driver: + host["data"]["connection_options"]["napalm"]["platform"] = device.platform.napalm_driver return host @staticmethod From 72c723edc40190a025872c92642044bfcf3d679d Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 7 Jan 2022 14:27:04 -0600 Subject: [PATCH 08/57] rerun black --- development/nautobot_config.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 776a5fb..fd494b0 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -134,9 +134,7 @@ "connection_options": { "napalm": { "extras": { - "optional_args": { - "global_delay_factor": 1 - }, + "optional_args": {"global_delay_factor": 1}, }, }, "netmiko": { From 043f1a98498c8b87560faf4d16d6f892a90bcc04 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 7 Jan 2022 14:34:49 -0600 Subject: [PATCH 09/57] update readme with new dictionary paths --- README.md | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e4a3880..3355209 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,18 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "napalm_extras": {}, - "netmiko_extras": {}, + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { @@ -61,8 +71,18 @@ Alternatively you can use the `CredentialsSettingsVars` class to set the usernam PLUGINS_CONFIG = { "nautobot_plugin_nornir": { "nornir_settings": { - "napalm_extras": {}, - "netmiko_extras": {}, + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", "runner": { "plugin": "threaded", @@ -87,8 +107,7 @@ The plugin behavior can be controlled with the following list of settings. | username | ntc | N/A | The username when leveraging the `CredentialsSettingsVars` credential provider. | | password | password123 | N/A | The password when leveraging the `CredentialsSettingsVars` credential provider. | | secret | password123 | N/A | The secret password when leveraging the `CredentialsSettingsVars` credential provider, **placeholder only, not currently functioning**. | -| netmiko_extras | {"global_delay_factor": 1} | N/A | Netmiko Extras can be used to control Netmiko settings for the connection. E.g. banner_timeout, conn_timeout. | -| napalm_extras | {"global_delay_factor": 1} | N/A | Napalm `optional_args` can be used to control Napalm settings. Options are listed [here](https://napalm.readthedocs.io/en/latest/support/#list-of-supported-optional-arguments). | +| connection_options | {"netmiko": {"extras": "global_delay_factor": 1}}} | N/A | Connection Options for the given plugin provider in use. | Finally, as root, restart Nautobot and the Nautobot worker. From da6d7ea4baf755ff6654911aee6f9c2f102a1bcf Mon Sep 17 00:00:00 2001 From: Jeff Kala <48843785+jeffkala@users.noreply.github.com> Date: Mon, 10 Jan 2022 08:39:44 -0600 Subject: [PATCH 10/57] Apply suggestions from code review Co-authored-by: Ken Celenza --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 2c41943..27b7691 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -177,11 +177,13 @@ def create_host(self, device, cred, params: Dict): for nornir_provider, nornir_options in PLUGIN_CFG["connection_options"].items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS['nornir_provider'] else: - secret_path = CONNECTION_SECRETS_PATHS.get(nornir_provider) + continue _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) else: - # Still support current pattern + # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { "netmiko": {"extras": {}}, "napalm": {"extras": {"optional_args": {}}}, @@ -196,6 +198,8 @@ def create_host(self, device, cred, params: Dict): host["groups"] = self.get_host_groups(device=device) if device.platform.napalm_driver: + if not host["data"]["connection_options"].get("napalm"): + host["data"]["connection_options"]["napalm"] = {} host["data"]["connection_options"]["napalm"]["platform"] = device.platform.napalm_driver return host From c4b3f0cff092ba5d6f7be12b85a4adcc69d5c59a Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 10 Jan 2022 09:36:47 -0600 Subject: [PATCH 11/57] run black --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 27b7691..9cc00ad 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -178,7 +178,7 @@ def create_host(self, device, cred, params: Dict): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS['nornir_provider'] + secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] else: continue _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) From 82d828e76075a1d5d2c65a205ba4572e10741d4f Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 10 Jan 2022 16:34:16 -0600 Subject: [PATCH 12/57] fix python rendering in README to format with black --- README.md | 97 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 3355209..698c7ba 100644 --- a/README.md +++ b/README.md @@ -40,62 +40,63 @@ Once installed, the plugin needs to be enabled in your `nautobot_config.py` PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { - "nautobot_plugin_nornir": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, - "nornir_settings": { - "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", - "runner": { - "plugin": "threaded", - "options": { - "num_workers": 20, + "nautobot_plugin_nornir": { + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, }, - }, - }, - } + "nornir_settings": { + "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", + "runner": { + "plugin": "threaded", + "options": { + "num_workers": 20, + }, + }, + }, + } +} ``` Alternatively you can use the `CredentialsSettingsVars` class to set the username and password via settings. ```python PLUGINS_CONFIG = { - "nautobot_plugin_nornir": { - "nornir_settings": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, - "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", - "runner": { - "plugin": "threaded", - "options": { - "num_workers": 20, + "nautobot_plugin_nornir": { + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, }, - }, - }, - "dispatcher_mapping": None, - "username": "ntc", - "password": "password123", - "secret": "password123", - } + "nornir_settings": { + "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", + "runner": { + "plugin": "threaded", + "options": { + "num_workers": 20, + }, + }, + }, + "dispatcher_mapping": None, + "username": "ntc", + "password": "password123", + "secret": "password123", + } } ``` The plugin behavior can be controlled with the following list of settings. From 688464c998ad4991c83c01ffd640ab2c45dbd58c Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 21 Jan 2022 16:03:50 -0600 Subject: [PATCH 13/57] refactor to pull conn options from config context --- development/nautobot_config.py | 13 +------------ .../plugins/inventory/nautobot_orm.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index fd494b0..3d1dd7b 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -131,18 +131,7 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, + "use_config_context": True, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 9cc00ad..a5090d6 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,8 +6,10 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, + PLUGIN_CFG) +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -173,15 +175,16 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - if PLUGIN_CFG.get("connection_options"): - for nornir_provider, nornir_options in PLUGIN_CFG["connection_options"].items(): + if PLUGIN_CFG.get("use_config_context"): + conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + for nornir_provider, nornir_options in conn_options.items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] else: continue - _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + _set_dict_key_path(conn_options, secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From 525238ec7683c4102a667562e3fdc6fef4d0f1af Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 21 Jan 2022 16:54:58 -0600 Subject: [PATCH 14/57] fix dict key call --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index a5090d6..7707659 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -181,7 +181,7 @@ def create_host(self, device, cred, params: Dict): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue _set_dict_key_path(conn_options, secret_path, secret) From 8c9985bfbc92b08c221030a524bfd09635bffb86 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 08:22:03 -0600 Subject: [PATCH 15/57] update settings --- development/nautobot_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 3d1dd7b..4625d3a 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -131,7 +131,7 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "use_config_context": True, + "use_config_context": {"use_config_context": {"secrets": True, "connection_options": True}}, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { From ad4682af3e37426977ca5c5b933544d9d6eb10c8 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 10:44:59 -0600 Subject: [PATCH 16/57] update to merge conn options from global and config context --- README.md | 23 ++----------- development/nautobot_config.py | 15 ++++++++- .../plugins/inventory/nautobot_orm.py | 33 +++++++++++-------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 698c7ba..b5d9e1b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { + "use_config_context": {"connection_options": True}, "connection_options": { "napalm": { "extras": { @@ -71,27 +72,7 @@ Alternatively you can use the `CredentialsSettingsVars` class to set the usernam ```python PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, - "nornir_settings": { - "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", - "runner": { - "plugin": "threaded", - "options": { - "num_workers": 20, - }, - }, - }, + # ... "dispatcher_mapping": None, "username": "ntc", "password": "password123", diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 4625d3a..0e04df4 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -131,7 +131,20 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "use_config_context": {"use_config_context": {"secrets": True, "connection_options": True}}, + "use_config_context": {"connection_options": True}, + # Setting connection options globally + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 7707659..b9538ba 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,10 +6,8 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, - PLUGIN_CFG) -from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, - Host, Hosts, Inventory, ParentGroups) +from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -175,16 +173,23 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - if PLUGIN_CFG.get("use_config_context"): - conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] - for nornir_provider, nornir_options in conn_options.items(): - if nornir_options.get("connection_secret_path"): - secret_path = nornir_options.pop("connection_secret_path") - elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] - else: - continue - _set_dict_key_path(conn_options, secret_path, secret) + # Get global connection_options first. + if PLUGIN_CFG.get("connection_options"): + global_options = PLUGIN_CFG.get("connection_options") + # Get connection_options from device config context. + if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + # Merge connection_options global --> config_context. + conn_options = global_options.update(config_context_options) + for nornir_provider, nornir_options in conn_options: + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] + secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] + else: + continue + _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From 2f824232393dab2b1f03f3aa05719152f574a448 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 13:26:45 -0600 Subject: [PATCH 17/57] support global and config context --- .../plugins/inventory/nautobot_orm.py | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index b9538ba..9ffa88e 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -173,23 +173,26 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - # Get global connection_options first. - if PLUGIN_CFG.get("connection_options"): - global_options = PLUGIN_CFG.get("connection_options") - # Get connection_options from device config context. - if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] - # Merge connection_options global --> config_context. - conn_options = global_options.update(config_context_options) - for nornir_provider, nornir_options in conn_options: - if nornir_options.get("connection_secret_path"): - secret_path = nornir_options.pop("connection_secret_path") - elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] - secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] - else: - continue - _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + if PLUGIN_CFG.get("connection_options") or PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + # Get global connection_options first. + if PLUGIN_CFG.get("connection_options"): + conn_options = PLUGIN_CFG.get("connection_options") + # Get connection_options from device config_context. + if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + # Merge connection_options global --> config_context. + conn_options = conn_options.update(config_context_options) + else: + conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + for nornir_provider, nornir_options in conn_options: + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] + else: + continue + _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From fef0ca1188b9eebe0931e544c0c2f788f51a9e48 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 13:28:40 -0600 Subject: [PATCH 18/57] fix set key path add debug --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 9ffa88e..e1f6607 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -192,7 +192,7 @@ def create_host(self, device, cred, params: Dict): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + _set_dict_key_path(conn_options, secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { @@ -207,6 +207,7 @@ def create_host(self, device, cred, params: Dict): host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret host["groups"] = self.get_host_groups(device=device) + print(host["data"]["connection_options"]) if device.platform.napalm_driver: if not host["data"]["connection_options"].get("napalm"): From 26f1b4039e6d385e693fa1d44cc165a026ed89e1 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 14:07:44 -0600 Subject: [PATCH 19/57] add debugs --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index e1f6607..44ded4a 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -177,13 +177,17 @@ def create_host(self, device, cred, params: Dict): # Get global connection_options first. if PLUGIN_CFG.get("connection_options"): conn_options = PLUGIN_CFG.get("connection_options") + print(f"global options: {conn_options}") # Get connection_options from device config_context. if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. conn_options = conn_options.update(config_context_options) + print(f"merged conn options {conn_options}") else: conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + print(f"after else {conn_options}") for nornir_provider, nornir_options in conn_options: if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") From 1a351ba6e06eaddf80ea6874b1278db4a4d5b5ed Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 14:35:11 -0600 Subject: [PATCH 20/57] update merge of dicts --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 44ded4a..0b21ce1 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -183,7 +183,7 @@ def create_host(self, device, cred, params: Dict): config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. - conn_options = conn_options.update(config_context_options) + conn_options = {**conn_options, **config_context_options} print(f"merged conn options {conn_options}") else: conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] From 09dd8703190d4bb57f0178209a7d5c81bc3f2cf2 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 14:52:37 -0600 Subject: [PATCH 21/57] fix dict loop --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 0b21ce1..c5e3b32 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -188,7 +188,8 @@ def create_host(self, device, cred, params: Dict): else: conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] print(f"after else {conn_options}") - for nornir_provider, nornir_options in conn_options: + # {'napalm': {'extras': {'optional_args': {'global_delay_factor': 1}}}, 'netmiko': {'extras': {'global_delay_factor': 1}} + for nornir_provider, nornir_options in conn_options.items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): From c705c5bd7d508257614e3715e6ed41403e47192c Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 15:49:05 -0600 Subject: [PATCH 22/57] fix dict loop --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c5e3b32..4ab115c 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -197,7 +197,7 @@ def create_host(self, device, cred, params: Dict): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path(conn_options, secret_path, secret) + _set_dict_key_path({"connection_options": conn_options}, secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From d81581fadc1b2b35891789d9a7a844d52d089da4 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 16:09:50 -0600 Subject: [PATCH 23/57] tsing fix to new function to merge conn options --- .../plugins/inventory/nautobot_orm.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 4ab115c..37627c1 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,8 +6,10 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, + PLUGIN_CFG) +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -194,10 +196,10 @@ def create_host(self, device, cred, params: Dict): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] - secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path({"connection_options": conn_options}, secret_path, secret) + _set_dict_key_path(conn_options, secret_path, secret) + host["data"]["connection_options"] = conn_options else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From 73ab96502316cd7f6c494da5afa9cdd73fd8890e Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 16:44:13 -0600 Subject: [PATCH 24/57] tsing fix to new function to merge conn options --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 37627c1..6129ce2 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -182,13 +182,13 @@ def create_host(self, device, cred, params: Dict): print(f"global options: {conn_options}") # Get connection_options from device config_context. if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + config_context_options = device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. conn_options = {**conn_options, **config_context_options} print(f"merged conn options {conn_options}") else: - conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + conn_options = device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) print(f"after else {conn_options}") # {'napalm': {'extras': {'optional_args': {'global_delay_factor': 1}}}, 'netmiko': {'extras': {'global_delay_factor': 1}} for nornir_provider, nornir_options in conn_options.items(): From ee9580f8fa257b805cc3a63dc39350d47bbdb3d5 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Wed, 29 Dec 2021 11:58:34 -0600 Subject: [PATCH 25/57] add extra for connections --- .../plugins/inventory/nautobot_orm.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c544a22..c7a73fb 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -5,18 +5,9 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string -from nornir.core.inventory import ( - Inventory, - ConnectionOptions, - Defaults, - Groups, - Host, - Hosts, - Group, - ParentGroups, -) - from nautobot.dcim.models import Device +from nautobot_plugin_nornir.constants import PLUGIN_CFG +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -148,8 +139,10 @@ def create_host(self, device, cred, params: Dict): host = { "data": { "connection_options": { - "netmiko": {"extras": {}}, - "napalm": {"extras": {"optional_args": {}}}, + # "netmiko": {"extras": {}}, + "netmiko": {"extras": PLUGIN_CFG.get("napalm_extras", {})}, + # "napalm": {"extras": {"optional_args": {}}}, + "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("netmiko_extras", {})}}, }, }, } From 3b92fa5d0ae79fc67d98f3c6835299c4e465b0e1 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 09:34:07 -0600 Subject: [PATCH 26/57] add debugs --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c7a73fb..fa396e0 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -7,7 +7,8 @@ from django.utils.module_loading import import_string from nautobot.dcim.models import Device from nautobot_plugin_nornir.constants import PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -136,6 +137,7 @@ def create_host(self, device, cred, params: Dict): Returns: dict: Nornir Host dictionnary """ + print(f"============={PLUGIN_CFG}\n=============") host = { "data": { "connection_options": { @@ -146,6 +148,7 @@ def create_host(self, device, cred, params: Dict): }, }, } + print(f"=============\nhost\n{host}\n=============") if "use_fqdn" in params and params.get("use_fqdn"): host["hostname"] = f"{device.name}.{params.get('fqdn')}" else: From 2b24c2d1a11ae98a35135d7e068dad90b7d30c19 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 09:55:03 -0600 Subject: [PATCH 27/57] cleanups --- .../plugins/inventory/nautobot_orm.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index fa396e0..85c81c4 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -7,8 +7,7 @@ from django.utils.module_loading import import_string from nautobot.dcim.models import Device from nautobot_plugin_nornir.constants import PLUGIN_CFG -from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, - Host, Hosts, Inventory, ParentGroups) +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -137,18 +136,14 @@ def create_host(self, device, cred, params: Dict): Returns: dict: Nornir Host dictionnary """ - print(f"============={PLUGIN_CFG}\n=============") host = { "data": { "connection_options": { - # "netmiko": {"extras": {}}, - "netmiko": {"extras": PLUGIN_CFG.get("napalm_extras", {})}, - # "napalm": {"extras": {"optional_args": {}}}, - "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("netmiko_extras", {})}}, + "netmiko": {"extras": PLUGIN_CFG.get("netmiko_extras", {})}, + "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("napalm_extras", {})}}, }, }, } - print(f"=============\nhost\n{host}\n=============") if "use_fqdn" in params and params.get("use_fqdn"): host["hostname"] = f"{device.name}.{params.get('fqdn')}" else: From 9e33b32e9a162f739777bf072b604fff1b87cce4 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 30 Dec 2021 11:28:54 -0600 Subject: [PATCH 28/57] cleanups add to readme, fix spelling --- README.md | 8 ++++++-- .../tests/inventory/test_nautobot_orm.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2229fed..c162c2b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { + "napalm_extras": {}, + "netmiko_extras": {}, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { @@ -59,6 +61,8 @@ Alternatively you can use the `CredentialsSettingsVars` class to set the usernam PLUGINS_CONFIG = { "nautobot_plugin_nornir": { "nornir_settings": { + "napalm_extras": {}, + "netmiko_extras": {}, "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", "runner": { "plugin": "threaded", @@ -109,7 +113,7 @@ The `dispatcher_mapping` configuration option can be set to extend or map the pl The above example demonstrates the following use cases. * Creating a custom only local dispatcher -* Mapping a user defined and preffered platform slug name to expected driver (e.g. ios -> cisco_ios) +* Mapping a user defined and preferred platform slug name to expected driver (e.g. ios -> cisco_ios) * Overloading platform slug keys, by mapping ios and ios_xe to the same class * Leveraging the existing "default" Netmiko driver @@ -118,7 +122,7 @@ allow users to define their own mappings as described above. # Inventory -The Nautobot ORM inventory is rather static in nature at this point. The user has the ability to define the `default` data. The native capabilites +The Nautobot ORM inventory is rather static in nature at this point. The user has the ability to define the `default` data. The native capabilities include. * Providing an object called within the `obj` key that is a Nautobot `Device` object instance. diff --git a/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py b/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py index fc2b830..8e4bd1c 100644 --- a/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py +++ b/nautobot_plugin_nornir/tests/inventory/test_nautobot_orm.py @@ -2,7 +2,7 @@ from unittest import skip from django.test import TestCase -from nautobot.dcim.models import Device, Manufacturer, Site, DeviceType, DeviceRole +from nautobot.dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site from nautobot_plugin_nornir.plugins.inventory.nautobot_orm import NautobotORMInventory From 52de2eef64f685770575ac54aa7b054e8a361c96 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 7 Jan 2022 14:02:51 -0600 Subject: [PATCH 29/57] rework to support generic connection_options --- development/nautobot_config.py | 14 +++++ nautobot_plugin_nornir/constants.py | 6 +++ .../plugins/inventory/nautobot_orm.py | 51 ++++++++++++------- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 9f4a133..b01a573 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -132,6 +132,20 @@ PLUGINS_CONFIG = { "nautobot_plugin_nornir": { "use_config_context": {"secrets": True}, + "connection_options": { + "napalm": { + "extras": { + "optional_args": { + "global_delay_factor": 1 + }, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { diff --git a/nautobot_plugin_nornir/constants.py b/nautobot_plugin_nornir/constants.py index 42e89d3..280c813 100644 --- a/nautobot_plugin_nornir/constants.py +++ b/nautobot_plugin_nornir/constants.py @@ -12,3 +12,9 @@ NORNIR_SETTINGS = PLUGIN_CFG.get("nornir_settings", _NORNIR_SETTINGS) DEFAULT_DRIVERS_MAPPING = PLUGIN_CFG.get("dispatcher_mapping", _DEFAULT_DRIVERS_MAPPING) + +CONNECTION_SECRETS_PATHS = { + "netmiko": "netmiko.extras.secret", + "napalm": "napalm.extras.optional_args.secret", + "scrapli": "scrapli.extras.auth_secondary", +} diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 85c81c4..2c41943 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,11 +6,20 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import PLUGIN_CFG +from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException +def _set_dict_key_path(dictionary, key_path, value): + *keys, last_key = key_path.split(".") + pointer = dictionary + for key in keys: + + pointer = pointer.setdefault(key, {}) + pointer[last_key] = value + + def _set_host(data: Dict[str, Any], name: str, groups, host, defaults) -> Host: connection_option = {} for key, value in data.get("connection_options", {}).items(): @@ -136,14 +145,7 @@ def create_host(self, device, cred, params: Dict): Returns: dict: Nornir Host dictionnary """ - host = { - "data": { - "connection_options": { - "netmiko": {"extras": PLUGIN_CFG.get("netmiko_extras", {})}, - "napalm": {"extras": {"optional_args": PLUGIN_CFG.get("napalm_extras", {})}}, - }, - }, - } + host = {"data": {}} if "use_fqdn" in params and params.get("use_fqdn"): host["hostname"] = f"{device.name}.{params.get('fqdn')}" else: @@ -156,9 +158,6 @@ def create_host(self, device, cred, params: Dict): if not device.platform: raise NornirNautobotException(f"Platform missing from device {device.name}") host["platform"] = device.platform.slug - if device.platform.napalm_driver: - host["data"]["connection_options"]["napalm"]["platform"] = device.platform.napalm_driver - host["data"]["id"] = device.id host["data"]["type"] = device.device_type.slug host["data"]["site"] = device.site.slug @@ -174,14 +173,30 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - # Use secret if specified. - # Netmiko - host["data"]["connection_options"]["netmiko"]["extras"]["secret"] = secret - - # Napalm - host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret + if PLUGIN_CFG.get("connection_options"): + for nornir_provider, nornir_options in PLUGIN_CFG["connection_options"].items(): + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + else: + secret_path = CONNECTION_SECRETS_PATHS.get(nornir_provider) + _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + else: + # Still support current pattern + host["data"]["connection_options"] = { + "netmiko": {"extras": {}}, + "napalm": {"extras": {"optional_args": {}}}, + } + # Use secret if specified. + # Netmiko + host["data"]["connection_options"]["netmiko"]["extras"]["secret"] = secret + + # Napalm + host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret host["groups"] = self.get_host_groups(device=device) + + if device.platform.napalm_driver: + host["data"]["connection_options"]["napalm"]["platform"] = device.platform.napalm_driver return host @staticmethod From f096ddc2e143b12c825dbfdd625f3ce9e19f0bdd Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 7 Jan 2022 14:27:04 -0600 Subject: [PATCH 30/57] rerun black --- development/nautobot_config.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index b01a573..f09eb9c 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -135,9 +135,7 @@ "connection_options": { "napalm": { "extras": { - "optional_args": { - "global_delay_factor": 1 - }, + "optional_args": {"global_delay_factor": 1}, }, }, "netmiko": { From 762bed0eaed2222ed5d2eb44377ddde4300b24c4 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 7 Jan 2022 14:34:49 -0600 Subject: [PATCH 31/57] update readme with new dictionary paths --- README.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c162c2b..023c526 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,18 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "napalm_extras": {}, - "netmiko_extras": {}, + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", "runner": { @@ -61,8 +71,18 @@ Alternatively you can use the `CredentialsSettingsVars` class to set the usernam PLUGINS_CONFIG = { "nautobot_plugin_nornir": { "nornir_settings": { - "napalm_extras": {}, - "netmiko_extras": {}, + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, + }, "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", "runner": { "plugin": "threaded", From 28bb19d15dddf670411c45ac50f2184b82059058 Mon Sep 17 00:00:00 2001 From: Jeff Kala <48843785+jeffkala@users.noreply.github.com> Date: Mon, 10 Jan 2022 08:39:44 -0600 Subject: [PATCH 32/57] Apply suggestions from code review Co-authored-by: Ken Celenza --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 2c41943..27b7691 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -177,11 +177,13 @@ def create_host(self, device, cred, params: Dict): for nornir_provider, nornir_options in PLUGIN_CFG["connection_options"].items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS['nornir_provider'] else: - secret_path = CONNECTION_SECRETS_PATHS.get(nornir_provider) + continue _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) else: - # Still support current pattern + # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { "netmiko": {"extras": {}}, "napalm": {"extras": {"optional_args": {}}}, @@ -196,6 +198,8 @@ def create_host(self, device, cred, params: Dict): host["groups"] = self.get_host_groups(device=device) if device.platform.napalm_driver: + if not host["data"]["connection_options"].get("napalm"): + host["data"]["connection_options"]["napalm"] = {} host["data"]["connection_options"]["napalm"]["platform"] = device.platform.napalm_driver return host From 65c8dbb8bb269f73024e89d182a7bc47c92735a1 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 10 Jan 2022 09:36:47 -0600 Subject: [PATCH 33/57] run black --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 27b7691..9cc00ad 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -178,7 +178,7 @@ def create_host(self, device, cred, params: Dict): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS['nornir_provider'] + secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] else: continue _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) From 39d027671a4ea5751c8b91abcdbd4d52df7d4263 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 10 Jan 2022 16:34:16 -0600 Subject: [PATCH 34/57] fix python rendering in README to format with black --- README.md | 97 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 023c526..83c1780 100644 --- a/README.md +++ b/README.md @@ -40,62 +40,63 @@ Once installed, the plugin needs to be enabled in your `nautobot_config.py` PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { - "nautobot_plugin_nornir": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, - "nornir_settings": { - "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", - "runner": { - "plugin": "threaded", - "options": { - "num_workers": 20, + "nautobot_plugin_nornir": { + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, }, - }, - }, - } + "nornir_settings": { + "credentials": "nautobot_plugin_nornir.plugins.credentials.env_vars.CredentialsEnvVars", + "runner": { + "plugin": "threaded", + "options": { + "num_workers": 20, + }, + }, + }, + } +} ``` Alternatively you can use the `CredentialsSettingsVars` class to set the username and password via settings. ```python PLUGINS_CONFIG = { - "nautobot_plugin_nornir": { - "nornir_settings": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, - "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", - "runner": { - "plugin": "threaded", - "options": { - "num_workers": 20, + "nautobot_plugin_nornir": { + "connection_options": { + "napalm": { + "extras": { + "optional_args": {"global_delay_factor": 1}, + }, + }, + "netmiko": { + "extras": { + "global_delay_factor": 1, + }, + }, }, - }, - }, - "dispatcher_mapping": None, - "username": "ntc", - "password": "password123", - "secret": "password123", - } + "nornir_settings": { + "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", + "runner": { + "plugin": "threaded", + "options": { + "num_workers": 20, + }, + }, + }, + "dispatcher_mapping": None, + "username": "ntc", + "password": "password123", + "secret": "password123", + } } ``` The plugin behavior can be controlled with the following list of settings. From 88be5e5ab7d6df85ea3d1ad273d1fb0b52fe6a60 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 21 Jan 2022 16:03:50 -0600 Subject: [PATCH 35/57] refactor to pull conn options from config context --- .../plugins/inventory/nautobot_orm.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 9cc00ad..a5090d6 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,8 +6,10 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, + PLUGIN_CFG) +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -173,15 +175,16 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - if PLUGIN_CFG.get("connection_options"): - for nornir_provider, nornir_options in PLUGIN_CFG["connection_options"].items(): + if PLUGIN_CFG.get("use_config_context"): + conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + for nornir_provider, nornir_options in conn_options.items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] else: continue - _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + _set_dict_key_path(conn_options, secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From 17c32d24a6405d9751ca127335f54eb22f1b19b5 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 21 Jan 2022 16:54:58 -0600 Subject: [PATCH 36/57] fix dict key call --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index a5090d6..7707659 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -181,7 +181,7 @@ def create_host(self, device, cred, params: Dict): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue _set_dict_key_path(conn_options, secret_path, secret) From 405c3150f96c236608d79a2c6d3713ae28961ccc Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 08:22:03 -0600 Subject: [PATCH 37/57] update settings --- development/nautobot_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/development/nautobot_config.py b/development/nautobot_config.py index f09eb9c..a8dbe52 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -131,7 +131,7 @@ # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "use_config_context": {"secrets": True}, + "use_config_context": {"use_config_context": {"secrets": True, "connection_options": True}}, "connection_options": { "napalm": { "extras": { From a74eba924660240659e6a48d6bf544e59bb2932f Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 10:44:59 -0600 Subject: [PATCH 38/57] update to merge conn options from global and config context --- README.md | 23 ++----------- .../plugins/inventory/nautobot_orm.py | 33 +++++++++++-------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 83c1780..ad6ff8e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { + "use_config_context": {"connection_options": True}, "connection_options": { "napalm": { "extras": { @@ -71,27 +72,7 @@ Alternatively you can use the `CredentialsSettingsVars` class to set the usernam ```python PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "connection_options": { - "napalm": { - "extras": { - "optional_args": {"global_delay_factor": 1}, - }, - }, - "netmiko": { - "extras": { - "global_delay_factor": 1, - }, - }, - }, - "nornir_settings": { - "credentials": "nautobot_plugin_nornir.plugins.credentials.settings_vars.CredentialsSettingsVars", - "runner": { - "plugin": "threaded", - "options": { - "num_workers": 20, - }, - }, - }, + # ... "dispatcher_mapping": None, "username": "ntc", "password": "password123", diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 7707659..b9538ba 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,10 +6,8 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, - PLUGIN_CFG) -from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, - Host, Hosts, Inventory, ParentGroups) +from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -175,16 +173,23 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - if PLUGIN_CFG.get("use_config_context"): - conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] - for nornir_provider, nornir_options in conn_options.items(): - if nornir_options.get("connection_secret_path"): - secret_path = nornir_options.pop("connection_secret_path") - elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] - else: - continue - _set_dict_key_path(conn_options, secret_path, secret) + # Get global connection_options first. + if PLUGIN_CFG.get("connection_options"): + global_options = PLUGIN_CFG.get("connection_options") + # Get connection_options from device config context. + if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + # Merge connection_options global --> config_context. + conn_options = global_options.update(config_context_options) + for nornir_provider, nornir_options in conn_options: + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] + secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] + else: + continue + _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From bf5992b22f274d9c607b7cc9a4ebaf7b9ec4c25e Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 13:26:45 -0600 Subject: [PATCH 39/57] support global and config context --- .../plugins/inventory/nautobot_orm.py | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index b9538ba..9ffa88e 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -173,23 +173,26 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - # Get global connection_options first. - if PLUGIN_CFG.get("connection_options"): - global_options = PLUGIN_CFG.get("connection_options") - # Get connection_options from device config context. - if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] - # Merge connection_options global --> config_context. - conn_options = global_options.update(config_context_options) - for nornir_provider, nornir_options in conn_options: - if nornir_options.get("connection_secret_path"): - secret_path = nornir_options.pop("connection_secret_path") - elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] - secret_path = CONNECTION_SECRETS_PATHS["nornir_provider"] - else: - continue - _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + if PLUGIN_CFG.get("connection_options") or PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + # Get global connection_options first. + if PLUGIN_CFG.get("connection_options"): + conn_options = PLUGIN_CFG.get("connection_options") + # Get connection_options from device config_context. + if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + # Merge connection_options global --> config_context. + conn_options = conn_options.update(config_context_options) + else: + conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + for nornir_provider, nornir_options in conn_options: + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] + else: + continue + _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From 89210671ee83bdaa304d1c36b51af1317b6ef4a6 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 13:28:40 -0600 Subject: [PATCH 40/57] fix set key path add debug --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 9ffa88e..e1f6607 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -192,7 +192,7 @@ def create_host(self, device, cred, params: Dict): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path(PLUGIN_CFG["connection_options"], secret_path, secret) + _set_dict_key_path(conn_options, secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { @@ -207,6 +207,7 @@ def create_host(self, device, cred, params: Dict): host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret host["groups"] = self.get_host_groups(device=device) + print(host["data"]["connection_options"]) if device.platform.napalm_driver: if not host["data"]["connection_options"].get("napalm"): From 070f74e8d1ff0df24a8131e32cc76de2684d9114 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 14:07:44 -0600 Subject: [PATCH 41/57] add debugs --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index e1f6607..44ded4a 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -177,13 +177,17 @@ def create_host(self, device, cred, params: Dict): # Get global connection_options first. if PLUGIN_CFG.get("connection_options"): conn_options = PLUGIN_CFG.get("connection_options") + print(f"global options: {conn_options}") # Get connection_options from device config_context. if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. conn_options = conn_options.update(config_context_options) + print(f"merged conn options {conn_options}") else: conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + print(f"after else {conn_options}") for nornir_provider, nornir_options in conn_options: if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") From 29ddb3650e31db9acde31186ff53a51264b3055a Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 14:35:11 -0600 Subject: [PATCH 42/57] update merge of dicts --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 44ded4a..0b21ce1 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -183,7 +183,7 @@ def create_host(self, device, cred, params: Dict): config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. - conn_options = conn_options.update(config_context_options) + conn_options = {**conn_options, **config_context_options} print(f"merged conn options {conn_options}") else: conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] From bd9e046341e7bf7723b2ed8ee0a44f27cabda97a Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 14:52:37 -0600 Subject: [PATCH 43/57] fix dict loop --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 0b21ce1..c5e3b32 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -188,7 +188,8 @@ def create_host(self, device, cred, params: Dict): else: conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] print(f"after else {conn_options}") - for nornir_provider, nornir_options in conn_options: + # {'napalm': {'extras': {'optional_args': {'global_delay_factor': 1}}}, 'netmiko': {'extras': {'global_delay_factor': 1}} + for nornir_provider, nornir_options in conn_options.items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): From e07d056a131470c64b4bd2f4a995b7f3763c9270 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 15:49:05 -0600 Subject: [PATCH 44/57] fix dict loop --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c5e3b32..4ab115c 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -197,7 +197,7 @@ def create_host(self, device, cred, params: Dict): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path(conn_options, secret_path, secret) + _set_dict_key_path({"connection_options": conn_options}, secret_path, secret) else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From aa8c8ee3b8a61d3c83ff9954e856149f12736cdc Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 16:09:50 -0600 Subject: [PATCH 45/57] tsing fix to new function to merge conn options --- .../plugins/inventory/nautobot_orm.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 4ab115c..37627c1 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,8 +6,10 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, + PLUGIN_CFG) +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -194,10 +196,10 @@ def create_host(self, device, cred, params: Dict): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] - secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path({"connection_options": conn_options}, secret_path, secret) + _set_dict_key_path(conn_options, secret_path, secret) + host["data"]["connection_options"] = conn_options else: # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X host["data"]["connection_options"] = { From a1929023189feac7191ada7fd05e835d0c30a3f1 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 16:44:13 -0600 Subject: [PATCH 46/57] tsing fix to new function to merge conn options --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 37627c1..6129ce2 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -182,13 +182,13 @@ def create_host(self, device, cred, params: Dict): print(f"global options: {conn_options}") # Get connection_options from device config_context. if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - config_context_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + config_context_options = device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. conn_options = {**conn_options, **config_context_options} print(f"merged conn options {conn_options}") else: - conn_options = device.get_config_context()["nautobot_plugin_nornir"]["connection_options"] + conn_options = device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) print(f"after else {conn_options}") # {'napalm': {'extras': {'optional_args': {'global_delay_factor': 1}}}, 'netmiko': {'extras': {'global_delay_factor': 1}} for nornir_provider, nornir_options in conn_options.items(): From e54513a87f3e0e2d4c5a0648d87b16cd71b93544 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 17:14:14 -0600 Subject: [PATCH 47/57] rebase and update readme --- README.md | 6 +++--- .../plugins/inventory/nautobot_orm.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ad6ff8e..5fb63fa 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "use_config_context": {"connection_options": True}, + "use_config_context": {"secrets", False, "connection_options": True}, "connection_options": { "napalm": { "extras": { @@ -89,7 +89,7 @@ The plugin behavior can be controlled with the following list of settings. | username | ntc | N/A | The username when leveraging the `CredentialsSettingsVars` credential provider. | | password | password123 | N/A | The password when leveraging the `CredentialsSettingsVars` credential provider. | | secret | password123 | N/A | The secret password when leveraging the `CredentialsSettingsVars` credential provider.| -| use_config_context | {"secrets": False} | Whether to pull Secret Access Type from Config Context.| +| use_config_context | {"secrets": False, "connection_options": False} | Whether to pull Secret Access Type from Config Context.| Finally, as root, restart Nautobot and the Nautobot worker. @@ -196,7 +196,7 @@ Out of the box, users have access to three classes: ```python PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "use_config_context": {"secrets": True}, + "use_config_context": {"secrets": True, "connection_options": False}, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.nautobot_secrets.CredentialsNautobotSecrets", # ... diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 6129ce2..c01be20 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,10 +6,8 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, - PLUGIN_CFG) -from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, - Host, Hosts, Inventory, ParentGroups) +from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -182,13 +180,17 @@ def create_host(self, device, cred, params: Dict): print(f"global options: {conn_options}") # Get connection_options from device config_context. if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - config_context_options = device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) + config_context_options = ( + device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) + ) print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. conn_options = {**conn_options, **config_context_options} print(f"merged conn options {conn_options}") else: - conn_options = device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) + conn_options = ( + device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) + ) print(f"after else {conn_options}") # {'napalm': {'extras': {'optional_args': {'global_delay_factor': 1}}}, 'netmiko': {'extras': {'global_delay_factor': 1}} for nornir_provider, nornir_options in conn_options.items(): From 094b02bafd8ea505827376b1248055d7ffe0d459 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 24 Jan 2022 17:18:13 -0600 Subject: [PATCH 48/57] remove debugs --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index c01be20..bfcc051 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -177,22 +177,17 @@ def create_host(self, device, cred, params: Dict): # Get global connection_options first. if PLUGIN_CFG.get("connection_options"): conn_options = PLUGIN_CFG.get("connection_options") - print(f"global options: {conn_options}") # Get connection_options from device config_context. if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): config_context_options = ( device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) ) - print(f"config contet options {config_context_options}") # Merge connection_options global --> config_context. conn_options = {**conn_options, **config_context_options} - print(f"merged conn options {conn_options}") else: conn_options = ( device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) ) - print(f"after else {conn_options}") - # {'napalm': {'extras': {'optional_args': {'global_delay_factor': 1}}}, 'netmiko': {'extras': {'global_delay_factor': 1}} for nornir_provider, nornir_options in conn_options.items(): if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") @@ -216,7 +211,6 @@ def create_host(self, device, cred, params: Dict): host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret host["groups"] = self.get_host_groups(device=device) - print(host["data"]["connection_options"]) if device.platform.napalm_driver: if not host["data"]["connection_options"].get("napalm"): From bcb22cb3de238e63c53123668c84e22b3903a254 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Wed, 26 Jan 2022 16:05:54 -0600 Subject: [PATCH 49/57] revamp conn options merge --- .../plugins/inventory/nautobot_orm.py | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index bfcc051..524e799 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -173,42 +173,39 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - if PLUGIN_CFG.get("connection_options") or PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - # Get global connection_options first. - if PLUGIN_CFG.get("connection_options"): - conn_options = PLUGIN_CFG.get("connection_options") - # Get connection_options from device config_context. - if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): - config_context_options = ( - device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) - ) - # Merge connection_options global --> config_context. - conn_options = {**conn_options, **config_context_options} - else: - conn_options = ( - device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) - ) - for nornir_provider, nornir_options in conn_options.items(): + """ + Steps to reconcile the connection options + 1. Check for Global Option in plugin config + a. If global options exist, check for plugin config config_config extras set to True + a. If True, merge options together where config_context is preferred. + b. if set to False only return global options + 2. If global doesn't exist, check for config_context extras set to True + a. grab options from CC data for dev-obj + b. if none set, (default dict struct should be added) + 3. If no global, and no config_context + a. default dict struct should be added + """ + + def build_out_secret_paths(connection_options): + for nornir_provider, nornir_options in connection_options.items(): + # Offers extensibility to nornir plugins not listed in constants.py under CONNECTION_SECRETS_PATHS. if nornir_options.get("connection_secret_path"): secret_path = nornir_options.pop("connection_secret_path") elif CONNECTION_SECRETS_PATHS.get(nornir_provider): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path(conn_options, secret_path, secret) - host["data"]["connection_options"] = conn_options + _set_dict_key_path(connection_options, secret_path, secret) + + global_options = PLUGIN_CFG.get("connection_options", {"netmiko": {}, "napalm": {}}) + if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): + config_context_options = ( + device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) + ) + conn_options = build_out_secret_paths({**global_options, **config_context_options}) else: - # Supporting, but not documenting, and will be deprecated in nautobot-plugin-nornir 2.X - host["data"]["connection_options"] = { - "netmiko": {"extras": {}}, - "napalm": {"extras": {"optional_args": {}}}, - } - # Use secret if specified. - # Netmiko - host["data"]["connection_options"]["netmiko"]["extras"]["secret"] = secret - - # Napalm - host["data"]["connection_options"]["napalm"]["extras"]["optional_args"]["secret"] = secret + conn_options = build_out_secret_paths(global_options) + host["data"]["connection_options"] = conn_options host["groups"] = self.get_host_groups(device=device) From 515e963e455c4580aef0bbb5178b7a7463094edd Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Wed, 26 Jan 2022 17:07:04 -0600 Subject: [PATCH 50/57] cleanup and run black --- .../plugins/inventory/nautobot_orm.py | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 524e799..840eacc 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -20,6 +20,18 @@ def _set_dict_key_path(dictionary, key_path, value): pointer[last_key] = value +def _build_out_secret_paths(connection_options, device_secret): + for nornir_provider, nornir_options in connection_options.items(): + # Offers extensibility to nornir plugins not listed in constants.py under CONNECTION_SECRETS_PATHS. + if nornir_options.get("connection_secret_path"): + secret_path = nornir_options.pop("connection_secret_path") + elif CONNECTION_SECRETS_PATHS.get(nornir_provider): + secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] + else: + continue + _set_dict_key_path(connection_options, secret_path, device_secret) + + def _set_host(data: Dict[str, Any], name: str, groups, host, defaults) -> Host: connection_option = {} for key, value in data.get("connection_options", {}).items(): @@ -173,38 +185,14 @@ def create_host(self, device, cred, params: Dict): # require password for now host["password"] = password - """ - Steps to reconcile the connection options - 1. Check for Global Option in plugin config - a. If global options exist, check for plugin config config_config extras set to True - a. If True, merge options together where config_context is preferred. - b. if set to False only return global options - 2. If global doesn't exist, check for config_context extras set to True - a. grab options from CC data for dev-obj - b. if none set, (default dict struct should be added) - 3. If no global, and no config_context - a. default dict struct should be added - """ - - def build_out_secret_paths(connection_options): - for nornir_provider, nornir_options in connection_options.items(): - # Offers extensibility to nornir plugins not listed in constants.py under CONNECTION_SECRETS_PATHS. - if nornir_options.get("connection_secret_path"): - secret_path = nornir_options.pop("connection_secret_path") - elif CONNECTION_SECRETS_PATHS.get(nornir_provider): - secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] - else: - continue - _set_dict_key_path(connection_options, secret_path, secret) - - global_options = PLUGIN_CFG.get("connection_options", {"netmiko": {}, "napalm": {}}) + global_options = PLUGIN_CFG.get("connection_options", {"netmiko": {}, "napalm": {}, "scrapli": {}}) if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): config_context_options = ( device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) ) - conn_options = build_out_secret_paths({**global_options, **config_context_options}) + conn_options = _build_out_secret_paths({**global_options, **config_context_options}, secret) else: - conn_options = build_out_secret_paths(global_options) + conn_options = _build_out_secret_paths(global_options, secret) host["data"]["connection_options"] = conn_options host["groups"] = self.get_host_groups(device=device) From 630e0fb5489462e75f28f8c8b79dc21d6c7d88b5 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Wed, 26 Jan 2022 20:12:27 -0600 Subject: [PATCH 51/57] add a debug --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 840eacc..fde03c5 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -195,6 +195,7 @@ def create_host(self, device, cred, params: Dict): conn_options = _build_out_secret_paths(global_options, secret) host["data"]["connection_options"] = conn_options + print(f'DEBUG CONN OPTIONS\n {host["data"]["connection_options"]}') host["groups"] = self.get_host_groups(device=device) if device.platform.napalm_driver: From 40e19253d07d4ffdd1a2780989086a80a6f4d92a Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Wed, 26 Jan 2022 20:37:05 -0600 Subject: [PATCH 52/57] add a debug --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index fde03c5..d34fe01 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -186,13 +186,16 @@ def create_host(self, device, cred, params: Dict): host["password"] = password global_options = PLUGIN_CFG.get("connection_options", {"netmiko": {}, "napalm": {}, "scrapli": {}}) + print(f"GLOBAL_OPTIONS:\n{global_options}") if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): config_context_options = ( device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) ) conn_options = _build_out_secret_paths({**global_options, **config_context_options}, secret) + print(f"conn options from if:\n{conn_options}") else: conn_options = _build_out_secret_paths(global_options, secret) + print(f"conn options from else:\n{conn_options}") host["data"]["connection_options"] = conn_options print(f'DEBUG CONN OPTIONS\n {host["data"]["connection_options"]}') From 8668dedb4def56f6b01a3b8287594bd2acfc3973 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 27 Jan 2022 08:11:14 -0600 Subject: [PATCH 53/57] add missing return statement --- nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index d34fe01..938e698 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,8 +6,10 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG -from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups +from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, + PLUGIN_CFG) +from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, + Host, Hosts, Inventory, ParentGroups) from nornir_nautobot.exceptions import NornirNautobotException @@ -29,7 +31,7 @@ def _build_out_secret_paths(connection_options, device_secret): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - _set_dict_key_path(connection_options, secret_path, device_secret) + return _set_dict_key_path(connection_options, secret_path, device_secret) def _set_host(data: Dict[str, Any], name: str, groups, host, defaults) -> Host: From 4b8be067ca2ebc99d286031c61a40fca819835ae Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 27 Jan 2022 08:27:53 -0600 Subject: [PATCH 54/57] fix the dictionary building process --- .../plugins/inventory/nautobot_orm.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index 938e698..fc39335 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -6,10 +6,8 @@ from django.db.models import QuerySet from django.utils.module_loading import import_string from nautobot.dcim.models import Device -from nautobot_plugin_nornir.constants import (CONNECTION_SECRETS_PATHS, - PLUGIN_CFG) -from nornir.core.inventory import (ConnectionOptions, Defaults, Group, Groups, - Host, Hosts, Inventory, ParentGroups) +from nautobot_plugin_nornir.constants import CONNECTION_SECRETS_PATHS, PLUGIN_CFG +from nornir.core.inventory import ConnectionOptions, Defaults, Group, Groups, Host, Hosts, Inventory, ParentGroups from nornir_nautobot.exceptions import NornirNautobotException @@ -17,7 +15,6 @@ def _set_dict_key_path(dictionary, key_path, value): *keys, last_key = key_path.split(".") pointer = dictionary for key in keys: - pointer = pointer.setdefault(key, {}) pointer[last_key] = value @@ -31,7 +28,7 @@ def _build_out_secret_paths(connection_options, device_secret): secret_path = CONNECTION_SECRETS_PATHS[nornir_provider] else: continue - return _set_dict_key_path(connection_options, secret_path, device_secret) + _set_dict_key_path(connection_options, secret_path, device_secret) def _set_host(data: Dict[str, Any], name: str, groups, host, defaults) -> Host: @@ -193,11 +190,12 @@ def create_host(self, device, cred, params: Dict): config_context_options = ( device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) ) - conn_options = _build_out_secret_paths({**global_options, **config_context_options}, secret) + conn_options = {**global_options, **config_context_options} print(f"conn options from if:\n{conn_options}") else: - conn_options = _build_out_secret_paths(global_options, secret) + conn_options = global_options print(f"conn options from else:\n{conn_options}") + _build_out_secret_paths(conn_options, secret) host["data"]["connection_options"] = conn_options print(f'DEBUG CONN OPTIONS\n {host["data"]["connection_options"]}') From 6cc829002c4027023270bb51b996692589a9cae6 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Thu, 27 Jan 2022 09:15:25 -0600 Subject: [PATCH 55/57] update readme cleanup code and run black --- README.md | 75 +++++++++++++++++-- .../plugins/inventory/nautobot_orm.py | 7 +- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5fb63fa..c4c35cd 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ PLUGINS = ["nautobot_plugin_nornir"] PLUGINS_CONFIG = { "nautobot_plugin_nornir": { "use_config_context": {"secrets", False, "connection_options": True}, + # Optionally set global connection options. "connection_options": { "napalm": { "extras": { @@ -89,7 +90,24 @@ The plugin behavior can be controlled with the following list of settings. | username | ntc | N/A | The username when leveraging the `CredentialsSettingsVars` credential provider. | | password | password123 | N/A | The password when leveraging the `CredentialsSettingsVars` credential provider. | | secret | password123 | N/A | The secret password when leveraging the `CredentialsSettingsVars` credential provider.| -| use_config_context | {"secrets": False, "connection_options": False} | Whether to pull Secret Access Type from Config Context.| +| connection_options | N/A | {"netmiko": {"extras": {"global_delay_factor": 1}}} | Set Nornir connection options globally to be used with **all** connections. +| use_config_context | {"secrets": True, "connection_options": True} | {"secrets": False, "connection_options": False} | Whether to pull Secret Access Type, and/or Connection Options from Config Context.| + +> By default the device secret connection option path will be set for connections using: Napalm, Netmiko, and Scrapli. If an additional path needs to be registered it can be done by setting it inside the config context data. See below for an example. + +```yaml +--- +_metadata: + name: spine + weight: 1000 + description: Group Definitions for device type SPINE + is_active: true + device-roles: + - slug: spine +nautobot_plugin_nornir: + pluginx: + connection_secret_path: "pluginx.extras.secret" +``` Finally, as root, restart Nautobot and the Nautobot worker. @@ -133,6 +151,53 @@ include. * Provide credentials for NAPALM and Netmiko. * Link to the credential class as defined by the `nornir_settings['settings']` definition. + - Enabling the use of Config Context: + ```python + PLUGINS_CONFIG = { + "nautobot_plugin_nornir": { + "use_config_context": {"connection_options": True}, + "nornir_settings": { + "credentials": "nautobot_plugin_nornir.plugins.credentials.nautobot_secrets.CredentialsNautobotSecrets", + # ... + } + } + } + ``` + + - Local Device Config Context: + ```json + {"nautobot_plugin_nornir": { + "connection_options": { + "napalm": { + "extras": { + "optional_args": { + "global_delay_factor": 5 + } + } + } + } + } + } + ``` + + - Device Type Config Context: + ```yaml + --- + _metadata: + name: spine + weight: 1000 + description: Group Definitions for device type SPINE + is_active: true + device-roles: + - slug: spine + nautobot_plugin_nornir: + connection_options: + napalm: + extras: + optional_args: + global_delay_factor: 5 + ``` + # Credentials There is a `NautobotORMCredentials` class that describes what methods a Nautobot Nornir credential class should have. @@ -196,7 +261,7 @@ Out of the box, users have access to three classes: ```python PLUGINS_CONFIG = { "nautobot_plugin_nornir": { - "use_config_context": {"secrets": True, "connection_options": False}, + "use_config_context": {"secrets": True}, "nornir_settings": { "credentials": "nautobot_plugin_nornir.plugins.credentials.nautobot_secrets.CredentialsNautobotSecrets", # ... @@ -206,10 +271,8 @@ Out of the box, users have access to three classes: ``` - Local Device Config Context: - ```yaml - --- - nautobot_plugin_nornir: - secret_access_type: SSH # "GENERIC", "CONSOLE", "GNMI", "HTTP", "NETCONF", "REST", "RESTCONF", "SNMP", "SSH" + ```json + {"nautobot_plugin_nornir": {"secret_access_type": "SSH"}} ``` - Device Type Config Context: diff --git a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py index fc39335..af225fa 100644 --- a/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py +++ b/nautobot_plugin_nornir/plugins/inventory/nautobot_orm.py @@ -185,20 +185,17 @@ def create_host(self, device, cred, params: Dict): host["password"] = password global_options = PLUGIN_CFG.get("connection_options", {"netmiko": {}, "napalm": {}, "scrapli": {}}) - print(f"GLOBAL_OPTIONS:\n{global_options}") if PLUGIN_CFG.get("use_config_context", {}).get("connection_options"): config_context_options = ( device.get_config_context().get("nautobot_plugin_nornir", {}).get("connection_options", {}) ) conn_options = {**global_options, **config_context_options} - print(f"conn options from if:\n{conn_options}") else: conn_options = global_options - print(f"conn options from else:\n{conn_options}") + _build_out_secret_paths(conn_options, secret) - host["data"]["connection_options"] = conn_options - print(f'DEBUG CONN OPTIONS\n {host["data"]["connection_options"]}') + host["data"]["connection_options"] = conn_options host["groups"] = self.get_host_groups(device=device) if device.platform.napalm_driver: From 5ee00ef5dfcf99934a055cf1683aa39242bf0d50 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 31 Jan 2022 11:14:07 -0600 Subject: [PATCH 56/57] add key table for config contexts --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c4c35cd..dcb959c 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,18 @@ The plugin behavior can be controlled with the following list of settings. | connection_options | N/A | {"netmiko": {"extras": {"global_delay_factor": 1}}} | Set Nornir connection options globally to be used with **all** connections. | use_config_context | {"secrets": True, "connection_options": True} | {"secrets": False, "connection_options": False} | Whether to pull Secret Access Type, and/or Connection Options from Config Context.| -> By default the device secret connection option path will be set for connections using: Napalm, Netmiko, and Scrapli. If an additional path needs to be registered it can be done by setting it inside the config context data. See below for an example. + +The plugin behavior can be extended further with [config context](https://nautobot.readthedocs.io/en/stable/models/extras/gitrepository/#configuration-contexts) data. The plugin currently implements two options: Nornir connection options, and secrets. The supported settings are listed below. + +The root key for this plugin is `nautobot_plugin_nornir`. + +| Key | Description | +| ------- | ------------------------------------ | +| connection_options | Dictionary representation of a Nornir Plugins connection options. | +| connection_secret_path | Dotted expression of the dictionary path where a device secret should be stored for a given Nornir Plugin. | + + +By default the device secret connection option path will be set for connections using: Napalm, Netmiko, and Scrapli. If an additional path needs to be registered it can be done by setting it inside the config context data. See below for an example. ```yaml --- From f9d55fcf90faad00a86576cf84aa1a347539ab5e Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Mon, 31 Jan 2022 11:22:31 -0600 Subject: [PATCH 57/57] add key table for config contexts with secrets access type --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcb959c..0c6d227 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ The root key for this plugin is `nautobot_plugin_nornir`. | ------- | ------------------------------------ | | connection_options | Dictionary representation of a Nornir Plugins connection options. | | connection_secret_path | Dotted expression of the dictionary path where a device secret should be stored for a given Nornir Plugin. | - +| secret_access_type | Type of Secret Access Type to use. Examples. "GENERIC", "CONSOLE", "GNMI", "HTTP", "NETCONF", "REST", "RESTCONF", "SNMP", "SSH"| By default the device secret connection option path will be set for connections using: Napalm, Netmiko, and Scrapli. If an additional path needs to be registered it can be done by setting it inside the config context data. See below for an example.