The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6436
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Adds support for `lxc exec` for VMs via `lxd-agent`. This is a WIP.
From e50caecd0d2a48a351446778ea68020789f18ff7 Mon Sep 17 00:00:00 2001 From: Thomas Hipp <thomas.h...@canonical.com> Date: Mon, 28 Oct 2019 12:29:49 +0100 Subject: [PATCH 1/5] lxd/vm: Implement Exec for VMs Signed-off-by: Thomas Hipp <thomas.h...@canonical.com> --- lxd/vm_qemu.go | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go index eca1bbe0e8..53cabf528f 100644 --- a/lxd/vm_qemu.go +++ b/lxd/vm_qemu.go @@ -1969,8 +1969,42 @@ func (vm *vmQemu) Console() (*os.File, error) { } func (vm *vmQemu) Exec(command []string, env map[string]string, stdin *os.File, stdout *os.File, stderr *os.File, wait bool, cwd string, uid uint32, gid uint32) (*exec.Cmd, int, int, error) { - return nil, 0, 0, fmt.Errorf("Exec Not implemented") + agent, err := lxdClient.ConnectLXDHTTP(nil, vm.agentClient) + if err != nil { + return nil, 0, 0, err + } + + post := api.InstanceExecPost{ + Command: command, + WaitForWS: wait, + Interactive: stdin == stdout, + Environment: env, + User: uid, + Group: gid, + Cwd: cwd, + } + + args := lxdClient.InstanceExecArgs{ + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, + DataDone: make(chan bool), + } + + op, err := agent.ExecInstance("", post, &args) + if err != nil { + return nil, -1, -1, err + } + + err = op.Wait() + if err != nil { + return nil, -1, -1, err + } + opAPI := op.Get() + + <-args.DataDone + return nil, int(opAPI.Metadata["return"].(float64)), -1, nil } func (vm *vmQemu) Render() (interface{}, interface{}, error) { From 6be5a4af1ffe09f313d1690bd8a7837ba101266c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 11 Nov 2019 12:30:07 +0000 Subject: [PATCH 2/5] lxd-agent/exec: Proper logger Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd-agent/exec.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lxd-agent/exec.go b/lxd-agent/exec.go index 32170b01ff..562f6d8ae3 100644 --- a/lxd-agent/exec.go +++ b/lxd-agent/exec.go @@ -20,6 +20,7 @@ import ( "github.com/lxc/lxd/lxd/response" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" + "github.com/lxc/lxd/shared/logger" "github.com/lxc/lxd/shared/netutils" ) @@ -263,7 +264,7 @@ func (s *execWs) Do(op *operations.Operation) error { } if err != nil { - log.Printf("Got error getting next reader %s", err) + logger.Debugf("Got error getting next reader %s", err) er, ok := err.(*websocket.CloseError) if !ok { break @@ -276,30 +277,30 @@ func (s *execWs) Do(op *operations.Operation) error { // If an abnormal closure occurred, kill the attached process. err := unix.Kill(attachedChildPid, unix.SIGKILL) if err != nil { - log.Printf("Failed to send SIGKILL to pid %d\n", attachedChildPid) + logger.Errorf("Failed to send SIGKILL to pid %d\n", attachedChildPid) } else { - log.Printf("Sent SIGKILL to pid %d\n", attachedChildPid) + logger.Infof("Sent SIGKILL to pid %d\n", attachedChildPid) } return } buf, err := ioutil.ReadAll(r) if err != nil { - log.Printf("Failed to read message %s\n", err) + logger.Errorf("Failed to read message %s\n", err) break } command := api.ContainerExecControl{} if err := json.Unmarshal(buf, &command); err != nil { - log.Printf("Failed to unmarshal control socket command: %s\n", err) + logger.Errorf("Failed to unmarshal control socket command: %s\n", err) continue } if command.Command == "window-resize" { winchWidth, err := strconv.Atoi(command.Args["width"]) if err != nil { - log.Printf("Unable to extract window width: %s\n", err) + logger.Errorf("Unable to extract window width: %s\n", err) continue } @@ -329,12 +330,12 @@ func (s *execWs) Do(op *operations.Operation) error { conn := s.conns[0] s.connsLock.Unlock() - log.Println("Starting to mirror websocket") + logger.Info("Starting to mirror websocket") readDone, writeDone := netutils.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd())) <-readDone <-writeDone - log.Println("Finished to mirror websocket") + logger.Info("Finished to mirror websocket") conn.Close() wgEOF.Done() From 35dbf3eca5339ab2df1918331afa96b6fee5dff8 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 11 Nov 2019 12:30:23 +0000 Subject: [PATCH 3/5] lxd-agent: Setup proper logger Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd-agent/main.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lxd-agent/main.go b/lxd-agent/main.go index f3f28b13da..170c26cd33 100644 --- a/lxd-agent/main.go +++ b/lxd-agent/main.go @@ -5,6 +5,9 @@ import ( "github.com/spf13/cobra" + "github.com/lxc/lxd/lxd/events" + "github.com/lxc/lxd/shared/logger" + "github.com/lxc/lxd/shared/logging" "github.com/lxc/lxd/shared/version" ) @@ -35,8 +38,15 @@ func main() { app.SetVersionTemplate("{{.Version}}\n") app.Version = version.Version + // Setup logger + log, err := logging.GetLogger("", "", globalCmd.flagLogDebug, globalCmd.flagLogDebug, events.NewEventHandler()) + if err != nil { + os.Exit(1) + } + logger.Log = log + // Run the main command and handle errors - err := app.Execute() + err = app.Execute() if err != nil { os.Exit(1) } From 4c80875e98ca61504e84502466208de091e85571 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 11 Nov 2019 12:30:41 +0000 Subject: [PATCH 4/5] lxd/container/exec: Don't require cmd to be returned from inst.Exec() This isn't needed when using lxd-agent. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container_exec.go | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/lxd/container_exec.go b/lxd/container_exec.go index b8e2622590..1459cf1b25 100644 --- a/lxd/container_exec.go +++ b/lxd/container_exec.go @@ -322,22 +322,25 @@ func (s *execWs) Do(op *operations.Operation) error { attachedChildIsBorn <- attachedPid } - err = cmd.Wait() - if err == nil { - return finisher(0, nil) - } + if cmd != nil { + err = cmd.Wait() + if err == nil { + return finisher(0, nil) + } - exitErr, ok := err.(*exec.ExitError) - if ok { - status, ok := exitErr.Sys().(syscall.WaitStatus) + exitErr, ok := err.(*exec.ExitError) if ok { - return finisher(status.ExitStatus(), nil) - } + status, ok := exitErr.Sys().(syscall.WaitStatus) + if ok { + return finisher(status.ExitStatus(), nil) + } - if status.Signaled() { - // 128 + n == Fatal error signal "n" - return finisher(128+int(status.Signal()), nil) + if status.Signaled() { + // 128 + n == Fatal error signal "n" + return finisher(128+int(status.Signal()), nil) + } } + } return finisher(-1, nil) From 3120be9ee0de52285b2f824b7d5a7f95c29ffa55 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 11 Nov 2019 12:31:07 +0000 Subject: [PATCH 5/5] lxd-agent/exec: Add buffered channel to prevent deadlock on cmd exit Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd-agent/exec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd-agent/exec.go b/lxd-agent/exec.go index 562f6d8ae3..946f0ba657 100644 --- a/lxd-agent/exec.go +++ b/lxd-agent/exec.go @@ -236,7 +236,7 @@ func (s *execWs) Do(op *operations.Operation) error { stderr = ttys[2] } - controlExit := make(chan bool) + controlExit := make(chan bool, 1) attachedChildIsBorn := make(chan int) attachedChildIsDead := make(chan bool, 1) var wgEOF sync.WaitGroup
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel