netbox-config-diff 2.1.0__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netbox-config-diff-2.1.0/netbox_config_diff.egg-info → netbox-config-diff-2.2.0}/PKG-INFO +10 -4
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/README.md +8 -2
- netbox-config-diff-2.2.0/docs/media/screenshots/navbar.png +0 -0
- netbox-config-diff-2.2.0/docs/media/screenshots/script.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/__init__.py +1 -1
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/base.py +18 -3
- netbox-config-diff-2.2.0/netbox_config_diff/migrations/0008_alter_configcompliance_device.py +21 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/models/data_models.py +4 -1
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/models/models.py +1 -1
- netbox-config-diff-2.2.0/netbox_config_diff/navigation.py +47 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/configcompliance/config.html +1 -1
- netbox-config-diff-2.1.0/netbox_config_diff/templates/netbox_config_diff/configcompliance.html → netbox-config-diff-2.2.0/netbox_config_diff/templates/netbox_config_diff/configcompliance/data.html +8 -8
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html +1 -1
- netbox-config-diff-2.1.0/netbox_config_diff/templates/netbox_config_diff/configcompliance/base.html → netbox-config-diff-2.2.0/netbox_config_diff/templates/netbox_config_diff/configcompliance.html +1 -1
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/views/compliance.py +41 -1
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0/netbox_config_diff.egg-info}/PKG-INFO +10 -4
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff.egg-info/SOURCES.txt +2 -1
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/pyproject.toml +1 -1
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/tests/conftest.py +1 -0
- netbox-config-diff-2.1.0/docs/media/screenshots/navbar.png +0 -0
- netbox-config-diff-2.1.0/docs/media/screenshots/script.png +0 -0
- netbox-config-diff-2.1.0/netbox_config_diff/navigation.py +0 -46
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/LICENSE +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/MANIFEST.in +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/development/configuration.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-diff.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-error.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-list.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-missing-extra.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-ok.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/config-temp-substitute.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-approve-button.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-approved.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-collecting-diff-button.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-completed.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-created.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-diffs-tab.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-job-log.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-schedule-button.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-scheduled.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-unapprove-button.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-unschedule-button.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/platformsetting.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/render-temp-substitute.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/script-list.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/substitute.png +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/api/__init__.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/api/serializers.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/api/urls.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/api/views.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/choices.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/__init__.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/secrets.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/utils.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/__init__.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/base.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/exceptions.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/factory.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/platforms.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/utils.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/constants.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/filtersets.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/forms.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/graphql.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/jobs.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0001_initial.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0002_add_script.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0003_configcompliance_actual_config_and_more.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0004_update_script.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0005_configcompliance_extra_missing.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0006_substitute.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/0007_configurationrequest.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/__init__.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/models/__init__.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/models/base.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/scripts/config_diff.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/search.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/static/netbox_config_diff/diff2html-ui.min.js +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/static/netbox_config_diff/diff2html.dark.min.css +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/static/netbox_config_diff/diff2html.min.css +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/tables.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/base.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/diffs.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/configurationrequest.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/inc/diff.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/inc/job_log.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/platformsetting.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/templates/netbox_config_diff/substitute.html +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/urls.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/views/__init__.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/views/base.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/views/configuration.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff.egg-info/dependency_links.txt +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff.egg-info/requires.txt +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff.egg-info/top_level.txt +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/requirements/base.txt +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/requirements/dev.txt +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/requirements/test.txt +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/setup.cfg +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/tests/factories.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/tests/test_compliance.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/tests/test_compliance_utils.py +0 -0
- {netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/tests/test_urls.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-config-diff
|
|
3
|
-
Version: 2.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
7
7
|
License: Apache License
|
|
@@ -328,13 +328,19 @@ python manage.py collectstatic --noinput
|
|
|
328
328
|
Restart NetBox service:
|
|
329
329
|
|
|
330
330
|
```bash
|
|
331
|
-
systemctl restart netbox
|
|
331
|
+
systemctl restart netbox netbox-rq
|
|
332
332
|
```
|
|
333
333
|
<!--install-end-->
|
|
334
334
|
<!--usage-start-->
|
|
335
335
|
## Usage
|
|
336
336
|
|
|
337
|
-
Read this [doc](
|
|
337
|
+
Read this [doc](https://miaow2.github.io/netbox-config-diff/colliecting-diffs/) about collecting diffs, for configuration management read [this](https://miaow2.github.io/netbox-config-diff/configuratiom-management/)
|
|
338
|
+
|
|
339
|
+
## Video
|
|
340
|
+
|
|
341
|
+
My presention about plugin at October NetBox community call (19.10.2023).
|
|
342
|
+
|
|
343
|
+
[](https://youtu.be/B4uhtYh278o?t=425)
|
|
338
344
|
<!--usage-end-->
|
|
339
345
|
|
|
340
346
|
## Screenshots
|
|
@@ -97,13 +97,19 @@ python manage.py collectstatic --noinput
|
|
|
97
97
|
Restart NetBox service:
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
|
-
systemctl restart netbox
|
|
100
|
+
systemctl restart netbox netbox-rq
|
|
101
101
|
```
|
|
102
102
|
<!--install-end-->
|
|
103
103
|
<!--usage-start-->
|
|
104
104
|
## Usage
|
|
105
105
|
|
|
106
|
-
Read this [doc](
|
|
106
|
+
Read this [doc](https://miaow2.github.io/netbox-config-diff/colliecting-diffs/) about collecting diffs, for configuration management read [this](https://miaow2.github.io/netbox-config-diff/configuratiom-management/)
|
|
107
|
+
|
|
108
|
+
## Video
|
|
109
|
+
|
|
110
|
+
My presention about plugin at October NetBox community call (19.10.2023).
|
|
111
|
+
|
|
112
|
+
[](https://youtu.be/B4uhtYh278o?t=425)
|
|
107
113
|
<!--usage-end-->
|
|
108
114
|
|
|
109
115
|
## Screenshots
|
|
Binary file
|
|
Binary file
|
|
@@ -9,10 +9,11 @@ from dcim.choices import DeviceStatusChoices
|
|
|
9
9
|
from dcim.models import Device, DeviceRole, Site
|
|
10
10
|
from django.conf import settings
|
|
11
11
|
from django.db.models import Q
|
|
12
|
-
from extras.scripts import MultiObjectVar, ObjectVar
|
|
12
|
+
from extras.scripts import MultiObjectVar, ObjectVar, TextVar
|
|
13
13
|
from jinja2.exceptions import TemplateError
|
|
14
14
|
from netutils.config.compliance import diff_network_config
|
|
15
15
|
from utilities.exceptions import AbortScript
|
|
16
|
+
from utilities.utils import render_jinja2
|
|
16
17
|
|
|
17
18
|
from netbox_config_diff.models import ConplianceDeviceDataClass
|
|
18
19
|
|
|
@@ -52,6 +53,11 @@ class ConfigDiffBase(SecretsMixin):
|
|
|
52
53
|
},
|
|
53
54
|
description="Define synced DataSource, if you want compare configs stored in it wihout connecting to devices",
|
|
54
55
|
)
|
|
56
|
+
name_template = TextVar(
|
|
57
|
+
required=False,
|
|
58
|
+
description="Jinja2 template code for the device name in Data source. "
|
|
59
|
+
"Reference the object as <code>{{ object }}</code>.",
|
|
60
|
+
)
|
|
55
61
|
|
|
56
62
|
def run_script(self, data: dict) -> None:
|
|
57
63
|
devices = self.validate_data(data)
|
|
@@ -155,17 +161,26 @@ class ConfigDiffBase(SecretsMixin):
|
|
|
155
161
|
auth_secondary=auth_secondary,
|
|
156
162
|
rendered_config=rendered_config,
|
|
157
163
|
error=error,
|
|
164
|
+
device=device,
|
|
158
165
|
)
|
|
159
166
|
|
|
160
167
|
def get_config_from_datasource(self, devices: list[ConplianceDeviceDataClass]) -> None:
|
|
161
168
|
for device in devices:
|
|
162
|
-
if
|
|
169
|
+
if self.data["name_template"]:
|
|
170
|
+
try:
|
|
171
|
+
device_name = render_jinja2(self.data["name_template"], {"object": device.device}).strip()
|
|
172
|
+
except Exception as e:
|
|
173
|
+
self.log_failure(f"Error in rendering data source name for {device.name}: {e}, using device name.")
|
|
174
|
+
device_name = device.name
|
|
175
|
+
else:
|
|
176
|
+
device_name = device.name
|
|
177
|
+
if df := DataFile.objects.filter(source=self.data["data_source"], path__icontains=device_name).first():
|
|
163
178
|
if config := df.data_as_string:
|
|
164
179
|
device.actual_config = config
|
|
165
180
|
else:
|
|
166
181
|
device.error = f"Data in file {df} is broken, skiping device {device.name}"
|
|
167
182
|
else:
|
|
168
|
-
device.error = f"Not found file in DataSource for
|
|
183
|
+
device.error = f"Not found file in DataSource for name {device_name}"
|
|
169
184
|
|
|
170
185
|
def get_actual_configs(self, devices: list[ConplianceDeviceDataClass]) -> None:
|
|
171
186
|
if self.data["data_source"]:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from django.db import migrations, models
|
|
2
|
+
import django.db.models.deletion
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Migration(migrations.Migration):
|
|
6
|
+
dependencies = [
|
|
7
|
+
("dcim", "0181_rename_device_role_device_role"),
|
|
8
|
+
("netbox_config_diff", "0007_configurationrequest"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AlterField(
|
|
13
|
+
model_name="configcompliance",
|
|
14
|
+
name="device",
|
|
15
|
+
field=models.OneToOneField(
|
|
16
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
17
|
+
related_name="config_compliance",
|
|
18
|
+
to="dcim.device",
|
|
19
|
+
),
|
|
20
|
+
),
|
|
21
|
+
]
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/models/data_models.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import traceback
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
|
+
from dcim.models import Device
|
|
4
5
|
from scrapli import AsyncScrapli
|
|
5
6
|
|
|
6
7
|
from netbox_config_diff.choices import ConfigComplianceStatusChoices
|
|
@@ -113,10 +114,12 @@ class BaseDeviceDataClass:
|
|
|
113
114
|
|
|
114
115
|
class ConplianceDeviceDataClass(BaseDeviceDataClass):
|
|
115
116
|
command: str
|
|
117
|
+
device: Device | None = None
|
|
116
118
|
|
|
117
|
-
def __init__(self, command: str, **kwargs) -> None:
|
|
119
|
+
def __init__(self, command: str, device: Device, **kwargs) -> None:
|
|
118
120
|
super().__init__(**kwargs)
|
|
119
121
|
self.command = command
|
|
122
|
+
self.device = device
|
|
120
123
|
|
|
121
124
|
async def get_actual_config(self) -> None:
|
|
122
125
|
if self.error is not None:
|
|
@@ -24,7 +24,7 @@ class ConfigCompliance(AbsoluteURLMixin, ChangeLoggingMixin, models.Model):
|
|
|
24
24
|
device = models.OneToOneField(
|
|
25
25
|
to="dcim.Device",
|
|
26
26
|
on_delete=models.CASCADE,
|
|
27
|
-
related_name="
|
|
27
|
+
related_name="config_compliance",
|
|
28
28
|
)
|
|
29
29
|
status = models.CharField(
|
|
30
30
|
max_length=50,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from extras.plugins import PluginMenu, PluginMenuButton, PluginMenuItem
|
|
2
|
+
from utilities.choices import ButtonColorChoices
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_add_button(model: str) -> PluginMenuButton:
|
|
6
|
+
return PluginMenuButton(
|
|
7
|
+
link=f"plugins:netbox_config_diff:{model}_add",
|
|
8
|
+
title="Add",
|
|
9
|
+
icon_class="mdi mdi-plus-thick",
|
|
10
|
+
color=ButtonColorChoices.GREEN,
|
|
11
|
+
permissions=[f"netbox_config_diff.add_{model}"],
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_menu_item(model: str, verbose_name: str, add_button: bool = True) -> PluginMenuItem:
|
|
16
|
+
return PluginMenuItem(
|
|
17
|
+
link=f"plugins:netbox_config_diff:{model}_list",
|
|
18
|
+
link_text=verbose_name,
|
|
19
|
+
buttons=[get_add_button(model)] if add_button else [],
|
|
20
|
+
permissions=[f"netbox_config_diff.view_{model}"],
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
compliance_items = (
|
|
25
|
+
get_menu_item("platformsetting", "Platform Settings"),
|
|
26
|
+
get_menu_item("configcompliance", "Config Compliances", add_button=False),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
config_items = (
|
|
30
|
+
get_menu_item("configurationrequest", "Configuration Requests"),
|
|
31
|
+
get_menu_item("substitute", "Substitutes"),
|
|
32
|
+
PluginMenuItem(
|
|
33
|
+
link="plugins:netbox_config_diff:configurationrequest_job_list",
|
|
34
|
+
link_text="Jobs",
|
|
35
|
+
buttons=[],
|
|
36
|
+
permissions=["core.view_job"],
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
menu = PluginMenu(
|
|
41
|
+
label="Config Diff Plugin",
|
|
42
|
+
groups=(
|
|
43
|
+
("Compliance", compliance_items),
|
|
44
|
+
("Config Management", config_items),
|
|
45
|
+
),
|
|
46
|
+
icon_class="mdi mdi-vector-difference",
|
|
47
|
+
)
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
{% extends
|
|
1
|
+
{% extends base_template %}
|
|
2
2
|
{% load static %}
|
|
3
3
|
|
|
4
4
|
{% block content %}
|
|
5
5
|
<div class="row mb-3">
|
|
6
6
|
<div class="col col-md-6">
|
|
7
7
|
<div class="card">
|
|
8
|
-
<h5 class="card-header">{{
|
|
8
|
+
<h5 class="card-header">{{ instance|meta:"verbose_name"|bettertitle }}</h5>
|
|
9
9
|
<div class="card-body">
|
|
10
10
|
<table class="table table-hover attr-table">
|
|
11
11
|
<tr>
|
|
12
12
|
<th scope="row">Device</th>
|
|
13
|
-
<td>{{
|
|
13
|
+
<td>{{ instance.device|linkify }}</td>
|
|
14
14
|
</tr>
|
|
15
15
|
<tr>
|
|
16
16
|
<th scope="row">Status</th>
|
|
17
|
-
<td>{% badge
|
|
17
|
+
<td>{% badge instance.get_status_display bg_color=instance.get_status_color %}</td>
|
|
18
18
|
</tr>
|
|
19
19
|
</table>
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
23
|
-
{% if
|
|
23
|
+
{% if instance.error %}
|
|
24
24
|
<div class="col col-md-6">
|
|
25
25
|
<div class="card">
|
|
26
26
|
<h5 class="card-header">Error</h5>
|
|
27
27
|
<div class="card-body">
|
|
28
|
-
<pre class="block">{{
|
|
28
|
+
<pre class="block">{{ instance.error }}</pre>
|
|
29
29
|
</div>
|
|
30
30
|
</div>
|
|
31
31
|
</div>
|
|
32
32
|
{% endif %}
|
|
33
33
|
</div>
|
|
34
|
-
{% if
|
|
34
|
+
{% if instance.diff %}
|
|
35
35
|
<div class="row mb-3">
|
|
36
36
|
<div class="col col-md-12">
|
|
37
37
|
<div class="card">
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
stickyFileHeaders: false,
|
|
71
71
|
drawFileList: false,
|
|
72
72
|
};
|
|
73
|
-
const jsonDiff = `{{
|
|
73
|
+
const jsonDiff = `{{ instance.diff|safe }}`;
|
|
74
74
|
var targetElement = document.getElementById('diffElement');
|
|
75
75
|
var diff2htmlUi = new Diff2HtmlUI(targetElement, jsonDiff, configuration);
|
|
76
76
|
diff2htmlUi.draw();
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/views/compliance.py
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from dcim.models import Device
|
|
1
2
|
from django.http import HttpResponse
|
|
2
|
-
from django.shortcuts import render
|
|
3
|
+
from django.shortcuts import redirect, render
|
|
3
4
|
from django.utils.translation import gettext as _
|
|
4
5
|
from netbox.views import generic
|
|
5
6
|
from utilities.views import ViewTab, register_model_view
|
|
@@ -51,6 +52,14 @@ class BaseConfigComplianceConfigView(generic.ObjectView):
|
|
|
51
52
|
@register_model_view(ConfigCompliance)
|
|
52
53
|
class ConfigComplianceView(generic.ObjectView):
|
|
53
54
|
queryset = ConfigCompliance.objects.all()
|
|
55
|
+
base_template = "netbox_config_diff/configcompliance.html"
|
|
56
|
+
template_name = "netbox_config_diff/configcompliance/data.html"
|
|
57
|
+
|
|
58
|
+
def get_extra_context(self, request, instance):
|
|
59
|
+
return {
|
|
60
|
+
"instance": instance,
|
|
61
|
+
"base_template": self.base_template,
|
|
62
|
+
}
|
|
54
63
|
|
|
55
64
|
|
|
56
65
|
@register_model_view(ConfigCompliance, "rendered-config")
|
|
@@ -113,6 +122,37 @@ class ConfigComplianceMissingExtraConfigView(generic.ObjectView):
|
|
|
113
122
|
)
|
|
114
123
|
|
|
115
124
|
|
|
125
|
+
@register_model_view(Device, "config_compliance", "config-compliance")
|
|
126
|
+
class ConfigComplianceDeviceView(generic.ObjectView):
|
|
127
|
+
queryset = Device.objects.all()
|
|
128
|
+
base_template = "dcim/device/base.html"
|
|
129
|
+
template_name = "netbox_config_diff/configcompliance/data.html"
|
|
130
|
+
tab = ViewTab(
|
|
131
|
+
label=_("Config Compliance"),
|
|
132
|
+
weight=2110,
|
|
133
|
+
badge=lambda obj: 1 if hasattr(obj, "config_compliance") else 0,
|
|
134
|
+
hide_if_empty=True,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def get(self, request, **kwargs):
|
|
138
|
+
instance = self.get_object(**kwargs)
|
|
139
|
+
|
|
140
|
+
if not hasattr(instance, "config_compliance"):
|
|
141
|
+
return redirect("dcim:device", pk=instance.pk)
|
|
142
|
+
|
|
143
|
+
return render(
|
|
144
|
+
request,
|
|
145
|
+
self.get_template_name(),
|
|
146
|
+
{
|
|
147
|
+
"object": instance,
|
|
148
|
+
"instance": instance.config_compliance,
|
|
149
|
+
"tab": self.tab,
|
|
150
|
+
"base_template": self.base_template,
|
|
151
|
+
**self.get_extra_context(request, instance),
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
116
156
|
class ConfigComplianceListView(generic.ObjectListView):
|
|
117
157
|
queryset = ConfigCompliance.objects.prefetch_related("device")
|
|
118
158
|
filterset = ConfigComplianceFilterSet
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-config-diff
|
|
3
|
-
Version: 2.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
7
7
|
License: Apache License
|
|
@@ -328,13 +328,19 @@ python manage.py collectstatic --noinput
|
|
|
328
328
|
Restart NetBox service:
|
|
329
329
|
|
|
330
330
|
```bash
|
|
331
|
-
systemctl restart netbox
|
|
331
|
+
systemctl restart netbox netbox-rq
|
|
332
332
|
```
|
|
333
333
|
<!--install-end-->
|
|
334
334
|
<!--usage-start-->
|
|
335
335
|
## Usage
|
|
336
336
|
|
|
337
|
-
Read this [doc](
|
|
337
|
+
Read this [doc](https://miaow2.github.io/netbox-config-diff/colliecting-diffs/) about collecting diffs, for configuration management read [this](https://miaow2.github.io/netbox-config-diff/configuratiom-management/)
|
|
338
|
+
|
|
339
|
+
## Video
|
|
340
|
+
|
|
341
|
+
My presention about plugin at October NetBox community call (19.10.2023).
|
|
342
|
+
|
|
343
|
+
[](https://youtu.be/B4uhtYh278o?t=425)
|
|
338
344
|
<!--usage-end-->
|
|
339
345
|
|
|
340
346
|
## Screenshots
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff.egg-info/SOURCES.txt
RENAMED
|
@@ -63,6 +63,7 @@ netbox_config_diff/migrations/0004_update_script.py
|
|
|
63
63
|
netbox_config_diff/migrations/0005_configcompliance_extra_missing.py
|
|
64
64
|
netbox_config_diff/migrations/0006_substitute.py
|
|
65
65
|
netbox_config_diff/migrations/0007_configurationrequest.py
|
|
66
|
+
netbox_config_diff/migrations/0008_alter_configcompliance_device.py
|
|
66
67
|
netbox_config_diff/migrations/__init__.py
|
|
67
68
|
netbox_config_diff/models/__init__.py
|
|
68
69
|
netbox_config_diff/models/base.py
|
|
@@ -76,8 +77,8 @@ netbox_config_diff/templates/netbox_config_diff/configcompliance.html
|
|
|
76
77
|
netbox_config_diff/templates/netbox_config_diff/configurationrequest.html
|
|
77
78
|
netbox_config_diff/templates/netbox_config_diff/platformsetting.html
|
|
78
79
|
netbox_config_diff/templates/netbox_config_diff/substitute.html
|
|
79
|
-
netbox_config_diff/templates/netbox_config_diff/configcompliance/base.html
|
|
80
80
|
netbox_config_diff/templates/netbox_config_diff/configcompliance/config.html
|
|
81
|
+
netbox_config_diff/templates/netbox_config_diff/configcompliance/data.html
|
|
81
82
|
netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html
|
|
82
83
|
netbox_config_diff/templates/netbox_config_diff/configurationrequest/base.html
|
|
83
84
|
netbox_config_diff/templates/netbox_config_diff/configurationrequest/diffs.html
|
|
@@ -7,7 +7,7 @@ requires = [
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "netbox-config-diff"
|
|
10
|
-
description = "
|
|
10
|
+
description = "Push rendered device configurations from NetBox to devices and apply them."
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
keywords = [
|
|
13
13
|
"netbox",
|
|
Binary file
|
|
Binary file
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
from extras.plugins import PluginMenuButton, PluginMenuItem
|
|
2
|
-
from utilities.choices import ButtonColorChoices
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def get_add_button(model: str) -> PluginMenuButton:
|
|
6
|
-
return PluginMenuButton(
|
|
7
|
-
link=f"plugins:netbox_config_diff:{model}_add",
|
|
8
|
-
title="Add",
|
|
9
|
-
icon_class="mdi mdi-plus-thick",
|
|
10
|
-
color=ButtonColorChoices.GREEN,
|
|
11
|
-
permissions=[f"netbox_config_diff.add_{model}"],
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
menu_items = (
|
|
16
|
-
PluginMenuItem(
|
|
17
|
-
link="plugins:netbox_config_diff:platformsetting_list",
|
|
18
|
-
link_text="Platform Settings",
|
|
19
|
-
buttons=[get_add_button("platformsetting")],
|
|
20
|
-
permissions=["netbox_config_diff.view_platformsetting"],
|
|
21
|
-
),
|
|
22
|
-
PluginMenuItem(
|
|
23
|
-
link="plugins:netbox_config_diff:configcompliance_list",
|
|
24
|
-
link_text="Config Compliances",
|
|
25
|
-
buttons=[],
|
|
26
|
-
permissions=["netbox_config_diff.view_configcompliance"],
|
|
27
|
-
),
|
|
28
|
-
PluginMenuItem(
|
|
29
|
-
link="plugins:netbox_config_diff:configurationrequest_list",
|
|
30
|
-
link_text="Configuration Requests",
|
|
31
|
-
buttons=[get_add_button("configurationrequest")],
|
|
32
|
-
permissions=["netbox_config_diff.view_configurationrequest"],
|
|
33
|
-
),
|
|
34
|
-
PluginMenuItem(
|
|
35
|
-
link="plugins:netbox_config_diff:configurationrequest_job_list",
|
|
36
|
-
link_text="Jobs",
|
|
37
|
-
buttons=[],
|
|
38
|
-
permissions=["core.view_job"],
|
|
39
|
-
),
|
|
40
|
-
PluginMenuItem(
|
|
41
|
-
link="plugins:netbox_config_diff:substitute_list",
|
|
42
|
-
link_text="Substitutes",
|
|
43
|
-
buttons=[get_add_button("substitute")],
|
|
44
|
-
permissions=["netbox_config_diff.view_substitute"],
|
|
45
|
-
),
|
|
46
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-diff.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-error.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-list.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/compliance-ok.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-approve-button.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-approved.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-completed.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-diffs-tab.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-schedule-button.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-scheduled.png
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/cr-unapprove-button.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/docs/media/screenshots/platformsetting.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.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.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/__init__.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/secrets.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/compliance/utils.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/__init__.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/base.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/exceptions.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/factory.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/configurator/platforms.py
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.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.1.0 → netbox-config-diff-2.2.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
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/migrations/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.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
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff/views/configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.0}/netbox_config_diff.egg-info/requires.txt
RENAMED
|
File without changes
|
{netbox-config-diff-2.1.0 → netbox-config-diff-2.2.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
|
|
File without changes
|