diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index 550a489..82d00da 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -355,27 +355,11 @@ class ControlPlaneCRD(ServalaModelMixin, models.Model): def __str__(self): return f"{self.service_offering} on {self.control_plane} with {self.service_definition}" - @cached_property - def group(self): - return self.service_definition.api_definition["group"] - - @cached_property - def version(self): - return self.service_definition.api_definition["version"] - - @cached_property - def kind(self): - return self.service_definition.api_definition["kind"] - - @cached_property - def kind_plural(self): - plural = self.kind.lower() - if not plural.endswith("s"): - plural = f"{plural}s" - return plural - @cached_property def resource_definition(self): + kind = self.service_definition.api_definition["kind"] + group = self.service_definition.api_definition["group"] + version = self.service_definition.api_definition["version"] client = self.control_plane.get_kubernetes_client() extensions_api = kubernetes.client.ApiextensionsV1Api(client) @@ -384,10 +368,10 @@ class ControlPlaneCRD(ServalaModelMixin, models.Model): for crd in crds.items: if matching_crd: break - if crd.spec.group == self.group: + if crd.spec.group == group: for served_version in crd.spec.versions: - if served_version.name == self.version and served_version.served: - if crd.spec.names.kind == self.kind: + if served_version.name == version and served_version.served: + if crd.spec.names.kind == kind: matching_crd = crd break return matching_crd @@ -398,8 +382,9 @@ class ControlPlaneCRD(ServalaModelMixin, models.Model): if result := cache.get(cache_key): return result + version = self.service_definition.api_definition["version"] for v in self.resource_definition.spec.versions: - if v.name == self.version: + if v.name == version: result = v.schema.open_apiv3_schema.to_dict() timeout_seconds = 60 * 60 * 24 cache.set(cache_key, result, timeout=timeout_seconds) @@ -410,9 +395,9 @@ class ControlPlaneCRD(ServalaModelMixin, models.Model): from servala.core.crd import generate_django_model kwargs = { - "group": self.group, - "version": self.version, - "kind": self.kind, + key: value + for key, value in self.service_definition.api_definition.items() + if key in ("group", "version", "kind") } return generate_django_model(self.resource_schema, **kwargs) @@ -532,9 +517,12 @@ class ServiceInstance(ServalaModelMixin, models.Model): ) try: + 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"{context.group}/{context.version}", - "kind": context.kind, + "apiVersion": f"{group}/{version}", + "kind": kind, "metadata": { "name": name, "namespace": organization.namespace, @@ -546,11 +534,15 @@ class ServiceInstance(ServalaModelMixin, models.Model): 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=context.group, - version=context.version, + group=group, + version=version, namespace=organization.namespace, - plural=context.kind_plural, + plural=plural, body=create_data, ) except Exception as e: @@ -564,121 +556,3 @@ class ServiceInstance(ServalaModelMixin, models.Model): raise ValidationError(_("Kubernetes API error: {}").format(str(e))) raise ValidationError(_("Error creating instance: {}").format(str(e))) return instance - - @cached_property - def kubernetes_object(self): - """Fetch the Kubernetes custom resource object""" - try: - api_instance = client.CustomObjectsApi( - self.context.control_plane.get_kubernetes_client() - ) - - return api_instance.get_namespaced_custom_object( - group=self.context.group, - version=self.context.version, - namespace=self.organization.namespace, - plural=self.context.kind_plural, - name=self.name, - ) - except ApiException as e: - if e.status == 404: - return None - raise - - @cached_property - def spec(self): - if not self.kubernetes_object: - return {} - if not (spec := self.kubernetes_object.get("spec")): - return {} - - # Remove fields that shouldn't be displayed - spec = spec.copy() - spec.pop("resourceRef", None) - spec.pop("writeConnectionSecretToRef", None) - return spec - - @cached_property - def status_conditions(self): - if not self.kubernetes_object: - return [] - if not (status := self.kubernetes_object.get("status")): - return [] - return status.get("conditions") or [] - - @cached_property - def connection_credentials(self): - """ - Get connection credentials via spec.resourceRef. - The resource referenced there has the information which secret - we want in spec.writeConnectionSecretToRef.name and spec.writeConnectionSecretToRef.namespace. - """ - if not self.kubernetes_object: - return {} - if not ( - resource_ref := self.kubernetes_object.get("spec", {}).get("resourceRef") - ): - return {} - - try: - group = resource_ref.get("apiVersion", "").split("/")[0] - version = resource_ref.get("apiVersion", "").split("/")[1] - kind = resource_ref.get("kind") - name = resource_ref.get("name") - namespace = resource_ref.get("namespace", self.organization.namespace) - - if not all([group, version, kind, name]): - return {} - - plural = kind.lower() - if not plural.endswith("s"): - plural = f"{plural}s" - - api_instance = client.CustomObjectsApi( - self.context.control_plane.get_kubernetes_client() - ) - - referenced_obj = api_instance.get_namespaced_custom_object( - group=group, - version=version, - namespace=namespace, - plural=plural, - name=name, - ) - - secret_ref = referenced_obj.get("spec", {}).get( - "writeConnectionSecretToRef" - ) - if not secret_ref: - return {} - - secret_name = secret_ref.get("name") - secret_namespace = secret_ref.get("namespace", namespace) - - if not secret_name: - return {} - - # Get the secret data - v1 = kubernetes.client.CoreV1Api( - self.context.control_plane.get_kubernetes_client() - ) - secret = v1.read_namespaced_secret( - name=secret_name, namespace=secret_namespace - ) - - # Secret data is base64 encoded - credentials = {} - if hasattr(secret, "data") and secret.data: - import base64 - - for key, value in secret.data.items(): - try: - credentials[key] = base64.b64decode(value).decode("utf-8") - except Exception: - credentials[key] = f"" - - return credentials - except ApiException as e: - return {"error": str(e)} - except Exception as e: - return {"error": str(e)} diff --git a/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html b/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html index b4049a8..7a949f1 100644 --- a/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html +++ b/src/servala/frontend/templates/frontend/organizations/service_instance_detail.html @@ -7,13 +7,11 @@ {% endblock html_title %} {% block content %}
-
-
-
-
-

