From 3735f0db141f187b381bc1dc23576e6da3efdbb5 Mon Sep 17 00:00:00 2001 From: Josh VanDeraa Date: Tue, 27 Oct 2020 20:35:46 -0500 Subject: [PATCH 01/16] Adds doc to run migrations after updates. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c015dfb..3088281 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,12 @@ currently two strategies, strict and loose. Strict has to be a direct match, nor using a slug. Loose allows a range of search criteria to match a single object. If multiple objects are returned an error is raised. +## Upgrades + +When a new release comes out it is best practice to initiated a migration of the database to account +for any new migrations that may be needed to the DB. Execute a `python manage.py migrate`from the +NetBox install `netbox/` directory. + ## Usage ### Preparation From 19185f452965d04a2695976036028c0ced8b9270 Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Wed, 4 Nov 2020 11:11:37 +0100 Subject: [PATCH 02/16] Refactor of DNS resolving --- netbox_onboarding/helpers.py | 52 +++++++++++++++++++ netbox_onboarding/netdev_keeper.py | 45 ---------------- netbox_onboarding/tests/test_netdev_keeper.py | 21 +++----- netbox_onboarding/worker.py | 4 ++ 4 files changed, 64 insertions(+), 58 deletions(-) create mode 100644 netbox_onboarding/helpers.py diff --git a/netbox_onboarding/helpers.py b/netbox_onboarding/helpers.py new file mode 100644 index 0000000..dd39387 --- /dev/null +++ b/netbox_onboarding/helpers.py @@ -0,0 +1,52 @@ +"""OnboardingTask Django model. + +(c) 2020 Network To Code +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import socket + +import netaddr +from netaddr.core import AddrFormatError + +from .exceptions import OnboardException + + +def onboarding_task_fqdn_to_ip(ot): + """Method to assure OT has FQDN resolved to IP address and rewritten into OT. + + If it is a DNS name, attempt to resolve the DNS address and assign the IP address to the + name. + + Returns: + None + + Raises: + OnboardException("fail-general"): + When a prefix was entered for an IP address + OnboardException("fail-dns"): + When a Name lookup via DNS fails to resolve an IP address + """ + try: + # If successful, this is an IP address and can pass + netaddr.IPAddress(ot.ip_address) + # Raise an Exception for Prefix values + except ValueError: + raise OnboardException(reason="fail-general", message=f"ERROR appears a prefix was entered: {ot.ip_address}") + # An AddrFormatError exception means that there is not an IP address in the field, and should continue on + except AddrFormatError: + try: + # Perform DNS Lookup + ot.ip_address = socket.gethostbyname(ot.ip_address) + ot.save() + except socket.gaierror: + # DNS Lookup has failed, Raise an exception for unable to complete DNS lookup + raise OnboardException(reason="fail-dns", message=f"ERROR failed to complete DNS lookup: {ot.ip_address}") diff --git a/netbox_onboarding/netdev_keeper.py b/netbox_onboarding/netdev_keeper.py index 07fb1b8..1ab88e1 100644 --- a/netbox_onboarding/netdev_keeper.py +++ b/netbox_onboarding/netdev_keeper.py @@ -16,11 +16,9 @@ import logging import socket -import netaddr from django.conf import settings from napalm import get_network_driver from napalm.base.exceptions import ConnectionException, CommandErrorException -from netaddr.core import AddrFormatError from netmiko.ssh_autodetect import SSHDetect from netmiko.ssh_exception import NetMikoAuthenticationException from netmiko.ssh_exception import NetMikoTimeoutException @@ -96,46 +94,6 @@ def __init__( # pylint: disable=R0913 self.onboarding_class = StandaloneOnboarding self.driver_addon_result = None - def check_ip(self): - """Method to check if the IP address form field was an IP address. - - If it is a DNS name, attempt to resolve the DNS address and assign the IP address to the - name. - - Returns: - (bool): True if the IP address is an IP address, or a DNS entry was found and - reassignment of the ot.ip_address was done. - False if unable to find a device IP (error) - - Raises: - OnboardException("fail-general"): - When a prefix was entered for an IP address - OnboardException("fail-dns"): - When a Name lookup via DNS fails to resolve an IP address - """ - try: - # Assign checked_ip to None for error handling - # If successful, this is an IP address and can pass - checked_ip = netaddr.IPAddress(self.hostname) - return True - # Catch when someone has put in a prefix address, raise an exception - except ValueError: - raise OnboardException( - reason="fail-general", message=f"ERROR appears a prefix was entered: {self.hostname}" - ) - # An AddrFormatError exception means that there is not an IP address in the field, and should continue on - except AddrFormatError: - try: - # Do a lookup of name to get the IP address to connect to - checked_ip = socket.gethostbyname(self.hostname) - self.hostname = checked_ip - return True - except socket.gaierror: - # DNS Lookup has failed, Raise an exception for unable to complete DNS lookup - raise OnboardException( - reason="fail-dns", message=f"ERROR failed to complete DNS lookup: {self.hostname}" - ) - def check_reachability(self): """Ensure that the device at the mgmt-ipaddr provided is reachable. @@ -231,9 +189,6 @@ def get_onboarding_facts(self): OnboardException('fail-general'): Any other unexpected device comms failure. """ - # Check to see if the IP address entered was an IP address or a DNS entry, get the IP address - self.check_ip() - self.check_reachability() logger.info("COLLECT: device information %s", self.hostname) diff --git a/netbox_onboarding/tests/test_netdev_keeper.py b/netbox_onboarding/tests/test_netdev_keeper.py index 36623da..d709a72 100644 --- a/netbox_onboarding/tests/test_netdev_keeper.py +++ b/netbox_onboarding/tests/test_netdev_keeper.py @@ -19,8 +19,8 @@ from dcim.models import Site, DeviceRole, Platform from netbox_onboarding.exceptions import OnboardException +from netbox_onboarding.helpers import onboarding_task_fqdn_to_ip from netbox_onboarding.models import OnboardingTask -from netbox_onboarding.netdev_keeper import NetdevKeeper class NetdevKeeperTestCase(TestCase): @@ -46,37 +46,32 @@ def setUp(self): ip_address="192.0.2.1/32", site=self.site1, role=self.device_role1, platform=self.platform1 ) - @mock.patch("netbox_onboarding.netdev_keeper.socket.gethostbyname") + @mock.patch("netbox_onboarding.helpers.socket.gethostbyname") def test_check_ip(self, mock_get_hostbyname): """Check DNS to IP address.""" # Look up response value mock_get_hostbyname.return_value = "192.0.2.1" - # Create a Device Keeper object of the device - ndk4 = NetdevKeeper(hostname=self.onboarding_task4.ip_address) - - # Check that the IP address is returned - self.assertTrue(ndk4.check_ip()) + # FQDN -> IP + onboarding_task_fqdn_to_ip(ot=self.onboarding_task4) # Run the check to change the IP address - self.assertEqual(ndk4.hostname, "192.0.2.1") + self.assertEqual(self.onboarding_task4.ip_address, "192.0.2.1") - @mock.patch("netbox_onboarding.netdev_keeper.socket.gethostbyname") + @mock.patch("netbox_onboarding.helpers.socket.gethostbyname") def test_failed_check_ip(self, mock_get_hostbyname): """Check DNS to IP address failing.""" # Look up a failed response mock_get_hostbyname.side_effect = gaierror(8) - ndk5 = NetdevKeeper(hostname=self.onboarding_task5.ip_address) - ndk7 = NetdevKeeper(hostname=self.onboarding_task7.ip_address) # Check for bad.local raising an exception with self.assertRaises(OnboardException) as exc_info: - ndk5.check_ip() + onboarding_task_fqdn_to_ip(ot=self.onboarding_task5) self.assertEqual(exc_info.exception.message, "ERROR failed to complete DNS lookup: bad.local") self.assertEqual(exc_info.exception.reason, "fail-dns") # Check for exception with prefix address entered with self.assertRaises(OnboardException) as exc_info: - ndk7.check_ip() + onboarding_task_fqdn_to_ip(ot=self.onboarding_task7) self.assertEqual(exc_info.exception.reason, "fail-prefix") self.assertEqual(exc_info.exception.message, "ERROR appears a prefix was entered: 192.0.2.1/32") diff --git a/netbox_onboarding/worker.py b/netbox_onboarding/worker.py index e4202a3..623aa80 100644 --- a/netbox_onboarding/worker.py +++ b/netbox_onboarding/worker.py @@ -22,6 +22,7 @@ from .choices import OnboardingFailChoices from .choices import OnboardingStatusChoices from .exceptions import OnboardException +from .helpers import onboarding_task_fqdn_to_ip from .metrics import onboardingtask_results_counter from .models import OnboardingDevice from .models import OnboardingTask @@ -43,6 +44,9 @@ def onboard_device(task_id, credentials): # pylint: disable=too-many-statements ot = OnboardingTask.objects.get(id=task_id) + # Rewrite FQDN to IP for Onboarding Task + onboarding_task_fqdn_to_ip(ot) + logger.info("START: onboard device") onboarded_device = None From 7fe584b368080c913292827a3fd6728138509584 Mon Sep 17 00:00:00 2001 From: Josh VanDeraa Date: Wed, 11 Nov 2020 21:28:21 -0600 Subject: [PATCH 03/16] Updates per feedback. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 3088281..7f1437d 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,7 @@ objects are returned an error is raised. ## Upgrades -When a new release comes out it is best practice to initiated a migration of the database to account -for any new migrations that may be needed to the DB. Execute a `python manage.py migrate`from the -NetBox install `netbox/` directory. +When a new release comes out it may be necessary to run a migration of the database to account for any changes in the data models used by this plugin. Execute the command `python3 manage.py migrate`from the NetBox install `netbox/` directory after updating the package. ## Usage From 04e60aeb52036f1446a0b2efe66f11cda20e19b7 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Wed, 29 Jul 2020 17:47:35 -0400 Subject: [PATCH 04/16] Napalm and Netmiko optional arguments --- netbox_onboarding/netdev_keeper.py | 40 ++++++++++++++++++++++++------ netbox_onboarding/onboard.py | 19 +++++++++++--- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/netbox_onboarding/netdev_keeper.py b/netbox_onboarding/netdev_keeper.py index 1ab88e1..2a35849 100644 --- a/netbox_onboarding/netdev_keeper.py +++ b/netbox_onboarding/netdev_keeper.py @@ -19,6 +19,7 @@ from django.conf import settings from napalm import get_network_driver from napalm.base.exceptions import ConnectionException, CommandErrorException +from napalm.base.netmiko_helpers import netmiko_args from netmiko.ssh_autodetect import SSHDetect from netmiko.ssh_exception import NetMikoAuthenticationException from netmiko.ssh_exception import NetMikoTimeoutException @@ -62,7 +63,15 @@ class NetdevKeeper: """Used to maintain information about the network device during the onboarding process.""" def __init__( # pylint: disable=R0913 - self, hostname, port=None, timeout=None, username=None, password=None, secret=None, napalm_driver=None + self, + hostname, + port=None, + timeout=None, + username=None, + password=None, + secret=None, + napalm_driver=None, + optional_args=None, ): """Initialize the network device keeper instance and ensure the required configuration parameters are provided. @@ -83,10 +92,11 @@ def __init__( # pylint: disable=R0913 self.hostname = hostname self.port = port self.timeout = timeout - self.username = username or settings.NAPALM_USERNAME - self.password = password or settings.NAPALM_PASSWORD - self.secret = secret or settings.NAPALM_ARGS.get("secret", None) + self.username = username + self.password = password + self.secret = secret self.napalm_driver = napalm_driver + self.optional_args = optional_args self.facts = None self.ip_ifs = None @@ -120,14 +130,25 @@ def guess_netmiko_device_type(self): """Guess the device type of host, based on Netmiko.""" guessed_device_type = None + netmiko_optional_args = netmiko_args(self.optional_args) + remote_device = { "device_type": "autodetect", "host": self.hostname, "username": self.username, "password": self.password, - "secret": self.secret, + **netmiko_optional_args, } + if self.secret: + remote_device["secret"] = self.secret + + if self.port: + remote_device["port"] = self.port + + if self.timeout: + remote_device["timeout"] = self.timeout + try: logger.info("INFO guessing device type: %s", self.hostname) guesser = SSHDetect(**remote_device) @@ -201,8 +222,13 @@ def get_onboarding_facts(self): self.check_napalm_driver_name() driver = get_network_driver(self.napalm_driver) - optional_args = settings.NAPALM_ARGS.copy() - optional_args["secret"] = self.secret + + optional_args = self.optional_args.copy() + if self.port: + optional_args["port"] = self.port + + if self.secret: + optional_args["secret"] = self.secret napalm_device = driver( hostname=self.hostname, diff --git a/netbox_onboarding/onboard.py b/netbox_onboarding/onboard.py index cbe68c0..27e631c 100644 --- a/netbox_onboarding/onboard.py +++ b/netbox_onboarding/onboard.py @@ -12,6 +12,8 @@ limitations under the License. """ +import json + from django.conf import settings from .netdev_keeper import NetdevKeeper @@ -34,6 +36,16 @@ def napalm_driver(self): return None + @property + def optional_args(self): + """Return platform optional args.""" + if self.ot.platform and self.ot.platform.napalm_args: + napalm_args = json.loads(self.ot.platform.napalm_args) + + return napalm_args + + return {} + @property def ip_address(self): """Return ot's ip address.""" @@ -86,10 +98,11 @@ def __init__(self, ot, username, password, secret): hostname=otm.ip_address, port=otm.port, timeout=otm.timeout, - username=self.username, - password=self.password, - secret=self.secret, + username=self.username or settings.NAPALM_USERNAME, + password=self.password or settings.NAPALM_PASSWORD, + secret=self.secret or otm.optional_args.get("secret", None) or settings.NAPALM_ARGS.get("secret", None), napalm_driver=otm.napalm_driver, + optional_args=otm.optional_args or settings.NAPALM_ARGS, ) netdev.get_onboarding_facts() From 493aca39002b7121628d9c72431a3ea2e9a330b5 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Fri, 13 Nov 2020 10:55:13 -0500 Subject: [PATCH 05/16] Add CODEOWNERS file --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..69fff31 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Default owners for all files in this repository +* @dgarros @mzbroch \ No newline at end of file From 3fd770cdc34e0383b7a1ea0e45ca63f5843de90a Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Thu, 12 Nov 2020 12:37:11 +0100 Subject: [PATCH 06/16] Load driver extensions flag --- netbox_onboarding/netdev_keeper.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/netbox_onboarding/netdev_keeper.py b/netbox_onboarding/netdev_keeper.py index 2a35849..6450163 100644 --- a/netbox_onboarding/netdev_keeper.py +++ b/netbox_onboarding/netdev_keeper.py @@ -104,6 +104,9 @@ def __init__( # pylint: disable=R0913 self.onboarding_class = StandaloneOnboarding self.driver_addon_result = None + # Enable loading driver extensions + self.load_driver_extension = True + def check_reachability(self): """Ensure that the device at the mgmt-ipaddr provided is reachable. @@ -248,7 +251,7 @@ def get_onboarding_facts(self): module_name = PLUGIN_SETTINGS["onboarding_extensions_map"].get(self.napalm_driver) - if module_name: + if module_name and self.load_driver_extension: try: module = importlib.import_module(module_name) driver_addon_class = module.OnboardingDriverExtensions(napalm_device=napalm_device) From b184a9f441231136e4157e929a763141e5c42b68 Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Thu, 12 Nov 2020 13:13:21 +0100 Subject: [PATCH 07/16] Credentials attribute in onboarding class --- netbox_onboarding/onboard.py | 15 ++++++++------- netbox_onboarding/onboarding/onboarding.py | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/netbox_onboarding/onboard.py b/netbox_onboarding/onboard.py index 27e631c..4edd3c2 100644 --- a/netbox_onboarding/onboard.py +++ b/netbox_onboarding/onboard.py @@ -87,20 +87,20 @@ class OnboardingManager: def __init__(self, ot, username, password, secret): """Inits class.""" - self.username = username - self.password = password - self.secret = secret - # Create instance of Onboarding Task Manager class: otm = OnboardingTaskManager(ot) + self.username = username or settings.NAPALM_USERNAME + self.password = password or settings.NAPALM_PASSWORD + self.secret = secret or otm.optional_args.get("secret", None) or settings.NAPALM_ARGS.get("secret", None) + netdev = NetdevKeeper( hostname=otm.ip_address, port=otm.port, timeout=otm.timeout, - username=self.username or settings.NAPALM_USERNAME, - password=self.password or settings.NAPALM_PASSWORD, - secret=self.secret or otm.optional_args.get("secret", None) or settings.NAPALM_ARGS.get("secret", None), + username=self.username, + password=self.password, + secret=self.secret, napalm_driver=otm.napalm_driver, optional_args=otm.optional_args or settings.NAPALM_ARGS, ) @@ -129,6 +129,7 @@ def __init__(self, ot, username, password, secret): } onboarding_cls = netdev_dict["onboarding_class"]() + onboarding_cls.credentials = {"username": self.username, "password": self.password, "secret": self.secret} onboarding_cls.run(onboarding_kwargs=onboarding_kwargs) self.created_device = onboarding_cls.created_device diff --git a/netbox_onboarding/onboarding/onboarding.py b/netbox_onboarding/onboarding/onboarding.py index 763e21b..5fe3ad6 100644 --- a/netbox_onboarding/onboarding/onboarding.py +++ b/netbox_onboarding/onboarding/onboarding.py @@ -21,6 +21,7 @@ class Onboarding: def __init__(self): """Init the class.""" self.created_device = None + self.credentials = None def run(self, onboarding_kwargs): """Implement run method.""" From 31bbdd4779ccc565adb7459aed7cdce9e509c165 Mon Sep 17 00:00:00 2001 From: Nick Niehoff Date: Mon, 16 Nov 2020 18:42:38 -0700 Subject: [PATCH 08/16] Updating dependencies and allowing for Napalm 3.x. --- .pylintrc | 26 - development/base_configuration.py | 8 +- development/netbox_v2.8.3/configuration.py | 4 + netbox_onboarding/tests/test_api.py | 2 +- poetry.lock | 1006 +++++++++++--------- pyproject.toml | 41 +- tasks.py | 2 +- 7 files changed, 623 insertions(+), 466 deletions(-) delete mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index b5b73b9..0000000 --- a/.pylintrc +++ /dev/null @@ -1,26 +0,0 @@ -[MASTER] -# Include the pylint_django plugin to avoid spurious warnings about Django patterns -load-plugins=pylint_django - -# Don't cache data for later comparisons -persistent=no - -[BASIC] -# Don't require docstrings for inner Meta classes (or private classes starting with _) -no-docstring-rgx=^(_|Meta$) -# Allow "ot" (OnboardingTask instance) as an acceptable variable name -good-names=ot, - -[MISCELLANEOUS] -# Don't currently throw warnings for TODO comments - we should eventually remove this -notes=FIXME,XXX, - -[MESSAGE CONTROL] -# Disabled due to contention with Black: bad-continuation, line-too-long -# Disabled due to noise: too-few-public-methods, too-many-ancestors, too-many-instance-attributes -disable=bad-continuation, - line-too-long, - too-few-public-methods, - too-many-ancestors, - too-many-instance-attributes, - duplicate-code diff --git a/development/base_configuration.py b/development/base_configuration.py index 12aa5a1..06467cc 100644 --- a/development/base_configuration.py +++ b/development/base_configuration.py @@ -43,7 +43,6 @@ "PORT": int(os.environ.get("REDIS_PORT", 6379)), "PASSWORD": os.environ.get("REDIS_PASSWORD", ""), "DATABASE": 1, - "DEFAULT_TIMEOUT": 300, "SSL": bool(os.environ.get("REDIS_SSL", False)), }, "tasks": { @@ -51,11 +50,12 @@ "PORT": int(os.environ.get("REDIS_PORT", 6379)), "PASSWORD": os.environ.get("REDIS_PASSWORD", ""), "DATABASE": 0, - "DEFAULT_TIMEOUT": 300, "SSL": bool(os.environ.get("REDIS_SSL", False)), }, } +RQ_DEFAULT_TIMEOUT = 300 + ######################### # # @@ -179,11 +179,11 @@ # Remote authentication support REMOTE_AUTH_ENABLED = False -REMOTE_AUTH_BACKEND = "utilities.auth_backends.RemoteUserBackend" +REMOTE_AUTH_BACKEND = "netbox.authentication.RemoteUserBackend" REMOTE_AUTH_HEADER = "HTTP_REMOTE_USER" REMOTE_AUTH_AUTO_CREATE_USER = True REMOTE_AUTH_DEFAULT_GROUPS = [] -REMOTE_AUTH_DEFAULT_PERMISSIONS = [] +REMOTE_AUTH_DEFAULT_PERMISSIONS = {} # This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. RELEASE_CHECK_TIMEOUT = 24 * 3600 diff --git a/development/netbox_v2.8.3/configuration.py b/development/netbox_v2.8.3/configuration.py index 00f4829..c27860c 100644 --- a/development/netbox_v2.8.3/configuration.py +++ b/development/netbox_v2.8.3/configuration.py @@ -2,3 +2,7 @@ from .base_configuration import * # pylint: disable=relative-beyond-top-level, wildcard-import # Overrides specific to this version go here +REMOTE_AUTH_BACKEND = "utilities.auth_backends.RemoteUserBackend" +REMOTE_AUTH_DEFAULT_PERMISSIONS = [] +REDIS["caching"]["DEFAULT_TIMEOUT"] = 300 # pylint: disable=undefined-variable +REDIS["tasks"]["DEFAULT_TIMEOUT"] = 300 # pylint: disable=undefined-variable diff --git a/netbox_onboarding/tests/test_api.py b/netbox_onboarding/tests/test_api.py index c4c3145..26e5e60 100644 --- a/netbox_onboarding/tests/test_api.py +++ b/netbox_onboarding/tests/test_api.py @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and limitations under the License. """ -from django.contrib.auth.models import User +from django.contrib.auth.models import User # pylint: disable=imported-auth-user from django.test import TestCase from django.urls import reverse from rest_framework import status diff --git a/poetry.lock b/poetry.lock index 30a31b3..f9a5156 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,79 +1,77 @@ [[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = "*" -version = "1.4.4" [[package]] -category = "dev" -description = "An abstract syntax tree for Python with inference support." name = "astroid" +version = "2.4.2" +description = "An abstract syntax tree for Python with inference support." +category = "dev" optional = false python-versions = ">=3.5" -version = "2.4.1" [package.dependencies] lazy-object-proxy = ">=1.4.0,<1.5.0" six = ">=1.12,<2.0" +typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} wrapt = ">=1.11,<2.0" -[package.dependencies.typed-ast] -python = "<3.8" -version = ">=1.4.0,<1.5" - [[package]] -category = "dev" -description = "Classes Without Boilerplate" name = "attrs" +version = "20.3.0" +description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" [package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] -category = "dev" -description = "Security oriented static analyser for python code." name = "bandit" +version = "1.6.2" +description = "Security oriented static analyser for python code." +category = "dev" optional = false python-versions = "*" -version = "1.6.2" [package.dependencies] +colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} GitPython = ">=1.0.1" PyYAML = ">=3.13" -colorama = ">=0.3.9" six = ">=1.10.0" stevedore = ">=1.20.0" [[package]] -category = "main" -description = "Modern password hashing for your software and your servers" name = "bcrypt" +version = "3.2.0" +description = "Modern password hashing for your software and your servers" +category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.1.7" +python-versions = ">=3.6" [package.dependencies] cffi = ">=1.1" six = ">=1.4.1" [package.extras] -tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)"] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] [[package]] -category = "dev" -description = "The uncompromising code formatter." name = "black" +version = "19.10b0" +description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.6" -version = "19.10b0" [package.dependencies] appdirs = "*" @@ -88,39 +86,39 @@ typed-ast = ">=1.4.0" d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] -category = "main" -description = "Python package for providing Mozilla's CA Bundle." name = "certifi" +version = "2020.11.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = "*" -version = "2020.4.5.1" [[package]] -category = "main" -description = "Foreign Function Interface for Python calling C code." name = "cffi" +version = "1.14.3" +description = "Foreign Function Interface for Python calling C code." +category = "main" optional = false python-versions = "*" -version = "1.14.0" [package.dependencies] pycparser = "*" [[package]] -category = "main" -description = "Universal encoding detector for Python 2 and 3" name = "chardet" +version = "3.0.4" +description = "Universal encoding detector for Python 2 and 3" +category = "main" optional = false python-versions = "*" -version = "3.0.4" [[package]] -category = "main" -description = "Parse, Audit, Query, Build, and Modify Cisco IOS-style configurations" name = "ciscoconfparse" +version = "1.5.19" +description = "Parse, Audit, Query, Build, and Modify Cisco IOS-style configurations" +category = "main" optional = false python-versions = "*" -version = "1.5.4" [package.dependencies] colorama = "*" @@ -128,119 +126,150 @@ dnspython = "*" passlib = "*" [[package]] -category = "dev" -description = "Composable command line interface toolkit" name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.2" [[package]] -category = "main" -description = "Cross-platform colored terminal text." name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.4.3" [[package]] -category = "main" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." name = "cryptography" +version = "3.2.1" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -version = "2.9.2" [package.dependencies] cffi = ">=1.8,<1.11.3 || >1.11.3" six = ">=1.4.1" [package.extras] -docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] -idna = ["idna (>=2.1)"] -pep8test = ["flake8", "flake8-import-order", "pep8-naming"] -test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pytest (>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] -category = "main" -description = "DNS toolkit" name = "dnspython" +version = "2.0.0" +description = "DNS toolkit" +category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.16.0" +python-versions = ">=3.6" [package.extras] -DNSSEC = ["pycryptodome", "ecdsa (>=0.13)"] -IDNA = ["idna (>=2.1)"] +dnssec = ["cryptography (>=2.6)"] +doh = ["requests", "requests-toolbelt"] +idna = ["idna (>=2.1)"] +curio = ["curio (>=1.2)", "sniffio (>=1.1)"] +trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"] [[package]] -category = "main" -description = "Clean single-source support for Python 3 and 2" name = "future" +version = "0.18.2" +description = "Clean single-source support for Python 3 and 2" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.18.2" [[package]] -category = "dev" -description = "Git Object Database" name = "gitdb" +version = "4.0.5" +description = "Git Object Database" +category = "dev" optional = false python-versions = ">=3.4" -version = "4.0.5" [package.dependencies] smmap = ">=3.0.1,<4" [[package]] -category = "dev" -description = "Python Git Library" name = "gitpython" +version = "3.1.11" +description = "Python Git Library" +category = "dev" optional = false python-versions = ">=3.4" -version = "3.1.2" [package.dependencies] gitdb = ">=4.0.1,<5" [[package]] -category = "main" -description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.9" [[package]] +name = "importlib-metadata" +version = "2.0.0" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] + +[[package]] +name = "importlib-resources" +version = "3.3.0" +description = "Read resources from Python packages" category = "main" -description = "Pythonic task execution" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" + +[package.dependencies] +zipp = {version = ">=0.4", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["sphinx", "rst.linker", "jaraco.packaging"] + +[[package]] name = "invoke" +version = "1.4.1" +description = "Pythonic task execution" +category = "main" optional = false python-versions = "*" -version = "1.4.1" [[package]] -category = "dev" -description = "A Python utility / library to sort Python imports." name = "isort" +version = "5.6.4" +description = "A Python utility / library to sort Python imports." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "4.3.21" +python-versions = ">=3.6,<4.0" [package.extras] -pipfile = ["pipreqs", "requirementslib"] -pyproject = ["toml"] -requirements = ["pipreqs", "pip-api"] -xdg_home = ["appdirs (>=1.4.0)"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] [[package]] -category = "main" -description = "A very fast and expressive template engine." name = "jinja2" +version = "2.11.2" +description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" @@ -249,39 +278,42 @@ MarkupSafe = ">=0.23" i18n = ["Babel (>=0.8)"] [[package]] -category = "main" -description = "Junos 'EZ' automation for non-programmers" name = "junos-eznc" +version = "2.5.4" +description = "Junos 'EZ' automation for non-programmers" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.2.1" [package.dependencies] -PyYAML = ">=5.1" jinja2 = ">=2.7.1" lxml = ">=3.2.4" -ncclient = ">=0.5.4" +ncclient = ">=0.6.3" netaddr = "*" paramiko = ">=1.15.2" +pyparsing = "*" pyserial = "*" +PyYAML = ">=5.1" scp = ">=0.7.0" six = "*" +transitions = "*" +yamlordereddictloader = "*" [[package]] -category = "dev" -description = "A fast and thorough lazy object proxy." name = "lazy-object-proxy" +version = "1.4.3" +description = "A fast and thorough lazy object proxy." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.4.3" [[package]] -category = "main" -description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." name = "lxml" +version = "4.6.1" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" -version = "4.5.0" [package.extras] cssselect = ["cssselect (>=0.7)"] @@ -290,108 +322,109 @@ htmlsoup = ["beautifulsoup4"] source = ["Cython (>=0.29.7)"] [[package]] -category = "main" -description = "Safely add untrusted strings to HTML/XML markup." name = "markupsafe" +version = "1.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.1.1" [[package]] -category = "dev" -description = "McCabe checker, plugin for flake8" name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" -version = "0.6.1" [[package]] -category = "main" -description = "Network Automation and Programmability Abstraction Layer with Multivendor support" name = "napalm" +version = "3.2.0" +description = "Network Automation and Programmability Abstraction Layer with Multivendor support" +category = "main" optional = false python-versions = "*" -version = "2.5.0" [package.dependencies] cffi = ">=1.11.3" ciscoconfparse = "*" future = "*" jinja2 = "*" -junos-eznc = "2.2.1" +junos-eznc = ">=2.2.1" +lxml = ">=4.3.0" netaddr = "*" -netmiko = "2.4.2" -nxapi-plumbing = ">=0.5.2" -paramiko = ">=2.4.2" -pyIOSXR = ">=0.53" -pyYAML = "*" +netmiko = ">=3.1.0" +paramiko = ">=2.6.0" pyeapi = ">=0.8.2" +pyYAML = "*" +requests = ">=2.7.0" scp = "*" -setuptools = ">=38.4.0" textfsm = "*" [[package]] -category = "main" -description = "Python library for NETCONF clients" name = "ncclient" +version = "0.6.9" +description = "Python library for NETCONF clients" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.6.7" [package.dependencies] lxml = ">=3.3.0" paramiko = ">=1.15.0" -setuptools = ">0.6" six = "*" [[package]] -category = "main" -description = "A network address manipulation library for Python" name = "netaddr" +version = "0.8.0" +description = "A network address manipulation library for Python" +category = "main" optional = false python-versions = "*" -version = "0.7.19" + +[package.dependencies] +importlib-resources = {version = "*", markers = "python_version < \"3.7\""} [[package]] -category = "main" -description = "Multi-vendor library to simplify Paramiko SSH connections to network devices" name = "netmiko" +version = "3.3.2" +description = "Multi-vendor library to simplify Paramiko SSH connections to network devices" +category = "main" optional = false python-versions = "*" -version = "2.4.2" [package.dependencies] -paramiko = ">=2.4.3" +importlib-resources = {version = "*", markers = "python_version < \"3.7\""} +ntc-templates = "*" +paramiko = ">=2.6.0" pyserial = "*" scp = ">=0.13.2" -setuptools = ">=38.4.0" -textfsm = "*" +tenacity = "*" [package.extras] -test = ["pyyaml (5.1)", "pytest (>=4.6.3)"] +test = ["pyyaml (>=5.1.2)", "pytest (>=5.1.2)"] [[package]] +name = "ntc-templates" +version = "1.6.0" +description = "Package to return structured data from the output of network devices." category = "main" -description = "A library for managing Cisco devices through NX-API using XML or jsonrpc." -name = "nxapi-plumbing" optional = false python-versions = "*" -version = "0.5.2" [package.dependencies] -future = "*" -lxml = "*" -requests = ">=2.7.0" -scp = "*" -six = "*" +textfsm = ">=1.1.0" + +[package.extras] +dev = ["pytest", "pyyaml", "black", "yamllint", "ruamel.yaml"] [[package]] -category = "main" -description = "SSH2 protocol library" name = "paramiko" +version = "2.7.2" +description = "SSH2 protocol library" +category = "main" optional = false python-versions = "*" -version = "2.7.1" [package.dependencies] bcrypt = ">=3.1.3" @@ -405,61 +438,61 @@ gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] invoke = ["invoke (>=1.3)"] [[package]] -category = "main" -description = "comprehensive password hashing framework supporting over 30 schemes" name = "passlib" +version = "1.7.4" +description = "comprehensive password hashing framework supporting over 30 schemes" +category = "main" optional = false python-versions = "*" -version = "1.7.2" [package.extras] argon2 = ["argon2-cffi (>=18.2.0)"] bcrypt = ["bcrypt (>=3.1.0)"] -build_docs = ["sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)", "cloud-sptheme (>=1.10.0)"] +build_docs = ["sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)", "cloud-sptheme (>=1.10.1)"] totp = ["cryptography"] [[package]] -category = "dev" -description = "Utility library for gitignore style pattern matching of file paths." name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.8.0" [[package]] -category = "dev" -description = "Python Build Reasonableness" name = "pbr" +version = "5.5.1" +description = "Python Build Reasonableness" +category = "dev" optional = false -python-versions = "*" -version = "5.4.5" +python-versions = ">=2.6" [[package]] -category = "main" -description = "C parser in Python" name = "pycparser" +version = "2.20" +description = "C parser in Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.20" [[package]] -category = "dev" -description = "Python docstring style checker" name = "pydocstyle" +version = "5.1.1" +description = "Python docstring style checker" +category = "dev" optional = false python-versions = ">=3.5" -version = "5.0.2" [package.dependencies] snowballstemmer = "*" [[package]] -category = "main" -description = "Python Client for eAPI" name = "pyeapi" +version = "0.8.4" +description = "Python Client for eAPI" +category = "main" optional = false python-versions = "*" -version = "0.8.3" [package.dependencies] netaddr = "*" @@ -469,39 +502,27 @@ dev = ["check-manifest", "pep8", "pyflakes", "twine"] test = ["coverage", "mock"] [[package]] -category = "main" -description = "Python API to interact with network devices running IOS-XR" -name = "pyiosxr" -optional = false -python-versions = "*" -version = "0.53" - -[package.dependencies] -lxml = ">=3.2.4" -netmiko = ">=1.4.3" - -[[package]] -category = "dev" -description = "python code static checker" name = "pylint" +version = "2.6.0" +description = "python code static checker" +category = "dev" optional = false python-versions = ">=3.5.*" -version = "2.5.2" [package.dependencies] astroid = ">=2.4.0,<=2.5" -colorama = "*" -isort = ">=4.2.5,<5" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" toml = ">=0.7.1" [[package]] -category = "dev" -description = "A Pylint plugin to help Pylint understand the Django web framework" name = "pylint-django" +version = "2.3.0" +description = "A Pylint plugin to help Pylint understand the Django web framework" +category = "dev" optional = false python-versions = "*" -version = "2.0.15" [package.dependencies] pylint = ">=2.0" @@ -512,23 +533,23 @@ for_tests = ["coverage", "django-tables2", "factory-boy", "pytest"] with_django = ["django"] [[package]] -category = "dev" -description = "Utilities and helpers for writing Pylint plugins" name = "pylint-plugin-utils" +version = "0.6" +description = "Utilities and helpers for writing Pylint plugins" +category = "dev" optional = false python-versions = "*" -version = "0.6" [package.dependencies] pylint = ">=1.7" [[package]] -category = "main" -description = "Python binding to the Networking and Cryptography (NaCl) library" name = "pynacl" +version = "1.4.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +category = "main" optional = false -python-versions = "*" -version = "1.3.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] cffi = ">=1.4.1" @@ -536,161 +557,222 @@ six = "*" [package.extras] docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] -tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)", "hypothesis (>=3.27.0)"] +tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"] [[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" category = "main" -description = "Python Serial Port Extension" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] name = "pyserial" +version = "3.4" +description = "Python Serial Port Extension" +category = "main" optional = false python-versions = "*" -version = "3.4" [[package]] -category = "main" -description = "YAML parser and emitter for Python" name = "pyyaml" +version = "5.3.1" +description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "5.3.1" [[package]] -category = "dev" -description = "Alternative regular expression module, to replace re." name = "regex" +version = "2020.11.13" +description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = "*" -version = "2020.5.7" [[package]] -category = "main" -description = "Python HTTP for Humans." name = "requests" +version = "2.25.0" +description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.23.0" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<4" idna = ">=2.5,<3" -urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" +urllib3 = ">=1.21.1,<1.27" [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] -category = "main" -description = "scp module for paramiko" name = "scp" +version = "0.13.3" +description = "scp module for paramiko" +category = "main" optional = false python-versions = "*" -version = "0.13.2" [package.dependencies] paramiko = "*" [[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.15.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.14.0" [[package]] -category = "dev" -description = "A pure Python implementation of a sliding window memory map manager" name = "smmap" +version = "3.0.4" +description = "A pure Python implementation of a sliding window memory map manager" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.0.4" [[package]] -category = "dev" -description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." name = "snowballstemmer" +version = "2.0.0" +description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." +category = "dev" optional = false python-versions = "*" -version = "2.0.0" [[package]] -category = "dev" -description = "Manage dynamic plugins for Python applications" name = "stevedore" +version = "3.2.2" +description = "Manage dynamic plugins for Python applications" +category = "dev" optional = false -python-versions = "*" -version = "1.32.0" +python-versions = ">=3.6" [package.dependencies] +importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} pbr = ">=2.0.0,<2.1.0 || >2.1.0" -six = ">=1.10.0" [[package]] +name = "tenacity" +version = "6.2.0" +description = "Retry code until it succeeds" category = "main" -description = "Python module for parsing semi-structured text into python tables." -name = "textfsm" optional = false python-versions = "*" + +[package.dependencies] +six = ">=1.9.0" + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "textfsm" version = "1.1.0" +description = "Python module for parsing semi-structured text into python tables." +category = "main" +optional = false +python-versions = "*" [package.dependencies] future = "*" six = "*" [[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "transitions" +version = "0.8.5" +description = "A lightweight, object-oriented Python state machine implementation with many extensions." +category = "main" optional = false python-versions = "*" -version = "0.10.0" + +[package.dependencies] +six = "*" + +[package.extras] +diagrams = ["pygraphviz"] +test = ["pytest"] [[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" +version = "1.4.1" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = "*" -version = "1.4.1" [[package]] -category = "main" -description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" +version = "1.26.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.9" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] -category = "dev" -description = "Module for decorators, wrappers and monkey patching." name = "wrapt" +version = "1.12.1" +description = "Module for decorators, wrappers and monkey patching." +category = "dev" optional = false python-versions = "*" -version = "1.12.1" [[package]] -category = "dev" -description = "A linter for YAML files." name = "yamllint" +version = "1.25.0" +description = "A linter for YAML files." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.23.0" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" [package.dependencies] pathspec = ">=0.5.3" pyyaml = "*" +[[package]] +name = "yamlordereddictloader" +version = "0.4.0" +description = "YAML loader and dump for PyYAML allowing to keep keys order." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "zipp" +version = "3.4.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + [metadata] -content-hash = "66290887d2a6c0c442753e1249f93c48131afaba828e2b7272f91b7dab23c615" +lock-version = "1.1" python-versions = "^3.6 || ^3.7 || ^3.8" +content-hash = "127437ec893ce3e444d94f980dcfe772206c2d863258ab939de4595c17109672" [metadata.files] appdirs = [ @@ -698,115 +780,115 @@ appdirs = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] astroid = [ - {file = "astroid-2.4.1-py3-none-any.whl", hash = "sha256:d8506842a3faf734b81599c8b98dcc423de863adcc1999248480b18bd31a0f38"}, - {file = "astroid-2.4.1.tar.gz", hash = "sha256:4c17cea3e592c21b6e222f673868961bad77e1f985cb1694ed077475a89229c1"}, + {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, + {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, ] attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, + {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, + {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, ] bandit = [ {file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"}, {file = "bandit-1.6.2.tar.gz", hash = "sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"}, ] bcrypt = [ - {file = "bcrypt-3.1.7-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7"}, - {file = "bcrypt-3.1.7-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31"}, - {file = "bcrypt-3.1.7-cp27-cp27m-win32.whl", hash = "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161"}, - {file = "bcrypt-3.1.7-cp27-cp27m-win_amd64.whl", hash = "sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e"}, - {file = "bcrypt-3.1.7-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0"}, - {file = "bcrypt-3.1.7-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052"}, - {file = "bcrypt-3.1.7-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105"}, - {file = "bcrypt-3.1.7-cp34-cp34m-win32.whl", hash = "sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de"}, - {file = "bcrypt-3.1.7-cp34-cp34m-win_amd64.whl", hash = "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133"}, - {file = "bcrypt-3.1.7-cp35-cp35m-win32.whl", hash = "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5"}, - {file = "bcrypt-3.1.7-cp35-cp35m-win_amd64.whl", hash = "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09"}, - {file = "bcrypt-3.1.7-cp36-cp36m-win32.whl", hash = "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c"}, - {file = "bcrypt-3.1.7-cp36-cp36m-win_amd64.whl", hash = "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89"}, - {file = "bcrypt-3.1.7-cp37-cp37m-win32.whl", hash = "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294"}, - {file = "bcrypt-3.1.7-cp37-cp37m-win_amd64.whl", hash = "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc"}, - {file = "bcrypt-3.1.7-cp38-cp38-win32.whl", hash = "sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1"}, - {file = "bcrypt-3.1.7-cp38-cp38-win_amd64.whl", hash = "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752"}, - {file = "bcrypt-3.1.7.tar.gz", hash = "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42"}, + {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, + {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, + {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, + {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, ] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, ] certifi = [ - {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, - {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, + {file = "certifi-2020.11.8-py2.py3-none-any.whl", hash = "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd"}, + {file = "certifi-2020.11.8.tar.gz", hash = "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"}, ] cffi = [ - {file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"}, - {file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"}, - {file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"}, - {file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"}, - {file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"}, - {file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"}, - {file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"}, - {file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"}, - {file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"}, - {file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"}, - {file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"}, - {file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"}, - {file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"}, - {file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"}, - {file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"}, - {file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"}, - {file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"}, - {file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"}, - {file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"}, - {file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"}, - {file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"}, - {file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"}, - {file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"}, - {file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"}, - {file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"}, - {file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"}, - {file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"}, - {file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"}, + {file = "cffi-1.14.3-2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc"}, + {file = "cffi-1.14.3-2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768"}, + {file = "cffi-1.14.3-2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d"}, + {file = "cffi-1.14.3-2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1"}, + {file = "cffi-1.14.3-2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca"}, + {file = "cffi-1.14.3-2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730"}, + {file = "cffi-1.14.3-cp27-cp27m-win32.whl", hash = "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d"}, + {file = "cffi-1.14.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4"}, + {file = "cffi-1.14.3-cp35-cp35m-win32.whl", hash = "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d"}, + {file = "cffi-1.14.3-cp35-cp35m-win_amd64.whl", hash = "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537"}, + {file = "cffi-1.14.3-cp36-cp36m-win32.whl", hash = "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0"}, + {file = "cffi-1.14.3-cp36-cp36m-win_amd64.whl", hash = "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394"}, + {file = "cffi-1.14.3-cp37-cp37m-win32.whl", hash = "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc"}, + {file = "cffi-1.14.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9"}, + {file = "cffi-1.14.3-cp38-cp38-win32.whl", hash = "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522"}, + {file = "cffi-1.14.3-cp38-cp38-win_amd64.whl", hash = "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c"}, + {file = "cffi-1.14.3-cp39-cp39-win32.whl", hash = "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b"}, + {file = "cffi-1.14.3-cp39-cp39-win_amd64.whl", hash = "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3"}, + {file = "cffi-1.14.3.tar.gz", hash = "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] ciscoconfparse = [ - {file = "ciscoconfparse-1.5.4-py3-none-any.whl", hash = "sha256:7ca494721c0f659655f647b271351fb4c5adfdcb5c8f5a0a9cf7f6c22b1d0441"}, - {file = "ciscoconfparse-1.5.4.tar.gz", hash = "sha256:8b6f1585d5771ee678be56fe4dd405ead5420b93f6e7df1838cf0537f32ad986"}, + {file = "ciscoconfparse-1.5.19-py3-none-any.whl", hash = "sha256:b5b406407174ac3239ec07e21f62b003175dd4db770d157c5b2c05345aa08140"}, + {file = "ciscoconfparse-1.5.19.tar.gz", hash = "sha256:6aa1644224234a09f12224ffa616847bce02e6c2c15d2dd53857a07556d4ae20"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] colorama = [ - {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, - {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] cryptography = [ - {file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"}, - {file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"}, - {file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"}, - {file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"}, - {file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"}, - {file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"}, - {file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"}, - {file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"}, - {file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"}, - {file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"}, - {file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"}, - {file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"}, - {file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"}, - {file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"}, - {file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"}, - {file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"}, - {file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"}, - {file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"}, - {file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"}, + {file = "cryptography-3.2.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:6dc59630ecce8c1f558277ceb212c751d6730bd12c80ea96b4ac65637c4f55e7"}, + {file = "cryptography-3.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:75e8e6684cf0034f6bf2a97095cb95f81537b12b36a8fedf06e73050bb171c2d"}, + {file = "cryptography-3.2.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4e7268a0ca14536fecfdf2b00297d4e407da904718658c1ff1961c713f90fd33"}, + {file = "cryptography-3.2.1-cp27-cp27m-win32.whl", hash = "sha256:7117319b44ed1842c617d0a452383a5a052ec6aa726dfbaffa8b94c910444297"}, + {file = "cryptography-3.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:a733671100cd26d816eed39507e585c156e4498293a907029969234e5e634bc4"}, + {file = "cryptography-3.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:a75f306a16d9f9afebfbedc41c8c2351d8e61e818ba6b4c40815e2b5740bb6b8"}, + {file = "cryptography-3.2.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5849d59358547bf789ee7e0d7a9036b2d29e9a4ddf1ce5e06bb45634f995c53e"}, + {file = "cryptography-3.2.1-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:bd717aa029217b8ef94a7d21632a3bb5a4e7218a4513d2521c2a2fd63011e98b"}, + {file = "cryptography-3.2.1-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:efe15aca4f64f3a7ea0c09c87826490e50ed166ce67368a68f315ea0807a20df"}, + {file = "cryptography-3.2.1-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77"}, + {file = "cryptography-3.2.1-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:7b8d9d8d3a9bd240f453342981f765346c87ade811519f98664519696f8e6ab7"}, + {file = "cryptography-3.2.1-cp35-cp35m-win32.whl", hash = "sha256:d3545829ab42a66b84a9aaabf216a4dce7f16dbc76eb69be5c302ed6b8f4a29b"}, + {file = "cryptography-3.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:a4e27ed0b2504195f855b52052eadcc9795c59909c9d84314c5408687f933fc7"}, + {file = "cryptography-3.2.1-cp36-abi3-win32.whl", hash = "sha256:13b88a0bd044b4eae1ef40e265d006e34dbcde0c2f1e15eb9896501b2d8f6c6f"}, + {file = "cryptography-3.2.1-cp36-abi3-win_amd64.whl", hash = "sha256:07ca431b788249af92764e3be9a488aa1d39a0bc3be313d826bbec690417e538"}, + {file = "cryptography-3.2.1-cp36-cp36m-win32.whl", hash = "sha256:a035a10686532b0587d58a606004aa20ad895c60c4d029afa245802347fab57b"}, + {file = "cryptography-3.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:d26a2557d8f9122f9bf445fc7034242f4375bd4e95ecda007667540270965b13"}, + {file = "cryptography-3.2.1-cp37-cp37m-win32.whl", hash = "sha256:545a8550782dda68f8cdc75a6e3bf252017aa8f75f19f5a9ca940772fc0cb56e"}, + {file = "cryptography-3.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:55d0b896631412b6f0c7de56e12eb3e261ac347fbaa5d5e705291a9016e5f8cb"}, + {file = "cryptography-3.2.1-cp38-cp38-win32.whl", hash = "sha256:3cd75a683b15576cfc822c7c5742b3276e50b21a06672dc3a800a2d5da4ecd1b"}, + {file = "cryptography-3.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:d25cecbac20713a7c3bc544372d42d8eafa89799f492a43b79e1dfd650484851"}, + {file = "cryptography-3.2.1.tar.gz", hash = "sha256:d3d5e10be0cf2a12214ddee45c6bd203dab435e3d83b4560c03066eda600bfe3"}, ] dnspython = [ - {file = "dnspython-1.16.0-py2.py3-none-any.whl", hash = "sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"}, - {file = "dnspython-1.16.0.zip", hash = "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01"}, + {file = "dnspython-2.0.0-py3-none-any.whl", hash = "sha256:40bb3c24b9d4ec12500f0124288a65df232a3aa749bb0c39734b782873a2544d"}, + {file = "dnspython-2.0.0.zip", hash = "sha256:044af09374469c3a39eeea1a146e8cac27daec951f1f1f157b1962fc7cb9d1b7"}, ] future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, @@ -816,12 +898,20 @@ gitdb = [ {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.2-py3-none-any.whl", hash = "sha256:da3b2cf819974789da34f95ac218ef99f515a928685db141327c09b73dd69c09"}, - {file = "GitPython-3.1.2.tar.gz", hash = "sha256:864a47472548f3ba716ca202e034c1900f197c0fb3a08f641c20c3cafd15ed94"}, + {file = "GitPython-3.1.11-py3-none-any.whl", hash = "sha256:6eea89b655917b500437e9668e4a12eabdcf00229a0df1762aabd692ef9b746b"}, + {file = "GitPython-3.1.11.tar.gz", hash = "sha256:befa4d101f91bad1b632df4308ec64555db684c360bd7d2130b4807d49ce86b8"}, ] idna = [ - {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, - {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, +] +importlib-metadata = [ + {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, + {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, +] +importlib-resources = [ + {file = "importlib_resources-3.3.0-py2.py3-none-any.whl", hash = "sha256:a3d34a8464ce1d5d7c92b0ea4e921e696d86f2aa212e684451cb1482c8d84ed5"}, + {file = "importlib_resources-3.3.0.tar.gz", hash = "sha256:7b51f0106c8ec564b1bef3d9c588bc694ce2b92125bbb6278f4f2f5b54ec3592"}, ] invoke = [ {file = "invoke-1.4.1-py2-none-any.whl", hash = "sha256:93e12876d88130c8e0d7fd6618dd5387d6b36da55ad541481dfa5e001656f134"}, @@ -829,16 +919,16 @@ invoke = [ {file = "invoke-1.4.1.tar.gz", hash = "sha256:de3f23bfe669e3db1085789fd859eb8ca8e0c5d9c20811e2407fa042e8a5e15d"}, ] isort = [ - {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, - {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"}, + {file = "isort-5.6.4-py3-none-any.whl", hash = "sha256:dcab1d98b469a12a1a624ead220584391648790275560e1a43e54c5dceae65e7"}, + {file = "isort-5.6.4.tar.gz", hash = "sha256:dcaeec1b5f0eca77faea2a35ab790b4f3680ff75590bfcb7145986905aab2f58"}, ] jinja2 = [ {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, ] junos-eznc = [ - {file = "junos-eznc-2.2.1.tar.gz", hash = "sha256:0133a10ba3d46ddf70f0ba6620aa3b92e5533f08c57edd000dbffd8fe60d586d"}, - {file = "junos_eznc-2.2.1-py2.py3-none-any.whl", hash = "sha256:0a5c650e819b12b44ae8c47f7dfa8944e5402ef4d58b05523984d397a79329b6"}, + {file = "junos-eznc-2.5.4.tar.gz", hash = "sha256:bf036d0af9ee5c5e4f517cb5fc902fe891fa120e18f459805862c53d4a97193a"}, + {file = "junos_eznc-2.5.4-py2.py3-none-any.whl", hash = "sha256:e05c36d56d8b8d13b1fb3bb763828bb3ee80fa1dcadc3a6762e8e2568504676d"}, ] lazy-object-proxy = [ {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, @@ -864,33 +954,43 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, ] lxml = [ - {file = "lxml-4.5.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0701f7965903a1c3f6f09328c1278ac0eee8f56f244e66af79cb224b7ef3801c"}, - {file = "lxml-4.5.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:06d4e0bbb1d62e38ae6118406d7cdb4693a3fa34ee3762238bcb96c9e36a93cd"}, - {file = "lxml-4.5.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5828c7f3e615f3975d48f40d4fe66e8a7b25f16b5e5705ffe1d22e43fb1f6261"}, - {file = "lxml-4.5.0-cp27-cp27m-win32.whl", hash = "sha256:afdb34b715daf814d1abea0317b6d672476b498472f1e5aacbadc34ebbc26e89"}, - {file = "lxml-4.5.0-cp27-cp27m-win_amd64.whl", hash = "sha256:585c0869f75577ac7a8ff38d08f7aac9033da2c41c11352ebf86a04652758b7a"}, - {file = "lxml-4.5.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:8a0ebda56ebca1a83eb2d1ac266649b80af8dd4b4a3502b2c1e09ac2f88fe128"}, - {file = "lxml-4.5.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:fe976a0f1ef09b3638778024ab9fb8cde3118f203364212c198f71341c0715ca"}, - {file = "lxml-4.5.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7bc1b221e7867f2e7ff1933165c0cec7153dce93d0cdba6554b42a8beb687bdb"}, - {file = "lxml-4.5.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d068f55bda3c2c3fcaec24bd083d9e2eede32c583faf084d6e4b9daaea77dde8"}, - {file = "lxml-4.5.0-cp35-cp35m-win32.whl", hash = "sha256:e4aa948eb15018a657702fee0b9db47e908491c64d36b4a90f59a64741516e77"}, - {file = "lxml-4.5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:1f2c4ec372bf1c4a2c7e4bb20845e8bcf8050365189d86806bad1e3ae473d081"}, - {file = "lxml-4.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5d467ce9c5d35b3bcc7172c06320dddb275fea6ac2037f72f0a4d7472035cea9"}, - {file = "lxml-4.5.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:95e67224815ef86924fbc2b71a9dbd1f7262384bca4bc4793645794ac4200717"}, - {file = "lxml-4.5.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ebec08091a22c2be870890913bdadd86fcd8e9f0f22bcb398abd3af914690c15"}, - {file = "lxml-4.5.0-cp36-cp36m-win32.whl", hash = "sha256:deadf4df349d1dcd7b2853a2c8796593cc346600726eff680ed8ed11812382a7"}, - {file = "lxml-4.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f2b74784ed7e0bc2d02bd53e48ad6ba523c9b36c194260b7a5045071abbb1012"}, - {file = "lxml-4.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fa071559f14bd1e92077b1b5f6c22cf09756c6de7139370249eb372854ce51e6"}, - {file = "lxml-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:edc15fcfd77395e24543be48871c251f38132bb834d9fdfdad756adb6ea37679"}, - {file = "lxml-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd52e796fee7171c4361d441796b64df1acfceb51f29e545e812f16d023c4bbc"}, - {file = "lxml-4.5.0-cp37-cp37m-win32.whl", hash = "sha256:90ed0e36455a81b25b7034038e40880189169c308a3df360861ad74da7b68c1a"}, - {file = "lxml-4.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:df533af6f88080419c5a604d0d63b2c33b1c0c4409aba7d0cb6de305147ea8c8"}, - {file = "lxml-4.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b4b2c63cc7963aedd08a5f5a454c9f67251b1ac9e22fd9d72836206c42dc2a72"}, - {file = "lxml-4.5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e5d842c73e4ef6ed8c1bd77806bf84a7cb535f9c0cf9b2c74d02ebda310070e1"}, - {file = "lxml-4.5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:63dbc21efd7e822c11d5ddbedbbb08cd11a41e0032e382a0fd59b0b08e405a3a"}, - {file = "lxml-4.5.0-cp38-cp38-win32.whl", hash = "sha256:4235bc124fdcf611d02047d7034164897ade13046bda967768836629bc62784f"}, - {file = "lxml-4.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:d5b3c4b7edd2e770375a01139be11307f04341ec709cf724e0f26ebb1eef12c3"}, - {file = "lxml-4.5.0.tar.gz", hash = "sha256:8620ce80f50d023d414183bf90cc2576c2837b88e00bea3f33ad2630133bbb60"}, + {file = "lxml-4.6.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:4b7572145054330c8e324a72d808c8c8fbe12be33368db28c39a255ad5f7fb51"}, + {file = "lxml-4.6.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:302160eb6e9764168e01d8c9ec6becddeb87776e81d3fcb0d97954dd51d48e0a"}, + {file = "lxml-4.6.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d4ad7fd3269281cb471ad6c7bafca372e69789540d16e3755dd717e9e5c9d82f"}, + {file = "lxml-4.6.1-cp27-cp27m-win32.whl", hash = "sha256:189ad47203e846a7a4951c17694d845b6ade7917c47c64b29b86526eefc3adf5"}, + {file = "lxml-4.6.1-cp27-cp27m-win_amd64.whl", hash = "sha256:56eff8c6fb7bc4bcca395fdff494c52712b7a57486e4fbde34c31bb9da4c6cc4"}, + {file = "lxml-4.6.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:23c83112b4dada0b75789d73f949dbb4e8f29a0a3511647024a398ebd023347b"}, + {file = "lxml-4.6.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0e89f5d422988c65e6936e4ec0fe54d6f73f3128c80eb7ecc3b87f595523607b"}, + {file = "lxml-4.6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2358809cc64394617f2719147a58ae26dac9e21bae772b45cfb80baa26bfca5d"}, + {file = "lxml-4.6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:be1ebf9cc25ab5399501c9046a7dcdaa9e911802ed0e12b7d620cd4bbf0518b3"}, + {file = "lxml-4.6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:4fff34721b628cce9eb4538cf9a73d02e0f3da4f35a515773cce6f5fe413b360"}, + {file = "lxml-4.6.1-cp35-cp35m-win32.whl", hash = "sha256:475325e037fdf068e0c2140b818518cf6bc4aa72435c407a798b2db9f8e90810"}, + {file = "lxml-4.6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:f98b6f256be6cec8dd308a8563976ddaff0bdc18b730720f6f4bee927ffe926f"}, + {file = "lxml-4.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:be7c65e34d1b50ab7093b90427cbc488260e4b3a38ef2435d65b62e9fa3d798a"}, + {file = "lxml-4.6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d18331ea905a41ae71596502bd4c9a2998902328bbabd29e3d0f5f8569fabad1"}, + {file = "lxml-4.6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3d9b2b72eb0dbbdb0e276403873ecfae870599c83ba22cadff2db58541e72856"}, + {file = "lxml-4.6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d20d32cbb31d731def4b1502294ca2ee99f9249b63bc80e03e67e8f8e126dea8"}, + {file = "lxml-4.6.1-cp36-cp36m-win32.whl", hash = "sha256:d182eada8ea0de61a45a526aa0ae4bcd222f9673424e65315c35820291ff299c"}, + {file = "lxml-4.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:c0dac835c1a22621ffa5e5f999d57359c790c52bbd1c687fe514ae6924f65ef5"}, + {file = "lxml-4.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d84d741c6e35c9f3e7406cb7c4c2e08474c2a6441d59322a00dcae65aac6315d"}, + {file = "lxml-4.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8862d1c2c020cb7a03b421a9a7b4fe046a208db30994fc8ff68c627a7915987f"}, + {file = "lxml-4.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3a7a380bfecc551cfd67d6e8ad9faa91289173bdf12e9cfafbd2bdec0d7b1ec1"}, + {file = "lxml-4.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:2d6571c48328be4304aee031d2d5046cbc8aed5740c654575613c5a4f5a11311"}, + {file = "lxml-4.6.1-cp37-cp37m-win32.whl", hash = "sha256:803a80d72d1f693aa448566be46ffd70882d1ad8fc689a2e22afe63035eb998a"}, + {file = "lxml-4.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:24e811118aab6abe3ce23ff0d7d38932329c513f9cef849d3ee88b0f848f2aa9"}, + {file = "lxml-4.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2e311a10f3e85250910a615fe194839a04a0f6bc4e8e5bb5cac221344e3a7891"}, + {file = "lxml-4.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a71400b90b3599eb7bf241f947932e18a066907bf84617d80817998cee81e4bf"}, + {file = "lxml-4.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:211b3bcf5da70c2d4b84d09232534ad1d78320762e2c59dedc73bf01cb1fc45b"}, + {file = "lxml-4.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e65c221b2115a91035b55a593b6eb94aa1206fa3ab374f47c6dc10d364583ff9"}, + {file = "lxml-4.6.1-cp38-cp38-win32.whl", hash = "sha256:d6f8c23f65a4bfe4300b85f1f40f6c32569822d08901db3b6454ab785d9117cc"}, + {file = "lxml-4.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:573b2f5496c7e9f4985de70b9bbb4719ffd293d5565513e04ac20e42e6e5583f"}, + {file = "lxml-4.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:098fb713b31050463751dcc694878e1d39f316b86366fb9fe3fbbe5396ac9fab"}, + {file = "lxml-4.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:1d87936cb5801c557f3e981c9c193861264c01209cb3ad0964a16310ca1b3301"}, + {file = "lxml-4.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2d5896ddf5389560257bbe89317ca7bcb4e54a02b53a3e572e1ce4226512b51b"}, + {file = "lxml-4.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9b06690224258db5cd39a84e993882a6874676f5de582da57f3df3a82ead9174"}, + {file = "lxml-4.6.1-cp39-cp39-win32.whl", hash = "sha256:bb252f802f91f59767dcc559744e91efa9df532240a502befd874b54571417bd"}, + {file = "lxml-4.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ecaef52fd9b9535ae5f01a1dd2651f6608e4ec9dc136fc4dfe7ebe3c3ddb230"}, + {file = "lxml-4.6.1.tar.gz", hash = "sha256:c152b2e93b639d1f36ec5a8ca24cde4a8eefb2b6b83668fcd8e83a67badcb367"}, ] markupsafe = [ {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, @@ -932,87 +1032,86 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] napalm = [ - {file = "napalm-2.5.0-py2.py3-none-any.whl", hash = "sha256:c2b34f8ae287329e44960d4c3c8902f00fd43ae8b049aa89b8ded5ba10c46fd9"}, - {file = "napalm-2.5.0.tar.gz", hash = "sha256:f49a38cf4fb712642b7644c272b18be0c5c6fe97c076ec26d3bb378d1768901b"}, + {file = "napalm-3.2.0-py2.py3-none-any.whl", hash = "sha256:6ab07a8a360150198b3c33c2fa4e92a9658cda9821736d24f2399343425d2af3"}, + {file = "napalm-3.2.0.tar.gz", hash = "sha256:6e69a505f5d4a678c42f048d13153afabf10b7fec72868e3bfb53ff4089206fc"}, ] ncclient = [ - {file = "ncclient-0.6.7.tar.gz", hash = "sha256:efdf3c868cd9f104d4e9fe4c233df78bfbbed4b3d78ba19dc27cec3cf6a63680"}, + {file = "ncclient-0.6.9.tar.gz", hash = "sha256:0112f2ad41fb658f52446d870853a63691d69299c73c7351c520d38dbd8dc0c4"}, ] netaddr = [ - {file = "netaddr-0.7.19-py2.py3-none-any.whl", hash = "sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca"}, - {file = "netaddr-0.7.19.tar.gz", hash = "sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd"}, + {file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"}, + {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"}, ] netmiko = [ - {file = "netmiko-2.4.2-py2.py3-none-any.whl", hash = "sha256:bc284272d76defd5af59a748478aae99af462793f0898f4ab43c28c9a2000e42"}, - {file = "netmiko-2.4.2.tar.gz", hash = "sha256:e6b0cb98afb51fd1fb1d04d024d7572a0b5297dfa0bd18405ee36580deea65a1"}, + {file = "netmiko-3.3.2-py2.py3-none-any.whl", hash = "sha256:1f8b86432fde2fb3c15ed86e130a05e7da358aa1de23fc7c520d8dbac2d4781a"}, + {file = "netmiko-3.3.2.tar.gz", hash = "sha256:84832d2b7d19ef28b7255a6e0217a68ed5727c03206a5e74abc101dc42550d97"}, ] -nxapi-plumbing = [ - {file = "nxapi_plumbing-0.5.2.tar.gz", hash = "sha256:6f54f9983f023bd75b60acd907ff47f559541cc2b98f4fa638b8585ca0de0fb5"}, +ntc-templates = [ + {file = "ntc_templates-1.6.0-py3-none-any.whl", hash = "sha256:a45ca5bf20d8b4585d63f732f3f605761e20279734dab76d1960c082fd6f2417"}, + {file = "ntc_templates-1.6.0.tar.gz", hash = "sha256:a4420beee9cc14797d945b51bffd6e0126913b2dbc672d2e0a1530d3fec5b28d"}, ] paramiko = [ - {file = "paramiko-2.7.1-py2.py3-none-any.whl", hash = "sha256:9c980875fa4d2cb751604664e9a2d0f69096643f5be4db1b99599fe114a97b2f"}, - {file = "paramiko-2.7.1.tar.gz", hash = "sha256:920492895db8013f6cc0179293147f830b8c7b21fdfc839b6bad760c27459d9f"}, + {file = "paramiko-2.7.2-py2.py3-none-any.whl", hash = "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898"}, + {file = "paramiko-2.7.2.tar.gz", hash = "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035"}, ] passlib = [ - {file = "passlib-1.7.2-py2.py3-none-any.whl", hash = "sha256:68c35c98a7968850e17f1b6892720764cc7eed0ef2b7cb3116a89a28e43fe177"}, - {file = "passlib-1.7.2.tar.gz", hash = "sha256:8d666cef936198bc2ab47ee9b0410c94adf2ba798e5a84bf220be079ae7ab6a8"}, + {file = "passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1"}, + {file = "passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04"}, ] pathspec = [ - {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, - {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, ] pbr = [ - {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, - {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, + {file = "pbr-5.5.1-py2.py3-none-any.whl", hash = "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"}, + {file = "pbr-5.5.1.tar.gz", hash = "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9"}, ] pycparser = [ {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, ] pydocstyle = [ - {file = "pydocstyle-5.0.2-py3-none-any.whl", hash = "sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586"}, - {file = "pydocstyle-5.0.2.tar.gz", hash = "sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"}, + {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"}, + {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"}, ] pyeapi = [ - {file = "pyeapi-0.8.3.tar.gz", hash = "sha256:b90f9463ffad72df0c6179f4b1c248785f42206f7c43655da1217e368a992479"}, -] -pyiosxr = [ - {file = "pyIOSXR-0.53.tar.gz", hash = "sha256:0e25d6871b48db81511c03261924ef23169c66e80321801b9bb221a3b74e370e"}, + {file = "pyeapi-0.8.4.tar.gz", hash = "sha256:c33ad1eadd8ebac75f63488df9412081ce0b024c9e1da12a37196a5c60427c54"}, ] pylint = [ - {file = "pylint-2.5.2-py3-none-any.whl", hash = "sha256:dd506acce0427e9e08fb87274bcaa953d38b50a58207170dbf5b36cf3e16957b"}, - {file = "pylint-2.5.2.tar.gz", hash = "sha256:b95e31850f3af163c2283ed40432f053acbc8fc6eba6a069cb518d9dbf71848c"}, + {file = "pylint-2.6.0-py3-none-any.whl", hash = "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"}, + {file = "pylint-2.6.0.tar.gz", hash = "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210"}, ] pylint-django = [ - {file = "pylint-django-2.0.15.tar.gz", hash = "sha256:06a64331c498a3f049ba669dc0c174b92209e164198d43e589b1096ee616d5f8"}, - {file = "pylint_django-2.0.15-py3-none-any.whl", hash = "sha256:3d3436ba8d0fae576ae2db160e33a8f2746a101fda4463f2b3ff3a8b6fccec38"}, + {file = "pylint-django-2.3.0.tar.gz", hash = "sha256:b8dcb6006ae9fa911810aba3bec047b9410b7d528f89d5aca2506b03c9235a49"}, + {file = "pylint_django-2.3.0-py3-none-any.whl", hash = "sha256:770e0c55fb054c6378e1e8bb3fe22c7032a2c38ba1d1f454206ee9c6591822d7"}, ] pylint-plugin-utils = [ {file = "pylint-plugin-utils-0.6.tar.gz", hash = "sha256:57625dcca20140f43731311cd8fd879318bf45a8b0fd17020717a8781714a25a"}, {file = "pylint_plugin_utils-0.6-py3-none-any.whl", hash = "sha256:2f30510e1c46edf268d3a195b2849bd98a1b9433229bb2ba63b8d776e1fc4d0a"}, ] pynacl = [ - {file = "PyNaCl-1.3.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621"}, - {file = "PyNaCl-1.3.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39"}, - {file = "PyNaCl-1.3.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:05c26f93964373fc0abe332676cb6735f0ecad27711035b9472751faa8521255"}, - {file = "PyNaCl-1.3.0-cp27-cp27m-win32.whl", hash = "sha256:a14e499c0f5955dcc3991f785f3f8e2130ed504fa3a7f44009ff458ad6bdd17f"}, - {file = "PyNaCl-1.3.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0"}, - {file = "PyNaCl-1.3.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1"}, - {file = "PyNaCl-1.3.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0d0a8171a68edf51add1e73d2159c4bc19fc0718e79dec51166e940856c2f28e"}, - {file = "PyNaCl-1.3.0-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1"}, - {file = "PyNaCl-1.3.0-cp34-abi3-manylinux1_i686.whl", hash = "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786"}, - {file = "PyNaCl-1.3.0-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415"}, - {file = "PyNaCl-1.3.0-cp34-cp34m-win32.whl", hash = "sha256:7d3ce02c0784b7cbcc771a2da6ea51f87e8716004512493a2b69016326301c3b"}, - {file = "PyNaCl-1.3.0-cp34-cp34m-win_amd64.whl", hash = "sha256:1c780712b206317a746ace34c209b8c29dbfd841dfbc02aa27f2084dd3db77ae"}, - {file = "PyNaCl-1.3.0-cp35-cp35m-win32.whl", hash = "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310"}, - {file = "PyNaCl-1.3.0-cp35-cp35m-win_amd64.whl", hash = "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a"}, - {file = "PyNaCl-1.3.0-cp36-cp36m-win32.whl", hash = "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20"}, - {file = "PyNaCl-1.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b"}, - {file = "PyNaCl-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:2d23c04e8d709444220557ae48ed01f3f1086439f12dbf11976e849a4926db56"}, - {file = "PyNaCl-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715"}, - {file = "PyNaCl-1.3.0-cp38-cp38-win32.whl", hash = "sha256:53126cd91356342dcae7e209f840212a58dcf1177ad52c1d938d428eebc9fee5"}, - {file = "PyNaCl-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:bf459128feb543cfca16a95f8da31e2e65e4c5257d2f3dfa8c0c1031139c9c92"}, - {file = "PyNaCl-1.3.0.tar.gz", hash = "sha256:0c6100edd16fefd1557da078c7a31e7b7d7a52ce39fdca2bec29d4f7b6e7600c"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-win32.whl", hash = "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80"}, + {file = "PyNaCl-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7"}, + {file = "PyNaCl-1.4.0-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122"}, + {file = "PyNaCl-1.4.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d"}, + {file = "PyNaCl-1.4.0-cp35-abi3-win32.whl", hash = "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634"}, + {file = "PyNaCl-1.4.0-cp35-abi3-win_amd64.whl", hash = "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6"}, + {file = "PyNaCl-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4"}, + {file = "PyNaCl-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25"}, + {file = "PyNaCl-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4"}, + {file = "PyNaCl-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6"}, + {file = "PyNaCl-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f"}, + {file = "PyNaCl-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f"}, + {file = "PyNaCl-1.4.0-cp38-cp38-win32.whl", hash = "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96"}, + {file = "PyNaCl-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420"}, + {file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyserial = [ {file = "pyserial-3.4-py2.py3-none-any.whl", hash = "sha256:e0770fadba80c31013896c7e6ef703f72e7834965954a78e71a3049488d4d7d8"}, @@ -1032,39 +1131,59 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] regex = [ - {file = "regex-2020.5.7-cp27-cp27m-win32.whl", hash = "sha256:5493a02c1882d2acaaf17be81a3b65408ff541c922bfd002535c5f148aa29f74"}, - {file = "regex-2020.5.7-cp27-cp27m-win_amd64.whl", hash = "sha256:021a0ae4d2baeeb60a3014805a2096cb329bd6d9f30669b7ad0da51a9cb73349"}, - {file = "regex-2020.5.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4df91094ced6f53e71f695c909d9bad1cca8761d96fd9f23db12245b5521136e"}, - {file = "regex-2020.5.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7ce4a213a96d6c25eeae2f7d60d4dad89ac2b8134ec3e69db9bc522e2c0f9388"}, - {file = "regex-2020.5.7-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b059e2476b327b9794c792c855aa05531a3f3044737e455d283c7539bd7534d"}, - {file = "regex-2020.5.7-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:652ab4836cd5531d64a34403c00ada4077bb91112e8bcdae933e2eae232cf4a8"}, - {file = "regex-2020.5.7-cp36-cp36m-win32.whl", hash = "sha256:1e2255ae938a36e9bd7db3b93618796d90c07e5f64dd6a6750c55f51f8b76918"}, - {file = "regex-2020.5.7-cp36-cp36m-win_amd64.whl", hash = "sha256:8127ca2bf9539d6a64d03686fd9e789e8c194fc19af49b69b081f8c7e6ecb1bc"}, - {file = "regex-2020.5.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f7f2f4226db6acd1da228adf433c5c3792858474e49d80668ea82ac87cf74a03"}, - {file = "regex-2020.5.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2bc6a17a7fa8afd33c02d51b6f417fc271538990297167f68a98cae1c9e5c945"}, - {file = "regex-2020.5.7-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b7c9f65524ff06bf70c945cd8d8d1fd90853e27ccf86026af2afb4d9a63d06b1"}, - {file = "regex-2020.5.7-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:fa09da4af4e5b15c0e8b4986a083f3fd159302ea115a6cc0649cd163435538b8"}, - {file = "regex-2020.5.7-cp37-cp37m-win32.whl", hash = "sha256:669a8d46764a09f198f2e91fc0d5acdac8e6b620376757a04682846ae28879c4"}, - {file = "regex-2020.5.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b5b5b2e95f761a88d4c93691716ce01dc55f288a153face1654f868a8034f494"}, - {file = "regex-2020.5.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0ff50843535593ee93acab662663cb2f52af8e31c3f525f630f1dc6156247938"}, - {file = "regex-2020.5.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1b17bf37c2aefc4cac8436971fe6ee52542ae4225cfc7762017f7e97a63ca998"}, - {file = "regex-2020.5.7-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:04d6e948ef34d3eac133bedc0098364a9e635a7914f050edb61272d2ddae3608"}, - {file = "regex-2020.5.7-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5b741ecc3ad3e463d2ba32dce512b412c319993c1bb3d999be49e6092a769fb2"}, - {file = "regex-2020.5.7-cp38-cp38-win32.whl", hash = "sha256:099568b372bda492be09c4f291b398475587d49937c659824f891182df728cdf"}, - {file = "regex-2020.5.7-cp38-cp38-win_amd64.whl", hash = "sha256:3ab5e41c4ed7cd4fa426c50add2892eb0f04ae4e73162155cd668257d02259dd"}, - {file = "regex-2020.5.7.tar.gz", hash = "sha256:73a10404867b835f1b8a64253e4621908f0d71150eb4e97ab2e7e441b53e9451"}, + {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, + {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, + {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, + {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, + {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, + {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, + {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, + {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, + {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, + {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, + {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, + {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, + {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, ] requests = [ - {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, - {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, + {file = "requests-2.25.0-py2.py3-none-any.whl", hash = "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"}, + {file = "requests-2.25.0.tar.gz", hash = "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8"}, ] scp = [ - {file = "scp-0.13.2-py2.py3-none-any.whl", hash = "sha256:26c0bbc7ea29c30ec096ae67b0afa7a6b7c557b2ce8f740109ee72a0d52af7d1"}, - {file = "scp-0.13.2.tar.gz", hash = "sha256:ef9d6e67c0331485d3db146bf9ee9baff8a48f3eb0e6c08276a8584b13bf34b3"}, + {file = "scp-0.13.3-py2.py3-none-any.whl", hash = "sha256:f2fa9fb269ead0f09b4e2ceb47621beb7000c135f272f6b70d3d9d29928d7bf0"}, + {file = "scp-0.13.3.tar.gz", hash = "sha256:8bd748293d7362073169b96ce4b8c4f93bcc62cfc5f7e1d949e01e406a025bd4"}, ] six = [ - {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, - {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] smmap = [ {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, @@ -1075,16 +1194,23 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] stevedore = [ - {file = "stevedore-1.32.0-py2.py3-none-any.whl", hash = "sha256:a4e7dc759fb0f2e3e2f7d8ffe2358c19d45b9b8297f393ef1256858d82f69c9b"}, - {file = "stevedore-1.32.0.tar.gz", hash = "sha256:18afaf1d623af5950cc0f7e75e70f917784c73b652a34a12d90b309451b5500b"}, + {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, + {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, +] +tenacity = [ + {file = "tenacity-6.2.0-py2.py3-none-any.whl", hash = "sha256:5a5d3dcd46381abe8b4f82b5736b8726fd3160c6c7161f53f8af7f1eb9b82173"}, + {file = "tenacity-6.2.0.tar.gz", hash = "sha256:29ae90e7faf488a8628432154bb34ace1cca58244c6ea399fd33f066ac71339a"}, ] textfsm = [ {file = "textfsm-1.1.0-py2.py3-none-any.whl", hash = "sha256:0aef3f9cad3d03905915fd62bff358c42b7dc35c863ff2cb0b5324c2b746cc24"}, ] toml = [ - {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, - {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, - {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +transitions = [ + {file = "transitions-0.8.5-py2.py3-none-any.whl", hash = "sha256:bb05d3283c91e091046ed5484da2e4f8b489eb5f1bca1a5c76d47d19d703b3ff"}, + {file = "transitions-0.8.5.tar.gz", hash = "sha256:e441c66a0c753d56c01c3e5e547f21dbe4a5569c939f12477475c5e81d79769b"}, ] typed-ast = [ {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, @@ -1094,29 +1220,45 @@ typed-ast = [ {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f"}, {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298"}, {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d"}, {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, + {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c"}, + {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072"}, + {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91"}, + {file = "typed_ast-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d"}, + {file = "typed_ast-1.4.1-cp39-cp39-win32.whl", hash = "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395"}, + {file = "typed_ast-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] urllib3 = [ - {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, - {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, + {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, + {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, ] wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] yamllint = [ - {file = "yamllint-1.23.0-py2.py3-none-any.whl", hash = "sha256:0fa69bf8a86182b7fe14918bdd3a30354c869966bbc7cbfff176af71bda9c806"}, - {file = "yamllint-1.23.0.tar.gz", hash = "sha256:59f3ff77f44e7f46be6aecdb985830f73a1c51e290b7082a7d38c2ae1940f4a9"}, + {file = "yamllint-1.25.0-py2.py3-none-any.whl", hash = "sha256:c7be4d0d2584a1b561498fa9acb77ad22eb434a109725c7781373ae496d823b3"}, + {file = "yamllint-1.25.0.tar.gz", hash = "sha256:b1549cbe5b47b6ba67bdeea31720f5c51431a4d0c076c1557952d841f7223519"}, +] +yamlordereddictloader = [ + {file = "yamlordereddictloader-0.4.0.tar.gz", hash = "sha256:7f30f0b99ea3f877f7cb340c570921fa9d639b7f69cba18be051e27f8de2080e"}, +] +zipp = [ + {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, + {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, ] diff --git a/pyproject.toml b/pyproject.toml index 7029357..38cf21a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,10 +19,11 @@ packages = [ [tool.poetry.dependencies] python = "^3.6 || ^3.7 || ^3.8" -invoke = "^1.4.1" -napalm = "^2.5.0" +napalm = ">=2.5.0, <4" +zipp = "^3.4.0" [tool.poetry.dev-dependencies] +invoke = "^1.4.1" black = "^19.10b0" yamllint = "^1.23.0" bandit = "^1.6.2" @@ -52,6 +53,42 @@ exclude = ''' # the root of the project ) ''' + +[tool.pylint.master] +# Include the pylint_django plugin to avoid spurious warnings about Django patterns +load-plugins="pylint_django" + +# Don't cache data for later comparisons +persistent="no" + +[tool.pylint.basic] +# No docstrings required for private methods (Pylint default), or for test_ functions, or for inner Meta classes. +no-docstring-rgx="^(_|test_|Meta$)" +# Allow "ot" (OnboardingTask instance) as an acceptable variable name +good-names="ot," + +[tool.pylint.messages_control] +# Line length is enforced by Black, so pylint doesn't need to check it. +# Pylint and Black disagree about how to format multi-line arrays; Black wins. +# Disabled due to noise: too-few-public-methods, too-many-ancestors, too-many-instance-attributes +disable = """, + line-too-long, + bad-continuation, + too-few-public-methods, + too-many-ancestors, + too-many-instance-attributes, + duplicate-code, + raise-missing-from, + super-with-arguments + """ + +[tool.pylint.miscellaneous] +# Don't flag TODO as a failure, let us commit with things that still need to be done in the code +notes = """, + FIXME, + XXX, + """ + [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" diff --git a/tasks.py b/tasks.py index 77d4bf2..11a6560 100644 --- a/tasks.py +++ b/tasks.py @@ -231,7 +231,7 @@ def pylint(context, netbox_ver=NETBOX_VER, python_ver=PYTHON_VER): # We exclude the /migrations/ directory since it is autogenerated code context.run( f"{docker} sh -c \"cd /source && find . -name '*.py' -not -path '*/migrations/*' | " - 'PYTHONPATH=/opt/netbox/netbox xargs pylint"', + 'PYTHONPATH=/opt/netbox/netbox DJANGO_SETTINGS_MODULE=netbox.settings xargs pylint"', env={"NETBOX_VER": netbox_ver, "PYTHON_VER": python_ver}, pty=True, ) From 258907743af5733f89e6712a2628fe9c352bb540 Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Fri, 18 Dec 2020 12:22:13 +0100 Subject: [PATCH 09/16] Modified functions ensure_interface and ensure_primary_ip to check for class attributes --- netbox_onboarding/netbox_keeper.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/netbox_onboarding/netbox_keeper.py b/netbox_onboarding/netbox_keeper.py index 2ebe9c4..85e2f52 100644 --- a/netbox_onboarding/netbox_keeper.py +++ b/netbox_onboarding/netbox_keeper.py @@ -401,23 +401,25 @@ def ensure_device_instance(self, default_status=PLUGIN_SETTINGS["default_device_ def ensure_interface(self): """Ensures that the interface associated with the mgmt_ipaddr exists and is assigned to the device.""" - self.nb_mgmt_ifname, _ = Interface.objects.get_or_create(name=self.netdev_mgmt_ifname, device=self.device) + if self.netdev_mgmt_ifname: + self.nb_mgmt_ifname, _ = Interface.objects.get_or_create(name=self.netdev_mgmt_ifname, device=self.device) def ensure_primary_ip(self): """Ensure mgmt_ipaddr exists in IPAM, has the device interface, and is assigned as the primary IP address.""" # see if the primary IP address exists in IPAM - self.nb_primary_ip, created = IPAddress.objects.get_or_create( - address=f"{self.netdev_mgmt_ip_address}/{self.netdev_mgmt_pflen}" - ) + if self.netdev_mgmt_ip_address and self.netdev_mgmt_pflen: + self.nb_primary_ip, created = IPAddress.objects.get_or_create( + address=f"{self.netdev_mgmt_ip_address}/{self.netdev_mgmt_pflen}" + ) - if created or not self.nb_primary_ip in self.nb_mgmt_ifname.ip_addresses.all(): - logger.info("ASSIGN: IP address %s to %s", self.nb_primary_ip.address, self.nb_mgmt_ifname.name) - self.nb_mgmt_ifname.ip_addresses.add(self.nb_primary_ip) - self.nb_mgmt_ifname.save() + if created or not self.nb_primary_ip in self.nb_mgmt_ifname.ip_addresses.all(): + logger.info("ASSIGN: IP address %s to %s", self.nb_primary_ip.address, self.nb_mgmt_ifname.name) + self.nb_mgmt_ifname.ip_addresses.add(self.nb_primary_ip) + self.nb_mgmt_ifname.save() - # Ensure the primary IP is assigned to the device - self.device.primary_ip4 = self.nb_primary_ip - self.device.save() + # Ensure the primary IP is assigned to the device + self.device.primary_ip4 = self.nb_primary_ip + self.device.save() def ensure_device(self): """Ensure that the device represented by the DevNetKeeper exists in the NetBox system.""" From bb7d2940d9987d96e5ac444fba1cd34552023e59 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Fri, 18 Dec 2020 07:36:53 -0500 Subject: [PATCH 10/16] Update project for 2.10 --- .travis.yml | 5 +- development/Dockerfile | 2 +- ...base_configuration.py => configuration.py} | 159 ++++++++++++------ development/dev.env | 35 ++-- development/docker-compose.yml | 6 +- development/netbox_master/configuration.py | 4 - development/netbox_v2.8.3/configuration.py | 8 - netbox_onboarding/__init__.py | 1 + netbox_onboarding/release.py | 1 + netbox_onboarding/views.py | 54 ++++-- 10 files changed, 177 insertions(+), 98 deletions(-) rename development/{base_configuration.py => configuration.py} (60%) delete mode 100644 development/netbox_master/configuration.py delete mode 100644 development/netbox_v2.8.3/configuration.py diff --git a/.travis.yml b/.travis.yml index 5c1309e..0bb1414 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,9 @@ env: # Each version of NetBox listed here must have a corresponding directory/configuration file # under development/netbox_/configuration.py matrix: - - NETBOX_VER=v2.8.3 - - NETBOX_VER=master + - NETBOX_VER=v2.8.9 + - NETBOX_VER=v2.9.9 + - NETBOX_VER=v2.10.1 # Encrypted value for PYPI_TOKEN, this secret has been generated with the following command # travis encrypt PYPI_TOKEN= --add env.global --com # Might need to update it once the repo is publish (travis-ci.org vs travis-ci.com) diff --git a/development/Dockerfile b/development/Dockerfile index 602937d..626a1a6 100644 --- a/development/Dockerfile +++ b/development/Dockerfile @@ -2,7 +2,6 @@ ARG python_ver=3.7 FROM python:${python_ver} -ARG netbox_ver=master ENV PYTHONUNBUFFERED 1 RUN mkdir -p /opt @@ -15,6 +14,7 @@ RUN pip install --upgrade pip\ # ------------------------------------------------------------------------------------- # Remove redis==3.4.1 from the requirements.txt file as a workaround to #4910 # https://github.com/netbox-community/netbox/issues/4910, required for version 2.8.8 and earlier +ARG netbox_ver=master RUN git clone --single-branch --branch ${netbox_ver} https://github.com/netbox-community/netbox.git /opt/netbox/ && \ cd /opt/netbox/ && \ sed -i '/^redis\=\=/d' /opt/netbox/requirements.txt && \ diff --git a/development/base_configuration.py b/development/configuration.py similarity index 60% rename from development/base_configuration.py rename to development/configuration.py index 06467cc..fa96a47 100644 --- a/development/base_configuration.py +++ b/development/configuration.py @@ -1,5 +1,39 @@ -"""NetBox configuration file.""" +"""NetBox configuration.""" import os +from distutils.util import strtobool +from django.core.exceptions import ImproperlyConfigured +from .settings import VERSION # pylint: disable=relative-beyond-top-level + + +# Enforce required configuration parameters +for key in [ + "ALLOWED_HOSTS", + "POSTGRES_DB", + "POSTGRES_USER", + "POSTGRES_HOST", + "POSTGRES_PASSWORD", + "REDIS_HOST", + "REDIS_PASSWORD", + "SECRET_KEY", +]: + if not os.environ.get(key): + raise ImproperlyConfigured(f"Required environment variable {key} is missing.") + + +def is_truthy(arg): + """Convert "truthy" strings into Booleans. + + Examples: + >>> is_truthy('yes') + True + Args: + arg (str): Truthy string (True values are y, yes, t, true, on and 1; false values are n, no, + f, false, off and 0. Raises ValueError if val is anything else. + """ + if isinstance(arg, bool): + return arg + return bool(strtobool(arg)) + # For reference see http://netbox.readthedocs.io/en/latest/configuration/mandatory-settings/ # Based on https://github.com/digitalocean/netbox/blob/develop/netbox/netbox/configuration.example.py @@ -16,46 +50,52 @@ # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. # # Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] -ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(" ") +ALLOWED_HOSTS = os.environ["ALLOWED_HOSTS"].split(" ") # PostgreSQL database configuration. DATABASE = { - "NAME": os.environ.get("DB_NAME", "netbox"), # Database name - "USER": os.environ.get("DB_USER", ""), # PostgreSQL username - "PASSWORD": os.environ.get("DB_PASSWORD", ""), + "NAME": os.environ["POSTGRES_DB"], # Database name + "USER": os.environ["POSTGRES_USER"], # PostgreSQL username + "PASSWORD": os.environ["POSTGRES_PASSWORD"], # PostgreSQL password - "HOST": os.environ.get("DB_HOST", "localhost"), # Database server - "PORT": os.environ.get("DB_PORT", ""), # Database port (leave blank for default) + "HOST": os.environ["POSTGRES_HOST"], # Database server + "PORT": 5432 if not os.environ.get("POSTGRES_PORT", False) else int(os.environ["POSTGRES_PORT"]), # Database port } # This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. # For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and # symbols. NetBox will not run without this defined. For more information, see # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY -SECRET_KEY = os.environ.get("SECRET_KEY", "") +SECRET_KEY = os.environ["SECRET_KEY"] # Redis database settings. The Redis database is used for caching and background processing such as webhooks # Seperate sections for webhooks and caching allow for connecting to seperate Redis instances/datbases if desired. # Full connection details are required in both sections, even if they are the same. REDIS = { "caching": { - "HOST": os.environ.get("REDIS_HOST", "redis"), + "HOST": os.environ["REDIS_HOST"], "PORT": int(os.environ.get("REDIS_PORT", 6379)), - "PASSWORD": os.environ.get("REDIS_PASSWORD", ""), + "PASSWORD": os.environ["REDIS_PASSWORD"], "DATABASE": 1, - "SSL": bool(os.environ.get("REDIS_SSL", False)), + "SSL": is_truthy(os.environ.get("REDIS_SSL", False)), }, "tasks": { - "HOST": os.environ.get("REDIS_HOST", "redis"), + "HOST": os.environ["REDIS_HOST"], "PORT": int(os.environ.get("REDIS_PORT", 6379)), - "PASSWORD": os.environ.get("REDIS_PASSWORD", ""), + "PASSWORD": os.environ["REDIS_PASSWORD"], "DATABASE": 0, - "SSL": bool(os.environ.get("REDIS_SSL", False)), + "SSL": is_truthy(os.environ.get("REDIS_SSL", False)), }, } -RQ_DEFAULT_TIMEOUT = 300 - +if VERSION.startswith("2.8."): + # NetBox 2.8.x Specific Settings + REDIS["caching"]["DEFAULT_TIMEOUT"] = 300 + REDIS["tasks"]["DEFAULT_TIMEOUT"] = 300 +elif VERSION.startswith("2.9.") or VERSION.startswith("2.10."): + RQ_DEFAULT_TIMEOUT = 300 +else: + raise ImproperlyConfigured(f"Version {VERSION} of NetBox is unsupported at this time.") ######################### # # @@ -71,8 +111,8 @@ # Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same # content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. -BANNER_TOP = os.environ.get("BANNER_TOP", None) -BANNER_BOTTOM = os.environ.get("BANNER_BOTTOM", None) +BANNER_TOP = os.environ.get("BANNER_TOP", "") +BANNER_BOTTOM = os.environ.get("BANNER_BOTTOM", "") # Text to include on the login page above the login form. HTML is allowed. BANNER_LOGIN = os.environ.get("BANNER_LOGIN", "") @@ -87,58 +127,65 @@ # API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be # allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or # CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers -CORS_ORIGIN_ALLOW_ALL = True +CORS_ORIGIN_ALLOW_ALL = is_truthy(os.environ.get("CORS_ORIGIN_ALLOW_ALL", False)) CORS_ORIGIN_WHITELIST = [] CORS_ORIGIN_REGEX_WHITELIST = [] # Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal # sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging # on a production system. -DEBUG = True -DEVELOPER = True +DEBUG = is_truthy(os.environ.get("DEBUG", False)) +DEVELOPER = is_truthy(os.environ.get("DEVELOPER", False)) # Email settings EMAIL = { - "SERVER": "localhost", - "PORT": 25, - "USERNAME": "", - "PASSWORD": "", - "TIMEOUT": 10, - "FROM_EMAIL": "", + "SERVER": os.environ.get("EMAIL_SERVER", "localhost"), + "PORT": int(os.environ.get("EMAIL_PORT", 25)), + "USERNAME": os.environ.get("EMAIL_USERNAME", ""), + "PASSWORD": os.environ.get("EMAIL_PASSWORD", ""), + "TIMEOUT": int(os.environ.get("EMAIL_TIMEOUT", 10)), # seconds + "FROM_EMAIL": os.environ.get("EMAIL_FROM", ""), } # Enforcement of unique IP space can be toggled on a per-VRF basis. # To enforce unique IP space within the global table (all prefixes and IP addresses not assigned to a VRF), # set ENFORCE_GLOBAL_UNIQUE to True. -ENFORCE_GLOBAL_UNIQUE = False +ENFORCE_GLOBAL_UNIQUE = is_truthy(os.environ.get("ENFORCE_GLOBAL_UNIQUE", False)) + +# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks). +# HTTP_PROXIES = { +# "http": "http://192.0.2.1:3128", +# "https": "http://192.0.2.1:1080", +# } + +# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing +# NetBox from an internal IP. +INTERNAL_IPS = ("127.0.0.1", "::1") + +LOG_LEVEL = os.environ.get("LOG_LEVEL", "DEBUG" if DEBUG else "INFO") # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: # https://docs.djangoproject.com/en/1.11/topics/logging/ LOGGING = { "version": 1, "disable_existing_loggers": False, - "formatters": {"rq_console": {"format": "%(asctime)s %(message)s", "datefmt": "%H:%M:%S",},}, - "handlers": { - "rq_console": { - "level": "DEBUG", - "class": "rq.utils.ColorizingStreamHandler", - "formatter": "rq_console", - "exclude": ["%(asctime)s"], + "formatters": { + "verbose": { + "format": "{asctime} {levelname} {message} - {name} - {module} - {pathname}:{lineno}", + "datefmt": "%H:%M:%S", + "style": "{", }, }, - "loggers": {"rq.worker": {"handlers": ["rq_console"], "level": "DEBUG"},}, + "handlers": {"console": {"level": "DEBUG", "class": "rq.utils.ColorizingStreamHandler", "formatter": "verbose"}}, + "root": {"handlers": ["console"], "level": LOG_LEVEL}, } # Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users # are permitted to access most data in NetBox (excluding secrets) but not make any changes. -LOGIN_REQUIRED = False - -# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set: -# BASE_PATH = 'netbox/' -BASE_PATH = os.environ.get("BASE_PATH", "") +LOGIN_REQUIRED = is_truthy(os.environ.get("LOGIN_REQUIRED", False)) # Setting this to True will display a "maintenance mode" banner at the top of every page. -MAINTENANCE_MODE = os.environ.get("MAINTENANCE_MODE", False) +MAINTENANCE_MODE = is_truthy(os.environ.get("MAINTENANCE_MODE", False)) # An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. # "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request @@ -149,11 +196,14 @@ # the default value of this setting is derived from the installed location. MEDIA_ROOT = os.environ.get("MEDIA_ROOT", os.path.join(BASE_DIR, "media")) +# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' +METRICS_ENABLED = True + NAPALM_USERNAME = os.environ.get("NAPALM_USERNAME", "") NAPALM_PASSWORD = os.environ.get("NAPALM_PASSWORD", "") # NAPALM timeout (in seconds). (Default: 30) -NAPALM_TIMEOUT = os.environ.get("NAPALM_TIMEOUT", 30) +NAPALM_TIMEOUT = int(os.environ.get("NAPALM_TIMEOUT", 30)) # NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must # be provided as a dictionary. @@ -163,27 +213,34 @@ } # Determine how many objects to display per page within a list. (Default: 50) -PAGINATE_COUNT = os.environ.get("PAGINATE_COUNT", 50) +PAGINATE_COUNT = int(os.environ.get("PAGINATE_COUNT", 50)) # Enable installed plugins. Add the name of each plugin to the list. PLUGINS = ["netbox_onboarding"] -PLUGINS_CONFIG = {"netbox_onboarding": {}} # Plugins configuration settings. These settings are used by various plugins that the user may have installed. # Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. -# PLUGINS_CONFIG = {} +PLUGINS_CONFIG = {} # When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to # prefer IPv4 instead. -PREFER_IPV4 = os.environ.get("PREFER_IPV4", False) +PREFER_IPV4 = is_truthy(os.environ.get("PREFER_IPV4", False)) # Remote authentication support REMOTE_AUTH_ENABLED = False -REMOTE_AUTH_BACKEND = "netbox.authentication.RemoteUserBackend" REMOTE_AUTH_HEADER = "HTTP_REMOTE_USER" REMOTE_AUTH_AUTO_CREATE_USER = True REMOTE_AUTH_DEFAULT_GROUPS = [] -REMOTE_AUTH_DEFAULT_PERMISSIONS = {} + +if VERSION.startswith("2.8."): + # NetBox 2.8.x Specific Settings + REMOTE_AUTH_BACKEND = "utilities.auth_backends.RemoteUserBackend" + REMOTE_AUTH_DEFAULT_PERMISSIONS = [] +elif VERSION.startswith("2.9.") or VERSION.startswith("2.10."): + REMOTE_AUTH_BACKEND = "netbox.authentication.RemoteUserBackend" + REMOTE_AUTH_DEFAULT_PERMISSIONS = {} +else: + raise ImproperlyConfigured(f"Version {VERSION} of NetBox is unsupported at this time.") # This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. RELEASE_CHECK_TIMEOUT = 24 * 3600 @@ -199,6 +256,10 @@ # this setting is derived from the installed location. REPORTS_ROOT = os.environ.get("REPORTS_ROOT", os.path.join(BASE_DIR, "reports")) +# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +SCRIPTS_ROOT = os.environ.get("SCRIPTS_ROOT", os.path.join(BASE_DIR, "scripts")) + # Time zone (default: UTC) TIME_ZONE = os.environ.get("TIME_ZONE", "UTC") diff --git a/development/dev.env b/development/dev.env index 7f813ec..407a94c 100644 --- a/development/dev.env +++ b/development/dev.env @@ -1,19 +1,28 @@ ALLOWED_HOSTS=* -DB_NAME=netbox -DB_USER=netbox -DB_PASSWORD=decinablesprewad -PGPASSWORD=decinablesprewad -DB_HOST=postgres -NAPALM_TIMEOUT=5 +BANNER_TOP="Onboarding plugin dev" +CHANGELOG_RETENTION=0 +DEBUG=True +DEVELOPER=True +EMAIL_FROM=netbox@example.com +EMAIL_PASSWORD= +EMAIL_PORT=25 +EMAIL_SERVER=localhost +EMAIL_TIMEOUT=5 +EMAIL_USERNAME=netbox MAX_PAGE_SIZE=0 -SECRET_KEY=bqn8nn4qmjvx4hv2u5qr4pp46s3w9skbb63y -POSTGRES_USER=netbox -POSTGRES_PASSWORD=decinablesprewad +METRICS_ENABLED=True +NAPALM_TIMEOUT=5 POSTGRES_DB=netbox -CHANGELOG_RETENTION=0 +POSTGRES_HOST=postgres +POSTGRES_PASSWORD=notverysecurepwd +POSTGRES_USER=netbox REDIS_HOST=redis +REDIS_PASSWORD=notverysecurepwd REDIS_PORT=6379 -# Uncomment REDIS_SSL if using SSL # REDIS_SSL=True -REDIS_PASSWORD=decinablesprewad - +# Uncomment REDIS_SSL if using SSL +SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj +SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 +SUPERUSER_EMAIL=admin@example.com +SUPERUSER_NAME=admin +SUPERUSER_PASSWORD=admin \ No newline at end of file diff --git a/development/docker-compose.yml b/development/docker-compose.yml index e1a2c9f..75e075c 100644 --- a/development/docker-compose.yml +++ b/development/docker-compose.yml @@ -17,8 +17,7 @@ services: env_file: - ./dev.env volumes: - - ./base_configuration.py:/opt/netbox/netbox/netbox/base_configuration.py - - ./netbox_${NETBOX_VER}/configuration.py:/opt/netbox/netbox/netbox/configuration.py + - ./configuration.py:/opt/netbox/netbox/netbox/configuration.py - ../:/source tty: true worker: @@ -32,8 +31,7 @@ services: env_file: - ./dev.env volumes: - - ./base_configuration.py:/opt/netbox/netbox/netbox/base_configuration.py - - ./netbox_${NETBOX_VER}/configuration.py:/opt/netbox/netbox/netbox/configuration.py + - ./configuration.py:/opt/netbox/netbox/netbox/configuration.py - ../netbox_onboarding:/source/netbox_onboarding tty: true postgres: diff --git a/development/netbox_master/configuration.py b/development/netbox_master/configuration.py deleted file mode 100644 index 81abf04..0000000 --- a/development/netbox_master/configuration.py +++ /dev/null @@ -1,4 +0,0 @@ -"""NetBox configuration file overrides specific to the latest MASTER version.""" -from .base_configuration import * # pylint: disable=relative-beyond-top-level, wildcard-import - -# Overrides specific to this version go here diff --git a/development/netbox_v2.8.3/configuration.py b/development/netbox_v2.8.3/configuration.py deleted file mode 100644 index c27860c..0000000 --- a/development/netbox_v2.8.3/configuration.py +++ /dev/null @@ -1,8 +0,0 @@ -"""NetBox configuration file overrides specific to version 2.8.3.""" -from .base_configuration import * # pylint: disable=relative-beyond-top-level, wildcard-import - -# Overrides specific to this version go here -REMOTE_AUTH_BACKEND = "utilities.auth_backends.RemoteUserBackend" -REMOTE_AUTH_DEFAULT_PERMISSIONS = [] -REDIS["caching"]["DEFAULT_TIMEOUT"] = 300 # pylint: disable=undefined-variable -REDIS["tasks"]["DEFAULT_TIMEOUT"] = 300 # pylint: disable=undefined-variable diff --git a/netbox_onboarding/__init__.py b/netbox_onboarding/__init__.py index d1bc886..e1d740d 100644 --- a/netbox_onboarding/__init__.py +++ b/netbox_onboarding/__init__.py @@ -28,6 +28,7 @@ class OnboardingConfig(PluginConfig): base_url = "onboarding" required_settings = [] min_version = "2.8.1" + max_version = "2.10.99" default_settings = { "create_platform_if_missing": True, "create_manufacturer_if_missing": True, diff --git a/netbox_onboarding/release.py b/netbox_onboarding/release.py index 648f8f3..5851b89 100644 --- a/netbox_onboarding/release.py +++ b/netbox_onboarding/release.py @@ -18,3 +18,4 @@ NETBOX_RELEASE_CURRENT = version.parse(settings.VERSION) NETBOX_RELEASE_28 = version.parse("2.8") NETBOX_RELEASE_29 = version.parse("2.9") +NETBOX_RELEASE_210 = version.parse("2.10") diff --git a/netbox_onboarding/views.py b/netbox_onboarding/views.py index 79ab623..56df140 100644 --- a/netbox_onboarding/views.py +++ b/netbox_onboarding/views.py @@ -16,9 +16,7 @@ from django.shortcuts import get_object_or_404, render from django.views.generic import View -from utilities.views import BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView - -from .release import NETBOX_RELEASE_CURRENT, NETBOX_RELEASE_29 +from .release import NETBOX_RELEASE_CURRENT, NETBOX_RELEASE_29, NETBOX_RELEASE_210 from .filters import OnboardingTaskFilter from .forms import OnboardingTaskForm, OnboardingTaskFilterForm, OnboardingTaskFeedCSVForm @@ -27,52 +25,74 @@ logger = logging.getLogger("rq.worker") +# pylint: disable=ungrouped-imports if NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_29: - from django.contrib.auth.mixins import PermissionRequiredMixin # pylint: disable=ungrouped-imports + from django.contrib.auth.mixins import PermissionRequiredMixin + from utilities.views import BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView class ReleaseMixinOnboardingTaskView(PermissionRequiredMixin, View): """Release Mixin View for presenting a single OnboardingTask.""" permission_required = "netbox_onboarding.view_onboardingtask" - class ReleaseMixinOnboardingTaskListView(PermissionRequiredMixin): + class ReleaseMixinOnboardingTaskListView(PermissionRequiredMixin, ObjectListView): """Release Mixin View for listing all extant OnboardingTasks.""" permission_required = "netbox_onboarding.view_onboardingtask" - class ReleaseMixinOnboardingTaskCreateView(PermissionRequiredMixin): + class ReleaseMixinOnboardingTaskCreateView(PermissionRequiredMixin, ObjectEditView): """Release Mixin View for creating a new OnboardingTask.""" permission_required = "netbox_onboarding.add_onboardingtask" - class ReleaseMixinOnboardingTaskBulkDeleteView(PermissionRequiredMixin): + class ReleaseMixinOnboardingTaskBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): """Release Mixin View for deleting one or more OnboardingTasks.""" permission_required = "netbox_onboarding.delete_onboardingtask" - class ReleaseMixinOnboardingTaskFeedBulkImportView(PermissionRequiredMixin): + class ReleaseMixinOnboardingTaskFeedBulkImportView(PermissionRequiredMixin, BulkImportView): """Release Mixin View for bulk-importing a CSV file to create OnboardingTasks.""" permission_required = "netbox_onboarding.add_onboardingtask" +elif NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_29 and NETBOX_RELEASE_CURRENT > NETBOX_RELEASE_210: + from utilities.views import ObjectView # pylint: disable=no-name-in-module + from utilities.views import BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView + + class ReleaseMixinOnboardingTaskView(ObjectView): + """Release Mixin View for presenting a single OnboardingTask.""" + + class ReleaseMixinOnboardingTaskListView(ObjectListView): + """Release Mixin View for listing all extant OnboardingTasks.""" + + class ReleaseMixinOnboardingTaskCreateView(ObjectEditView): + """Release Mixin View for creating a new OnboardingTask.""" + + class ReleaseMixinOnboardingTaskBulkDeleteView(BulkDeleteView): + """Release Mixin View for deleting one or more OnboardingTasks.""" + + class ReleaseMixinOnboardingTaskFeedBulkImportView(BulkImportView): + """Release Mixin View for bulk-importing a CSV file to create OnboardingTasks.""" + + else: - from utilities.views import ObjectView # pylint: disable=ungrouped-imports, no-name-in-module + from netbox.views.generic import ObjectView, BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView class ReleaseMixinOnboardingTaskView(ObjectView): """Release Mixin View for presenting a single OnboardingTask.""" - class ReleaseMixinOnboardingTaskListView: + class ReleaseMixinOnboardingTaskListView(ObjectListView): """Release Mixin View for listing all extant OnboardingTasks.""" - class ReleaseMixinOnboardingTaskCreateView: + class ReleaseMixinOnboardingTaskCreateView(ObjectEditView): """Release Mixin View for creating a new OnboardingTask.""" - class ReleaseMixinOnboardingTaskBulkDeleteView: + class ReleaseMixinOnboardingTaskBulkDeleteView(BulkDeleteView): """Release Mixin View for deleting one or more OnboardingTasks.""" - class ReleaseMixinOnboardingTaskFeedBulkImportView: + class ReleaseMixinOnboardingTaskFeedBulkImportView(BulkImportView): """Release Mixin View for bulk-importing a CSV file to create OnboardingTasks.""" @@ -88,7 +108,7 @@ def get(self, request, pk): # pylint: disable=invalid-name, missing-function-do return render(request, "netbox_onboarding/onboardingtask.html", {"onboardingtask": onboardingtask,}) -class OnboardingTaskListView(ReleaseMixinOnboardingTaskListView, ObjectListView): +class OnboardingTaskListView(ReleaseMixinOnboardingTaskListView): """View for listing all extant OnboardingTasks.""" queryset = OnboardingTask.objects.all().order_by("-id") @@ -98,7 +118,7 @@ class OnboardingTaskListView(ReleaseMixinOnboardingTaskListView, ObjectListView) template_name = "netbox_onboarding/onboarding_tasks_list.html" -class OnboardingTaskCreateView(ReleaseMixinOnboardingTaskCreateView, ObjectEditView): +class OnboardingTaskCreateView(ReleaseMixinOnboardingTaskCreateView): """View for creating a new OnboardingTask.""" model = OnboardingTask @@ -108,7 +128,7 @@ class OnboardingTaskCreateView(ReleaseMixinOnboardingTaskCreateView, ObjectEditV default_return_url = "plugins:netbox_onboarding:onboardingtask_list" -class OnboardingTaskBulkDeleteView(ReleaseMixinOnboardingTaskBulkDeleteView, BulkDeleteView): +class OnboardingTaskBulkDeleteView(ReleaseMixinOnboardingTaskBulkDeleteView): """View for deleting one or more OnboardingTasks.""" queryset = OnboardingTask.objects.filter() # TODO: can we exclude currently-running tasks? @@ -116,7 +136,7 @@ class OnboardingTaskBulkDeleteView(ReleaseMixinOnboardingTaskBulkDeleteView, Bul default_return_url = "plugins:netbox_onboarding:onboardingtask_list" -class OnboardingTaskFeedBulkImportView(ReleaseMixinOnboardingTaskFeedBulkImportView, BulkImportView): +class OnboardingTaskFeedBulkImportView(ReleaseMixinOnboardingTaskFeedBulkImportView): """View for bulk-importing a CSV file to create OnboardingTasks.""" queryset = OnboardingTask.objects.all() From e950c729bc2c50adad5f2475add1f7c9c252e7e0 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Tue, 22 Dec 2020 07:49:04 -0500 Subject: [PATCH 11/16] Cont working on support for Netbox 2.10 --- .travis.yml | 2 +- .../onboarding_task_edit.html | 6 ++++- netbox_onboarding/views.py | 25 ++++++++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0bb1414..45938f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ env: # under development/netbox_/configuration.py matrix: - NETBOX_VER=v2.8.9 - - NETBOX_VER=v2.9.9 + - NETBOX_VER=v2.9.11 - NETBOX_VER=v2.10.1 # Encrypted value for PYPI_TOKEN, this secret has been generated with the following command # travis encrypt PYPI_TOKEN= --add env.global --com diff --git a/netbox_onboarding/templates/netbox_onboarding/onboarding_task_edit.html b/netbox_onboarding/templates/netbox_onboarding/onboarding_task_edit.html index 538f2d2..f2142aa 100644 --- a/netbox_onboarding/templates/netbox_onboarding/onboarding_task_edit.html +++ b/netbox_onboarding/templates/netbox_onboarding/onboarding_task_edit.html @@ -1,2 +1,6 @@ -{% extends 'utilities/obj_edit.html' %} +{% if "2.8." in settings.VERSION or "2.9." in settings.VERSION %} + {% include 'utilities/obj_edit.html' %} +{% else %} + {% include 'generic/object_edit.html' %} +{% endif %} {% load form_helpers %} diff --git a/netbox_onboarding/views.py b/netbox_onboarding/views.py index 56df140..76aeed3 100644 --- a/netbox_onboarding/views.py +++ b/netbox_onboarding/views.py @@ -14,10 +14,9 @@ import logging from django.shortcuts import get_object_or_404, render -from django.views.generic import View -from .release import NETBOX_RELEASE_CURRENT, NETBOX_RELEASE_29, NETBOX_RELEASE_210 +from .release import NETBOX_RELEASE_CURRENT, NETBOX_RELEASE_29, NETBOX_RELEASE_210 from .filters import OnboardingTaskFilter from .forms import OnboardingTaskForm, OnboardingTaskFilterForm, OnboardingTaskFeedCSVForm from .models import OnboardingTask @@ -25,10 +24,11 @@ logger = logging.getLogger("rq.worker") -# pylint: disable=ungrouped-imports +# pylint: disable=ungrouped-imports,no-name-in-module if NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_29: from django.contrib.auth.mixins import PermissionRequiredMixin + from django.views.generic import View from utilities.views import BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView class ReleaseMixinOnboardingTaskView(PermissionRequiredMixin, View): @@ -57,9 +57,8 @@ class ReleaseMixinOnboardingTaskFeedBulkImportView(PermissionRequiredMixin, Bulk permission_required = "netbox_onboarding.add_onboardingtask" -elif NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_29 and NETBOX_RELEASE_CURRENT > NETBOX_RELEASE_210: - from utilities.views import ObjectView # pylint: disable=no-name-in-module - from utilities.views import BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView +elif NETBOX_RELEASE_29 < NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_210: + from utilities.views import ObjectView, BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView class ReleaseMixinOnboardingTaskView(ObjectView): """Release Mixin View for presenting a single OnboardingTask.""" @@ -78,21 +77,23 @@ class ReleaseMixinOnboardingTaskFeedBulkImportView(BulkImportView): else: - from netbox.views.generic import ObjectView, BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView + from netbox.views import generic - class ReleaseMixinOnboardingTaskView(ObjectView): + # ObjectView, BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView + + class ReleaseMixinOnboardingTaskView(generic.ObjectView): """Release Mixin View for presenting a single OnboardingTask.""" - class ReleaseMixinOnboardingTaskListView(ObjectListView): + class ReleaseMixinOnboardingTaskListView(generic.ObjectListView): """Release Mixin View for listing all extant OnboardingTasks.""" - class ReleaseMixinOnboardingTaskCreateView(ObjectEditView): + class ReleaseMixinOnboardingTaskCreateView(generic.ObjectEditView): """Release Mixin View for creating a new OnboardingTask.""" - class ReleaseMixinOnboardingTaskBulkDeleteView(BulkDeleteView): + class ReleaseMixinOnboardingTaskBulkDeleteView(generic.BulkDeleteView): """Release Mixin View for deleting one or more OnboardingTasks.""" - class ReleaseMixinOnboardingTaskFeedBulkImportView(BulkImportView): + class ReleaseMixinOnboardingTaskFeedBulkImportView(generic.BulkImportView): """Release Mixin View for bulk-importing a CSV file to create OnboardingTasks.""" From a62e754f3aa54799cf0a2c462260be827fd20274 Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Mon, 28 Dec 2020 14:23:03 +0100 Subject: [PATCH 12/16] Improved NetBox 'version attribute' handling --- .travis.yml | 5 ++--- development/configuration.py | 28 ++++++++++++++++++++-------- netbox_onboarding/release.py | 1 + netbox_onboarding/views.py | 4 ++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45938f7..e7fdd84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,11 @@ python: - '3.7' - '3.8' env: -# Each version of NetBox listed here must have a corresponding directory/configuration file -# under development/netbox_/configuration.py +# Each version of NetBox listed here uses configuration stored in development/configuration.py matrix: - NETBOX_VER=v2.8.9 - NETBOX_VER=v2.9.11 - - NETBOX_VER=v2.10.1 + - NETBOX_VER=v2.10.2 # Encrypted value for PYPI_TOKEN, this secret has been generated with the following command # travis encrypt PYPI_TOKEN= --add env.global --com # Might need to update it once the repo is publish (travis-ci.org vs travis-ci.com) diff --git a/development/configuration.py b/development/configuration.py index fa96a47..9825e21 100644 --- a/development/configuration.py +++ b/development/configuration.py @@ -1,10 +1,16 @@ """NetBox configuration.""" import os from distutils.util import strtobool +from packaging import version from django.core.exceptions import ImproperlyConfigured from .settings import VERSION # pylint: disable=relative-beyond-top-level +NETBOX_RELEASE_CURRENT = version.parse(VERSION) +NETBOX_RELEASE_28 = version.parse("2.8") +NETBOX_RELEASE_29 = version.parse("2.9") +NETBOX_RELEASE_211 = version.parse("2.11") + # Enforce required configuration parameters for key in [ "ALLOWED_HOSTS", @@ -32,7 +38,13 @@ def is_truthy(arg): """ if isinstance(arg, bool): return arg - return bool(strtobool(arg)) + + try: + bool_val = strtobool(arg) + except ValueError: + raise ImproperlyConfigured(f"Unexpected variable value: {arg}") # pylint: disable=raise-missing-from + + return bool(bool_val) # For reference see http://netbox.readthedocs.io/en/latest/configuration/mandatory-settings/ @@ -59,7 +71,7 @@ def is_truthy(arg): "PASSWORD": os.environ["POSTGRES_PASSWORD"], # PostgreSQL password "HOST": os.environ["POSTGRES_HOST"], # Database server - "PORT": 5432 if not os.environ.get("POSTGRES_PORT", False) else int(os.environ["POSTGRES_PORT"]), # Database port + "PORT": 5432 if "POSTGRES_PORT" not in os.environ else int(os.environ["POSTGRES_PORT"]), # Database port } # This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. @@ -88,14 +100,14 @@ def is_truthy(arg): }, } -if VERSION.startswith("2.8."): +if NETBOX_RELEASE_28 < NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_29: # NetBox 2.8.x Specific Settings REDIS["caching"]["DEFAULT_TIMEOUT"] = 300 REDIS["tasks"]["DEFAULT_TIMEOUT"] = 300 -elif VERSION.startswith("2.9.") or VERSION.startswith("2.10."): +elif NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_211: RQ_DEFAULT_TIMEOUT = 300 else: - raise ImproperlyConfigured(f"Version {VERSION} of NetBox is unsupported at this time.") + raise ImproperlyConfigured(f"Version {NETBOX_RELEASE_CURRENT} of NetBox is unsupported at this time.") ######################### # # @@ -232,15 +244,15 @@ def is_truthy(arg): REMOTE_AUTH_AUTO_CREATE_USER = True REMOTE_AUTH_DEFAULT_GROUPS = [] -if VERSION.startswith("2.8."): +if NETBOX_RELEASE_28 < NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_29: # NetBox 2.8.x Specific Settings REMOTE_AUTH_BACKEND = "utilities.auth_backends.RemoteUserBackend" REMOTE_AUTH_DEFAULT_PERMISSIONS = [] -elif VERSION.startswith("2.9.") or VERSION.startswith("2.10."): +elif NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_211: REMOTE_AUTH_BACKEND = "netbox.authentication.RemoteUserBackend" REMOTE_AUTH_DEFAULT_PERMISSIONS = {} else: - raise ImproperlyConfigured(f"Version {VERSION} of NetBox is unsupported at this time.") + raise ImproperlyConfigured(f"Version {NETBOX_RELEASE_CURRENT} of NetBox is unsupported at this time.") # This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. RELEASE_CHECK_TIMEOUT = 24 * 3600 diff --git a/netbox_onboarding/release.py b/netbox_onboarding/release.py index 5851b89..6df7a5c 100644 --- a/netbox_onboarding/release.py +++ b/netbox_onboarding/release.py @@ -19,3 +19,4 @@ NETBOX_RELEASE_28 = version.parse("2.8") NETBOX_RELEASE_29 = version.parse("2.9") NETBOX_RELEASE_210 = version.parse("2.10") +NETBOX_RELEASE_211 = version.parse("2.11") diff --git a/netbox_onboarding/views.py b/netbox_onboarding/views.py index 76aeed3..caa5afe 100644 --- a/netbox_onboarding/views.py +++ b/netbox_onboarding/views.py @@ -57,7 +57,7 @@ class ReleaseMixinOnboardingTaskFeedBulkImportView(PermissionRequiredMixin, Bulk permission_required = "netbox_onboarding.add_onboardingtask" -elif NETBOX_RELEASE_29 < NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_210: +elif NETBOX_RELEASE_29 <= NETBOX_RELEASE_CURRENT < NETBOX_RELEASE_210: from utilities.views import ObjectView, BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView class ReleaseMixinOnboardingTaskView(ObjectView): @@ -76,7 +76,7 @@ class ReleaseMixinOnboardingTaskFeedBulkImportView(BulkImportView): """Release Mixin View for bulk-importing a CSV file to create OnboardingTasks.""" -else: +elif NETBOX_RELEASE_CURRENT >= NETBOX_RELEASE_210: from netbox.views import generic # ObjectView, BulkDeleteView, BulkImportView, ObjectEditView, ObjectListView From bff85a75678c6509464cc6fb5d0d705bcf536444 Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Mon, 28 Dec 2020 20:18:44 +0100 Subject: [PATCH 13/16] Template updates to NetBox standard --- .../netbox_onboarding/onboardingtask.html | 32 +++++++++---------- netbox_onboarding/views.py | 4 +-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html b/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html index d638540..f6132f4 100644 --- a/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html +++ b/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html @@ -7,20 +7,20 @@
-

