netbox-config-diff 2.14.3__tar.gz → 2.15.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/PKG-INFO +3 -2
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/README.md +2 -1
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/__init__.py +3 -2
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/secrets.py +37 -21
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/PKG-INFO +3 -2
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/SOURCES.txt +1 -0
- netbox_config_diff-2.15.1/tests/test_secrets.py +135 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/LICENSE +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/MANIFEST.in +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/development/configuration.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-diff.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-error.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-list.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-missing-extra.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-ok.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-patch.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/config-temp-substitute.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-approve-button.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-approved.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-collecting-diff-button.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-completed.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-created.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-diffs-tab.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-job-log.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-schedule-button.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-scheduled.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-unapprove-button.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-unschedule-button.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/navbar.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/platformsetting.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/render-temp-substitute.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/script-list.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/script.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/substitute.png +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/api/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/api/serializers.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/api/urls.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/api/views.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/choices.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/base.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/utils.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/base.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/exceptions.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/factory.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/platforms.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/utils.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/constants.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/filtersets.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/forms/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/forms/general.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/enums.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/filters.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/schema.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/types.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/jobs.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0001_initial.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0002_add_script.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0003_configcompliance_actual_config_and_more.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0004_update_script.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0005_configcompliance_extra_missing.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0006_substitute.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0007_configurationrequest.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0008_alter_configcompliance_device.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0009_configcompliance_patch.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0010_create_script.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/0011_configurationrequest_owner.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/models/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/models/base.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/models/data_models.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/models/models.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/navigation.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/scripts/config_diff.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/search.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/static/netbox_config_diff/diff2html-ui.min.js +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/static/netbox_config_diff/diff2html.dark.min.css +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/static/netbox_config_diff/diff2html.min.css +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/tables.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configcompliance/config.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configcompliance/data.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configcompliance.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/base.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/diffs.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/configurationrequest.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/inc/commands_card.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/inc/diff.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/inc/job_log.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/platformsetting.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templates/netbox_config_diff/substitute.html +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templatetags/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templatetags/string_filters.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/urls.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/__init__.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/base.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/compliance.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/configuration.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/dependency_links.txt +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/requires.txt +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/top_level.txt +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/pyproject.toml +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/requirements/base.txt +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/requirements/dev.txt +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/requirements/test.txt +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/setup.cfg +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/tests/conftest.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/tests/factories.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/tests/test_compliance.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/tests/test_compliance_utils.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/tests/test_configurtion_request.py +0 -0
- {netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/tests/test_urls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-config-diff
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.15.1
|
|
4
4
|
Summary: Push rendered device configurations from NetBox to devices and apply them.
|
|
5
5
|
Author: Artem Kotik
|
|
6
6
|
Author-email: miaow2@yandex.ru
|
|
@@ -232,7 +232,7 @@ Requires-Dist: pytest==8.3.4; extra == "test"
|
|
|
232
232
|
Requires-Dist: pytest-django==4.9.0; extra == "test"
|
|
233
233
|
Dynamic: license-file
|
|
234
234
|
|
|
235
|
-
[](https://github.com/netbox-community/netbox)
|
|
235
|
+
[](https://github.com/netbox-community/netbox)
|
|
236
236
|
[](https://pypi.org/project/netbox-config-diff/)
|
|
237
237
|
[](https://badge.fury.io/py/netbox-config-diff)
|
|
238
238
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -289,6 +289,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
|
|
|
289
289
|
| 4.3 | =>2.10.0, <=2.12.0 |
|
|
290
290
|
| 4.4 | =>2.11.0, <=2.13.0 |
|
|
291
291
|
| 4.5 | =>2.14.0 |
|
|
292
|
+
| 4.6 | =>2.15.0 |
|
|
292
293
|
|
|
293
294
|
<!--install-start-->
|
|
294
295
|
## Installing
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/netbox-community/netbox)
|
|
1
|
+
[](https://github.com/netbox-community/netbox)
|
|
2
2
|
[](https://pypi.org/project/netbox-config-diff/)
|
|
3
3
|
[](https://badge.fury.io/py/netbox-config-diff)
|
|
4
4
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -55,6 +55,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
|
|
|
55
55
|
| 4.3 | =>2.10.0, <=2.12.0 |
|
|
56
56
|
| 4.4 | =>2.11.0, <=2.13.0 |
|
|
57
57
|
| 4.5 | =>2.14.0 |
|
|
58
|
+
| 4.6 | =>2.15.0 |
|
|
58
59
|
|
|
59
60
|
<!--install-start-->
|
|
60
61
|
## Installing
|
|
@@ -2,7 +2,7 @@ from netbox.plugins import PluginConfig
|
|
|
2
2
|
|
|
3
3
|
__author__ = "Artem Kotik"
|
|
4
4
|
__email__ = "miaow2@yandex.ru"
|
|
5
|
-
__version__ = "2.
|
|
5
|
+
__version__ = "2.15.1"
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class ConfigDiffConfig(PluginConfig):
|
|
@@ -15,12 +15,13 @@ class ConfigDiffConfig(PluginConfig):
|
|
|
15
15
|
base_url = "config-diff"
|
|
16
16
|
required_settings = ["USERNAME", "PASSWORD"]
|
|
17
17
|
min_version = "4.5.0"
|
|
18
|
-
max_version = "4.
|
|
18
|
+
max_version = "4.6.99"
|
|
19
19
|
default_settings = {
|
|
20
20
|
"USER_SECRET_ROLE": "Username",
|
|
21
21
|
"PASSWORD_SECRET_ROLE": "Password",
|
|
22
22
|
"SECOND_AUTH_SECRET_ROLE": "Second Auth",
|
|
23
23
|
"PATH_TO_SSH_CONFIG_FILE": "",
|
|
24
|
+
"SECRETS_PRECEDENCE": ["device", "role", "platform"],
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/secrets.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
from operator import attrgetter
|
|
2
3
|
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
from dcim.models import Device
|
|
@@ -34,8 +35,8 @@ class SecretsMixin:
|
|
|
34
35
|
sk = SessionKey.objects.get(userkey__user=self.request.user)
|
|
35
36
|
self.master_key = sk.get_master_key(self.session_key)
|
|
36
37
|
except Exception as e:
|
|
37
|
-
if
|
|
38
|
-
if
|
|
38
|
+
if hasattr(self, "logger"):
|
|
39
|
+
if hasattr(self.logger, "log_failure"):
|
|
39
40
|
self.logger.log_failure(f"Can't fetch master_key: {str(e)}")
|
|
40
41
|
else:
|
|
41
42
|
self.logger.error(f"Can't fetch master_key: {str(e)}")
|
|
@@ -49,28 +50,42 @@ class SecretsMixin:
|
|
|
49
50
|
return None
|
|
50
51
|
return secret.plaintext
|
|
51
52
|
|
|
53
|
+
def get_secret_value(self, objects: tuple[object | None, ...], role_name: str) -> str | None:
|
|
54
|
+
for obj in objects:
|
|
55
|
+
if not obj:
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
secrets = getattr(obj, "secrets", None)
|
|
59
|
+
if not secrets:
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
if secret := secrets.filter(role__name=role_name).first():
|
|
63
|
+
if value := self.get_secret(secret):
|
|
64
|
+
return value
|
|
65
|
+
|
|
66
|
+
return None
|
|
67
|
+
|
|
52
68
|
def get_credentials(self, device: Device) -> tuple[str, str, str, str]:
|
|
53
|
-
if not self.netbox_secrets_installed:
|
|
69
|
+
if not self.netbox_secrets_installed or not self.secrets_precedence:
|
|
54
70
|
return self.username, self.password, self.auth_secondary, self.default_desired_privilege_level
|
|
55
71
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
default_desired_privilege_level = self.default_desired_privilege_level
|
|
72
|
+
secret_objects: list[object] = []
|
|
73
|
+
for entry in self.secrets_precedence:
|
|
74
|
+
if entry == "device":
|
|
75
|
+
secret_objects.append(device)
|
|
76
|
+
continue
|
|
77
|
+
try:
|
|
78
|
+
secret_objects.append(attrgetter(entry)(device))
|
|
79
|
+
except AttributeError:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
username = self.get_secret_value(secret_objects, self.user_role) or self.username
|
|
83
|
+
password = self.get_secret_value(secret_objects, self.password_role) or self.password
|
|
84
|
+
auth_secondary = self.get_secret_value(secret_objects, self.auth_secondary_role) or self.auth_secondary
|
|
85
|
+
default_desired_privilege_level = (
|
|
86
|
+
self.get_secret_value(secret_objects, self.default_desired_privilege_level_role)
|
|
87
|
+
or self.default_desired_privilege_level
|
|
88
|
+
)
|
|
74
89
|
|
|
75
90
|
return username, password, auth_secondary, default_desired_privilege_level
|
|
76
91
|
|
|
@@ -83,6 +98,7 @@ class SecretsMixin:
|
|
|
83
98
|
self.default_desired_privilege_level_role = get_plugin_config(
|
|
84
99
|
"netbox_config_diff", "DEFAULT_DESIRED_PRIVILEGE_LEVEL_ROLE"
|
|
85
100
|
)
|
|
101
|
+
self.secrets_precedence = get_plugin_config("netbox_config_diff", "SECRETS_PRECEDENCE")
|
|
86
102
|
self.netbox_secrets_installed = True
|
|
87
103
|
|
|
88
104
|
self.username = get_plugin_config("netbox_config_diff", "USERNAME")
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-config-diff
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.15.1
|
|
4
4
|
Summary: Push rendered device configurations from NetBox to devices and apply them.
|
|
5
5
|
Author: Artem Kotik
|
|
6
6
|
Author-email: miaow2@yandex.ru
|
|
@@ -232,7 +232,7 @@ Requires-Dist: pytest==8.3.4; extra == "test"
|
|
|
232
232
|
Requires-Dist: pytest-django==4.9.0; extra == "test"
|
|
233
233
|
Dynamic: license-file
|
|
234
234
|
|
|
235
|
-
[](https://github.com/netbox-community/netbox)
|
|
235
|
+
[](https://github.com/netbox-community/netbox)
|
|
236
236
|
[](https://pypi.org/project/netbox-config-diff/)
|
|
237
237
|
[](https://badge.fury.io/py/netbox-config-diff)
|
|
238
238
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -289,6 +289,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
|
|
|
289
289
|
| 4.3 | =>2.10.0, <=2.12.0 |
|
|
290
290
|
| 4.4 | =>2.11.0, <=2.13.0 |
|
|
291
291
|
| 4.5 | =>2.14.0 |
|
|
292
|
+
| 4.6 | =>2.15.0 |
|
|
292
293
|
|
|
293
294
|
<!--install-start-->
|
|
294
295
|
## Installing
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from types import SimpleNamespace
|
|
2
|
+
|
|
3
|
+
from netbox_config_diff.compliance.secrets import SecretsMixin
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DummySecretsManager:
|
|
7
|
+
def __init__(self, by_role: dict[str, object]) -> None:
|
|
8
|
+
self.by_role = by_role
|
|
9
|
+
|
|
10
|
+
def filter(self, **kwargs):
|
|
11
|
+
return SimpleNamespace(first=lambda: self.by_role.get(kwargs["role__name"]))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DummySecretsMixin(SecretsMixin):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def build_mixin() -> DummySecretsMixin:
|
|
19
|
+
mixin = DummySecretsMixin()
|
|
20
|
+
mixin.netbox_secrets_installed = True
|
|
21
|
+
mixin.username = "default-user"
|
|
22
|
+
mixin.password = "default-pass"
|
|
23
|
+
mixin.auth_secondary = "default-secondary"
|
|
24
|
+
mixin.default_desired_privilege_level = "default-priv"
|
|
25
|
+
mixin.secrets_precedence = ["device", "role", "platform"]
|
|
26
|
+
|
|
27
|
+
mixin.user_role = "user-role"
|
|
28
|
+
mixin.password_role = "password-role"
|
|
29
|
+
mixin.auth_secondary_role = "secondary-role"
|
|
30
|
+
mixin.default_desired_privilege_level_role = "priv-role"
|
|
31
|
+
return mixin
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_credentials_prefers_device_then_role_then_platform() -> None:
|
|
35
|
+
mixin = build_mixin()
|
|
36
|
+
|
|
37
|
+
device = SimpleNamespace(
|
|
38
|
+
secrets=DummySecretsManager(
|
|
39
|
+
{
|
|
40
|
+
"user-role": SimpleNamespace(value="device-user"),
|
|
41
|
+
}
|
|
42
|
+
),
|
|
43
|
+
role=SimpleNamespace(
|
|
44
|
+
secrets=DummySecretsManager(
|
|
45
|
+
{
|
|
46
|
+
"user-role": SimpleNamespace(value="role-user"),
|
|
47
|
+
"password-role": SimpleNamespace(value="role-pass"),
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
),
|
|
51
|
+
platform=SimpleNamespace(
|
|
52
|
+
secrets=DummySecretsManager(
|
|
53
|
+
{
|
|
54
|
+
"user-role": SimpleNamespace(value="platform-user"),
|
|
55
|
+
"password-role": SimpleNamespace(value="platform-pass"),
|
|
56
|
+
"secondary-role": SimpleNamespace(value="platform-secondary"),
|
|
57
|
+
"priv-role": SimpleNamespace(value="platform-priv"),
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
mixin.get_secret = lambda secret: secret.value
|
|
63
|
+
|
|
64
|
+
assert mixin.get_credentials(device) == (
|
|
65
|
+
"device-user",
|
|
66
|
+
"role-pass",
|
|
67
|
+
"platform-secondary",
|
|
68
|
+
"platform-priv",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_get_credentials_skips_empty_secret_value() -> None:
|
|
73
|
+
mixin = build_mixin()
|
|
74
|
+
|
|
75
|
+
device = SimpleNamespace(
|
|
76
|
+
secrets=DummySecretsManager(
|
|
77
|
+
{
|
|
78
|
+
"password-role": SimpleNamespace(value=""),
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
role=SimpleNamespace(
|
|
82
|
+
secrets=DummySecretsManager(
|
|
83
|
+
{
|
|
84
|
+
"password-role": SimpleNamespace(value="role-pass"),
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
),
|
|
88
|
+
platform=SimpleNamespace(secrets=DummySecretsManager({})),
|
|
89
|
+
)
|
|
90
|
+
mixin.get_secret = lambda secret: secret.value
|
|
91
|
+
|
|
92
|
+
username, password, auth_secondary, default_desired_privilege_level = mixin.get_credentials(device)
|
|
93
|
+
|
|
94
|
+
assert username == "default-user"
|
|
95
|
+
assert password == "role-pass"
|
|
96
|
+
assert auth_secondary == "default-secondary"
|
|
97
|
+
assert default_desired_privilege_level == "default-priv"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_get_credentials_respects_custom_precedence() -> None:
|
|
101
|
+
mixin = build_mixin()
|
|
102
|
+
|
|
103
|
+
device = SimpleNamespace(
|
|
104
|
+
secrets=DummySecretsManager(
|
|
105
|
+
{
|
|
106
|
+
"password-role": SimpleNamespace(value="device-pass"),
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
role=SimpleNamespace(
|
|
110
|
+
secrets=DummySecretsManager(
|
|
111
|
+
{
|
|
112
|
+
"user-role": SimpleNamespace(value="role-user"),
|
|
113
|
+
"password-role": SimpleNamespace(value="role-pass"),
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
),
|
|
117
|
+
platform=SimpleNamespace(
|
|
118
|
+
secrets=DummySecretsManager(
|
|
119
|
+
{
|
|
120
|
+
"user-role": SimpleNamespace(value="platform-user"),
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
mixin.get_secret = lambda secret: secret.value
|
|
126
|
+
|
|
127
|
+
# Force precedence: platform -> device -> role
|
|
128
|
+
mixin.secrets_precedence = ["platform", "device", "role"]
|
|
129
|
+
|
|
130
|
+
assert mixin.get_credentials(device) == (
|
|
131
|
+
"platform-user",
|
|
132
|
+
"device-pass",
|
|
133
|
+
"default-secondary",
|
|
134
|
+
"default-priv",
|
|
135
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-diff.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-error.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-list.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-ok.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/compliance-patch.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-approve-button.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-approved.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-completed.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-created.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-diffs-tab.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-job-log.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/cr-scheduled.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/platformsetting.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/script-list.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/docs/media/screenshots/substitute.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/api/serializers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/__init__.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/base.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/compliance/utils.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/__init__.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/base.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/factory.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/platforms.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/configurator/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/forms/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/filters.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/graphql/schema.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/migrations/__init__.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/models/data_models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/scripts/config_diff.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/templatetags/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/compliance.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff/views/configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/requires.txt
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.3 → netbox_config_diff-2.15.1}/netbox_config_diff.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|