@@ -5,8 +5,10 @@ import (
55 "fmt"
66 "net"
77 "net/url"
8+ "os/exec"
89 "strconv"
910 "sync"
11+ "syscall"
1012 "time"
1113
1214 jsoniter "github.com/json-iterator/go"
@@ -349,6 +351,65 @@ var _ = Describe("podman machine start", func() {
349351 Expect (sshCertFile ).To (Exit (0 ))
350352 Expect (sshCertFile .outputToString ()).To (Equal (certFileName ))
351353 })
354+ It ("start interrupted by SIGTERM while waiting for VM start" , func () {
355+ if ! isVmtype (define .AppleHvVirt ) && ! isVmtype (define .LibKrun ) {
356+ Skip ("SIGTERM interruption is supported on macOS only" )
357+ }
358+ // Use the provider binary to pgrep the VM process
359+ var vmProcess string
360+ switch testProvider .VMType () {
361+ case define .AppleHvVirt :
362+ vmProcess = "vfkit"
363+ case define .LibKrun :
364+ vmProcess = "krunkit"
365+ default :
366+ }
367+
368+ i := new (initMachine )
369+ initSession , err := mb .setCmd (i .withImage (mb .imagePath )).run ()
370+ Expect (err ).ToNot (HaveOccurred ())
371+ Expect (initSession ).To (Exit (0 ))
372+
373+ s := new (startMachine )
374+ startSession , err := mb .setCmd (s ).runWithoutWait ()
375+ Expect (err ).ToNot (HaveOccurred ())
376+
377+ // Wait 45s for the VM process spawned by `podman machine start`
378+ Eventually (func () error {
379+ _ , err := exec .Command ("pgrep" , vmProcess ).Output ()
380+ return err
381+ }, 45 * time .Second , 500 * time .Millisecond ).Should (Succeed ())
382+
383+ // Send a term signal now (podman machine start is waiting for
384+ // the VM process readiness)
385+ startSession .Signal (syscall .SIGTERM )
386+
387+ // Wait 30s for the podman machine start process to return (no deadlock)
388+ Eventually (startSession , 30 * time .Second ).Should (Exit ())
389+ Expect (startSession .ExitCode ()).ToNot (Equal (0 ))
390+
391+ // Wait 30s for the VM process to return (SIGTERM has been forwarded)
392+ Eventually (func () error {
393+ _ , err := exec .Command ("pgrep" , vmProcess ).Output ()
394+ return err
395+ }, 30 * time .Second , 500 * time .Millisecond ).ShouldNot (Succeed ())
396+
397+ // Verify machine state is Stopped
398+ inspect := new (inspectMachine )
399+ inspectSession , err := mb .setCmd (inspect .withFormat ("{{.State}}" )).run ()
400+ Expect (err ).ToNot (HaveOccurred ())
401+ Expect (inspectSession ).To (Exit (0 ))
402+ Expect (inspectSession .outputToString ()).To (Equal (define .Stopped ))
403+
404+ // Verify no orphan gvproxy
405+ _ , err = pgrep ("gvproxy" )
406+ Expect (err ).To (HaveOccurred (), "gvproxy should not be running after SIGTERM cleanup" )
407+
408+ // Restart without interrupting and confirm that completes without error
409+ startSession , err = mb .setCmd (s ).run ()
410+ Expect (err ).ToNot (HaveOccurred ())
411+ Expect (startSession ).To (Exit (0 ))
412+ })
352413})
353414
354415func mapToPort (uris []string ) ([]string , error ) {
0 commit comments