diff --git a/src/servala/core/admin.py b/src/servala/core/admin.py index 7d110d1..746d5da 100644 --- a/src/servala/core/admin.py +++ b/src/servala/core/admin.py @@ -65,8 +65,7 @@ class OrganizationAdmin(admin.ModelAdmin): def get_readonly_fields(self, request, obj=None): readonly_fields = list(super().get_readonly_fields(request, obj) or []) - if obj: # If this is an edit (not a new organization) - readonly_fields.append("namespace") + readonly_fields.append("namespace") # Always read-only return readonly_fields diff --git a/src/servala/core/migrations/0003_alter_organization_namespace.py b/src/servala/core/migrations/0003_alter_organization_namespace.py new file mode 100644 index 0000000..3a01990 --- /dev/null +++ b/src/servala/core/migrations/0003_alter_organization_namespace.py @@ -0,0 +1,24 @@ +# Generated by Django 5.2b1 on 2025-04-09 14:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0002_alter_controlplanecrd_options_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="organization", + name="namespace", + field=models.CharField( + help_text="This namespace will be used for all Kubernetes resources.", + max_length=20, + null=True, + unique=True, + verbose_name="Kubernetes Namespace", + ), + ), + ] diff --git a/src/servala/core/models/organization.py b/src/servala/core/models/organization.py index 62894d5..7ebda11 100644 --- a/src/servala/core/models/organization.py +++ b/src/servala/core/models/organization.py @@ -9,19 +9,19 @@ from django_scopes import ScopedManager, scopes_disabled from servala.core import rules as perms from servala.core.models.mixins import ServalaModelMixin -from servala.core.validators import kubernetes_name_validator class Organization(ServalaModelMixin, models.Model): name = models.CharField(max_length=100, verbose_name=_("Name")) + # The namespace is generated as "org-{id}" in accordance with RFC 1035 Label Names. + # It is nullable as we need to write to the database in order to read the ID, but should + # not be null in practical use. namespace = models.CharField( - max_length=63, + max_length=20, verbose_name=_("Kubernetes Namespace"), + null=True, unique=True, - help_text=_( - "This namespace will be used for all Kubernetes resources. Cannot be changed after creation." - ), - validators=[kubernetes_name_validator], + help_text=_("This namespace will be used for all Kubernetes resources."), ) billing_entity = models.ForeignKey( @@ -90,6 +90,13 @@ class Organization(ServalaModelMixin, models.Model): def __str__(self): return self.name + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + if not self.namespace: + # Set namespace after initial save to ensure we have an ID + self.namespace = f"org-{self.pk}" + self.save(update_fields=["namespace"]) + class BillingEntity(ServalaModelMixin, models.Model): """ diff --git a/src/servala/frontend/forms/organization.py b/src/servala/frontend/forms/organization.py index d582ce9..41cc26c 100644 --- a/src/servala/frontend/forms/organization.py +++ b/src/servala/frontend/forms/organization.py @@ -1,6 +1,4 @@ -from django import forms from django.forms import ModelForm -from django.utils.translation import gettext_lazy as _ from servala.core.models import Organization from servala.frontend.forms.mixins import HtmxMixin @@ -9,19 +7,4 @@ from servala.frontend.forms.mixins import HtmxMixin class OrganizationForm(HtmxMixin, ModelForm): class Meta: model = Organization - fields = ("name", "namespace") - widgets = { - "namespace": forms.TextInput( - attrs={ - "pattern": "[a-z0-9]([-a-z0-9]*[a-z0-9])?", - "title": _( - 'Lowercase alphanumeric characters or "-", must start and end with alphanumeric' - ), - } - ) - } - help_texts = { - "namespace": _( - "This namespace will be used for all resources and cannot be changed later." - ) - } + fields = ("name",) diff --git a/src/servala/frontend/templates/frontend/organizations/update.html b/src/servala/frontend/templates/frontend/organizations/update.html index 993b76a..0d55f22 100644 --- a/src/servala/frontend/templates/frontend/organizations/update.html +++ b/src/servala/frontend/templates/frontend/organizations/update.html @@ -52,7 +52,7 @@