{% block title %}Device: {{ onboardingtask.ip_address }}{% endblock %}

+

{% block title %}Device: {{ object.ip_address }}{% endblock %}

@@ -36,51 +36,51 @@

{% block title %}Device: {{ onboardingtask.ip_address }}{% endblock %}

- + - + - + - + - + - + - + - + - + - + - + - +
Created Device{{ onboardingtask.created_device|placeholder }}{{ object.created_device|placeholder }}
IP Address{{ onboardingtask.ip_address|placeholder }}{{ object.ip_address|placeholder }}
Port{{ onboardingtask.port|placeholder }}{{ object.port|placeholder }}
Timeout{{ onboardingtask.timeout|placeholder }}{{ object.timeout|placeholder }}
Site{{ onboardingtask.site|placeholder }}{{ object.site|placeholder }}
Role{{ onboardingtask.role|placeholder }}{{ object.role|placeholder }}
Device Type{{ onboardingtask.device_type|placeholder }}{{ object.device_type|placeholder }}
Platform{{ onboardingtask.platform|placeholder }}{{ object.platform|placeholder }}
Status{{ onboardingtask.status|placeholder }}{{ object.status|placeholder }}
Failed Reason{{ onboardingtask.failed_reason|placeholder }}{{ object.failed_reason|placeholder }}
Message{{ onboardingtask.message|placeholder }}{{ object.message|placeholder }}
Created{{ onboardingtask.created|placeholder }}{{ object.created|placeholder }}
diff --git a/netbox_onboarding/views.py b/netbox_onboarding/views.py index caa5afe..ce84c2a 100644 --- a/netbox_onboarding/views.py +++ b/netbox_onboarding/views.py @@ -104,9 +104,9 @@ class OnboardingTaskView(ReleaseMixinOnboardingTaskView): def get(self, request, pk): # pylint: disable=invalid-name, missing-function-docstring """Get request.""" - onboardingtask = get_object_or_404(self.queryset, pk=pk) + instance = get_object_or_404(self.queryset, pk=pk) - return render(request, "netbox_onboarding/onboardingtask.html", {"onboardingtask": onboardingtask,}) + return render(request, "netbox_onboarding/onboardingtask.html", {"object": instance,}) class OnboardingTaskListView(ReleaseMixinOnboardingTaskListView): From 26214a5868dfef5695c0318373c7ac0582cdbed4 Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Mon, 28 Dec 2020 21:18:20 +0100 Subject: [PATCH 14/16] Button updates with NetBox 2.10 changes --- netbox_onboarding/navigation.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/netbox_onboarding/navigation.py b/netbox_onboarding/navigation.py index 3d1fb33..e812abb 100644 --- a/netbox_onboarding/navigation.py +++ b/netbox_onboarding/navigation.py @@ -15,6 +15,8 @@ from extras.plugins import PluginMenuButton, PluginMenuItem from utilities.choices import ButtonColorChoices +from .release import NETBOX_RELEASE_CURRENT, NETBOX_RELEASE_210 + menu_items = ( PluginMenuItem( link="plugins:netbox_onboarding:onboardingtask_list", @@ -24,14 +26,16 @@ PluginMenuButton( link="plugins:netbox_onboarding:onboardingtask_add", title="Onboard", - icon_class="fa fa-plus", + icon_class="mdi mdi-plus-thick" if NETBOX_RELEASE_CURRENT >= NETBOX_RELEASE_210 else "fa fa-plus", color=ButtonColorChoices.GREEN, permissions=["netbox_onboarding.add_onboardingtask"], ), PluginMenuButton( link="plugins:netbox_onboarding:onboardingtask_import", title="Bulk Onboard", - icon_class="fa fa-download", + icon_class="mdi mdi-database-import-outline" + if NETBOX_RELEASE_CURRENT >= NETBOX_RELEASE_210 + else "fa fa-download", color=ButtonColorChoices.BLUE, permissions=["netbox_onboarding.add_onboardingtask"], ), From 41e3b1aab1300d2a516bf24fe5d794ae086cb0ee Mon Sep 17 00:00:00 2001 From: Marek Zbroch Date: Tue, 29 Dec 2020 12:29:09 +0100 Subject: [PATCH 15/16] OnboardingTask Change Log backwards compatability for 2.8 and 2.9 NetBox versions --- .../netbox_onboarding/onboardingtask.html | 98 +------------------ .../onboardingtask_ge210.html | 93 ++++++++++++++++++ .../onboardingtask_lt210.html | 93 ++++++++++++++++++ netbox_onboarding/views.py | 4 +- 4 files changed, 194 insertions(+), 94 deletions(-) create mode 100644 netbox_onboarding/templates/netbox_onboarding/onboardingtask_ge210.html create mode 100644 netbox_onboarding/templates/netbox_onboarding/onboardingtask_lt210.html diff --git a/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html b/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html index f6132f4..1fb5224 100644 --- a/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html +++ b/netbox_onboarding/templates/netbox_onboarding/onboardingtask.html @@ -1,93 +1,5 @@ -{% extends 'base.html' %} -{% load helpers %} -{% load static %} - -{% block header %} -
-
- -
-
- -

