6aea953734
- Add SpawnService with container lifecycle (spawn/stop/status) - Generate Docker Compose services from tool manifests - Integrate Traefik label generation with subdomain routing - Mount workspace, config, and SSH key volumes - Add container status polling and health checks - Enhance tool instance API with spawn/stop/start/status endpoints - Add Traefik forwardAuth middleware for auth proxy - Update code-server manifest with runtime configuration
102 lines
3.3 KiB
Python
102 lines
3.3 KiB
Python
class TraefikLabelGenerator:
|
|
def __init__(self, domain: str, entrypoint: str = "websecure"):
|
|
self.domain = domain
|
|
self.entrypoint = entrypoint
|
|
|
|
def generate_subdomain(
|
|
self,
|
|
tool_key: str,
|
|
project_slug: str,
|
|
user_slug: str,
|
|
) -> str:
|
|
return f"{tool_key}-{project_slug}-{user_slug}.{self.domain}"
|
|
|
|
def generate_labels(
|
|
self,
|
|
instance_id: str,
|
|
tool_key: str,
|
|
project_slug: str,
|
|
user_slug: str,
|
|
container_port: int,
|
|
network_name: str = "tools",
|
|
) -> dict[str, str]:
|
|
subdomain = self.generate_subdomain(tool_key, project_slug, user_slug)
|
|
router_name = f"tool-{instance_id[:8]}"
|
|
service_name = f"tool-{instance_id[:8]}"
|
|
|
|
labels: dict[str, str] = {}
|
|
|
|
labels["traefik.enable"] = "true"
|
|
|
|
labels[f"traefik.http.routers.{router_name}.rule"] = (
|
|
f"Host(`{subdomain}`)"
|
|
)
|
|
labels[f"traefik.http.routers.{router_name}.entrypoints"] = (
|
|
self.entrypoint
|
|
)
|
|
labels[f"traefik.http.routers.{router_name}.service"] = service_name
|
|
|
|
if self.entrypoint == "websecure":
|
|
labels[f"traefik.http.routers.{router_name}.tls"] = "true"
|
|
labels[
|
|
f"traefik.http.routers.{router_name}.tls.certresolver"
|
|
] = "letsencrypt"
|
|
|
|
labels[f"traefik.http.services.{service_name}.loadbalancer.server.port"] = (
|
|
str(container_port)
|
|
)
|
|
labels[f"traefik.http.services.{service_name}.loadbalancer.server.scheme"] = (
|
|
"http"
|
|
)
|
|
|
|
middleware_name = f"tool-{instance_id[:8]}-sec"
|
|
labels[
|
|
f"traefik.http.middlewares.{middleware_name}.headers.stsSeconds"
|
|
] = "31536000"
|
|
labels[
|
|
f"traefik.http.middlewares.{middleware_name}.headers.stsIncludeSubdomains"
|
|
] = "true"
|
|
labels[
|
|
f"traefik.http.middlewares.{middleware_name}.headers.forceStsHeader"
|
|
] = "true"
|
|
labels[
|
|
f"traefik.http.middlewares.{middleware_name}.headers.contentTypeNosniff"
|
|
] = "true"
|
|
labels[
|
|
f"traefik.http.middlewares.{middleware_name}.headers.browserXssFilter"
|
|
] = "true"
|
|
labels[
|
|
f"traefik.http.middlewares.{middleware_name}.headers.customFrameOptionsValue"
|
|
] = "SAMEORIGIN"
|
|
|
|
labels[f"traefik.http.routers.{router_name}.middlewares"] = middleware_name
|
|
|
|
labels["traefik.docker.network"] = network_name
|
|
|
|
return labels
|
|
|
|
def generate_forward_auth_labels(
|
|
self,
|
|
instance_id: str,
|
|
auth_url: str,
|
|
) -> dict[str, str]:
|
|
router_name = f"tool-{instance_id[:8]}"
|
|
middleware_name = f"tool-{instance_id[:8]}-auth"
|
|
|
|
return {
|
|
f"traefik.http.middlewares.{middleware_name}.forwardauth.address": auth_url,
|
|
f"traefik.http.middlewares.{middleware_name}.forwardauth.trustForwardHeader": "true",
|
|
f"traefik.http.routers.{router_name}.middlewares": middleware_name,
|
|
}
|
|
|
|
def generate_removal_labels(
|
|
self,
|
|
instance_id: str,
|
|
) -> dict[str, str]:
|
|
router_name = f"tool-{instance_id[:8]}"
|
|
|
|
return {
|
|
"traefik.enable": "false",
|
|
f"traefik.http.routers.{router_name}.rule": "",
|
|
}
|