Skip to content
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/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
netbox_version: &nb_versions [v4.2.9, v4.3.6, v4.4.1]
netbox_version: &nb_versions [v4.3.7, v4.4.10, v4.5.0]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
build:
os: ubuntu-22.04
tools:
python: "3.10"
python: "3.12"

mkdocs:
configuration: mkdocs.yml
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<p>
<img src="https://github.com/amyasnikov/validity/actions/workflows/ci.yml/badge.svg" alt="CI">
<img src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/amyasnikov/9e518ae8babd18b7edd8ee5aad58146b/raw/cov.json" alt="Coverage">
<img src="https://img.shields.io/badge/Python-3.10+-blue.svg" alt="Python version">
<img src="https://img.shields.io/badge/NetBox-4.2|4.3|4.4-blue.svg" alt="NetBox version">
<img src="https://img.shields.io/badge/Python-3.12+-blue.svg" alt="Python version">
<img src="https://img.shields.io/badge/NetBox-4.3|4.4|4.5-blue.svg" alt="NetBox version">
</p>
</div>

Expand Down
2 changes: 1 addition & 1 deletion development/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.10-slim-bullseye
FROM python:3.12-slim

ARG NETBOX_VERSION=develop

Expand Down
25 changes: 23 additions & 2 deletions docs/installation/netbox_compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ In the table below you can find appropriate Validity version according to your N
<table class="tg"><thead>
<tr>
<th class="tg-r82u" colspan="2" rowspan="2"></th>
<th class="tg-c6ba" colspan="9">NetBox<br></th>
<th class="tg-c6ba" colspan="10">NetBox<br></th>
</tr>
<tr>
<th class="tg-5gjp">v3.4</th>
Expand All @@ -38,10 +38,11 @@ In the table below you can find appropriate Validity version according to your N
<th class="tg-5gjp">v4.2</th>
<th class="tg-5gjp">v4.3</th>
<th class="tg-5gjp">v4.4</th>
<th class="tg-5gjp">v4.5</th>
</tr></thead>
<tbody>
<tr>
<td class="tg-5iin" rowspan="7">Validity<br><br></td>
<td class="tg-5iin" rowspan="8">Validity<br><br></td>
<td class="tg-c6ba">v1.4</td>
<td class="tg-8g55">✅</td>
<td class="tg-8g55">✅</td>
Expand All @@ -52,6 +53,7 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v2.2</td>
Expand All @@ -64,6 +66,7 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v2.3</td>
Expand All @@ -76,6 +79,7 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v3.0</td>
Expand All @@ -88,6 +92,7 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v3.1</td>
Expand All @@ -100,6 +105,7 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55">✅</td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v3.2</td>
Expand All @@ -112,6 +118,7 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55">✅</td>
<td class="tg-8g55">✅</td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v3.3</td>
Expand All @@ -124,5 +131,19 @@ In the table below you can find appropriate Validity version according to your N
<td class="tg-8g55">✅</td>
<td class="tg-8g55">✅</td>
<td class="tg-8g55">✅</td>
<td class="tg-8g55"></td>
</tr>
<tr>
<td class="tg-c6ba">v3.4</td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55"></td>
<td class="tg-8g55">✅</td>
<td class="tg-8g55">✅</td>
<td class="tg-8g55">✅</td>
</tr>
</tbody></table>
7 changes: 3 additions & 4 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
boto3<2
deepdiff>=8.6.1,<9
dimi >=1.3.0,< 2
dimi >=1.5.0,< 2
django-bootstrap5 >=24.2,<25
dulwich # Core NetBox "optional" requirement
jq>=1.4.0,<2
netmiko>=4.0.0,<5
pydantic>=2.0.0,<3
scrapli_netconf==2025.1.30
scrapli_netconf==2026.1.12
simpleeval==1.0.3
strawberry-graphql>=0.268.1 # fix strawberry-graphql/strawberry#3807 for netbox < 4.3
textfsm>=1.1.3,<2
ttp==0.9.*
ttp<1
xmltodict<1
18 changes: 9 additions & 9 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
debugpy==1.8.1
factory_boy==3.3.0
debugpy==1.8.19
factory_boy==3.3.3
ipython
pre-commit==3.7.0
pytest==8.1.1
pytest-cov==5.0.0
pytest-django==4.8.0
pytest-subtests==0.12.1
ruff==0.3.4
tomli==2.0.1
pre-commit==4.5.1
pytest==9.0.2
pytest-cov==7.0.0
pytest-django==4.11.1
pytest-subtests==0.15.0
ruff==0.14.11
tomli==2.4.0
8 changes: 3 additions & 5 deletions validity/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ class NetBoxValidityConfig(PluginConfig):
version = "3.3.2"
base_url = "validity"
django_apps = ["django_bootstrap5"]
min_version = "4.2.0"
max_version = "4.4.99"
min_version = "4.3.0"
max_version = "4.5.99"
graphql_schema = "graphql.schema"

