Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions internal/cloning/cloning_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,23 @@ func (cs *CloningService) CloneTemplate(req CloneRequest) error {
// Release the vmid allocation mutex now that all of the VMs are cloned on proxmox
cs.vmidMutex.Unlock()

// 9. Configure VNet of all VMs
// 9. Wait for all router disks to be fully available before configuring VNets.
// Proxmox clone is two-phase: the clone lock (Phase 1) releases before the storage
// backend finishes writing the disk (Phase 2). If SetPodVnet runs before Phase 2
// completes, Proxmox's disk finalization can overwrite the net1 config change,
// leaving the router connected to the wrong vnet.
log.Printf("Waiting for router disks to be available before configuring VNets")
routerDiskReady := make(map[int]bool)
for _, routerInfo := range clonedRouters {
log.Printf("Waiting for router disk to be available for %s (VMID: %d)", routerInfo.TargetName, routerInfo.VMID)
if err := cs.ProxmoxService.WaitForDisk(routerInfo.Node, routerInfo.VMID, cs.Config.RouterWaitTimeout); err != nil {
errors = append(errors, fmt.Sprintf("router disk unavailable for %s: %v", routerInfo.TargetName, err))
} else {
routerDiskReady[routerInfo.VMID] = true
}
}

// 10. Configure VNet of all VMs
log.Printf("Configuring VNets for %d targets", len(req.Targets))
for _, target := range req.Targets {
vnetName := fmt.Sprintf("kamino%d", target.PodNumber)
Expand All @@ -281,7 +297,7 @@ func (cs *CloningService) CloneTemplate(req CloneRequest) error {
}
}

// 10. Start all routers and wait for them to be running
// 11. Start all routers and wait for them to be running
req.SSE.Send(
ProgressMessage{
Message: "Starting routers",
Expand All @@ -290,11 +306,7 @@ func (cs *CloningService) CloneTemplate(req CloneRequest) error {
)
log.Printf("Starting %d routers", len(clonedRouters))
for _, routerInfo := range clonedRouters {
// Wait for router disk to be available
log.Printf("Waiting for router disk to be available for %s (VMID: %d)", routerInfo.TargetName, routerInfo.VMID)
err = cs.ProxmoxService.WaitForDisk(routerInfo.Node, routerInfo.VMID, cs.Config.RouterWaitTimeout)
if err != nil {
errors = append(errors, fmt.Sprintf("router disk unavailable for %s: %v", routerInfo.TargetName, err))
if !routerDiskReady[routerInfo.VMID] {
continue
}

Expand All @@ -314,7 +326,7 @@ func (cs *CloningService) CloneTemplate(req CloneRequest) error {
}
}

// 11. Configure all pod routers (separate step after all routers are running)
// 12. Configure all pod routers (separate step after all routers are running)
req.SSE.Send(
ProgressMessage{
Message: "Configuring pod routers",
Expand Down
1 change: 1 addition & 0 deletions internal/proxmox/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ type ProxmoxNodeStatus struct {
}

type VirtualResourceConfig struct {
Name string `json:"name"`
HardDisk string `json:"scsi0"`
Lock string `json:"lock"`
Net0 string `json:"net0"`
Expand Down
2 changes: 1 addition & 1 deletion internal/proxmox/vms.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (s *ProxmoxService) WaitForDisk(node string, vmID int, maxWait time.Duratio

log.Printf("%+v", configResp)

if configResp.HardDisk != "" {
if configResp.HardDisk != "" && configResp.Name != "" {
log.Printf("/nodes/%s/storage/%s/content?vmid=%d", s.Config.Nodes[0], s.Config.StorageID, vmID)

pendingReq := tools.ProxmoxAPIRequest{
Expand Down