Initial commit
This commit is contained in:
commit
4ff9eac274
45 files changed
+2911
No files matched your search
@@ -0,0 +1,197 @@
|
||||
import json
|
||||
|
||||
import yaml
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from netbox.forms import (
|
||||
NetBoxModelBulkEditForm,
|
||||
NetBoxModelFilterSetForm,
|
||||
NetBoxModelForm,
|
||||
NetBoxModelImportForm,
|
||||
PrimaryModelForm,
|
||||
)
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms.fields import (
|
||||
DynamicModelChoiceField,
|
||||
DynamicModelMultipleChoiceField,
|
||||
TagFilterField,
|
||||
)
|
||||
from utilities.forms.rendering import FieldSet
|
||||
|
||||
from .models import (
|
||||
Service,
|
||||
ServiceStatusChoices,
|
||||
ServiceTemplate,
|
||||
ServiceTemplateStatusChoices,
|
||||
validate_tree,
|
||||
)
|
||||
|
||||
|
||||
# ── Service Template ─────────────────────────────────────────────────
|
||||
|
||||
class ServiceTemplateForm(PrimaryModelForm):
|
||||
tree_raw = forms.CharField(
|
||||
label=_("Requirement tree"),
|
||||
required=False,
|
||||
widget=forms.Textarea(
|
||||
attrs={
|
||||
"rows": 20,
|
||||
"class": "font-monospace",
|
||||
"placeholder": (
|
||||
'- name: routers\n'
|
||||
' object_type: dcim.device\n'
|
||||
' quantity: 2\n'
|
||||
' selector:\n'
|
||||
' type: netbox_filter\n'
|
||||
' filters:\n'
|
||||
' role: router\n'
|
||||
' children:\n'
|
||||
' - name: mgmt-ip\n'
|
||||
' object_type: ipam.ipaddress\n'
|
||||
' allocation:\n'
|
||||
' strategy: first_free\n'
|
||||
' prefix:\n'
|
||||
' type: prefix\n'
|
||||
' filters: {}\n'
|
||||
),
|
||||
},
|
||||
),
|
||||
help_text=_("Enter the requirement tree as YAML or JSON."),
|
||||
)
|
||||
|
||||
fieldsets = (
|
||||
FieldSet("name", "status", "tree_raw", name=_("Service Template")),
|
||||
FieldSet("description", "tags", name=_("Metadata")),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = ServiceTemplate
|
||||
fields = ("name", "status", "description", "comments")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.instance and self.instance.pk and self.instance.tree:
|
||||
self.fields["tree_raw"].initial = yaml.dump(
|
||||
self.instance.tree, default_flow_style=False, sort_keys=False,
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
raw = self.cleaned_data.get("tree_raw", "").strip()
|
||||
if not raw:
|
||||
self.instance.tree = []
|
||||
return self.cleaned_data
|
||||
|
||||
tree = None
|
||||
try:
|
||||
tree = json.loads(raw)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
pass
|
||||
|
||||
if tree is None:
|
||||
try:
|
||||
tree = yaml.safe_load(raw)
|
||||
except yaml.YAMLError as exc:
|
||||
self.add_error("tree_raw", _(f"Invalid YAML or JSON: {exc}"))
|
||||
return self.cleaned_data
|
||||
|
||||
if tree is None:
|
||||
tree = []
|
||||
|
||||
self.instance.tree = tree
|
||||
self.instance._tree_validated_by_form = True
|
||||
|
||||
try:
|
||||
validate_tree(tree)
|
||||
except ValidationError as exc:
|
||||
self.add_error("tree_raw", ValidationError(exc.messages))
|
||||
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
class ServiceTemplateFilterSetForm(NetBoxModelFilterSetForm):
|
||||
model = ServiceTemplate
|
||||
name = forms.CharField(required=False)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=ServiceTemplateStatusChoices,
|
||||
required=False,
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm):
|
||||
model = ServiceTemplate
|
||||
status = forms.ChoiceField(
|
||||
choices=ServiceTemplateStatusChoices,
|
||||
required=False,
|
||||
)
|
||||
description = forms.CharField(required=False)
|
||||
nullable_fields = ("description",)
|
||||
|
||||
|
||||
class ServiceTemplateImportForm(NetBoxModelImportForm):
|
||||
class Meta:
|
||||
model = ServiceTemplate
|
||||
fields = ("name", "status", "description", "comments", "tags")
|
||||
|
||||
|
||||
# ── Service ──────────────────────────────────────────────────────────
|
||||
|
||||
class ServiceForm(PrimaryModelForm):
|
||||
service_template = DynamicModelChoiceField(
|
||||
queryset=ServiceTemplate.objects.all(),
|
||||
)
|
||||
tenant = DynamicModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
)
|
||||
|
||||
fieldsets = (
|
||||
FieldSet("name", "service_template", "tenant", "status", "description", "tags", name=_("Service")),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
fields = ("name", "service_template", "tenant", "status", "description", "comments")
|
||||
|
||||
|
||||
class ServiceFilterSetForm(NetBoxModelFilterSetForm):
|
||||
model = Service
|
||||
name = forms.CharField(required=False)
|
||||
service_template = DynamicModelMultipleChoiceField(
|
||||
queryset=ServiceTemplate.objects.all(),
|
||||
required=False,
|
||||
)
|
||||
tenant = DynamicModelMultipleChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False,
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=ServiceStatusChoices,
|
||||
required=False,
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
class ServiceBulkEditForm(NetBoxModelBulkEditForm):
|
||||
model = Service
|
||||
status = forms.ChoiceField(
|
||||
choices=ServiceStatusChoices,
|
||||
required=False,
|
||||
)
|
||||
description = forms.CharField(required=False)
|
||||
nullable_fields = ("description",)
|
||||
|
||||
|
||||
# ── Resolve form ─────────────────────────────────────────────────────
|
||||
|
||||
class ResolveForm(forms.Form):
|
||||
mode = forms.ChoiceField(
|
||||
choices=(
|
||||
("dry_run", _("Dry Run")),
|
||||
("commit", _("Commit")),
|
||||
),
|
||||
initial="dry_run",
|
||||
widget=forms.RadioSelect,
|
||||
)
|
||||
Reference in new issue
Block a user