WIP
This commit is contained in:
parent
e70a0584c9
commit
a7a5b5c8ea
43 changed files with 5531 additions and 9 deletions
223
control_plane/admin.py
Normal file
223
control_plane/admin.py
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib import messages
|
||||
from django.db.models import Count
|
||||
from django.db.models import F
|
||||
|
||||
from control_plane.models import Deployment
|
||||
from control_plane.models import HostedSite
|
||||
from control_plane.models import RuntimeService
|
||||
from control_plane.models import RuntimeServiceKind
|
||||
from control_plane.models import Tenant
|
||||
from control_plane.tasks import provision_test_runtime_services
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.db.models import QuerySet
|
||||
from django.http import HttpRequest
|
||||
|
||||
RuntimeServiceInlineBase = admin.StackedInline[RuntimeService]
|
||||
TenantAdminBase = admin.ModelAdmin[Tenant]
|
||||
HostedSiteAdminBase = admin.ModelAdmin[HostedSite]
|
||||
DeploymentAdminBase = admin.ModelAdmin[Deployment]
|
||||
RuntimeServiceAdminBase = admin.ModelAdmin[RuntimeService]
|
||||
else:
|
||||
RuntimeServiceInlineBase = admin.StackedInline
|
||||
TenantAdminBase = admin.ModelAdmin
|
||||
HostedSiteAdminBase = admin.ModelAdmin
|
||||
DeploymentAdminBase = admin.ModelAdmin
|
||||
RuntimeServiceAdminBase = admin.ModelAdmin
|
||||
|
||||
|
||||
class RuntimeServiceInline(RuntimeServiceInlineBase):
|
||||
"""Allow deployment admins to create/edit related runtime services inline."""
|
||||
|
||||
model = RuntimeService
|
||||
extra = 0
|
||||
max_num = len(RuntimeServiceKind)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
@admin.register(Tenant)
|
||||
class TenantAdmin(TenantAdminBase):
|
||||
"""Expose tenants for admin-managed smoke data setup."""
|
||||
|
||||
list_display = ("slug", "display_name")
|
||||
search_fields = ("slug", "display_name")
|
||||
ordering = ("slug",)
|
||||
|
||||
|
||||
@admin.register(HostedSite)
|
||||
class HostedSiteAdmin(HostedSiteAdminBase):
|
||||
"""Expose hosted sites so admins can build deployment test graphs."""
|
||||
|
||||
list_display = ("slug", "display_name", "tenant_slug", "service_port")
|
||||
list_filter = ("tenant",)
|
||||
search_fields = (
|
||||
"slug",
|
||||
"display_name",
|
||||
"tenant__slug",
|
||||
"tenant__display_name",
|
||||
"wsgi_module",
|
||||
)
|
||||
ordering = ("tenant__slug", "slug")
|
||||
autocomplete_fields = ("tenant",)
|
||||
list_select_related = ("tenant",)
|
||||
|
||||
def get_queryset(self, request: HttpRequest) -> QuerySet[HostedSite]:
|
||||
"""Load tenant slug values for changelist rendering.
|
||||
|
||||
Returns:
|
||||
Hosted site queryset with tenant join and tenant slug annotation.
|
||||
"""
|
||||
return (
|
||||
super()
|
||||
.get_queryset(request)
|
||||
.select_related("tenant")
|
||||
.annotate(
|
||||
tenant_slug_value=F("tenant__slug"),
|
||||
)
|
||||
)
|
||||
|
||||
@admin.display(ordering="tenant__slug", description="Tenant")
|
||||
def tenant_slug(self, hosted_site: HostedSite) -> str:
|
||||
"""Return tenant slug for changelist display and sorting."""
|
||||
return str(vars(hosted_site)["tenant_slug_value"])
|
||||
|
||||
|
||||
@admin.register(Deployment)
|
||||
class DeploymentAdmin(DeploymentAdminBase):
|
||||
"""Expose deployments and queue test container provisioning."""
|
||||
|
||||
list_display = (
|
||||
"id",
|
||||
"status",
|
||||
"tenant_slug",
|
||||
"site_slug",
|
||||
"idempotency_key",
|
||||
"guest_port",
|
||||
"runtime_service_total",
|
||||
)
|
||||
list_filter = ("status",)
|
||||
search_fields = (
|
||||
"=id",
|
||||
"idempotency_key",
|
||||
"firecracker_vm_id",
|
||||
"hosted_site__slug",
|
||||
"hosted_site__tenant__slug",
|
||||
)
|
||||
ordering = ("hosted_site__tenant__slug", "hosted_site__slug", "-created_at")
|
||||
autocomplete_fields = ("hosted_site",)
|
||||
list_select_related = ("hosted_site__tenant",)
|
||||
inlines = (RuntimeServiceInline,)
|
||||
actions = ("create_test_containers",)
|
||||
|
||||
def get_queryset(self, request: HttpRequest) -> QuerySet[Deployment]:
|
||||
"""Load related hosted site and tenant rows for admin rendering.
|
||||
|
||||
Returns:
|
||||
Deployment queryset with hosted site and tenant joined.
|
||||
"""
|
||||
return (
|
||||
super()
|
||||
.get_queryset(request)
|
||||
.select_related("hosted_site__tenant")
|
||||
.annotate(
|
||||
tenant_slug_value=F("hosted_site__tenant__slug"),
|
||||
site_slug_value=F("hosted_site__slug"),
|
||||
runtime_service_total_value=Count("runtime_services", distinct=True),
|
||||
)
|
||||
)
|
||||
|
||||
@admin.display(ordering="hosted_site__tenant__slug", description="Tenant")
|
||||
def tenant_slug(self, deployment: Deployment) -> str:
|
||||
"""Return tenant slug for changelist display and sorting."""
|
||||
return str(vars(deployment)["tenant_slug_value"])
|
||||
|
||||
@admin.display(ordering="hosted_site__slug", description="Site")
|
||||
def site_slug(self, deployment: Deployment) -> str:
|
||||
"""Return hosted site slug for changelist display and sorting."""
|
||||
return str(vars(deployment)["site_slug_value"])
|
||||
|
||||
@admin.display(description="Runtime services")
|
||||
def runtime_service_total(self, deployment: Deployment) -> int:
|
||||
"""Return total runtime services currently linked to a deployment."""
|
||||
return int(vars(deployment)["runtime_service_total_value"])
|
||||
|
||||
@admin.action(description="Queue test container provisioning")
|
||||
def create_test_containers(
|
||||
self,
|
||||
request: HttpRequest,
|
||||
queryset: QuerySet[Deployment],
|
||||
) -> None:
|
||||
"""Queue Celery jobs that seed and provision local test containers."""
|
||||
deployment_ids = [str(deployment_id) for deployment_id in queryset.values_list("id", flat=True)]
|
||||
for deployment_id in deployment_ids:
|
||||
provision_test_runtime_services.delay(deployment_id)
|
||||
|
||||
self.message_user(
|
||||
request,
|
||||
(
|
||||
f"Queued test container provisioning for {len(deployment_ids)} deployments. "
|
||||
"Run a Celery worker to execute queued jobs."
|
||||
),
|
||||
level=messages.SUCCESS,
|
||||
)
|
||||
|
||||
|
||||
@admin.register(RuntimeService)
|
||||
class RuntimeServiceAdmin(RuntimeServiceAdminBase):
|
||||
"""Expose runtime service containers to Django admin users."""
|
||||
|
||||
list_display = (
|
||||
"container_name",
|
||||
"kind",
|
||||
"status",
|
||||
"tenant_slug",
|
||||
"site_slug",
|
||||
"internal_port",
|
||||
)
|
||||
list_filter = ("kind", "status")
|
||||
search_fields = (
|
||||
"container_name",
|
||||
"network_name",
|
||||
"hostname",
|
||||
"deployment__idempotency_key",
|
||||
"deployment__hosted_site__slug",
|
||||
"deployment__hosted_site__tenant__slug",
|
||||
)
|
||||
ordering = (
|
||||
"deployment__hosted_site__tenant__slug",
|
||||
"deployment__hosted_site__slug",
|
||||
"kind",
|
||||
)
|
||||
autocomplete_fields = ("deployment",)
|
||||
list_select_related = ("deployment__hosted_site__tenant",)
|
||||
|
||||
def get_queryset(self, request: HttpRequest) -> QuerySet[RuntimeService]:
|
||||
"""Load related deployment context for changelist rendering.
|
||||
|
||||
Returns:
|
||||
Runtime service queryset with deployment, site, and tenant joined.
|
||||
"""
|
||||
return (
|
||||
super()
|
||||
.get_queryset(request)
|
||||
.select_related("deployment__hosted_site__tenant")
|
||||
.annotate(
|
||||
tenant_slug_value=F("deployment__hosted_site__tenant__slug"),
|
||||
site_slug_value=F("deployment__hosted_site__slug"),
|
||||
)
|
||||
)
|
||||
|
||||
@admin.display(ordering="deployment__hosted_site__tenant__slug", description="Tenant")
|
||||
def tenant_slug(self, runtime_service: RuntimeService) -> str:
|
||||
"""Return tenant slug for changelist display and sorting."""
|
||||
return str(vars(runtime_service)["tenant_slug_value"])
|
||||
|
||||
@admin.display(ordering="deployment__hosted_site__slug", description="Site")
|
||||
def site_slug(self, runtime_service: RuntimeService) -> str:
|
||||
"""Return hosted site slug for changelist display and sorting."""
|
||||
return str(vars(runtime_service)["site_slug_value"])
|
||||
Loading…
Add table
Add a link
Reference in a new issue