Skip to content

Commit

Permalink
Closes #50: Add template field to ConfigDiffScript (#51)
Browse files Browse the repository at this point in the history
* Add name template for searching in DataSource

* Add docs for templating files name in DataSource
  • Loading branch information
miaow2 authored Jan 27, 2024
1 parent 04476cd commit f83d730
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 5 deletions.
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.5.9", "v3.6.4"]
netbox_version: ["v3.5.9", "v3.6.9"]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
11 changes: 11 additions & 0 deletions docs/colliecting-diffs.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ If you have configs in NetBox DataSource, you can define it, the script instead
!!! note
Only synced DataSources are acceptable

If in your DataSource config names are different from the hostnames of the devices, you can specify config name with Jinja2 template in `Name template` field.
Reference device with `{{ object }}` variable.

For example, config name is virtual chassis name plus `config` (`switchname-config`) and your devices names are `switchname1`, `switchname2` and etc.

You can define Jinja2 template with logic to use virtual chassis name if device is in chassis, else use device name:

```
{% if object.virtual_chassis %}{{ object.virtual_chassis.name }}-config{% else %}{{ object.name }}{% endif %}
```

![Screenshot of the script](media/screenshots/script.png)

## Results
Expand Down
Binary file modified docs/media/screenshots/script.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 18 additions & 3 deletions netbox_config_diff/compliance/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
from dcim.models import Device, DeviceRole, Site
from django.conf import settings
from django.db.models import Q
from extras.scripts import MultiObjectVar, ObjectVar
from extras.scripts import MultiObjectVar, ObjectVar, TextVar
from jinja2.exceptions import TemplateError
from netutils.config.compliance import diff_network_config
from utilities.exceptions import AbortScript
from utilities.utils import render_jinja2

from netbox_config_diff.models import ConplianceDeviceDataClass

Expand Down Expand Up @@ -52,6 +53,11 @@ class ConfigDiffBase(SecretsMixin):
},
description="Define synced DataSource, if you want compare configs stored in it wihout connecting to devices",
)
name_template = TextVar(
required=False,
description="Jinja2 template code for the device name in Data source. "
"Reference the object as <code>{{ object }}</code>.",
)

def run_script(self, data: dict) -> None:
devices = self.validate_data(data)
Expand Down Expand Up @@ -155,17 +161,26 @@ def get_devices_with_rendered_configs(self, devices: Iterable[Device]) -> Iterat
auth_secondary=auth_secondary,
rendered_config=rendered_config,
error=error,
device=device,
)

def get_config_from_datasource(self, devices: list[ConplianceDeviceDataClass]) -> None:
for device in devices:
if df := DataFile.objects.filter(source=self.data["data_source"], path__icontains=device.name).first():
if self.data["name_template"]:
try:
device_name = render_jinja2(self.data["name_template"], {"object": device.device}).strip()
except Exception as e:
self.log_failure(f"Error in rendering data source name for {device.name}: {e}, using device name.")
device_name = device.name
else:
device_name = device.name
if df := DataFile.objects.filter(source=self.data["data_source"], path__icontains=device_name).first():
if config := df.data_as_string:
device.actual_config = config
else:
device.error = f"Data in file {df} is broken, skiping device {device.name}"
else:
device.error = f"Not found file in DataSource for device {device.name}"
device.error = f"Not found file in DataSource for name {device_name}"

def get_actual_configs(self, devices: list[ConplianceDeviceDataClass]) -> None:
if self.data["data_source"]:
Expand Down
5 changes: 4 additions & 1 deletion netbox_config_diff/models/data_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import traceback
from dataclasses import dataclass

from dcim.models import Device
from scrapli import AsyncScrapli

from netbox_config_diff.choices import ConfigComplianceStatusChoices
Expand Down Expand Up @@ -113,10 +114,12 @@ def send_to_db(self) -> None:

class ConplianceDeviceDataClass(BaseDeviceDataClass):
command: str
device: Device | None = None

def __init__(self, command: str, **kwargs) -> None:
def __init__(self, command: str, device: Device, **kwargs) -> None:
super().__init__(**kwargs)
self.command = command
self.device = device

async def get_actual_config(self) -> None:
if self.error is not None:
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def factory(**fields: Unpack["DeviceDataClassData"]) -> "DeviceDataClassData":
"password": faker.password(),
"auth_strict_key": False,
"transport": "asyncssh",
"device": None,
}
return data | fields

Expand Down

0 comments on commit f83d730

Please sign in to comment.