{% block title %}Device: {{ object.ip_address }}{% endblock %}

- - -{% endblock %} - -{% block content %} -
-
-
-
- Onboarding Task -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Created Device{{ object.created_device|placeholder }}
IP Address{{ object.ip_address|placeholder }}
Port{{ object.port|placeholder }}
Timeout{{ object.timeout|placeholder }}
Site{{ object.site|placeholder }}
Role{{ object.role|placeholder }}
Device Type{{ object.device_type|placeholder }}
Platform{{ object.platform|placeholder }}
Status{{ object.status|placeholder }}
Failed Reason{{ object.failed_reason|placeholder }}
Message{{ object.message|placeholder }}
Created{{ object.created|placeholder }}
-
-
-
-{% endblock %} - -{% block javascript %} - -{% endblock %} +{% if "2.8." in settings.VERSION or "2.9." in settings.VERSION %} + {% include 'netbox_onboarding/onboardingtask_lt210.html' %} +{% else %} + {% include 'netbox_onboarding/onboardingtask_ge210.html' %} +{% endif %} diff --git a/netbox_onboarding/templates/netbox_onboarding/onboardingtask_ge210.html b/netbox_onboarding/templates/netbox_onboarding/onboardingtask_ge210.html new file mode 100644 index 0000000..f6132f4 --- /dev/null +++ b/netbox_onboarding/templates/netbox_onboarding/onboardingtask_ge210.html @@ -0,0 +1,93 @@ +{% extends 'base.html' %} +{% load helpers %} +{% load static %} + +{% block header %} +
+
+ +
+
+ +

