diff --git a/internal/qemu/start_linux.go b/internal/qemu/start_linux.go index a7869a2..ae03254 100644 --- a/internal/qemu/start_linux.go +++ b/internal/qemu/start_linux.go @@ -65,29 +65,18 @@ func Start(cfg Config) error { sorted := make([]DiskConfig, len(cfg.Disks)) copy(sorted, cfg.Disks) - // vd* avant sd* : les disques virtio-blk bootent en premier. - // À lettre égale de type, ordre alphabétique. - sort.Slice(sorted, func(i, j int) bool { - iVirtio := strings.HasPrefix(sorted[i].Dev, "vd") - jVirtio := strings.HasPrefix(sorted[j].Dev, "vd") - if iVirtio != jVirtio { - return iVirtio - } - return sorted[i].Dev < sorted[j].Dev - }) + sort.Slice(sorted, func(i, j int) bool { return sorted[i].Dev < sorted[j].Dev }) - for idx, d := range sorted { - bootindex := idx + 1 + for _, d := range sorted { if strings.HasPrefix(d.Dev, "sd") { scsiID := int(d.Dev[2] - 'a') args = append(args, "-drive", fmt.Sprintf("file=%s,if=none,id=%s", d.Path, d.Dev), - "-device", fmt.Sprintf("scsi-hd,drive=%s,bus=scsi0.0,scsi-id=%d,bootindex=%d", d.Dev, scsiID, bootindex), + "-device", fmt.Sprintf("scsi-hd,drive=%s,bus=scsi0.0,scsi-id=%d", d.Dev, scsiID), ) } else { args = append(args, - "-drive", fmt.Sprintf("file=%s,if=none,id=%s", d.Path, d.Dev), - "-device", fmt.Sprintf("virtio-blk-pci,drive=%s,bootindex=%d", d.Dev, bootindex), + "-drive", fmt.Sprintf("file=%s,if=virtio,id=%s", d.Path, d.Dev), ) } } diff --git a/internal/vm/delete.go b/internal/vm/delete.go index 3d808e6..7e47f3f 100644 --- a/internal/vm/delete.go +++ b/internal/vm/delete.go @@ -33,18 +33,25 @@ func StopVM(db *badger.DB, name string, cfg *configuration.Config) error { socketPath := filepath.Join(cfg.QEMU.QMPDir, name+".sock") - if _, err := os.Stat(socketPath); err == nil { - // socket présent : tenter l'arrêt gracieux - if _, err := qmp.Send(socketPath, []string{`{"execute":"system_powerdown"}`}); err == nil { - waitQMPDead(socketPath, - time.Duration(cfg.Dispatcher.TimeoutSeconds)*time.Second, - time.Duration(cfg.Dispatcher.PollSeconds)*time.Second, - ) - } - // connexion QMP échouée : QEMU déjà mort + if _, err := qmp.Send(socketPath, []string{`{"execute":"system_powerdown"}`}); err != nil { + return fmt.Errorf("qmp system_powerdown: %w", err) } - // socket absent ou QEMU déjà arrêté : cleanup direct + // attendre l'arrêt effectif de la VM ; forcer via quit après timeout + timeout := time.After(time.Duration(cfg.Dispatcher.TimeoutSeconds) * time.Second) + poll := time.Duration(cfg.Dispatcher.PollSeconds) * time.Second + stopped := false + for !stopped { + select { + case <-timeout: + qmp.Send(socketPath, []string{`{"execute":"quit"}`}) + stopped = true + case <-time.After(poll): + if _, err := qmp.Send(socketPath, nil); err != nil { + stopped = true + } + } + } if err := netns.Call(d.vpcName, func() error { return iptables.DeleteMetadataRedirect(d.ip, d.interfaceIP, d.metadataPort) @@ -67,18 +74,3 @@ func StopVM(db *badger.DB, name string, cfg *configuration.Config) error { return kv.AddInDB(db, "vm/"+name+"/state", "stopped") } - -func waitQMPDead(socketPath string, timeout, poll time.Duration) { - timer := time.After(timeout) - for { - select { - case <-timer: - qmp.Send(socketPath, []string{`{"execute":"quit"}`}) - return - case <-time.After(poll): - if _, err := qmp.Send(socketPath, nil); err != nil { - return - } - } - } -}