Generate organization namespaces

This commit is contained in:
Tobias Kunze 2025-04-09 16:05:31 +02:00
parent d53804b8d0
commit 973988c91e
5 changed files with 40 additions and 27 deletions

View file

@ -65,8 +65,7 @@ class OrganizationAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
readonly_fields = list(super().get_readonly_fields(request, obj) or []) 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") # Always read-only
readonly_fields.append("namespace")
return readonly_fields return readonly_fields

View file

@ -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",
),
),
]

View file

@ -9,19 +9,19 @@ from django_scopes import ScopedManager, scopes_disabled
from servala.core import rules as perms from servala.core import rules as perms
from servala.core.models.mixins import ServalaModelMixin from servala.core.models.mixins import ServalaModelMixin
from servala.core.validators import kubernetes_name_validator
class Organization(ServalaModelMixin, models.Model): class Organization(ServalaModelMixin, models.Model):
name = models.CharField(max_length=100, verbose_name=_("Name")) 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( namespace = models.CharField(
max_length=63, max_length=20,
verbose_name=_("Kubernetes Namespace"), verbose_name=_("Kubernetes Namespace"),
null=True,
unique=True, unique=True,
help_text=_( help_text=_("This namespace will be used for all Kubernetes resources."),
"This namespace will be used for all Kubernetes resources. Cannot be changed after creation."
),
validators=[kubernetes_name_validator],
) )
billing_entity = models.ForeignKey( billing_entity = models.ForeignKey(
@ -90,6 +90,13 @@ class Organization(ServalaModelMixin, models.Model):
def __str__(self): def __str__(self):
return self.name 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): class BillingEntity(ServalaModelMixin, models.Model):
""" """

View file

@ -1,6 +1,4 @@
from django import forms
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import gettext_lazy as _
from servala.core.models import Organization from servala.core.models import Organization
from servala.frontend.forms.mixins import HtmxMixin from servala.frontend.forms.mixins import HtmxMixin
@ -9,19 +7,4 @@ from servala.frontend.forms.mixins import HtmxMixin
class OrganizationForm(HtmxMixin, ModelForm): class OrganizationForm(HtmxMixin, ModelForm):
class Meta: class Meta:
model = Organization model = Organization
fields = ("name", "namespace") fields = ("name",)
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."
)
}

View file

@ -52,7 +52,7 @@
</th> </th>
<td> <td>
<div>{{ form.instance.namespace }}</div> <div>{{ form.instance.namespace }}</div>
<small class="text-muted">{% translate "The namespace cannot be changed after creation." %}</small> <small class="text-muted">{% translate "System-generated namespace for Kubernetes resources." %}</small>
</td> </td>
</tr> </tr>
</tbody> </tbody>