mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
pkg/machine/qemu: start VM check if qemu is alive
When trying to connect to the qemu ready socket we should check if the qemu process is still running, if it is not we can just error out. There is no point in retrying. To do so we have to directly call wait with WNOHANG. Also change StartProcess to os/exec package which is higher level and allows us to use a buffer as qemu stderr fd. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
@ -5,6 +5,7 @@ package qemu
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -138,7 +139,7 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
|||||||
cmd = append(cmd, []string{
|
cmd = append(cmd, []string{
|
||||||
"-device", "virtio-serial",
|
"-device", "virtio-serial",
|
||||||
// qemu needs to establish the long name; other connections can use the symlink'd
|
// qemu needs to establish the long name; other connections can use the symlink'd
|
||||||
// Note both id and chardev start with an extra "a" becuase qemu requires that it
|
// Note both id and chardev start with an extra "a" because qemu requires that it
|
||||||
// starts with an letter but users can also use numbers
|
// starts with an letter but users can also use numbers
|
||||||
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=a" + vm.Name + "_ready",
|
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=a" + vm.Name + "_ready",
|
||||||
"-device", "virtserialport,chardev=a" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0",
|
"-device", "virtserialport,chardev=a" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0",
|
||||||
@ -573,15 +574,25 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
files := []*os.File{dnr, dnw, dnw, fd}
|
files := []*os.File{dnr, dnw, dnw, fd}
|
||||||
attr.Files = files
|
attr.Files = files
|
||||||
logrus.Debug(v.CmdLine)
|
logrus.Debug(v.CmdLine)
|
||||||
cmd := v.CmdLine
|
cmdLine := v.CmdLine
|
||||||
|
|
||||||
// Disable graphic window when not in debug mode
|
// Disable graphic window when not in debug mode
|
||||||
// Done in start, so we're not suck with the debug level we used on init
|
// Done in start, so we're not suck with the debug level we used on init
|
||||||
if !logrus.IsLevelEnabled(logrus.DebugLevel) {
|
if !logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||||
cmd = append(cmd, "-display", "none")
|
cmdLine = append(cmdLine, "-display", "none")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = os.StartProcess(v.CmdLine[0], cmd, attr)
|
stderrBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
cmd := &exec.Cmd{
|
||||||
|
Args: cmdLine,
|
||||||
|
Path: cmdLine[0],
|
||||||
|
Stdin: dnr,
|
||||||
|
Stdout: dnw,
|
||||||
|
Stderr: stderrBuf,
|
||||||
|
ExtraFiles: []*os.File{fd},
|
||||||
|
}
|
||||||
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// check if qemu was not found
|
// check if qemu was not found
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
@ -592,15 +603,17 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd[0], err = cfg.FindHelperBinary(QemuCommand, true)
|
cmdLine[0], err = cfg.FindHelperBinary(QemuCommand, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = os.StartProcess(cmd[0], cmd, attr)
|
cmd.Path = cmdLine[0]
|
||||||
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to execute %q: %w", cmd, err)
|
return fmt.Errorf("unable to execute %q: %w", cmd, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
defer cmd.Process.Release() //nolint:errcheck
|
||||||
fmt.Println("Waiting for VM ...")
|
fmt.Println("Waiting for VM ...")
|
||||||
socketPath, err := getRuntimeDir()
|
socketPath, err := getRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -615,6 +628,16 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// check if qemu is still alive
|
||||||
|
var status syscall.WaitStatus
|
||||||
|
pid, err := syscall.Wait4(cmd.Process.Pid, &status, syscall.WNOHANG, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read qemu process status: %w", err)
|
||||||
|
}
|
||||||
|
if pid > 0 {
|
||||||
|
// child exited
|
||||||
|
return fmt.Errorf("qemu exited unexpectedly with exit code %d, stderr: %s", status.ExitStatus(), stderrBuf.String())
|
||||||
|
}
|
||||||
time.Sleep(wait)
|
time.Sleep(wait)
|
||||||
wait++
|
wait++
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user