From c449618012d5fe74b325c0258a6c1ccd16891cf8 Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Thu, 2 Jul 2026 18:51:31 +0000 Subject: [PATCH] fix multiple possible concurrent map write issues, fix issue with VM instacne types returning prematurely --- app/model.go | 23 ++++++++++++++++++----- app/types.go | 21 +++++++++++++-------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/app/model.go b/app/model.go index 47796c7..9a0d018 100644 --- a/app/model.go +++ b/app/model.go @@ -186,8 +186,6 @@ func (cluster *Cluster) BuildNode(nodeName string) error { return nil } - cluster.Nodes[nodeName] = node - // get node's VMs vms, err := node.VirtualMachines() if err != nil { @@ -242,6 +240,10 @@ func (cluster *Cluster) BuildNode(nodeName string) error { node.cluster = cluster + cluster.NodesLock.Lock() + cluster.Nodes[nodeName] = node + cluster.NodesLock.Unlock() + return nil } @@ -317,12 +319,11 @@ func (node *Node) BuildInstance(instancetype InstanceType, vmid uint) error { if err != nil && node.Instances[instanceID] != nil { // node is unreachable and did exist previously // assume the instance is gone and delete from cluster + log.Printf("[ERR ] error retrieving %s.%d: %s", node.Name, instanceID, err) delete(node.Instances, instanceID) return nil } - node.Instances[instanceID] = instance - for volid := range instance.configDisks { wg.Go(func() error { err = instance.RebuildVolume(node, volid) @@ -363,11 +364,16 @@ func (node *Node) BuildInstance(instancetype InstanceType, vmid uint) error { err = instance.RebuildBoot(node) if err != nil { log.Printf("[ERR ] error rebuilding boot: %s", err) + return err } - return err } instance.node = node + + node.InstancesLock.Lock() + node.Instances[instanceID] = instance + node.InstancesLock.Unlock() + return nil } @@ -382,7 +388,10 @@ func (instance *Instance) RebuildVolume(node *Node, volid string) error { voltype := AnyPrefixes(volid, paas.VolumeTypes) volume.Type = voltype volume.Volume_ID = VolumeID(volid) + + instance.VolumesLock.Lock() instance.Volumes[VolumeID(volid)] = volume + instance.VolumesLock.Unlock() return nil } @@ -396,7 +405,9 @@ func (instance *Instance) RebuildNet(node *Node, netid string) error { return nil } + instance.NetsLock.Lock() instance.Nets[NetID(netid)] = netinfo + instance.NetsLock.Unlock() return nil } @@ -420,7 +431,9 @@ func (instance *Instance) RebuildDevice(node *Node, deviceid string) error { // sub function assignment not supported yet } + instance.DevicesLock.Lock() instance.Devices[DeviceID(instanceDeviceBusID)].Device_ID = DeviceID(deviceid) + instance.DevicesLock.Unlock() return nil } diff --git a/app/types.go b/app/types.go index 86aeaaf..aa58f43 100644 --- a/app/types.go +++ b/app/types.go @@ -14,10 +14,11 @@ import ( // override Nodes map to new custom Node type type Cluster struct { paas.Cluster - lock sync.Mutex - pve ProxmoxClient - Nodes map[string]*Node `json:"nodes"` - OK bool + lock sync.Mutex + pve ProxmoxClient + NodesLock sync.Mutex + Nodes map[string]*Node `json:"nodes"` + OK bool } // add mutex and pve api Node object @@ -25,10 +26,11 @@ type Cluster struct { type Node struct { lock sync.Mutex paas.Node - Instances map[InstanceID]*Instance `json:"instances"` - pvenode *proxmox.Node - storage map[string][]*proxmox.StorageContent - cluster *Cluster + InstancesLock sync.Mutex // lock for Instances map + Instances map[InstanceID]*Instance `json:"instances"` + pvenode *proxmox.Node + storage map[string][]*proxmox.StorageContent + cluster *Cluster } type InstanceID = paas.InstanceID @@ -41,6 +43,9 @@ const CT InstanceType = paas.CT type Instance struct { lock sync.Mutex paas.Instance + VolumesLock sync.Mutex // lock for Volumes map + NetsLock sync.Mutex // lock for Nets map + DevicesLock sync.Mutex // lock for Devices map pveconfig any configDisks map[string]string configNets map[string]string