diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index ea8c973..b4d27b3 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -1,5 +1,6 @@ import copy import json +import re import kubernetes import rules @@ -604,6 +605,32 @@ class ServiceInstance(ServalaModelMixin, models.Model): spec_data = prune_empty_data(spec_data) return spec_data + @classmethod + def _format_kubernetes_error(cls, error_message): + """ + Format Kubernetes API error messages for better user experience. + Converts validation error arrays into unordered lists. + """ + # Pattern to match validation errors in brackets + pattern = r"\[([^\]]+)\]" + match = re.search(pattern, error_message) + + if not match: + return error_message + + errors_text = match.group(1) + # Split by comma and clean up each error + errors = [error.strip() for error in errors_text.split(",")] + + if len(errors) > 1: + # Format as HTML unordered list + error_list = "".join(f"
  • {error}
  • " for error in errors) + # Replace the bracketed section with the formatted list + formatted_message = re.sub(pattern, f"", error_message) + return mark_safe(formatted_message) + + return error_message + @classmethod def create_instance(cls, name, organization, context, created_by, spec_data): # Ensure the namespace exists @@ -657,12 +684,21 @@ class ServiceInstance(ServalaModelMixin, models.Model): try: error_body = json.loads(e.body) reason = error_body.get("message", str(e)) - message = _(f"Kubernetes API error: {reason}.") + formatted_reason = cls._format_kubernetes_error(reason) + message = _("Error reported by control plane: {reason}").format( + reason=formatted_reason + ) raise ValidationError(organization.add_support_message(message)) except (ValueError, TypeError): - message = _(f"Kubernetes API error: {str(e)}.") + formatted_error = cls._format_kubernetes_error(str(e)) + message = _("Error reported by control plane: {error}").format( + error=formatted_error + ) raise ValidationError(organization.add_support_message(message)) - message = _(f"Error creating instance: {str(e)}.") + formatted_error = cls._format_kubernetes_error(str(e)) + message = _("Error creating instance: {error}").format( + error=formatted_error + ) raise ValidationError(organization.add_support_message(message)) return instance @@ -685,19 +721,28 @@ class ServiceInstance(ServalaModelMixin, models.Model): except ApiException as e: if e.status == 404: message = _( - "Service instance not found in Kubernetes. It may have been deleted externally." + "Service instance not found in control plane. It may have been deleted externally." ) raise ValidationError(self.organization.add_support_message(message)) try: error_body = json.loads(e.body) reason = error_body.get("message", str(e)) - message = _(f"Kubernetes API error updating instance: {reason}.") + formatted_reason = self._format_kubernetes_error(reason) + message = _( + "Error reported by control plane while updating instance: {reason}" + ).format(reason=formatted_reason) raise ValidationError(self.organization.add_support_message(message)) except (ValueError, TypeError): - message = _(f"Kubernetes API error updating instance: {str(e)}.") + formatted_error = self._format_kubernetes_error(str(e)) + message = _( + "Error reported by control plane while updating instance: {error}" + ).format(error=formatted_error) raise ValidationError(self.organization.add_support_message(message)) except Exception as e: - message = _(f"Error updating instance: {str(e)}.") + formatted_error = self._format_kubernetes_error(str(e)) + message = _("Error updating instance: {error}").format( + error=formatted_error + ) raise ValidationError(self.organization.add_support_message(message)) @transaction.atomic