netbox-config-diff 2.2.0__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netbox-config-diff-2.2.0/netbox_config_diff.egg-info → netbox_config_diff-2.4.0}/PKG-INFO +3 -2
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/README.md +1 -1
- netbox_config_diff-2.4.0/docs/media/screenshots/compliance-patch.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/__init__.py +1 -1
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/api/serializers.py +1 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/base.py +4 -1
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/utils.py +18 -1
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/base.py +5 -2
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/platforms.py +70 -3
- netbox_config_diff-2.4.0/netbox_config_diff/migrations/0009_configcompliance_patch.py +16 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/models/data_models.py +2 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/models/models.py +3 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/configcompliance/config.html +2 -1
- netbox_config_diff-2.4.0/netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html +14 -0
- netbox_config_diff-2.4.0/netbox_config_diff/templates/netbox_config_diff/configcompliance/patch.html +11 -0
- netbox_config_diff-2.4.0/netbox_config_diff/templates/netbox_config_diff/inc/commands_card.html +16 -0
- netbox_config_diff-2.4.0/netbox_config_diff/views/base.py +52 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/views/compliance.py +29 -40
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0/netbox_config_diff.egg-info}/PKG-INFO +3 -2
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff.egg-info/SOURCES.txt +4 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff.egg-info/requires.txt +1 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/requirements/base.txt +1 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/tests/test_compliance.py +1 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/tests/test_compliance_utils.py +1 -1
- netbox-config-diff-2.2.0/netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html +0 -42
- netbox-config-diff-2.2.0/netbox_config_diff/views/base.py +0 -13
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/LICENSE +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/MANIFEST.in +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/development/configuration.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-diff.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-error.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-list.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-missing-extra.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-ok.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/config-temp-substitute.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-approve-button.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-approved.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-collecting-diff-button.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-completed.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-created.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-diffs-tab.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-job-log.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-schedule-button.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-scheduled.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-unapprove-button.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-unschedule-button.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/navbar.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/platformsetting.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/render-temp-substitute.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/script-list.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/script.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/substitute.png +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/api/__init__.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/api/urls.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/api/views.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/choices.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/__init__.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/secrets.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/__init__.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/exceptions.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/factory.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/utils.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/constants.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/filtersets.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/forms.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/graphql.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/jobs.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0001_initial.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0002_add_script.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0003_configcompliance_actual_config_and_more.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0004_update_script.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0005_configcompliance_extra_missing.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0006_substitute.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0007_configurationrequest.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0008_alter_configcompliance_device.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/__init__.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/models/__init__.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/models/base.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/navigation.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/scripts/config_diff.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/search.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/static/netbox_config_diff/diff2html-ui.min.js +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/static/netbox_config_diff/diff2html.dark.min.css +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/static/netbox_config_diff/diff2html.min.css +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/tables.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/configcompliance/data.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/configcompliance.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/base.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/diffs.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/configurationrequest.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/inc/diff.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/inc/job_log.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/platformsetting.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/templates/netbox_config_diff/substitute.html +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/urls.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/views/__init__.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/views/configuration.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff.egg-info/dependency_links.txt +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff.egg-info/top_level.txt +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/pyproject.toml +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/requirements/dev.txt +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/requirements/test.txt +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/setup.cfg +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/tests/conftest.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/tests/factories.py +0 -0
- {netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/tests/test_urls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-config-diff
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -218,6 +218,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
218
218
|
Requires-Python: >=3.10
|
|
219
219
|
Description-Content-Type: text/markdown
|
|
220
220
|
License-File: LICENSE
|
|
221
|
+
Requires-Dist: hier-config==2.2.3
|
|
221
222
|
Requires-Dist: netutils==1.5.0
|
|
222
223
|
Requires-Dist: scrapli[asyncssh]==2023.07.30
|
|
223
224
|
Requires-Dist: scrapli-cfg==2023.07.30
|
|
@@ -275,7 +276,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
|
|
|
275
276
|
|
|
276
277
|
| NetBox Version | Plugin Version |
|
|
277
278
|
|----------------|----------------|
|
|
278
|
-
|
|
|
279
|
+
| 3.5, 3.6, 3.7 | =>0.1.0 |
|
|
279
280
|
|
|
280
281
|
<!--install-start-->
|
|
281
282
|
## Installing
|
|
@@ -44,7 +44,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
|
|
|
44
44
|
|
|
45
45
|
| NetBox Version | Plugin Version |
|
|
46
46
|
|----------------|----------------|
|
|
47
|
-
|
|
|
47
|
+
| 3.5, 3.6, 3.7 | =>0.1.0 |
|
|
48
48
|
|
|
49
49
|
<!--install-start-->
|
|
50
50
|
## Installing
|
|
Binary file
|
|
@@ -18,7 +18,7 @@ from utilities.utils import render_jinja2
|
|
|
18
18
|
from netbox_config_diff.models import ConplianceDeviceDataClass
|
|
19
19
|
|
|
20
20
|
from .secrets import SecretsMixin
|
|
21
|
-
from .utils import PLATFORM_MAPPING, CustomChoiceVar, exclude_lines, get_unified_diff
|
|
21
|
+
from .utils import PLATFORM_MAPPING, CustomChoiceVar, exclude_lines, get_remediation_commands, get_unified_diff
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class ConfigDiffBase(SecretsMixin):
|
|
@@ -204,3 +204,6 @@ class ConfigDiffBase(SecretsMixin):
|
|
|
204
204
|
device.extra = diff_network_config(
|
|
205
205
|
cleaned_config, device.rendered_config, PLATFORM_MAPPING[device.platform]
|
|
206
206
|
)
|
|
207
|
+
device.patch = get_remediation_commands(
|
|
208
|
+
device.name, device.platform, cleaned_config, device.rendered_config
|
|
209
|
+
)
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/utils.py
RENAMED
|
@@ -3,6 +3,7 @@ from difflib import unified_diff
|
|
|
3
3
|
|
|
4
4
|
from django.forms import ChoiceField
|
|
5
5
|
from extras.scripts import ScriptVariable
|
|
6
|
+
from hier_config import Host
|
|
6
7
|
|
|
7
8
|
PLATFORM_MAPPING = {
|
|
8
9
|
"arista_eos": "arista_eos",
|
|
@@ -19,6 +20,15 @@ PLATFORM_MAPPING = {
|
|
|
19
20
|
"ruckus_fastiron": "ruckus_fastiron",
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
REMEDIATION_MAPPING = {
|
|
24
|
+
"arista_eos": "eos",
|
|
25
|
+
"cisco_iosxe": "ios",
|
|
26
|
+
"cisco_iosxr": "iosxr",
|
|
27
|
+
"cisco_nxos": "nxos",
|
|
28
|
+
"juniper_junos": "junos",
|
|
29
|
+
"vyos_vyos": "vyos",
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
|
|
23
33
|
class CustomChoiceVar(ScriptVariable):
|
|
24
34
|
form_field = ChoiceField
|
|
@@ -30,8 +40,8 @@ class CustomChoiceVar(ScriptVariable):
|
|
|
30
40
|
|
|
31
41
|
def get_unified_diff(rendered_config: str, actual_config: str, device: str) -> str:
|
|
32
42
|
diff = unified_diff(
|
|
33
|
-
rendered_config.strip().splitlines(),
|
|
34
43
|
actual_config.splitlines(),
|
|
44
|
+
rendered_config.strip().splitlines(),
|
|
35
45
|
fromfiledate=device,
|
|
36
46
|
tofiledate=device,
|
|
37
47
|
lineterm="",
|
|
@@ -43,3 +53,10 @@ def exclude_lines(text: str, regexs: list) -> str:
|
|
|
43
53
|
for item in regexs:
|
|
44
54
|
text = re.sub(item, "", text, flags=re.I | re.M)
|
|
45
55
|
return text.strip()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_remediation_commands(name: str, platform: str, actual_config: str, rendered_config: str) -> str:
|
|
59
|
+
host = Host(hostname=name, os=REMEDIATION_MAPPING.get(platform, "ios"))
|
|
60
|
+
host.load_running_config(config_text=actual_config)
|
|
61
|
+
host.load_generated_config(config_text=rendered_config)
|
|
62
|
+
return host.remediation_config_filtered_text(include_tags={}, exclude_tags={})
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/base.py
RENAMED
|
@@ -14,7 +14,7 @@ from scrapli_cfg.response import ScrapliCfgResponse
|
|
|
14
14
|
from utilities.utils import NetBoxFakeRequest
|
|
15
15
|
|
|
16
16
|
from netbox_config_diff.compliance.secrets import SecretsMixin
|
|
17
|
-
from netbox_config_diff.compliance.utils import PLATFORM_MAPPING, get_unified_diff
|
|
17
|
+
from netbox_config_diff.compliance.utils import PLATFORM_MAPPING, get_remediation_commands, get_unified_diff
|
|
18
18
|
from netbox_config_diff.configurator.exceptions import DeviceConfigurationError, DeviceValidationError
|
|
19
19
|
from netbox_config_diff.configurator.utils import CustomLogger
|
|
20
20
|
from netbox_config_diff.constants import ACCEPTABLE_DRIVERS
|
|
@@ -126,7 +126,7 @@ class Configurator(SecretsMixin):
|
|
|
126
126
|
)
|
|
127
127
|
device.rendered_config = rendered_config
|
|
128
128
|
else:
|
|
129
|
-
actual_config = await conn.get_config()
|
|
129
|
+
actual_config = await conn.get_config(config_template=device.rendered_config)
|
|
130
130
|
device.actual_config = conn.clean_config(actual_config.result)
|
|
131
131
|
|
|
132
132
|
device.diff = get_unified_diff(device.rendered_config, device.actual_config, device.name)
|
|
@@ -137,6 +137,9 @@ class Configurator(SecretsMixin):
|
|
|
137
137
|
device.extra = diff_network_config(
|
|
138
138
|
device.actual_config, device.rendered_config, PLATFORM_MAPPING[device.platform]
|
|
139
139
|
)
|
|
140
|
+
device.patch = get_remediation_commands(
|
|
141
|
+
device.name, device.platform, device.actual_config, device.rendered_config
|
|
142
|
+
)
|
|
140
143
|
self.logger.log_info(f"Got diff from {device.name}")
|
|
141
144
|
except Exception:
|
|
142
145
|
error = traceback.format_exc()
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/platforms.py
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from typing import Pattern
|
|
2
|
+
from typing import Any, Pattern
|
|
3
3
|
|
|
4
4
|
from scrapli_cfg.exceptions import TemplateError
|
|
5
5
|
from scrapli_cfg.platform.core.arista_eos import AsyncScrapliCfgEOS
|
|
@@ -94,13 +94,17 @@ class CustomScrapliCfg:
|
|
|
94
94
|
"""
|
|
95
95
|
self.logger.info("fetching configuration and replacing with provided substitutes")
|
|
96
96
|
|
|
97
|
-
source_config = await self.get_config(source=source)
|
|
97
|
+
source_config = await self.get_config(config_template=config_template, source=source)
|
|
98
98
|
return source_config, self._render_substituted_config(
|
|
99
99
|
config_template=config_template,
|
|
100
100
|
substitutes=substitutes,
|
|
101
101
|
source_config=source_config.result,
|
|
102
102
|
)
|
|
103
103
|
|
|
104
|
+
async def get_config(self, **kwargs) -> ScrapliCfgResponse:
|
|
105
|
+
kwargs.pop("config_template", None)
|
|
106
|
+
return await super().get_config(**kwargs)
|
|
107
|
+
|
|
104
108
|
|
|
105
109
|
class CustomAsyncScrapliCfgEOS(CustomScrapliCfg, AsyncScrapliCfgEOS):
|
|
106
110
|
pass
|
|
@@ -119,4 +123,67 @@ class CustomAsyncScrapliCfgNXOS(CustomScrapliCfg, AsyncScrapliCfgNXOS):
|
|
|
119
123
|
|
|
120
124
|
|
|
121
125
|
class CustomAsyncScrapliCfgJunos(CustomScrapliCfg, AsyncScrapliCfgJunos):
|
|
122
|
-
|
|
126
|
+
is_set_config = False
|
|
127
|
+
|
|
128
|
+
async def get_config(self, config_template: str, source: str = "running") -> ScrapliCfgResponse:
|
|
129
|
+
response = self._pre_get_config(source=source)
|
|
130
|
+
|
|
131
|
+
command = "show configuration"
|
|
132
|
+
if re.findall(r"^set\s+", config_template, flags=re.I | re.M):
|
|
133
|
+
self.is_set_config = True
|
|
134
|
+
command += " | display set"
|
|
135
|
+
|
|
136
|
+
if self._in_configuration_session is True:
|
|
137
|
+
config_result = await self.conn.send_config(config=f"run {command}")
|
|
138
|
+
else:
|
|
139
|
+
config_result = await self.conn.send_command(command=command)
|
|
140
|
+
|
|
141
|
+
return self._post_get_config(
|
|
142
|
+
response=response,
|
|
143
|
+
source=source,
|
|
144
|
+
scrapli_responses=[config_result],
|
|
145
|
+
result=config_result.result,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
async def load_config(self, config: str, replace: bool = False, **kwargs: Any) -> ScrapliCfgResponse:
|
|
149
|
+
"""
|
|
150
|
+
Load configuration to a device
|
|
151
|
+
|
|
152
|
+
Supported kwargs:
|
|
153
|
+
set: bool indicating config is a "set" style config (ignored if replace is True)
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
config: string of the configuration to load
|
|
157
|
+
replace: replace the configuration or not, if false configuration will be loaded as a
|
|
158
|
+
merge operation
|
|
159
|
+
kwargs: additional kwargs that the implementing classes may need for their platform,
|
|
160
|
+
see above for junos supported kwargs
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
ScrapliCfgResponse: response object
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
N/A
|
|
167
|
+
|
|
168
|
+
"""
|
|
169
|
+
response = self._pre_load_config(config=config)
|
|
170
|
+
|
|
171
|
+
config = self._prepare_load_config(config=config, replace=replace)
|
|
172
|
+
|
|
173
|
+
config_result = await self.conn.send_config(config=config, privilege_level="root_shell")
|
|
174
|
+
|
|
175
|
+
if self.is_set_config is True:
|
|
176
|
+
load_config = f"load set {self.filesystem}{self.candidate_config_filename}"
|
|
177
|
+
else:
|
|
178
|
+
if self._replace is True:
|
|
179
|
+
load_config = f"load override {self.filesystem}{self.candidate_config_filename}"
|
|
180
|
+
else:
|
|
181
|
+
load_config = f"load merge {self.filesystem}{self.candidate_config_filename}"
|
|
182
|
+
|
|
183
|
+
load_result = await self.conn.send_config(config=load_config)
|
|
184
|
+
self._in_configuration_session = True
|
|
185
|
+
|
|
186
|
+
return self._post_load_config(
|
|
187
|
+
response=response,
|
|
188
|
+
scrapli_responses=[config_result, load_result],
|
|
189
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from django.db import migrations, models
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Migration(migrations.Migration):
|
|
5
|
+
|
|
6
|
+
dependencies = [
|
|
7
|
+
("netbox_config_diff", "0008_alter_configcompliance_device"),
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
operations = [
|
|
11
|
+
migrations.AddField(
|
|
12
|
+
model_name="configcompliance",
|
|
13
|
+
name="patch",
|
|
14
|
+
field=models.TextField(blank=True),
|
|
15
|
+
),
|
|
16
|
+
]
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/models/data_models.py
RENAMED
|
@@ -23,6 +23,7 @@ class BaseDeviceDataClass:
|
|
|
23
23
|
diff: str = ""
|
|
24
24
|
missing: str | None = None
|
|
25
25
|
extra: str | None = None
|
|
26
|
+
patch: str | None = None
|
|
26
27
|
error: str = ""
|
|
27
28
|
config_error: str | None = None
|
|
28
29
|
auth_strict_key: bool = False
|
|
@@ -99,6 +100,7 @@ class BaseDeviceDataClass:
|
|
|
99
100
|
"actual_config": self.actual_config or "",
|
|
100
101
|
"missing": self.missing or "",
|
|
101
102
|
"extra": self.extra or "",
|
|
103
|
+
"patch": self.patch or "",
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
def send_to_db(self) -> None:
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<div class="card">
|
|
9
9
|
<div class="card-header">
|
|
10
10
|
<div class="float-end">
|
|
11
|
+
{% copy_content config_field %}
|
|
11
12
|
<a href="?export=True" class="btn btn-sm btn-primary" role="button">
|
|
12
13
|
<i class="mdi mdi-download" aria-hidden="true"></i> Download
|
|
13
14
|
</a>
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
<h5>{{ header }}</h5>
|
|
16
17
|
</div>
|
|
17
18
|
{% if config %}
|
|
18
|
-
<pre class="card-body">{{ config }}</pre>
|
|
19
|
+
<pre class="card-body" id="{{ config_field }}">{{ config }}</pre>
|
|
19
20
|
{% else %}
|
|
20
21
|
<div class="card-body text-muted">No configuration</div>
|
|
21
22
|
{% endif %}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{% extends "netbox_config_diff/configcompliance.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ object }} - Missing/Extra{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="row">
|
|
7
|
+
<div class="col col-md-6">
|
|
8
|
+
{% include 'netbox_config_diff/inc/commands_card.html' with data=object.missing header='Missing' pre_id='missing' %}
|
|
9
|
+
</div>
|
|
10
|
+
<div class="col col-md-6">
|
|
11
|
+
{% include 'netbox_config_diff/inc/commands_card.html' with data=object.extra header='Extra' pre_id='extra' %}
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
{% endblock %}
|
netbox_config_diff-2.4.0/netbox_config_diff/templates/netbox_config_diff/configcompliance/patch.html
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{% extends "netbox_config_diff/configcompliance.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ object }} - Patch commands{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="row">
|
|
7
|
+
<div class="col col-md-6">
|
|
8
|
+
{% include 'netbox_config_diff/inc/commands_card.html' with data=object.patch header='Patch commands' pre_id='patch' %}
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
{% endblock %}
|
netbox_config_diff-2.4.0/netbox_config_diff/templates/netbox_config_diff/inc/commands_card.html
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<div class="card">
|
|
2
|
+
<div class="card-header">
|
|
3
|
+
<div class="float-end">
|
|
4
|
+
{% copy_content pre_id %}
|
|
5
|
+
<a href="?export_{{ pre_id }}=True" class="btn btn-sm btn-primary" role="button">
|
|
6
|
+
<i class="mdi mdi-download" aria-hidden="true"></i> Download
|
|
7
|
+
</a>
|
|
8
|
+
</div>
|
|
9
|
+
<h5>{{ header }}</h5>
|
|
10
|
+
</div>
|
|
11
|
+
{% if data %}
|
|
12
|
+
<pre class="card-body" id="{{ pre_id }}">{{ data }}</pre>
|
|
13
|
+
{% else %}
|
|
14
|
+
<div class="card-body text-muted">No commands</div>
|
|
15
|
+
{% endif %}
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from django.http import HttpResponse
|
|
2
|
+
from django.shortcuts import render
|
|
3
|
+
from django.urls import reverse
|
|
4
|
+
from netbox.views.generic import ObjectDeleteView, ObjectEditView, ObjectView
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseObjectDeleteView(ObjectDeleteView):
|
|
8
|
+
def get_return_url(self, request, obj=None):
|
|
9
|
+
return reverse(f"plugins:netbox_config_diff:{self.queryset.model._meta.model_name}_list")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseObjectEditView(ObjectEditView):
|
|
13
|
+
@property
|
|
14
|
+
def default_return_url(self) -> str:
|
|
15
|
+
return f"plugins:netbox_config_diff:{self.queryset.model._meta.model_name}_list"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseExportView(ObjectView):
|
|
19
|
+
def export_parts(self, name, lines, suffix):
|
|
20
|
+
response = HttpResponse(lines, content_type="text")
|
|
21
|
+
filename = f"{name}_{suffix}.txt"
|
|
22
|
+
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
|
23
|
+
return response
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BaseConfigComplianceConfigView(BaseExportView):
|
|
27
|
+
config_field = None
|
|
28
|
+
template_header = None
|
|
29
|
+
|
|
30
|
+
def get(self, request, **kwargs):
|
|
31
|
+
instance = self.get_object(**kwargs)
|
|
32
|
+
context = self.get_extra_context(request, instance)
|
|
33
|
+
|
|
34
|
+
if request.GET.get("export"):
|
|
35
|
+
return self.export_parts(instance.device.name, context["config"], self.config_field)
|
|
36
|
+
|
|
37
|
+
return render(
|
|
38
|
+
request,
|
|
39
|
+
self.get_template_name(),
|
|
40
|
+
{
|
|
41
|
+
"object": instance,
|
|
42
|
+
"tab": self.tab,
|
|
43
|
+
**context,
|
|
44
|
+
},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def get_extra_context(self, request, instance):
|
|
48
|
+
return {
|
|
49
|
+
"header": self.template_header,
|
|
50
|
+
"config": getattr(instance, self.config_field),
|
|
51
|
+
"config_field": self.config_field,
|
|
52
|
+
}
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/views/compliance.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from dcim.models import Device
|
|
2
|
-
from django.http import HttpResponse
|
|
3
2
|
from django.shortcuts import redirect, render
|
|
4
3
|
from django.utils.translation import gettext as _
|
|
5
4
|
from netbox.views import generic
|
|
@@ -15,38 +14,7 @@ from netbox_config_diff.forms import (
|
|
|
15
14
|
from netbox_config_diff.models import ConfigCompliance, PlatformSetting
|
|
16
15
|
from netbox_config_diff.tables import ConfigComplianceTable, PlatformSettingTable
|
|
17
16
|
|
|
18
|
-
from .base import BaseObjectDeleteView, BaseObjectEditView
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class BaseConfigComplianceConfigView(generic.ObjectView):
|
|
22
|
-
config_field = None
|
|
23
|
-
template_header = None
|
|
24
|
-
|
|
25
|
-
def get(self, request, **kwargs):
|
|
26
|
-
instance = self.get_object(**kwargs)
|
|
27
|
-
context = self.get_extra_context(request, instance)
|
|
28
|
-
|
|
29
|
-
if request.GET.get("export"):
|
|
30
|
-
response = HttpResponse(context["config"], content_type="text")
|
|
31
|
-
filename = f"{instance.device.name}_{self.config_field}.txt"
|
|
32
|
-
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
|
33
|
-
return response
|
|
34
|
-
|
|
35
|
-
return render(
|
|
36
|
-
request,
|
|
37
|
-
self.get_template_name(),
|
|
38
|
-
{
|
|
39
|
-
"object": instance,
|
|
40
|
-
"tab": self.tab,
|
|
41
|
-
**context,
|
|
42
|
-
},
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
def get_extra_context(self, request, instance):
|
|
46
|
-
return {
|
|
47
|
-
"header": self.template_header,
|
|
48
|
-
"config": getattr(instance, self.config_field),
|
|
49
|
-
}
|
|
17
|
+
from .base import BaseConfigComplianceConfigView, BaseExportView, BaseObjectDeleteView, BaseObjectEditView
|
|
50
18
|
|
|
51
19
|
|
|
52
20
|
@register_model_view(ConfigCompliance)
|
|
@@ -87,7 +55,7 @@ class ConfigComplianceActualConfigView(BaseConfigComplianceConfigView):
|
|
|
87
55
|
|
|
88
56
|
|
|
89
57
|
@register_model_view(ConfigCompliance, "missing-extra")
|
|
90
|
-
class ConfigComplianceMissingExtraConfigView(
|
|
58
|
+
class ConfigComplianceMissingExtraConfigView(BaseExportView):
|
|
91
59
|
queryset = ConfigCompliance.objects.all()
|
|
92
60
|
template_name = "netbox_config_diff/configcompliance/missing_extra.html"
|
|
93
61
|
tab = ViewTab(
|
|
@@ -95,12 +63,6 @@ class ConfigComplianceMissingExtraConfigView(generic.ObjectView):
|
|
|
95
63
|
weight=520,
|
|
96
64
|
)
|
|
97
65
|
|
|
98
|
-
def export_parts(self, name, lines, suffix):
|
|
99
|
-
response = HttpResponse(lines, content_type="text")
|
|
100
|
-
filename = f"{name}_{suffix}.txt"
|
|
101
|
-
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
|
102
|
-
return response
|
|
103
|
-
|
|
104
66
|
def get(self, request, **kwargs):
|
|
105
67
|
instance = self.get_object(**kwargs)
|
|
106
68
|
context = self.get_extra_context(request, instance)
|
|
@@ -122,6 +84,33 @@ class ConfigComplianceMissingExtraConfigView(generic.ObjectView):
|
|
|
122
84
|
)
|
|
123
85
|
|
|
124
86
|
|
|
87
|
+
@register_model_view(ConfigCompliance, "patch")
|
|
88
|
+
class ConfigCompliancePatchView(BaseExportView):
|
|
89
|
+
queryset = ConfigCompliance.objects.all()
|
|
90
|
+
template_name = "netbox_config_diff/configcompliance/patch.html"
|
|
91
|
+
tab = ViewTab(
|
|
92
|
+
label=_("Patch"),
|
|
93
|
+
weight=515,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def get(self, request, **kwargs):
|
|
97
|
+
instance = self.get_object(**kwargs)
|
|
98
|
+
context = self.get_extra_context(request, instance)
|
|
99
|
+
|
|
100
|
+
if request.GET.get("export_patch"):
|
|
101
|
+
return self.export_parts(instance.device.name, instance.patch, "patch")
|
|
102
|
+
|
|
103
|
+
return render(
|
|
104
|
+
request,
|
|
105
|
+
self.get_template_name(),
|
|
106
|
+
{
|
|
107
|
+
"object": instance,
|
|
108
|
+
"tab": self.tab,
|
|
109
|
+
**context,
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
125
114
|
@register_model_view(Device, "config_compliance", "config-compliance")
|
|
126
115
|
class ConfigComplianceDeviceView(generic.ObjectView):
|
|
127
116
|
queryset = Device.objects.all()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-config-diff
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -218,6 +218,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
218
218
|
Requires-Python: >=3.10
|
|
219
219
|
Description-Content-Type: text/markdown
|
|
220
220
|
License-File: LICENSE
|
|
221
|
+
Requires-Dist: hier-config==2.2.3
|
|
221
222
|
Requires-Dist: netutils==1.5.0
|
|
222
223
|
Requires-Dist: scrapli[asyncssh]==2023.07.30
|
|
223
224
|
Requires-Dist: scrapli-cfg==2023.07.30
|
|
@@ -275,7 +276,7 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
|
|
|
275
276
|
|
|
276
277
|
| NetBox Version | Plugin Version |
|
|
277
278
|
|----------------|----------------|
|
|
278
|
-
|
|
|
279
|
+
| 3.5, 3.6, 3.7 | =>0.1.0 |
|
|
279
280
|
|
|
280
281
|
<!--install-start-->
|
|
281
282
|
## Installing
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff.egg-info/SOURCES.txt
RENAMED
|
@@ -8,6 +8,7 @@ docs/media/screenshots/compliance-error.png
|
|
|
8
8
|
docs/media/screenshots/compliance-list.png
|
|
9
9
|
docs/media/screenshots/compliance-missing-extra.png
|
|
10
10
|
docs/media/screenshots/compliance-ok.png
|
|
11
|
+
docs/media/screenshots/compliance-patch.png
|
|
11
12
|
docs/media/screenshots/config-temp-substitute.png
|
|
12
13
|
docs/media/screenshots/cr-approve-button.png
|
|
13
14
|
docs/media/screenshots/cr-approved.png
|
|
@@ -64,6 +65,7 @@ netbox_config_diff/migrations/0005_configcompliance_extra_missing.py
|
|
|
64
65
|
netbox_config_diff/migrations/0006_substitute.py
|
|
65
66
|
netbox_config_diff/migrations/0007_configurationrequest.py
|
|
66
67
|
netbox_config_diff/migrations/0008_alter_configcompliance_device.py
|
|
68
|
+
netbox_config_diff/migrations/0009_configcompliance_patch.py
|
|
67
69
|
netbox_config_diff/migrations/__init__.py
|
|
68
70
|
netbox_config_diff/models/__init__.py
|
|
69
71
|
netbox_config_diff/models/base.py
|
|
@@ -80,8 +82,10 @@ netbox_config_diff/templates/netbox_config_diff/substitute.html
|
|
|
80
82
|
netbox_config_diff/templates/netbox_config_diff/configcompliance/config.html
|
|
81
83
|
netbox_config_diff/templates/netbox_config_diff/configcompliance/data.html
|
|
82
84
|
netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html
|
|
85
|
+
netbox_config_diff/templates/netbox_config_diff/configcompliance/patch.html
|
|
83
86
|
netbox_config_diff/templates/netbox_config_diff/configurationrequest/base.html
|
|
84
87
|
netbox_config_diff/templates/netbox_config_diff/configurationrequest/diffs.html
|
|
88
|
+
netbox_config_diff/templates/netbox_config_diff/inc/commands_card.html
|
|
85
89
|
netbox_config_diff/templates/netbox_config_diff/inc/diff.html
|
|
86
90
|
netbox_config_diff/templates/netbox_config_diff/inc/job_log.html
|
|
87
91
|
netbox_config_diff/views/__init__.py
|
|
@@ -56,4 +56,4 @@ def test_exclude_lines(regex: str, expected: str) -> None:
|
|
|
56
56
|
ids=["diff", "no diff"],
|
|
57
57
|
)
|
|
58
58
|
def test_get_unified_diff(render: str, actual: str, expected: str) -> None:
|
|
59
|
-
assert get_unified_diff(
|
|
59
|
+
assert get_unified_diff(actual, render, "test-1") == expected
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{% extends "netbox_config_diff/configcompliance.html" %}
|
|
2
|
-
|
|
3
|
-
{% block title %}{{ object }} - Missing/Extra{% endblock %}
|
|
4
|
-
|
|
5
|
-
{% block content %}
|
|
6
|
-
<div class="row">
|
|
7
|
-
<div class="col col-md-6">
|
|
8
|
-
<div class="card">
|
|
9
|
-
<div class="card-header">
|
|
10
|
-
<div class="float-end">
|
|
11
|
-
<a href="?export_missing=True" class="btn btn-sm btn-primary" role="button">
|
|
12
|
-
<i class="mdi mdi-download" aria-hidden="true"></i> Download
|
|
13
|
-
</a>
|
|
14
|
-
</div>
|
|
15
|
-
<h5>Missing</h5>
|
|
16
|
-
</div>
|
|
17
|
-
{% if object.missing %}
|
|
18
|
-
<pre class="card-body">{{ object.missing }}</pre>
|
|
19
|
-
{% else %}
|
|
20
|
-
<div class="card-body text-muted">No lines</div>
|
|
21
|
-
{% endif %}
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
<div class="col col-md-6">
|
|
25
|
-
<div class="card">
|
|
26
|
-
<div class="card-header">
|
|
27
|
-
<div class="float-end">
|
|
28
|
-
<a href="?export_extra=True" class="btn btn-sm btn-primary" role="button">
|
|
29
|
-
<i class="mdi mdi-download" aria-hidden="true"></i> Download
|
|
30
|
-
</a>
|
|
31
|
-
</div>
|
|
32
|
-
<h5>Extra</h5>
|
|
33
|
-
</div>
|
|
34
|
-
{% if object.extra %}
|
|
35
|
-
<pre class="card-body">{{ object.extra }}</pre>
|
|
36
|
-
{% else %}
|
|
37
|
-
<div class="card-body text-muted">No lines</div>
|
|
38
|
-
{% endif %}
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
{% endblock %}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from django.urls import reverse
|
|
2
|
-
from netbox.views.generic import ObjectDeleteView, ObjectEditView
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class BaseObjectDeleteView(ObjectDeleteView):
|
|
6
|
-
def get_return_url(self, request, obj=None):
|
|
7
|
-
return reverse(f"plugins:netbox_config_diff:{self.queryset.model._meta.model_name}_list")
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class BaseObjectEditView(ObjectEditView):
|
|
11
|
-
@property
|
|
12
|
-
def default_return_url(self) -> str:
|
|
13
|
-
return f"plugins:netbox_config_diff:{self.queryset.model._meta.model_name}_list"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-diff.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-error.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-list.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/compliance-ok.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-approve-button.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-approved.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-completed.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-diffs-tab.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-schedule-button.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-scheduled.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/cr-unapprove-button.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/platformsetting.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/docs/media/screenshots/script-list.png
RENAMED
|
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.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/__init__.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/compliance/secrets.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/__init__.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/exceptions.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/factory.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/configurator/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/0001_initial.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
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/migrations/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/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
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/netbox_config_diff/views/configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.2.0 → netbox_config_diff-2.4.0}/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
|