{% block title %}Device: {{ object.ip_address }}{% endblock %}

+ + +{% endblock %} + +{% block content %} +
+
+
+
+ Onboarding Task +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Created Device{{ object.created_device|placeholder }}
IP Address{{ object.ip_address|placeholder }}
Port{{ object.port|placeholder }}
Timeout{{ object.timeout|placeholder }}
Site{{ object.site|placeholder }}
Role{{ object.role|placeholder }}
Device Type{{ object.device_type|placeholder }}
Platform{{ object.platform|placeholder }}
Status{{ object.status|placeholder }}
Failed Reason{{ object.failed_reason|placeholder }}
Message{{ object.message|placeholder }}
Created{{ object.created|placeholder }}
+
+
+
+{% endblock %} + +{% block javascript %} + +{% endblock %} diff --git a/netbox_onboarding/templates/netbox_onboarding/onboardingtask_lt210.html b/netbox_onboarding/templates/netbox_onboarding/onboardingtask_lt210.html new file mode 100644 index 0000000..6f2f9b3 --- /dev/null +++ b/netbox_onboarding/templates/netbox_onboarding/onboardingtask_lt210.html @@ -0,0 +1,93 @@ +{% extends 'base.html' %} +{% load helpers %} +{% load static %} + +{% block header %} +
+
+ +
+
+ +

