Self-hosted, Docker-based agentic troubleshooting platform: FastAPI backend + LangGraph agent, Next.js UI, tiered LLM routing (local Ollama -> Gemini -> DeepSeek -> OpenRouter), MCP server manager, encrypted device credentials, RBAC, audit log, project-memory + Obsidian integrations, and editable troubleshooting decision rules tuned for the GeneseasX vessel stack. Co-authored-by: Cursor <cursoragent@cursor.com>
146 lines
4.6 KiB
Python
146 lines
4.6 KiB
Python
"""Predefined device/VM slots available when configuring a vessel.
|
|
|
|
Each catalog entry defines defaults (port, MCP, type). Per-vessel overrides
|
|
are stored on the Device row when the operator enables that slot.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from app.models.enums import DeviceType
|
|
from app.agent.asterisk_profiles import asterisk_container_name
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class CatalogEntry:
|
|
key: str
|
|
label: str
|
|
description: str
|
|
device_type: DeviceType
|
|
mcp_server: str | None
|
|
default_port: int
|
|
default_username: str | None = None
|
|
category: str = "core" # core | network | optional
|
|
|
|
|
|
# GeneseasX + common homelab/vessel gear
|
|
VESSEL_DEVICE_CATALOG: tuple[CatalogEntry, ...] = (
|
|
CatalogEntry(
|
|
key="proxmox",
|
|
label="Proxmox host",
|
|
description="Proxmox VE — API token (proxmox-mcp) with SSH fallback",
|
|
device_type=DeviceType.proxmox,
|
|
mcp_server="proxmox-mcp",
|
|
default_port=22,
|
|
default_username="root",
|
|
category="core",
|
|
),
|
|
CatalogEntry(
|
|
key="pfsense",
|
|
label="pfSense firewall",
|
|
description="pfSense REST API (pfSense package)",
|
|
device_type=DeviceType.pfsense,
|
|
mcp_server="pfsense-mcp",
|
|
default_port=40443,
|
|
category="core",
|
|
),
|
|
CatalogEntry(
|
|
key="docker_vm",
|
|
label="Docker VM (GeneseasX)",
|
|
description="Debian Docker VM hosting GeneseasX services",
|
|
device_type=DeviceType.geneseasx,
|
|
mcp_server="ssh-generic-mcp",
|
|
default_port=22,
|
|
default_username="root",
|
|
category="core",
|
|
),
|
|
CatalogEntry(
|
|
key="asterisk_geneseasx",
|
|
label="Asterisk VoIP (GeneseasX)",
|
|
description="Asterisk in Docker container `voip` on the GeneseasX Docker VM (SSH + docker exec)",
|
|
device_type=DeviceType.asterisk,
|
|
mcp_server="ssh-generic-mcp",
|
|
default_port=5022,
|
|
default_username="root",
|
|
category="core",
|
|
),
|
|
CatalogEntry(
|
|
key="asterisk_satbox",
|
|
label="Asterisk VoIP (TMGeneseas / satbox)",
|
|
description="Asterisk installed natively on Debian 9/10 host (SSH + asterisk CLI)",
|
|
device_type=DeviceType.asterisk,
|
|
mcp_server="ssh-generic-mcp",
|
|
default_port=22,
|
|
default_username="root",
|
|
category="core",
|
|
),
|
|
CatalogEntry(
|
|
key="debian_host",
|
|
label="Plain Debian server",
|
|
description="Standalone Debian 9/10 host (SSH)",
|
|
device_type=DeviceType.debian,
|
|
mcp_server="ssh-generic-mcp",
|
|
default_port=22,
|
|
default_username="root",
|
|
category="optional",
|
|
),
|
|
CatalogEntry(
|
|
key="fortigate",
|
|
label="FortiGate",
|
|
description="Standalone FortiGate (FortiOS REST API)",
|
|
device_type=DeviceType.fortigate,
|
|
mcp_server="fortigate-mcp",
|
|
default_port=443,
|
|
category="network",
|
|
),
|
|
CatalogEntry(
|
|
key="fortiswitch",
|
|
label="FortiSwitch",
|
|
description="FortiSwitch management API",
|
|
device_type=DeviceType.fortiswitch,
|
|
mcp_server="fortiswitch-mcp",
|
|
default_port=443,
|
|
category="network",
|
|
),
|
|
CatalogEntry(
|
|
key="tplink",
|
|
label="TP-Link device",
|
|
description="TP-Link switch/AP (SSH; MCP pending)",
|
|
device_type=DeviceType.tplink,
|
|
mcp_server=None,
|
|
default_port=22,
|
|
category="optional",
|
|
),
|
|
)
|
|
|
|
|
|
def catalog_by_key() -> dict[str, CatalogEntry]:
|
|
return {e.key: e for e in VESSEL_DEVICE_CATALOG}
|
|
|
|
|
|
def catalog_as_dicts() -> list[dict]:
|
|
from app.services.device_defaults import proxmox_api_configured, resolve_proxmox_api_defaults, resolve_slot_defaults
|
|
|
|
rows: list[dict] = []
|
|
for e in VESSEL_DEVICE_CATALOG:
|
|
env = resolve_slot_defaults(e.key, e)
|
|
row = {
|
|
"key": e.key,
|
|
"label": e.label,
|
|
"description": e.description,
|
|
"device_type": e.device_type.value,
|
|
"mcp_server": e.mcp_server,
|
|
"default_port": env.port if env.port is not None else e.default_port,
|
|
"default_username": env.username or e.default_username,
|
|
"has_default_secret": bool(env.secret),
|
|
"secret_kind": env.secret_kind,
|
|
"env_defaults_configured": env.from_env,
|
|
"asterisk_container": asterisk_container_name(e.key) or None,
|
|
"category": e.category,
|
|
}
|
|
if e.key == "proxmox":
|
|
api = resolve_proxmox_api_defaults("")
|
|
row["has_default_api"] = proxmox_api_configured(api)
|
|
rows.append(row)
|
|
return rows
|