# custom field
netbox_version = NetboxVersion(VERSION)

if netbox_version >= "4.3.0":
graphql_schema = "graphql.schema"

def _setup_queues(self):
django_settings = di["django_settings"]
for _, queue_name in di["validity_settings"].custom_queues:
Expand Down
22 changes: 11 additions & 11 deletions validity/graphql/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@
from core.models import Job
from dcim.graphql.filters import DeviceFilter
from django.db.models import Q, QuerySet
from netbox.graphql.filter_mixins import BaseFilterMixin, NetBoxModelFilterMixin
from strawberry.scalars import ID
from strawberry_django import FilterLookup

from validity import models
from validity.netbox_changes import BaseModelFilter, NetBoxModelFilter


@strawberry_django.filter_type(Job, lookups=True)
class JobFilter(NetBoxModelFilterMixin):
class JobFilter(NetBoxModelFilter):
pass


@strawberry_django.filter_type(models.ComplianceSelector, lookups=True)
class ComplianceSelectorFilter(NetBoxModelFilterMixin):
class ComplianceSelectorFilter(NetBoxModelFilter):
name: FilterLookup[str] | None = strawberry_django.filter_field()


@strawberry_django.filter_type(models.ComplianceTest, lookups=True)
class ComplianceTestFilter(NetBoxModelFilterMixin):
class ComplianceTestFilter(NetBoxModelFilter):
id: FilterLookup[ID] | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
selectors: Annotated["ComplianceSelectorFilter", strawberry.lazy("validity.graphql.filters")] | None = (
Expand All @@ -33,7 +33,7 @@ class ComplianceTestFilter(NetBoxModelFilterMixin):


@strawberry_django.filter_type(models.ComplianceTestResult, lookups=True)
class ComplianceTestResultFilter(BaseFilterMixin):
class ComplianceTestResultFilter(BaseModelFilter):
test: Annotated["ComplianceTestFilter", strawberry.lazy("validity.graphql.filters")] | None = (
strawberry_django.filter_field()
)
Expand All @@ -52,28 +52,28 @@ def latest(self, queryset: QuerySet, value: bool, prefix: str) -> tuple[QuerySet


@strawberry_django.filter_type(models.Serializer, lookups=True)
class SerializerFilter(NetBoxModelFilterMixin):
class SerializerFilter(NetBoxModelFilter):
name: FilterLookup[str] | None = strawberry_django.filter_field()


@strawberry_django.filter_type(models.NameSet, lookups=True)
class NameSetFilter(NetBoxModelFilterMixin):
class NameSetFilter(NetBoxModelFilter):
name: FilterLookup[str] | None = strawberry_django.filter_field()
_global: Annotated["bool", strawberry.lazy("builtins")] | None = strawberry_django.filter_field(name="global")


@strawberry_django.filter_type(models.ComplianceReport, lookups=True)
class ComplianceReportFilter(BaseFilterMixin):
class ComplianceReportFilter(BaseModelFilter):
jobs: list[Annotated["JobFilter", strawberry.lazy("validity.graphql.filters")]] = strawberry_django.filter_field()


@strawberry_django.filter_type(models.Poller, lookups=True)
class PollerFilter(NetBoxModelFilterMixin):
class PollerFilter(NetBoxModelFilter):
name: FilterLookup[str] | None = strawberry_django.filter_field()


@strawberry_django.filter_type(models.Command, lookups=True)
class CommandFilter(NetBoxModelFilterMixin):
class CommandFilter(NetBoxModelFilter):
name: FilterLookup[str] | None = strawberry_django.filter_field()
serializer: Annotated["SerializerFilter", strawberry.lazy("validity.graphql.filters")] | None = (
strawberry_django.filter_field()
Expand All @@ -85,7 +85,7 @@ class CommandFilter(NetBoxModelFilterMixin):


@strawberry_django.filter_type(models.BackupPoint, lookups=True)
class BackupPointFilter(NetBoxModelFilterMixin):
class BackupPointFilter(NetBoxModelFilter):
name: FilterLookup[str] | None = strawberry_django.filter_field()
data_source: Annotated["DataSourceFilter", strawberry.lazy("core.graphql.filters")] | None = (
strawberry_django.filter_field()
Expand Down
4 changes: 2 additions & 2 deletions validity/netbox_changes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
from validity import config


if config.netbox_version >= "4.4.0":
if config.netbox_version >= "4.5.0":
from .current import *
elif config.netbox_version >= "4.3.0":
elif config.netbox_version >= "4.4.0":
from .old import *
else:
from .oldest import *
23 changes: 4 additions & 19 deletions validity/netbox_changes/current.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
# NetBox 4.4
from typing import TYPE_CHECKING
# NetBox 4.5
from pydoc import locate

from .old import *


if TYPE_CHECKING:
from validity.models import ComplianceReport
from validity.scripts.data_models import RequestInfo


def get_logs(job):
return job.log_entries


def set_logs(job, logs):
job.log_entries = logs


def enqueue(report: "ComplianceReport", request: "RequestInfo"):
queue = {}
enqueue_event(queue, report, request, "object_created")
flush_events(queue.values())
BaseModelFilter = locate("netbox.graphql.filters.BaseModelFilter")
NetBoxModelFilter = locate("netbox.graphql.filters.NetBoxModelFilter")
23 changes: 22 additions & 1 deletion validity/netbox_changes/old.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,23 @@
# NetBox 4.3
# NetBox 4.4
from typing import TYPE_CHECKING

from .oldest import *


if TYPE_CHECKING:
from validity.models import ComplianceReport
from validity.scripts.data_models import RequestInfo


def get_logs(job):
return job.log_entries


def set_logs(job, logs):
job.log_entries = logs


def enqueue(report: "ComplianceReport", request: "RequestInfo"):
queue = {}
enqueue_event(queue, report, request, "object_created")
flush_events(queue.values())
7 changes: 6 additions & 1 deletion validity/netbox_changes/oldest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# NetBox 4.2
# NetBox 4.3
from pydoc import locate
from typing import TYPE_CHECKING

from extras.events import enqueue_event, flush_events
Expand All @@ -9,6 +10,10 @@
from validity.scripts.data_models import RequestInfo


BaseModelFilter = locate("netbox.graphql.filter_mixins.BaseFilterMixin")
NetBoxModelFilter = locate("netbox.graphql.filter_mixins.NetBoxModelFilterMixin")


def get_logs(job):
return job.data["log"]

Expand Down
1 change: 0 additions & 1 deletion validity/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,6 @@ class UserFactory(DjangoModelFactory):
password = factory.PostGenerationMethodCall("set_password", "admin")

is_superuser = True
is_staff = True
is_active = True

class Meta:
Expand Down
3 changes: 2 additions & 1 deletion validity/tests/test_graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class GraphQLTest:

@pytest.mark.django_db
def test_query(self, gql_query):
factories = self.factory if isinstance(self.factory, list) else [self.factory]
selftype = type(self)
factories = selftype.factory if isinstance(selftype.factory, list) else [selftype.factory]
for factory in factories:
factory()
resp = gql_query(self.query)
Expand Down