From a2c3695611b03648e929baa9d67fce7194de9cef Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Thu, 3 Apr 2025 16:20:52 +0200 Subject: [PATCH 1/4] Fix breaking tests --- src/tests/conftest.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tests/conftest.py b/src/tests/conftest.py index d88870e..a69e50c 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -15,12 +15,16 @@ def origin(): @pytest.fixture def organization(origin): - return Organization.objects.create(name="Test Org", origin=origin) + return Organization.objects.create( + name="Test Org", namespace="test-org", origin=origin + ) @pytest.fixture def other_organization(origin): - return Organization.objects.create(name="Test Org Alternate", origin=origin) + return Organization.objects.create( + name="Test Org Alternate", namespace="test-org-alternate", origin=origin + ) @pytest.fixture From 08fada04e032e25d6b5597609df3ac0aa53c4ecb Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Thu, 3 Apr 2025 17:17:33 +0200 Subject: [PATCH 2/4] Successfully create an instance --- src/servala/core/models/service.py | 30 +++++++++++++++++++++++++-- src/servala/frontend/views/service.py | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index 9e282a6..8156adf 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -6,7 +6,7 @@ from django.db import models from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from encrypted_fields.fields import EncryptedJSONField -from kubernetes import config +from kubernetes import client, config from kubernetes.client.rest import ApiException from servala.core.models.mixins import ServalaModelMixin @@ -137,7 +137,6 @@ class ControlPlane(ServalaModelMixin, models.Model): "clusters": [ { "cluster": { - "insecure-skip-tls-verify": True, "certificate-authority-data": self.api_credentials[ "certificate-authority-data" ], @@ -484,6 +483,33 @@ class ServiceInstance(ServalaModelMixin, models.Model): # Ensure the namespace exists context.control_plane.get_or_create_namespace(organization.namespace) + group = context.service_definition.api_definition["group"] + version = context.service_definition.api_definition["version"] + kind = context.service_definition.api_definition["kind"] + create_data = { + "apiVersion": f"{group}/{version}", + "kind": kind, + "metadata": { + "name": name, + "namespace": organization.namespace, + }, + "spec": spec_data or {}, + } + api_instance = client.CustomObjectsApi( + context.control_plane.get_kubernetes_client() + ) + plural = kind.lower() + if not plural.endswith("s"): + plural = f"{plural}s" + + api_instance.create_namespaced_custom_object( + group=group, + version=version, + namespace=organization.namespace, + plural=plural, + body=create_data, + ) + return cls.objects.create( name=name, organization=organization, diff --git a/src/servala/frontend/views/service.py b/src/servala/frontend/views/service.py index 1803dd0..c19aff5 100644 --- a/src/servala/frontend/views/service.py +++ b/src/servala/frontend/views/service.py @@ -131,7 +131,7 @@ class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView name=form.cleaned_data["name"], context=self.context_object, created_by=request.user, - spec_data=form.get_nested_data(), + spec_data=form.get_nested_data().get("spec"), ) return redirect(service_instance.urls.base) except Exception as e: From bc8c7a80b2cf499154827798a00d10ccf9288a78 Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Thu, 3 Apr 2025 17:39:49 +0200 Subject: [PATCH 3/4] Add required_label field to ControlPlane --- src/servala/core/admin.py | 2 +- ..._alter_controlplanecrd_options_and_more.py | 31 +++++++++++++++++++ src/servala/core/models/service.py | 12 +++++++ src/servala/settings.py | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/servala/core/migrations/0002_alter_controlplanecrd_options_and_more.py diff --git a/src/servala/core/admin.py b/src/servala/core/admin.py index dad3d6e..7d110d1 100644 --- a/src/servala/core/admin.py +++ b/src/servala/core/admin.py @@ -131,7 +131,7 @@ class ControlPlaneAdmin(admin.ModelAdmin): fieldsets = ( ( None, - {"fields": ("name", "description", "cloud_provider")}, + {"fields": ("name", "description", "cloud_provider", "required_label")}, ), ( _("API Credentials"), diff --git a/src/servala/core/migrations/0002_alter_controlplanecrd_options_and_more.py b/src/servala/core/migrations/0002_alter_controlplanecrd_options_and_more.py new file mode 100644 index 0000000..63cab45 --- /dev/null +++ b/src/servala/core/migrations/0002_alter_controlplanecrd_options_and_more.py @@ -0,0 +1,31 @@ +# Generated by Django 5.2b1 on 2025-04-03 15:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0001_initial"), + ] + + operations = [ + migrations.AlterModelOptions( + name="controlplanecrd", + options={ + "verbose_name": "ControlPlane CRD", + "verbose_name_plural": "ControlPlane CRDs", + }, + ), + migrations.AddField( + model_name="controlplane", + name="required_label", + field=models.CharField( + blank=True, + help_text="Label value for the 'appcat.vshn.io/provider-config' added to every instance on this plane.", + max_length=100, + null=True, + verbose_name="Required Label", + ), + ), + ] diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index 8156adf..f9afedc 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -1,5 +1,6 @@ import kubernetes import urlman +from django.conf import settings from django.core.cache import cache from django.core.exceptions import ValidationError from django.db import models @@ -106,6 +107,15 @@ class ControlPlane(ServalaModelMixin, models.Model): help_text="Required fields: certificate-authority-data, server (URL), token", validators=[validate_api_credentials], ) + required_label = models.CharField( + max_length=100, + blank=True, + null=True, + verbose_name=_("Required Label"), + help_text=_( + "Label value for the 'appcat.vshn.io/provider-config' added to every instance on this plane." + ), + ) cloud_provider = models.ForeignKey( to="CloudProvider", @@ -495,6 +505,8 @@ class ServiceInstance(ServalaModelMixin, models.Model): }, "spec": spec_data or {}, } + if label := context.control_plane.required_label: + create_data["metadata"]["labels"] = [{settings.DEFAULT_LABEL_KEY: label}] api_instance = client.CustomObjectsApi( context.control_plane.get_kubernetes_client() ) diff --git a/src/servala/settings.py b/src/servala/settings.py index 3e27e35..50b0c5e 100644 --- a/src/servala/settings.py +++ b/src/servala/settings.py @@ -210,6 +210,7 @@ LANGUAGE_COOKIE_NAME = "servala_lang" SESSION_COOKIE_NAME = "servala_sess" SESSION_COOKIE_SECURE = not DEBUG +DEFAULT_LABEL_KEY = "appcat.vshn.io/provider-config" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # TODO From a2ac202f265e8af45c5c7b6303ee652b7836ec7f Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Thu, 3 Apr 2025 17:41:07 +0200 Subject: [PATCH 4/4] Fix label metadata --- src/servala/core/models/service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index f9afedc..f60d57c 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -506,7 +506,7 @@ class ServiceInstance(ServalaModelMixin, models.Model): "spec": spec_data or {}, } if label := context.control_plane.required_label: - create_data["metadata"]["labels"] = [{settings.DEFAULT_LABEL_KEY: label}] + create_data["metadata"]["labels"] = {settings.DEFAULT_LABEL_KEY: label} api_instance = client.CustomObjectsApi( context.control_plane.get_kubernetes_client() )