From b8ec92858beb59d99a0e6120518dbf64fa0ccc62 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 1 Oct 2025 18:38:42 +0000 Subject: [PATCH] fix: standardize ID formats across mock data and frontend to match production Mock data was using inconsistent ID formats that didn't match production code. This caused alert matching and fallback ID generation to fail. Backend changes (mock generator): - VMs: Use conditional logic matching production - standalone nodes use "node-vmid", clusters use "instance-node-vmid" (generator.go:503-509, 584-590) - Containers: Same conditional logic as VMs (generator.go:584-590) - Storage: Always use "instance-node-name" format matching production (generator.go:875, 922, 947, 982) - Shared storage: Use "shared" as node name and correct instance (generator.go:1007-1008) Frontend changes: - Dashboard.tsx: Guest ID fallback now matches backend conditional logic (Dashboard.tsx:964-969) - Storage.tsx: Storage ID fallback now uses "instance-node-name" format (Storage.tsx:603) Production format (from monitor.go): - Guest IDs: Standalone uses "node-vmid", cluster uses "instance-node-vmid" - Storage IDs: Always "instance-node-name" - Node IDs: Always "instance-node" This ensures: 1. Alert resourceId matching works correctly 2. Frontend fallbacks (if ever needed) generate correct IDs 3. Mock data accurately represents production behavior 4. Consistent filtering by instance+node works across all resource types --- .../src/components/Dashboard/Dashboard.tsx | 6 +++- .../src/components/Storage/Storage.tsx | 2 +- internal/mock/generator.go | 32 ++++++++++++++----- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/frontend-modern/src/components/Dashboard/Dashboard.tsx b/frontend-modern/src/components/Dashboard/Dashboard.tsx index 7ff23c52b..137b54455 100644 --- a/frontend-modern/src/components/Dashboard/Dashboard.tsx +++ b/frontend-modern/src/components/Dashboard/Dashboard.tsx @@ -961,8 +961,12 @@ export function Dashboard(props: DashboardProps) { {(guest) => ( {(() => { + // Match backend ID generation logic: standalone nodes use "node-vmid", clusters use "instance-node-vmid" const guestId = - guest.id || `${guest.instance}-${guest.node}-${guest.vmid}`; + guest.id || + (guest.instance === guest.node + ? `${guest.node}-${guest.vmid}` + : `${guest.instance}-${guest.node}-${guest.vmid}`); const metadata = guestMetadata()[guestId] || guestMetadata()[`${guest.node}-${guest.vmid}`]; diff --git a/frontend-modern/src/components/Storage/Storage.tsx b/frontend-modern/src/components/Storage/Storage.tsx index 149e0051b..0d5a6b8fb 100644 --- a/frontend-modern/src/components/Storage/Storage.tsx +++ b/frontend-modern/src/components/Storage/Storage.tsx @@ -600,7 +600,7 @@ const Storage: Component = () => { const isDisabled = storage.status !== 'available'; const alertStyles = getAlertStyles( - storage.id || `${storage.instance}-${storage.name}`, + storage.id || `${storage.instance}-${storage.node}-${storage.name}`, activeAlerts, ); const alertBg = alertStyles.hasAlert diff --git a/internal/mock/generator.go b/internal/mock/generator.go index b2ebbe9eb..bcccc7757 100644 --- a/internal/mock/generator.go +++ b/internal/mock/generator.go @@ -500,6 +500,14 @@ func generateVM(nodeName string, instance string, vmid int, config MockConfig) m totalDisk := int64((32 + rand.Intn(468)) * 1024 * 1024 * 1024) // 32-500 GB usedDisk := int64(float64(totalDisk) * (0.1 + rand.Float64()*0.8)) + // Generate ID matching production logic: standalone uses "node-vmid", cluster uses "instance-node-vmid" + var vmID string + if instance == nodeName { + vmID = fmt.Sprintf("%s-%d", nodeName, vmid) + } else { + vmID = fmt.Sprintf("%s-%s-%d", instance, nodeName, vmid) + } + return models.VM{ Name: name, VMID: vmid, @@ -521,7 +529,7 @@ func generateVM(nodeName string, instance string, vmid int, config MockConfig) m NetworkIn: generateRealisticIO("network-in"), NetworkOut: generateRealisticIO("network-out"), Uptime: uptime, - ID: fmt.Sprintf("mock-%s-%d", nodeName, vmid), + ID: vmID, Tags: generateTags(), } } @@ -573,6 +581,14 @@ func generateContainer(nodeName string, instance string, vmid int, config MockCo totalDisk := int64((8 + rand.Intn(120)) * 1024 * 1024 * 1024) // 8-128 GB usedDisk := int64(float64(totalDisk) * (0.1 + rand.Float64()*0.6)) + // Generate ID matching production logic: standalone uses "node-vmid", cluster uses "instance-node-vmid" + var ctID string + if instance == nodeName { + ctID = fmt.Sprintf("%s-%d", nodeName, vmid) + } else { + ctID = fmt.Sprintf("%s-%s-%d", instance, nodeName, vmid) + } + return models.Container{ Name: name, VMID: vmid, @@ -594,7 +610,7 @@ func generateContainer(nodeName string, instance string, vmid int, config MockCo NetworkIn: generateRealisticIO("network-in-ct"), NetworkOut: generateRealisticIO("network-out-ct"), Uptime: uptime, - ID: fmt.Sprintf("mock-%s-%d", nodeName, vmid), + ID: ctID, Tags: generateTags(), } } @@ -856,7 +872,7 @@ func generateStorage(nodes []models.Node) []models.Storage { localTotal := int64(500 * 1024 * 1024 * 1024) // 500GB localUsed := int64(float64(localTotal) * (0.3 + rand.Float64()*0.5)) storage = append(storage, models.Storage{ - ID: fmt.Sprintf("%s-local", node.Name), + ID: fmt.Sprintf("%s-%s-local", node.Instance, node.Name), Name: "local", Node: node.Name, Instance: node.Instance, @@ -903,7 +919,7 @@ func generateStorage(nodes []models.Node) []models.Storage { } storage = append(storage, models.Storage{ - ID: fmt.Sprintf("%s-local-zfs", node.Name), + ID: fmt.Sprintf("%s-%s-local-zfs", node.Instance, node.Name), Name: "local-zfs", Node: node.Name, Instance: node.Instance, @@ -928,7 +944,7 @@ func generateStorage(nodes []models.Node) []models.Storage { used := int64(float64(total) * rand.Float64()) storage = append(storage, models.Storage{ - ID: fmt.Sprintf("%s-%s", node.Name, storageName), + ID: fmt.Sprintf("%s-%s-%s", node.Instance, node.Name, storageName), Name: storageName, Node: node.Name, Instance: node.Instance, @@ -963,7 +979,7 @@ func generateStorage(nodes []models.Node) []models.Storage { pbsTotal := int64(950 * 1024 * 1024 * 1024) // ~950GB matching real PBS pbsUsed := int64(float64(pbsTotal) * 0.14) // ~14% usage matching real data storage = append(storage, models.Storage{ - ID: fmt.Sprintf("%s-pbs-%s", node.Name, pbsTargetNode.Name), + ID: fmt.Sprintf("%s-%s-pbs-%s", node.Instance, node.Name, pbsTargetNode.Name), Name: fmt.Sprintf("pbs-%s", pbsTargetNode.Name), Node: node.Name, // The node that reports this storage Instance: node.Instance, @@ -988,8 +1004,8 @@ func generateStorage(nodes []models.Node) []models.Storage { storage = append(storage, models.Storage{ ID: "shared-storage", Name: "shared-storage", - Node: nodes[0].Name, // Associated with first node but shared - Instance: fmt.Sprintf("pve-%s", nodes[0].Name), + Node: "shared", // Shared storage uses "shared" as node per production code + Instance: nodes[0].Instance, Type: "nfs", Status: "available", Total: sharedTotal,