| .. | .. |
|---|
| 1 | | -import os |
|---|
| 1 | +import sys |
|---|
| 2 | 2 | from typing import Any |
|---|
| 3 | 3 | |
|---|
| 4 | | -import yaml |
|---|
| 5 | 4 | from fastapi import APIRouter, Depends, HTTPException, Query |
|---|
| 6 | 5 | |
|---|
| 7 | 6 | from app.auth import verify_token |
|---|
| 8 | 7 | from app.ops_runner import run_command |
|---|
| 9 | 8 | |
|---|
| 9 | +sys.path.insert(0, "/opt/infrastructure") |
|---|
| 10 | +from toolkit.descriptor import find as find_project # noqa: E402 |
|---|
| 11 | + |
|---|
| 10 | 12 | router = APIRouter() |
|---|
| 11 | 13 | |
|---|
| 12 | 14 | _DOCKER = "docker" |
|---|
| 13 | | -_REGISTRY_PATH = os.environ.get( |
|---|
| 14 | | - "REGISTRY_PATH", |
|---|
| 15 | | - "/opt/infrastructure/servers/hetzner-vps/registry.yaml", |
|---|
| 16 | | -) |
|---|
| 17 | | - |
|---|
| 18 | | -# --------------------------------------------------------------------------- |
|---|
| 19 | | -# Registry-based name prefix lookup (cached) |
|---|
| 20 | | -# --------------------------------------------------------------------------- |
|---|
| 21 | | -_prefix_cache: dict[str, str] | None = None |
|---|
| 22 | | - |
|---|
| 23 | | - |
|---|
| 24 | | -def _load_prefixes() -> dict[str, str]: |
|---|
| 25 | | - """Load project -> name_prefix mapping from the ops registry.""" |
|---|
| 26 | | - global _prefix_cache |
|---|
| 27 | | - if _prefix_cache is not None: |
|---|
| 28 | | - return _prefix_cache |
|---|
| 29 | | - |
|---|
| 30 | | - try: |
|---|
| 31 | | - with open(_REGISTRY_PATH) as f: |
|---|
| 32 | | - data = yaml.safe_load(f) |
|---|
| 33 | | - _prefix_cache = {} |
|---|
| 34 | | - for proj_name, cfg in data.get("projects", {}).items(): |
|---|
| 35 | | - _prefix_cache[proj_name] = cfg.get("name_prefix", proj_name) |
|---|
| 36 | | - return _prefix_cache |
|---|
| 37 | | - except Exception: |
|---|
| 38 | | - return {} |
|---|
| 39 | 15 | |
|---|
| 40 | 16 | |
|---|
| 41 | 17 | # --------------------------------------------------------------------------- |
|---|
| .. | .. |
|---|
| 76 | 52 | """ |
|---|
| 77 | 53 | Resolve the actual Docker container name from project/env/service. |
|---|
| 78 | 54 | |
|---|
| 79 | | - Uses the ops registry name_prefix mapping and tries patterns in order: |
|---|
| 80 | | - 1. {env}-{prefix}-{service} (mdf, seriousletter: dev-mdf-mysql-UUID) |
|---|
| 81 | | - 2. {prefix}-{service} (ringsaday: ringsaday-website-UUID, coolify: coolify-db) |
|---|
| 82 | | - 3. {prefix}-{env} (ringsaday: ringsaday-dev-UUID) |
|---|
| 83 | | - 4. exact {prefix} (coolify infra: coolify) |
|---|
| 55 | + Loads the project descriptor and expands container_prefix for the given |
|---|
| 56 | + env (e.g. "{env}-mdf" -> "dev-mdf"), then tries: |
|---|
| 57 | + 1. {expanded_prefix}-{service} e.g. dev-mdf-wordpress |
|---|
| 58 | + 2. exact match on expanded_prefix (infra containers with no service suffix) |
|---|
| 84 | 59 | """ |
|---|
| 85 | | - prefixes = _load_prefixes() |
|---|
| 86 | | - prefix = prefixes.get(project, project) |
|---|
| 60 | + desc = find_project(project) |
|---|
| 61 | + if desc is None: |
|---|
| 62 | + raise HTTPException( |
|---|
| 63 | + status_code=404, |
|---|
| 64 | + detail=f"Project '{project}' not found", |
|---|
| 65 | + ) |
|---|
| 87 | 66 | |
|---|
| 88 | | - # Pattern 1: {env}-{prefix}-{service} |
|---|
| 89 | | - hit = await _find_by_prefix(f"{env}-{prefix}-{service}") |
|---|
| 67 | + expanded_prefix = desc.container_prefix_for(env) |
|---|
| 68 | + |
|---|
| 69 | + # Pattern 1: {expanded_prefix}-{service} |
|---|
| 70 | + hit = await _find_by_prefix(f"{expanded_prefix}-{service}") |
|---|
| 90 | 71 | if hit: |
|---|
| 91 | 72 | return hit |
|---|
| 92 | 73 | |
|---|
| 93 | | - # Pattern 2: {prefix}-{service} |
|---|
| 94 | | - hit = await _find_by_prefix(f"{prefix}-{service}") |
|---|
| 95 | | - if hit: |
|---|
| 96 | | - return hit |
|---|
| 97 | | - |
|---|
| 98 | | - # Pattern 3: {prefix}-{env} |
|---|
| 99 | | - hit = await _find_by_prefix(f"{prefix}-{env}") |
|---|
| 100 | | - if hit: |
|---|
| 101 | | - return hit |
|---|
| 102 | | - |
|---|
| 103 | | - # Pattern 4: exact match when service == prefix (e.g., coolify) |
|---|
| 104 | | - if service == prefix: |
|---|
| 105 | | - hit = await _find_exact(prefix) |
|---|
| 74 | + # Pattern 2: exact match on prefix (infrastructure containers, e.g. "coolify") |
|---|
| 75 | + if service == expanded_prefix or service == desc.name: |
|---|
| 76 | + hit = await _find_exact(expanded_prefix) |
|---|
| 106 | 77 | if hit: |
|---|
| 107 | 78 | return hit |
|---|
| 108 | 79 | |
|---|