feat: project scaffold with models, config, and test fixtures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache/
|
||||||
|
*.egg-info/
|
||||||
|
venv/
|
||||||
|
.env
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerInfo(BaseModel):
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
status: str
|
||||||
|
image: str
|
||||||
|
created: str
|
||||||
|
uptime: str | None = None
|
||||||
|
is_swarm: bool = False
|
||||||
|
swarm_service: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerAction(BaseModel):
|
||||||
|
success: bool
|
||||||
|
message: str
|
||||||
|
|
||||||
|
|
||||||
|
class LogsResponse(BaseModel):
|
||||||
|
container: str
|
||||||
|
logs: str
|
||||||
|
|
||||||
|
|
||||||
|
class HealthResponse(BaseModel):
|
||||||
|
status: str
|
||||||
|
hostname: str
|
||||||
|
containers_total: int
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fastapi>=0.115.0
|
||||||
|
uvicorn>=0.34.0
|
||||||
|
docker>=7.0.0
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{"name": "hf-pdocker-01", "host": "192.168.86.192", "agent_port": 8889},
|
||||||
|
{"name": "hf-pdocker-02", "host": "192.168.86.100", "agent_port": 8889},
|
||||||
|
{"name": "bart", "host": "192.168.86.167", "agent_port": 8889}
|
||||||
|
]
|
||||||
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"id": "ai-agents",
|
||||||
|
"name": "AI Agents",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "ai-agents_margaret"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "ai-agents_spirit"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "ai-agents_bob"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "ai-agents_clippy"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "smart-home",
|
||||||
|
"name": "Smart Home",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "smarthome_homeassistant"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "smarthome_esphome"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "smarthome_mosquitto"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "monitoring",
|
||||||
|
"name": "Monitoring",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "monitoring_grafana"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "monitoring_prometheus"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "monitoring_alertmanager"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "monitoring_influxdb"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "monitoring_blackbox-exporter"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media",
|
||||||
|
"name": "Media",
|
||||||
|
"services": [
|
||||||
|
{"node": "bart", "container": "jellyfin"},
|
||||||
|
{"node": "bart", "container": "sonarr"},
|
||||||
|
{"node": "bart", "container": "radarr"},
|
||||||
|
{"node": "bart", "container": "sabnzbd"},
|
||||||
|
{"node": "bart", "container": "nzbhydra2"},
|
||||||
|
{"node": "bart", "container": "jellyseerr"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "matrix",
|
||||||
|
"name": "Matrix",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "matrix_synapse"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "matrix_synapse-db"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "matrix_wellknown"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "guacamole",
|
||||||
|
"name": "Guacamole",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "guacamole_guacamole"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "guacamole_guacd"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "guacamole_guacamole-db"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dev-tools",
|
||||||
|
"name": "Dev Tools",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-02", "container": "gitea"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "gitea-db"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "semaphore"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "semaphore-db"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "wikijs"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "wikijs-db"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "security",
|
||||||
|
"name": "Security",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-02", "container": "vaultwarden"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "trivy"},
|
||||||
|
{"node": "bart", "container": "openvas"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "network",
|
||||||
|
"name": "Network",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "traefik_traefik"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "adguard_adguardhome"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "unifi"},
|
||||||
|
{"node": "hf-pdocker-02", "container": "unifi-db"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "frigate",
|
||||||
|
"name": "Frigate",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "frigate"},
|
||||||
|
{"node": "hf-pdocker-01", "container": "frigate-notify"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class NodeConfig(BaseModel):
|
||||||
|
name: str
|
||||||
|
host: str
|
||||||
|
agent_port: int = 8889
|
||||||
|
|
||||||
|
|
||||||
|
class NodeStatus(BaseModel):
|
||||||
|
name: str
|
||||||
|
host: str
|
||||||
|
healthy: bool
|
||||||
|
containers_total: int = 0
|
||||||
|
error: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceRef(BaseModel):
|
||||||
|
node: str
|
||||||
|
container: str
|
||||||
|
|
||||||
|
|
||||||
|
class Group(BaseModel):
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
services: list[ServiceRef] = []
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsData(BaseModel):
|
||||||
|
groups: list[Group] = []
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceInfo(BaseModel):
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
node: str
|
||||||
|
status: str
|
||||||
|
image: str
|
||||||
|
created: str
|
||||||
|
uptime: str | None = None
|
||||||
|
is_swarm: bool = False
|
||||||
|
swarm_service: str | None = None
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fastapi>=0.115.0
|
||||||
|
uvicorn>=0.34.0
|
||||||
|
httpx>=0.28.0
|
||||||
|
aiofiles>=24.1.0
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sample_container():
|
||||||
|
return {
|
||||||
|
"id": "abc123",
|
||||||
|
"name": "test-container",
|
||||||
|
"status": "running",
|
||||||
|
"image": "nginx:latest",
|
||||||
|
"created": "2026-03-05T00:00:00Z",
|
||||||
|
"uptime": "2 hours",
|
||||||
|
"is_swarm": False,
|
||||||
|
"swarm_service": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sample_group():
|
||||||
|
return {
|
||||||
|
"id": "test-group",
|
||||||
|
"name": "Test Group",
|
||||||
|
"services": [
|
||||||
|
{"node": "hf-pdocker-01", "container": "test-container"},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pytest>=8.0.0
|
||||||
|
pytest-asyncio>=0.24.0
|
||||||
|
httpx>=0.28.0
|
||||||
Reference in New Issue
Block a user