From 332724fbdef0a1e7876198e526a3ec8f2297d9b2 Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Mon, 24 Mar 2025 15:21:13 +0100 Subject: [PATCH] Add ServiceDefinition admin integration --- src/servala/core/admin.py | 30 +++++++++++++++++- src/servala/core/forms.py | 64 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/servala/core/admin.py b/src/servala/core/admin.py index c1e65c6..c521cb6 100644 --- a/src/servala/core/admin.py +++ b/src/servala/core/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin, messages from django.utils.translation import gettext_lazy as _ -from servala.core.forms import ControlPlaneAdminForm +from servala.core.forms import ControlPlaneAdminForm, ServiceDefinitionAdminForm from servala.core.models import ( BillingEntity, CloudProvider, @@ -12,6 +12,7 @@ from servala.core.models import ( Plan, Service, ServiceCategory, + ServiceDefinition, ServiceOffering, User, ) @@ -170,6 +171,33 @@ class PlanAdmin(admin.ModelAdmin): autocomplete_fields = ("service_offering",) +@admin.register(ServiceDefinition) +class ServiceDefinitionAdmin(admin.ModelAdmin): + form = ServiceDefinitionAdminForm + list_display = ("name", "service", "control_plane") + list_filter = ("service", "control_plane") + search_fields = ("name", "description") + autocomplete_fields = ("service", "control_plane") + + fieldsets = ( + ( + None, + {"fields": ("name", "description", "service", "control_plane")}, + ), + ( + _("API Definition"), + { + "fields": ("api_group", "api_version", "api_kind"), + "description": _("API definition for the Kubernetes Custom Resource"), + }, + ), + ) + + def get_exclude(self, request, obj=None): + # Exclude the original api_definition field as we're using our custom fields + return ["api_definition"] + + @admin.register(ServiceOffering) class ServiceOfferingAdmin(admin.ModelAdmin): list_display = ("id", "service", "provider") diff --git a/src/servala/core/forms.py b/src/servala/core/forms.py index d7740ae..1fece41 100644 --- a/src/servala/core/forms.py +++ b/src/servala/core/forms.py @@ -1,7 +1,7 @@ from django import forms from django.utils.translation import gettext_lazy as _ -from servala.core.models import ControlPlane +from servala.core.models import ControlPlane, ServiceDefinition class ControlPlaneAdminForm(forms.ModelForm): @@ -70,3 +70,65 @@ class ControlPlaneAdminForm(forms.ModelForm): def save(self, *args, **kwargs): self.instance.api_credentials = self.cleaned_data["api_credentials"] return super().save(*args, **kwargs) + + +class ServiceDefinitionAdminForm(forms.ModelForm): + api_group = forms.CharField( + required=False, + help_text=_("API Group"), + ) + api_version = forms.CharField( + required=False, + help_text=_("API Version"), + ) + api_kind = forms.CharField( + required=False, + help_text=_("API Kind"), + ) + + class Meta: + model = ServiceDefinition + fields = "__all__" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # If we have existing api_definition, populate the individual fields + if self.instance.pk and self.instance.api_definition: + api_def = self.instance.api_definition + self.fields["api_group"].initial = api_def.get("group", "") + self.fields["api_version"].initial = api_def.get("version", "") + self.fields["api_kind"].initial = api_def.get("kind", "") + + def clean(self): + cleaned_data = super().clean() + + api_group = cleaned_data.get("api_group") + api_version = cleaned_data.get("api_version") + api_kind = cleaned_data.get("api_kind") + + if api_group and api_version and api_kind: + cleaned_data["api_definition"] = { + "group": api_group, + "version": api_version, + "kind": api_kind, + } + else: + if not (api_group or api_version or api_kind): + cleaned_data["api_definition"] = {} + else: + # Some fields are filled but not all – validation will fail at model level. + api_def = {} + if api_group: + api_def["group"] = api_group + if api_version: + api_def["version"] = api_version + if api_kind: + api_def["kind"] = api_kind + cleaned_data["api_definition"] = api_def + + return cleaned_data + + def save(self, *args, **kwargs): + self.instance.api_definition = self.cleaned_data["api_definition"] + return super().save(*args, **kwargs)