{% translate "Details" %}

-
-
+
+
+
+
+
{% translate "Details" %}
{% translate "Service" %}
@@ -51,119 +49,6 @@
- {% if instance.status_conditions %} -
-
-
-

{% translate "Status" %}

-
-
-
-
- - - - - - - - - - - - {% for condition in instance.status_conditions %} - - - - - - - - {% endfor %} - -
{% translate "Type" %}{% translate "Status" %}{% translate "Last Transition Time" %}{% translate "Reason" %}{% translate "Message" %}
{{ condition.type }} - {% if condition.status == "True" %} - True - {% elif condition.status == "False" %} - False - {% else %} - {{ condition.status }} - {% endif %} - {{ condition.lastTransitionTime }}{{ condition.reason }}{{ condition.message }}
-
-
-
-
-
- {% endif %} - {% if instance.spec %} -
-
-
-

{% translate "Specification" %}

-
-
-
- - - - - - - - - {% for key, value in instance.spec.items %} - - - - - {% endfor %} - -
{% translate "Property" %}{% translate "Value" %}
{{ key }} - {% if value|default:""|stringformat:"s"|slice:":1" == "{" or value|default:""|stringformat:"s"|slice:":1" == "[" %} -
{{ value|pprint }}
- {% else %} - {{ value }} - {% endif %} -
-
-
-
-
- {% endif %} - {% if instance.connection_credentials %} -
-
-

{% translate "Connection Credentials" %}

-
-
-
- - - - - - - - - {% for key, value in instance.connection_credentials.items %} - - - - - {% endfor %} - -
{% translate "Name" %}{% translate "Value" %}
{{ key }} - {% if key == "error" %} - {{ value }} - {% else %} - {{ value }} - {% endif %} -
-
-
-
- {% endif %}
{% endblock content %} diff --git a/src/servala/frontend/templatetags/pprint_filters.py b/src/servala/frontend/templatetags/pprint_filters.py deleted file mode 100644 index e20772e..0000000 --- a/src/servala/frontend/templatetags/pprint_filters.py +++ /dev/null @@ -1,12 +0,0 @@ -import json - -from django import template - -register = template.Library() - - -@register.filter -def pprint(value): - if isinstance(value, (dict, list)): - return json.dumps(value, indent=2) - return value