Skip to content

Closes #79: support for NetBox 4.1 #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
strategy:
max-parallel: 10
matrix:
netbox_version: ["v3.6.9", "v3.7.8", "v4.0.7"]
netbox_version: ["v3.7.8", "v4.0.7", "v4.1.1"]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![NetBox version](https://img.shields.io/badge/NetBox-3.6|3.7|4.0-blue.svg)](https://github.com/netbox-community/netbox)
[![NetBox version](https://img.shields.io/badge/NetBox-3.7|4.0|4.1-blue.svg)](https://github.com/netbox-community/netbox)
[![Supported Versions](https://img.shields.io/pypi/pyversions/netbox-config-diff.svg)](https://pypi.org/project/netbox-config-diff/)
[![PyPI version](https://badge.fury.io/py/netbox-config-diff.svg)](https://badge.fury.io/py/netbox-config-diff)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
Expand All @@ -9,8 +9,10 @@

[NetBox](https://github.com/netbox-community/netbox) plugin for Config Diff.

* Free software: Apache-2.0
* Documentation: https://miaow2.github.io/netbox-config-diff/
* Find diff between the rendered configuration for a device to its actual configuration, retrieved from the device itself, or stored in DataSource.
* Push the rendered configuration from NetBox to a device and apply it.

Documentation: https://miaow2.github.io/netbox-config-diff/

<!--about-start-->
## About
Expand Down Expand Up @@ -45,7 +47,10 @@ This is possible thanks to the scrapli_cfg. Read [Scrapli](https://github.com/sc
| NetBox Version | Plugin Version |
|----------------|------------------|
| 3.5 | =>0.1.0, <=2.5.0 |
| 3.6, 3.7, 4.0 | =>0.1.0 |
| 3.6 | =>0.1.0, <=2.6.0 |
| 3.7 | =>0.1.0 |
| 4.0 | =>2.6.0 |
| 4.1 | =>2.7.0 |

<!--install-start-->
## Installing
Expand Down
6 changes: 3 additions & 3 deletions netbox_config_diff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@

__author__ = "Artem Kotik"
__email__ = "miaow2@yandex.ru"
__version__ = "2.6.0"
__version__ = "2.7.0"


class ConfigDiffConfig(PluginConfig):
name = "netbox_config_diff"
verbose_name = "NetBox Config Diff Plugin"
description = "Find diff between the intended device configuration and actual."
description = "Find diff and push rendered device configurations from NetBox to devices and apply them."
author = __author__
author_email = __email__
version = __version__
base_url = "config-diff"
required_settings = ["USERNAME", "PASSWORD"]
min_version = "3.6.0"
min_version = "3.7.0"
default_settings = {
"USER_SECRET_ROLE": "Username",
"PASSWORD_SECRET_ROLE": "Password",
Expand Down
8 changes: 6 additions & 2 deletions netbox_config_diff/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
from dcim.api.serializers import NestedDeviceSerializer, NestedPlatformSerializer
from dcim.api.nested_serializers import NestedDeviceSerializer, NestedPlatformSerializer
from dcim.models import Device
from netbox.api.fields import ChoiceField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer
from netbox.settings import VERSION
from rest_framework import serializers
from rest_framework.serializers import ValidationError
from users.api.nested_serializers import NestedUserSerializer

from netbox_config_diff.choices import ConfigComplianceStatusChoices, ConfigurationRequestStatusChoices
from netbox_config_diff.constants import ACCEPTABLE_DRIVERS
from netbox_config_diff.models import ConfigCompliance, ConfigurationRequest, PlatformSetting, Substitute

if VERSION.startswith("3."):
from users.api.nested_serializers import NestedUserSerializer
from utilities.utils import local_now
elif VERSION.startswith("4.0"):
from users.api.nested_serializers import NestedUserSerializer
from utilities.datetime import local_now
else:
from users.api.serializers_.nested import NestedUserSerializer
from utilities.datetime import local_now


Expand Down
4 changes: 2 additions & 2 deletions netbox_config_diff/configurator/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ async def _push_one_config(self, device: ConfiguratorDeviceDataClass) -> None:
conn = self.connections[device.name]
response = await conn.load_config(config=device.rendered_config, replace=True)
if response.failed:
await self.abort_config("load", conn, response, device.name)
await self.abort_config("load", conn, response, device)
return
response = await conn.commit_config()
if response.failed:
await self.abort_config("commit", conn, response, device.name)
await self.abort_config("commit", conn, response, device)
return
self.unprocessed_devices.remove(device)
self.processed_devices.add(device)
Expand Down
25 changes: 21 additions & 4 deletions netbox_config_diff/forms/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
from utilities.utils import local_now
else:
from utilities.datetime import local_now
from utilities.forms.rendering import FieldSet


class ConfigComplianceFilterForm(NetBoxModelFilterSetForm):
model = ConfigCompliance
fieldsets = ((None, ("q", "device_id", "status")),)
if VERSION.startswith("3."):
fieldsets = ((None, ("q", "device_id", "status")),)
else:
fieldsets = (FieldSet("q", "device_id", "status"),)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
Expand Down Expand Up @@ -56,7 +60,10 @@ class Meta:

class PlatformSettingFilterForm(NetBoxModelFilterSetForm):
model = PlatformSetting
fieldsets = ((None, ("q", "platform_id", "tag")),)
if VERSION.startswith("3."):
fieldsets = ((None, ("q", "platform_id", "tag")),)
else:
fieldsets = (FieldSet("q", "filter_id", "tag"),)
platform_id = DynamicModelMultipleChoiceField(
queryset=Platform.objects.all(),
required=False,
Expand Down Expand Up @@ -84,7 +91,10 @@ class PlatformSettingBulkEditForm(NetBoxModelBulkEditForm):
)

model = PlatformSetting
fieldsets = ((None, ("driver", "command", "description", "exclude_regex")),)
if VERSION.startswith("3."):
fieldsets = ((None, ("driver", "command", "description", "exclude_regex")),)
else:
fieldsets = (FieldSet("driver", "command", "description", "exclude_regex"),)
nullable_fields = ("description", "exclude_regex")


Expand Down Expand Up @@ -135,7 +145,10 @@ def clean(self):

class ConfigurationRequestFilterForm(NetBoxModelFilterSetForm):
model = ConfigurationRequest
fieldsets = ((None, ("q", "created_by_id", "approved_by_id", "scheduled_by_id", "device_id", "status", "tag")),)
if VERSION.startswith("3."):
fieldsets = ((None, ("q", "created_by_id", "approved_by_id", "scheduled_by_id", "device_id", "status", "tag")),)
else:
fieldsets = (FieldSet("q", "created_by_id", "approved_by_id", "scheduled_by_id", "device_id", "status", "tag"),)
created_by_id = DynamicModelMultipleChoiceField(
queryset=get_user_model().objects.all(),
required=False,
Expand Down Expand Up @@ -201,6 +214,10 @@ class Meta:
class SubstituteFilterForm(NetBoxModelFilterSetForm):
model = Substitute
fieldsets = ((None, ("q", "platform_setting_id", "tag")),)
if VERSION.startswith("3."):
fieldsets = ((None, ("q", "platform_setting_id", "tag")),)
else:
fieldsets = (FieldSet("q", "platform_setting_id", "tag"),)
platform_setting_id = DynamicModelMultipleChoiceField(
queryset=PlatformSetting.objects.all(),
required=False,
Expand Down
39 changes: 39 additions & 0 deletions netbox_config_diff/migrations/0010_create_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from django.db import migrations

from extras.models import Script, ScriptModule
from netbox.settings import VERSION


def forward_func(apps, schema_editor):
if VERSION.startswith("3."):
return

if Script.objects.filter(name="ConfigDiffScript"):
return

obj = None
for module in ScriptModule.objects.all():
if module.python_name == "config_diff":
obj = module
break

if obj:
Script.objects.create(module=obj, name="ConfigDiffScript")


def reverse_func(apps, schema_editor):
if VERSION.startswith("3."):
return

if qs := Script.objects.filter(name="ConfigDiffScript"):
qs.delete()


class Migration(migrations.Migration):
dependencies = [
("netbox_config_diff", "0009_configcompliance_patch"),
]

operations = [
migrations.RunPython(forward_func, reverse_func),
]
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ <h5 class="card-header">{{ diff.name }} - No diff</h5>
</div>
{% endif %}
{% else %}
<div class="alert alert-warning text-end" role="alert">
<div class="float-start"><i class="mdi mdi-alert"></i>There is no diffs, run collect diffs</div>
<div class="alert alert-warning" role="alert">
<i class="mdi mdi-alert"></i>There is no diffs, run collect diffs
</div>
{% endif %}
{% endblock content %}
Expand Down
1 change: 1 addition & 0 deletions netbox_config_diff/views/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def get_extra_context(self, request, instance):

return {
"job": job,
"version": VERSION,
}


Expand Down
6 changes: 3 additions & 3 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
hier-config==2.2.3
netutils==1.9.0
scrapli[asyncssh]==2024.01.30
scrapli-cfg==2024.01.30
scrapli-community==2024.01.30
scrapli[asyncssh]==2024.07.30
scrapli-cfg==2024.07.30
scrapli-community==2024.07.30
Loading