netbox-config-diff 2.14.1__tar.gz → 2.14.3__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.1 → netbox_config_diff-2.14.3}/PKG-INFO +1 -1
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/__init__.py +1 -1
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/api/serializers.py +15 -12
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/filters.py +16 -16
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff.egg-info/PKG-INFO +1 -1
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff.egg-info/SOURCES.txt +1 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/tests/conftest.py +14 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/tests/factories.py +13 -0
- netbox_config_diff-2.14.3/tests/test_configurtion_request.py +229 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/LICENSE +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/MANIFEST.in +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/README.md +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/development/configuration.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-diff.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-error.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-list.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-missing-extra.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-ok.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-patch.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/config-temp-substitute.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-approve-button.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-approved.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-collecting-diff-button.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-completed.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-created.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-diffs-tab.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-job-log.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-schedule-button.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-scheduled.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-unapprove-button.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-unschedule-button.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/navbar.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/platformsetting.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/render-temp-substitute.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/script-list.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/script.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/substitute.png +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/api/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/api/urls.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/api/views.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/choices.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/base.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/secrets.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/utils.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/base.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/exceptions.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/factory.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/platforms.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/utils.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/constants.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/filtersets.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/forms/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/forms/general.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/enums.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/schema.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/types.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/jobs.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0001_initial.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0002_add_script.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0003_configcompliance_actual_config_and_more.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0004_update_script.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0005_configcompliance_extra_missing.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0006_substitute.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0007_configurationrequest.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0008_alter_configcompliance_device.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0009_configcompliance_patch.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0010_create_script.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/0011_configurationrequest_owner.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/models/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/models/base.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/models/data_models.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/models/models.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/navigation.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/scripts/config_diff.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/search.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/static/netbox_config_diff/diff2html-ui.min.js +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/static/netbox_config_diff/diff2html.dark.min.css +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/static/netbox_config_diff/diff2html.min.css +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/tables.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configcompliance/config.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configcompliance/data.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configcompliance/missing_extra.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configcompliance.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/base.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configurationrequest/diffs.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/configurationrequest.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/inc/commands_card.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/inc/diff.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/inc/job_log.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/platformsetting.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templates/netbox_config_diff/substitute.html +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templatetags/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templatetags/string_filters.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/urls.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/__init__.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/base.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/compliance.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/configuration.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff.egg-info/dependency_links.txt +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff.egg-info/requires.txt +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff.egg-info/top_level.txt +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/pyproject.toml +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/requirements/base.txt +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/requirements/dev.txt +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/requirements/test.txt +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/setup.cfg +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/tests/test_compliance.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/tests/test_compliance_utils.py +0 -0
- {netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/tests/test_urls.py +0 -0
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/api/serializers.py
RENAMED
|
@@ -101,21 +101,24 @@ class ConfigurationRequestSerializer(NetBoxModelSerializer):
|
|
|
101
101
|
|
|
102
102
|
def validate(self, data):
|
|
103
103
|
if data.get("devices"):
|
|
104
|
-
if devices := data["devices"].filter(
|
|
104
|
+
if devices := Device.objects.filter(id__in=[d.id for d in data["devices"]]).filter(
|
|
105
|
+
platform__platform_setting__isnull=True
|
|
106
|
+
):
|
|
105
107
|
platforms = {d.platform.name for d in devices}
|
|
106
108
|
raise ValidationError({"devices": f"Assign PlatformSetting for platform(s): {', '.join(platforms)}"})
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
for
|
|
111
|
-
if
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
)
|
|
110
|
+
unsupported_drivers = {
|
|
111
|
+
d.platform.platform_setting.driver
|
|
112
|
+
for d in data["devices"]
|
|
113
|
+
if d.platform.platform_setting.driver not in ACCEPTABLE_DRIVERS
|
|
114
|
+
}
|
|
115
|
+
if unsupported_drivers:
|
|
116
|
+
raise ValidationError({"devices": f"Driver(s) not supported: {', '.join(unsupported_drivers)}"})
|
|
117
|
+
|
|
118
|
+
devices_without_template = [d for d in data["devices"] if d.get_config_template() is None]
|
|
119
|
+
if devices_without_template:
|
|
120
|
+
names = ", ".join(d.name for d in devices_without_template)
|
|
121
|
+
raise ValidationError({"devices": f"Define config template for device(s): {names}"})
|
|
119
122
|
|
|
120
123
|
return super().validate(data)
|
|
121
124
|
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/filters.py
RENAMED
|
@@ -5,7 +5,7 @@ import strawberry
|
|
|
5
5
|
import strawberry_django
|
|
6
6
|
from netbox.graphql.filters import ChangeLoggedModelFilter, NetBoxModelFilter, PrimaryModelFilter
|
|
7
7
|
from strawberry.scalars import ID
|
|
8
|
-
from strawberry_django import DatetimeFilterLookup
|
|
8
|
+
from strawberry_django import DatetimeFilterLookup, StrFilterLookup
|
|
9
9
|
|
|
10
10
|
from netbox_config_diff.models import ConfigCompliance, ConfigurationRequest, PlatformSetting, Substitute
|
|
11
11
|
|
|
@@ -23,18 +23,18 @@ class ConfigComplianceFilter(ChangeLoggedModelFilter):
|
|
|
23
23
|
status: Annotated["ConfigComplianceStatusEnum", strawberry.lazy("netbox_config_diff.graphql.enums")] | None = (
|
|
24
24
|
strawberry_django.filter_field()
|
|
25
25
|
)
|
|
26
|
-
diff:
|
|
27
|
-
error:
|
|
28
|
-
actual_config:
|
|
29
|
-
rendered_config:
|
|
30
|
-
missing:
|
|
31
|
-
extra:
|
|
32
|
-
patch:
|
|
26
|
+
diff: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
27
|
+
error: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
28
|
+
actual_config: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
29
|
+
rendered_config: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
30
|
+
missing: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
31
|
+
extra: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
32
|
+
patch: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
@strawberry_django.filter(ConfigurationRequest, lookups=True)
|
|
36
36
|
class ConfigurationRequestFilter(PrimaryModelFilter):
|
|
37
|
-
description:
|
|
37
|
+
description: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
38
38
|
status: Annotated["ConfigurationRequestStatusEnum", strawberry.lazy("netbox_config_diff.graphql.enums")] | None = (
|
|
39
39
|
strawberry_django.filter_field()
|
|
40
40
|
)
|
|
@@ -64,10 +64,10 @@ class PlatformSettingFilter(NetBoxModelFilter):
|
|
|
64
64
|
strawberry_django.filter_field()
|
|
65
65
|
)
|
|
66
66
|
platform_id: ID | None = strawberry_django.filter_field()
|
|
67
|
-
driver:
|
|
68
|
-
description:
|
|
69
|
-
command:
|
|
70
|
-
exclude_regex:
|
|
67
|
+
driver: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
68
|
+
description: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
69
|
+
command: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
70
|
+
exclude_regex: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
@strawberry_django.filter(Substitute, lookups=True)
|
|
@@ -76,6 +76,6 @@ class SubstituteFilter(NetBoxModelFilter):
|
|
|
76
76
|
Annotated["PlatformSettingFilter", strawberry.lazy("netbox_config_diff.graphql.filters")] | None
|
|
77
77
|
) = strawberry_django.filter_field()
|
|
78
78
|
platform_setting_id: ID | None = strawberry_django.filter_field()
|
|
79
|
-
name:
|
|
80
|
-
description:
|
|
81
|
-
regexp:
|
|
79
|
+
name: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
80
|
+
description: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
81
|
+
regexp: StrFilterLookup[str] | None = strawberry_django.filter_field()
|
|
@@ -5,6 +5,7 @@ import pytest
|
|
|
5
5
|
from django.db import connection
|
|
6
6
|
from django.test.utils import setup_databases
|
|
7
7
|
from faker import Faker
|
|
8
|
+
from rest_framework.test import APIClient
|
|
8
9
|
from typing_extensions import Unpack
|
|
9
10
|
|
|
10
11
|
from netbox_config_diff.compliance.base import ConfigDiffBase
|
|
@@ -125,3 +126,16 @@ def devicedataclass_factory() -> "DeviceDataClassDataFactory":
|
|
|
125
126
|
def devicedataclass_data(devicedataclass_factory: "DeviceDataClassDataFactory") -> ConplianceDeviceDataClass:
|
|
126
127
|
data = devicedataclass_factory()
|
|
127
128
|
return ConplianceDeviceDataClass(**data)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.fixture
|
|
132
|
+
def api_client():
|
|
133
|
+
"""Basic API client fixture."""
|
|
134
|
+
return APIClient()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@pytest.fixture
|
|
138
|
+
def authenticated_api_client(api_client, admin_user):
|
|
139
|
+
"""Authenticated API client fixture using admin user."""
|
|
140
|
+
api_client.force_authenticate(user=admin_user)
|
|
141
|
+
return api_client
|
|
@@ -94,6 +94,19 @@ class ConfigComplianceFactory(DjangoModelFactory):
|
|
|
94
94
|
model = ConfigCompliance
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
class ConfigurationRequestFactory(DjangoModelFactory):
|
|
98
|
+
class Meta:
|
|
99
|
+
model = "netbox_config_diff.ConfigurationRequest"
|
|
100
|
+
|
|
101
|
+
@factory.post_generation
|
|
102
|
+
def devices(obj, create, extracted, **kwargs):
|
|
103
|
+
if not create:
|
|
104
|
+
return
|
|
105
|
+
if extracted:
|
|
106
|
+
for device in extracted:
|
|
107
|
+
obj.devices.add(device)
|
|
108
|
+
|
|
109
|
+
|
|
97
110
|
class DataSourceFactory(DjangoModelFactory):
|
|
98
111
|
name = factory.Sequence(lambda n: f"datasource-{n}")
|
|
99
112
|
source_url = factory.Sequence(lambda n: f"/tmp/{n}")
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
from http import HTTPStatus
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
from django.urls import reverse
|
|
6
|
+
from users.models import User
|
|
7
|
+
|
|
8
|
+
from netbox_config_diff.choices import ConfigurationRequestStatusChoices
|
|
9
|
+
from tests.factories import (
|
|
10
|
+
ConfigurationRequestFactory,
|
|
11
|
+
DeviceFactory,
|
|
12
|
+
PlatformSettingFactory,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.mark.django_db()
|
|
20
|
+
def test_configuration_request_list(authenticated_api_client):
|
|
21
|
+
device = DeviceFactory.create()
|
|
22
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
23
|
+
ConfigurationRequestFactory.create(devices=[device])
|
|
24
|
+
ConfigurationRequestFactory.create(devices=[device])
|
|
25
|
+
|
|
26
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
27
|
+
response = authenticated_api_client.get(url)
|
|
28
|
+
|
|
29
|
+
assert response.status_code == HTTPStatus.OK
|
|
30
|
+
assert response.json()["count"] == 2
|
|
31
|
+
assert len(response.json()["results"]) == 2
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.mark.django_db()
|
|
35
|
+
def test_configuration_request_retrieve(authenticated_api_client):
|
|
36
|
+
device = DeviceFactory.create()
|
|
37
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
38
|
+
cr = ConfigurationRequestFactory.create(devices=[device])
|
|
39
|
+
|
|
40
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-detail", args=[cr.pk])
|
|
41
|
+
response = authenticated_api_client.get(url)
|
|
42
|
+
|
|
43
|
+
assert response.status_code == HTTPStatus.OK
|
|
44
|
+
data = response.json()
|
|
45
|
+
assert data["id"] == cr.pk
|
|
46
|
+
assert data["status"]["value"] == ConfigurationRequestStatusChoices.CREATED
|
|
47
|
+
assert len(data["devices"]) == 1
|
|
48
|
+
assert data["devices"][0]["id"] == device.pk
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.mark.django_db()
|
|
52
|
+
def test_configuration_request_create_success(authenticated_api_client, admin_user):
|
|
53
|
+
device = DeviceFactory.create()
|
|
54
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
55
|
+
|
|
56
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
57
|
+
payload = {
|
|
58
|
+
"devices": [device.pk],
|
|
59
|
+
"description": "Test configuration request",
|
|
60
|
+
"comments": "Test comments",
|
|
61
|
+
}
|
|
62
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
63
|
+
|
|
64
|
+
assert response.status_code == HTTPStatus.CREATED
|
|
65
|
+
data = response.json()
|
|
66
|
+
assert data["status"]["value"] == ConfigurationRequestStatusChoices.CREATED
|
|
67
|
+
assert data["description"] == "Test configuration request"
|
|
68
|
+
assert data["comments"] == "Test comments"
|
|
69
|
+
assert len(data["devices"]) == 1
|
|
70
|
+
assert data["created_by"]["id"] == admin_user.pk
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@pytest.mark.django_db()
|
|
74
|
+
def test_configuration_request_create_multiple_devices(authenticated_api_client):
|
|
75
|
+
device1 = DeviceFactory.create()
|
|
76
|
+
device2 = DeviceFactory.create()
|
|
77
|
+
PlatformSettingFactory.create(platform=device1.platform)
|
|
78
|
+
PlatformSettingFactory.create(platform=device2.platform)
|
|
79
|
+
|
|
80
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
81
|
+
payload = {
|
|
82
|
+
"devices": [device1.pk, device2.pk],
|
|
83
|
+
"description": "Multi-device request",
|
|
84
|
+
}
|
|
85
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
86
|
+
|
|
87
|
+
assert response.status_code == HTTPStatus.CREATED
|
|
88
|
+
data = response.json()
|
|
89
|
+
assert len(data["devices"]) == 2
|
|
90
|
+
device_ids = {d["id"] for d in data["devices"]}
|
|
91
|
+
assert device1.pk in device_ids
|
|
92
|
+
assert device2.pk in device_ids
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@pytest.mark.django_db()
|
|
96
|
+
def test_configuration_request_create_no_platform_setting(authenticated_api_client):
|
|
97
|
+
device = DeviceFactory.create()
|
|
98
|
+
|
|
99
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
100
|
+
payload = {
|
|
101
|
+
"devices": [device.pk],
|
|
102
|
+
}
|
|
103
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
104
|
+
|
|
105
|
+
assert response.status_code == HTTPStatus.BAD_REQUEST
|
|
106
|
+
data = response.json()
|
|
107
|
+
assert "devices" in data
|
|
108
|
+
assert "Assign PlatformSetting" in str(data["devices"])
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@pytest.mark.django_db()
|
|
112
|
+
def test_configuration_request_create_unsupported_driver(authenticated_api_client):
|
|
113
|
+
device = DeviceFactory.create()
|
|
114
|
+
PlatformSettingFactory.create(platform=device.platform, driver="unsupported_driver")
|
|
115
|
+
|
|
116
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
117
|
+
payload = {
|
|
118
|
+
"devices": [device.pk],
|
|
119
|
+
}
|
|
120
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
121
|
+
|
|
122
|
+
assert response.status_code == HTTPStatus.BAD_REQUEST
|
|
123
|
+
data = response.json()
|
|
124
|
+
assert "devices" in data
|
|
125
|
+
assert "Driver(s) not supported" in str(data["devices"])
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.mark.django_db()
|
|
129
|
+
def test_configuration_request_create_no_config_template(authenticated_api_client):
|
|
130
|
+
device = DeviceFactory.create(config_template=None)
|
|
131
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
132
|
+
|
|
133
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
134
|
+
payload = {
|
|
135
|
+
"devices": [device.pk],
|
|
136
|
+
}
|
|
137
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
138
|
+
|
|
139
|
+
assert response.status_code == HTTPStatus.BAD_REQUEST
|
|
140
|
+
data = response.json()
|
|
141
|
+
assert "devices" in data
|
|
142
|
+
assert "Define config template" in str(data["devices"])
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@pytest.mark.django_db()
|
|
146
|
+
def test_configuration_request_create_mixed_valid_invalid_devices(authenticated_api_client):
|
|
147
|
+
valid_device = DeviceFactory.create()
|
|
148
|
+
PlatformSettingFactory.create(platform=valid_device.platform)
|
|
149
|
+
invalid_device = DeviceFactory.create()
|
|
150
|
+
|
|
151
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
152
|
+
payload = {
|
|
153
|
+
"devices": [valid_device.pk, invalid_device.pk],
|
|
154
|
+
}
|
|
155
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
156
|
+
|
|
157
|
+
assert response.status_code == HTTPStatus.BAD_REQUEST
|
|
158
|
+
data = response.json()
|
|
159
|
+
assert "devices" in data
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@pytest.mark.django_db()
|
|
163
|
+
def test_configuration_request_create_empty_devices(authenticated_api_client):
|
|
164
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
165
|
+
payload = {
|
|
166
|
+
"devices": [],
|
|
167
|
+
}
|
|
168
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
169
|
+
|
|
170
|
+
assert response.status_code == HTTPStatus.CREATED
|
|
171
|
+
data = response.json()
|
|
172
|
+
assert len(data["devices"]) == 0
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@pytest.mark.django_db()
|
|
176
|
+
def test_configuration_request_create_without_authentication(api_client):
|
|
177
|
+
device = DeviceFactory.create()
|
|
178
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
179
|
+
|
|
180
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
181
|
+
payload = {
|
|
182
|
+
"devices": [device.pk],
|
|
183
|
+
}
|
|
184
|
+
response = api_client.post(url, payload, format="json")
|
|
185
|
+
assert response.status_code == HTTPStatus.FORBIDDEN
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@pytest.mark.django_db()
|
|
189
|
+
def test_configuration_request_list_filtering(authenticated_api_client):
|
|
190
|
+
device = DeviceFactory.create()
|
|
191
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
192
|
+
|
|
193
|
+
cr = ConfigurationRequestFactory.create(devices=[device], status=ConfigurationRequestStatusChoices.CREATED)
|
|
194
|
+
ConfigurationRequestFactory.create(devices=[device], status=ConfigurationRequestStatusChoices.APPROVED)
|
|
195
|
+
|
|
196
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
197
|
+
|
|
198
|
+
response = authenticated_api_client.get(url, {"status": ConfigurationRequestStatusChoices.CREATED})
|
|
199
|
+
|
|
200
|
+
assert response.status_code == HTTPStatus.OK
|
|
201
|
+
data = response.json()
|
|
202
|
+
|
|
203
|
+
assert any(r["id"] == cr.pk for r in data["results"])
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@pytest.mark.django_db()
|
|
207
|
+
def test_configuration_request_retrieve_nonexistent(authenticated_api_client):
|
|
208
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-detail", args=[9999])
|
|
209
|
+
response = authenticated_api_client.get(url)
|
|
210
|
+
|
|
211
|
+
assert response.status_code == HTTPStatus.NOT_FOUND
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@pytest.mark.django_db()
|
|
215
|
+
def test_configuration_request_create_sets_created_by(authenticated_api_client, admin_user):
|
|
216
|
+
user2 = User.objects.create_user(username="user2", password="pass")
|
|
217
|
+
|
|
218
|
+
device = DeviceFactory.create()
|
|
219
|
+
PlatformSettingFactory.create(platform=device.platform)
|
|
220
|
+
|
|
221
|
+
url = reverse("plugins-api:netbox_config_diff-api:configurationrequest-list")
|
|
222
|
+
payload = {"devices": [device.pk]}
|
|
223
|
+
response = authenticated_api_client.post(url, payload, format="json")
|
|
224
|
+
|
|
225
|
+
assert response.status_code == HTTPStatus.CREATED
|
|
226
|
+
data = response.json()
|
|
227
|
+
|
|
228
|
+
assert data["created_by"]["id"] == admin_user.pk
|
|
229
|
+
assert data["created_by"]["id"] != user2.pk
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-diff.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-error.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-list.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-ok.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/compliance-patch.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-approve-button.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-approved.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-completed.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-created.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-diffs-tab.png
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-job-log.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/cr-scheduled.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/platformsetting.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/script-list.png
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/docs/media/screenshots/substitute.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/__init__.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/base.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/secrets.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/compliance/utils.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/__init__.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/base.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/factory.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/platforms.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/configurator/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/forms/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/graphql/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/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.1 → netbox_config_diff-2.14.3}/netbox_config_diff/migrations/__init__.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/models/data_models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/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.1 → netbox_config_diff-2.14.3}/netbox_config_diff/templatetags/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/compliance.py
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff/views/configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/netbox_config_diff.egg-info/requires.txt
RENAMED
|
File without changes
|
{netbox_config_diff-2.14.1 → netbox_config_diff-2.14.3}/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
|