diff --git a/lxd/instance/drivers/driver_qemu_cmd.go b/lxd/instance/drivers/driver_qemu_cmd.go index 7cbcb0d18068..845486de56d6 100644 --- a/lxd/instance/drivers/driver_qemu_cmd.go +++ b/lxd/instance/drivers/driver_qemu_cmd.go @@ -5,6 +5,8 @@ import ( "fmt" "io" "strconv" + "strings" + "syscall" "golang.org/x/sys/unix" @@ -13,6 +15,9 @@ import ( "github.com/canonical/lxd/shared/logger" ) +// ErrExecDisconnected is returned when the guest disconnects the exec session. +var ErrExecDisconnected = fmt.Errorf("Disconnected") + // Cmd represents a running command for an Qemu VM. type qemuCmd struct { attachedChildPid int @@ -77,8 +82,10 @@ func (c *qemuCmd) Wait() (int, error) { // Error of type EOF indicates the session ended unexpectedly, // so we inform the client of the disconnection with a more // descriptive message. - if errors.Is(err, io.EOF) { - return exitStatus, fmt.Errorf("Disconnected") + // The error can be different depending on why the VM disconnected + // so we handle these cases similarly. + if errors.Is(err, io.EOF) || strings.Contains(err.Error(), io.ErrUnexpectedEOF.Error()) || strings.Contains(err.Error(), syscall.ECONNRESET.Error()) { + return exitStatus, ErrExecDisconnected } return exitStatus, err diff --git a/lxd/instance_exec.go b/lxd/instance_exec.go index ccf4badbfff4..419238be53fb 100644 --- a/lxd/instance_exec.go +++ b/lxd/instance_exec.go @@ -23,6 +23,7 @@ import ( "github.com/canonical/lxd/lxd/cluster" "github.com/canonical/lxd/lxd/db/operationtype" "github.com/canonical/lxd/lxd/instance" + "github.com/canonical/lxd/lxd/instance/drivers" "github.com/canonical/lxd/lxd/instance/instancetype" "github.com/canonical/lxd/lxd/operations" "github.com/canonical/lxd/lxd/request" @@ -289,7 +290,14 @@ func (s *execWs) Do(op *operations.Operation) error { _ = pty.Close() } + // Make VM disconnections (shutdown/reboot) match containers. + if cmdErr == drivers.ErrExecDisconnected { + cmdResult = 129 + cmdErr = nil + } + metadata := shared.Jmap{"return": cmdResult} + err = op.ExtendMetadata(metadata) if err != nil { return err