{% block title %}Device: {{ onboardingtask.ip_address }}{% endblock %}

+ + +{% endblock %} + +{% block content %} +
+
+
+
+ Onboarding Task +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Created Device{{ onboardingtask.created_device|placeholder }}
IP Address{{ onboardingtask.ip_address|placeholder }}
Port{{ onboardingtask.port|placeholder }}
Timeout{{ onboardingtask.timeout|placeholder }}
Site{{ onboardingtask.site|placeholder }}
Role{{ onboardingtask.role|placeholder }}
Device Type{{ onboardingtask.device_type|placeholder }}
Platform{{ onboardingtask.platform|placeholder }}
Status{{ onboardingtask.status|placeholder }}
Failed Reason{{ onboardingtask.failed_reason|placeholder }}
Message{{ onboardingtask.message|placeholder }}
Created{{ onboardingtask.created|placeholder }}
+
+
+
+{% endblock %} + +{% block javascript %} + +{% endblock %} diff --git a/netbox_onboarding/views.py b/netbox_onboarding/views.py index ce84c2a..723f6a1 100644 --- a/netbox_onboarding/views.py +++ b/netbox_onboarding/views.py @@ -106,7 +106,9 @@ def get(self, request, pk): # pylint: disable=invalid-name, missing-function-do """Get request.""" instance = get_object_or_404(self.queryset, pk=pk) - return render(request, "netbox_onboarding/onboardingtask.html", {"object": instance,}) + return render( + request, "netbox_onboarding/onboardingtask.html", {"object": instance, "onboardingtask": instance} + ) class OnboardingTaskListView(ReleaseMixinOnboardingTaskListView): From 5f191577b43bcd762c14358e7e73c884d5e94740 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Tue, 29 Dec 2020 07:39:21 -0500 Subject: [PATCH 16/16] Upgrade version to 2.1.0 --- README.md | 8 ++++++-- netbox_onboarding/__init__.py | 2 +- pyproject.toml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7f1437d..15adc81 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,13 @@ pip install ntc-netbox-plugin-onboarding systemctl restart netbox netbox-rq ``` -> The ntc-netbox-plugin-onboarding v1.3 is compatible with NetBox 2.8 +### Compatibility Matrix -> The ntc-netbox-plugin-onboarding v2 is compatible with NetBox 2.8 and NetBox 2.9 +| | Netbox 2.8 | Netbox 2.9 | Netbox 2.10 | +|-----------------------|------------|------------|-------------| +| Onboarding Plugin 1.3 | X | | | +| Onboarding Plugin 2.0 | X | X | | +| Onboarding Plugin 2.1 | X | X | X | To ensure NetBox Onboarding plugin is automatically re-installed during future upgrades, create a file named `local_requirements.txt` (if not already existing) in the NetBox root directory (alongside `requirements.txt`) and list the `ntc-netbox-plugin-onboarding` package: diff --git a/netbox_onboarding/__init__.py b/netbox_onboarding/__init__.py index e1d740d..ac2781c 100644 --- a/netbox_onboarding/__init__.py +++ b/netbox_onboarding/__init__.py @@ -12,7 +12,7 @@ limitations under the License. """ -__version__ = "2.0.0" +__version__ = "2.1.0" from extras.plugins import PluginConfig diff --git a/pyproject.toml b/pyproject.toml index 38cf21a..bd17a17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ntc-netbox-plugin-onboarding" -version = "2.0.0" +version = "2.1.0" description = "A plugin for NetBox to easily onboard new devices." authors = ["Network to Code, LLC "] license = "Apache-2.0"