Initial commit: Agentic OS troubleshooting platform
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>
This commit is contained in:
145
backend/app/inventory_catalog.py
Normal file
145
backend/app/inventory_catalog.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user