export interface NetboxIP { id: number; address: string; } export interface NetboxCluster { id: number; name: string; url: string; } export interface NetboxDevice { id: number; name: string; url: string; } export interface NetboxCustomFields { docker_run_command?: string; docker_volumes?: string; [key: string]: any; } export interface NetboxVM { id: number; name: string; description?: string; // Kurze Beschreibung comments?: string; // Markdown Kommentare status: { value: string; label: string }; primary_ip?: NetboxIP; primary_ip4?: NetboxIP; cluster?: NetboxCluster; device?: NetboxDevice; // Das Host-Gerät custom_fields?: NetboxCustomFields; netboxUrl?: string; // Computed URL to NetBox UI } export interface NetboxResponse { count: number; next: string | null; previous: string | null; results: T[]; } // Helper to group containers by host (device) export type GroupedContainers = Record; const MOCK_DATA: NetboxVM[] = [ { id: 1, name: "nginx-proxy", description: "Reverse Proxy", comments: "Dies ist ein **wichtiger** Container.\nBitte nicht stoppen!", status: { value: "active", label: "Active" }, primary_ip4: { id: 10, address: "192.168.1.50/24" }, device: { id: 1, name: "docker-host-01", url: "" }, cluster: { id: 99, name: "Docker-Hosts", url: "" }, custom_fields: { docker_run_command: "docker run -d -p 80:80 --name nginx-proxy nginx:latest", docker_volumes: "-v /etc/nginx:/etc/nginx\n-v /var/log/nginx:/var/log/nginx" }, netboxUrl: "#", }, { id: 2, name: "postgres-db", description: "DB Main", status: { value: "active", label: "Active" }, primary_ip4: { id: 11, address: "192.168.1.51/24" }, device: { id: 1, name: "docker-host-01", url: "" }, cluster: { id: 99, name: "Docker-Hosts", url: "" }, custom_fields: { docker_run_command: "docker run -d postgres:14", }, netboxUrl: "#", }, { id: 3, name: "grafana", description: "Monitoring", status: { value: "staged", label: "Staged" }, device: { id: 2, name: "docker-host-02", url: "" }, cluster: { id: 99, name: "Docker-Hosts", url: "" }, custom_fields: { docker_run_command: "docker run -d grafana/grafana" }, netboxUrl: "#", }, ]; export async function getDockerContainers(): Promise { const apiUrl = process.env.NETBOX_API_URL; const apiToken = process.env.NETBOX_API_TOKEN; if (!apiUrl || !apiToken) { console.warn("NETBOX_API_URL or NETBOX_API_TOKEN not set. Using mock data."); return groupContainers(MOCK_DATA); } try { // Fetch VMs with role 'docker-container'. const res = await fetch( `${apiUrl}/api/virtualization/virtual-machines/?role=docker-container&limit=1000`, { headers: { Authorization: `Token ${apiToken}`, Accept: "application/json", }, next: { revalidate: 10 }, // Short cache for testing } ); if (!res.ok) { console.error("Failed to fetch from Netbox:", res.status, res.statusText); return groupContainers(MOCK_DATA); } const data: NetboxResponse = await res.json(); // Compute NetBox UI URL // Assumes apiUrl is something like "https://netbox.local/api" or "https://netbox.local/" // We want "https://netbox.local/virtualization/virtual-machines/{id}/" const baseUrl = apiUrl.replace(new RegExp("/api/?$"), "").replace(new RegExp("$"), ""); const enrichedResults = data.results.map(vm => ({ ...vm, netboxUrl: `${baseUrl}/virtualization/virtual-machines/${vm.id}/` })); return groupContainers(enrichedResults); } catch (error) { console.error("Error fetching netbox data:", error); return groupContainers(MOCK_DATA); } } function groupContainers(vms: NetboxVM[]): GroupedContainers { const grouped: GroupedContainers = {}; vms.forEach((vm) => { // Prioritize 'device' name, fallback to 'cluster' name, then "Unassigned" const hostName = vm.device?.name || vm.cluster?.name || "Unassigned"; if (!grouped[hostName]) { grouped[hostName] = []; } grouped[hostName].push(vm); }); return grouped; }