The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6517

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) ===

From 880fca008dd619f6f9e0add0f42aeb00b5970187 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Tue, 26 Nov 2019 19:59:36 -0500
Subject: [PATCH 1/4] shared: Cleanup console on error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 shared/network.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/shared/network.go b/shared/network.go
index beb927e66c..089480b318 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -474,6 +474,7 @@ func WebsocketConsoleMirror(conn *websocket.Conn, w 
io.WriteCloser, r io.ReadClo
                        if !ok {
                                r.Close()
                                logger.Debugf("sending write barrier")
+                               conn.WriteMessage(websocket.BinaryMessage, 
[]byte("\r"))
                                conn.WriteMessage(websocket.TextMessage, 
[]byte{})
                                readDone <- true
                                return
@@ -491,6 +492,7 @@ func WebsocketConsoleMirror(conn *websocket.Conn, w 
io.WriteCloser, r io.ReadClo
                                break
                        }
                }
+
                closeMsg := 
websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
                conn.WriteMessage(websocket.CloseMessage, closeMsg)
                readDone <- true

From 95eaf283341200b3c065ea1cb1fe9ec74454e6c2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Tue, 26 Nov 2019 20:00:00 -0500
Subject: [PATCH 2/4] lxd: Cleanup console on error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd/container_console.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lxd/container_console.go b/lxd/container_console.go
index 41440db208..791682db0d 100644
--- a/lxd/container_console.go
+++ b/lxd/container_console.go
@@ -222,9 +222,10 @@ func (s *consoleWs) Do(op *operations.Operation) error {
 
        // Get the console websocket and close it.
        s.connsLock.Lock()
-       consolConn := s.conns[0]
+       consoleConn := s.conns[0]
        s.connsLock.Unlock()
-       consolConn.Close()
+       consoleConn.WriteMessage(websocket.BinaryMessage, []byte("\n\r"))
+       consoleConn.Close()
 
        // Get the control websocket and close it.
        s.connsLock.Lock()

From d91543582f6b3efc03ae1455311b84da1888d82b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Tue, 26 Nov 2019 20:00:36 -0500
Subject: [PATCH 3/4] lxd/console: Improve disconnection handling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #6512

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd/container_console.go           |  5 +++--
 lxd/container_lxc.go               | 23 ++++++++++++++++++-----
 lxd/instance/instance_interface.go |  2 +-
 lxd/vm_qemu.go                     | 18 ++++++++++--------
 4 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/lxd/container_console.go b/lxd/container_console.go
index 791682db0d..e63d599dc0 100644
--- a/lxd/container_console.go
+++ b/lxd/container_console.go
@@ -112,7 +112,7 @@ func (s *consoleWs) Do(op *operations.Operation) error {
        <-s.allConnected
 
        // Get console from instance.
-       console, err := s.instance.Console()
+       console, consoleDisconnectCh, err := s.instance.Console()
        if err != nil {
                return err
        }
@@ -204,14 +204,15 @@ func (s *consoleWs) Do(op *operations.Operation) error {
                <-readDone
                logger.Debugf("Finished mirroring console to websocket")
                <-writeDone
-               conn.Close()
                close(mirrorDoneCh)
        }()
 
        // Wait until either the console or the websocket is done.
        select {
        case <-mirrorDoneCh:
+               close(consoleDisconnectCh)
        case <-consoleDoneCh:
+               close(consoleDisconnectCh)
        }
 
        // Write a reset escape sequence to the console to cancel any ongoing 
reads to the handle
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 4a8a41a203..c15289ac17 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -5837,7 +5837,9 @@ func (c *containerLXC) FileRemove(path string) error {
        return nil
 }
 
-func (c *containerLXC) Console() (*os.File, error) {
+func (c *containerLXC) Console() (*os.File, chan error, error) {
+       chDisconnect := make(chan error, 1)
+
        args := []string{
                c.state.OS.ExecPath,
                "forkconsole",
@@ -5849,7 +5851,7 @@ func (c *containerLXC) Console() (*os.File, error) {
 
        idmapset, err := c.CurrentIdmap()
        if err != nil {
-               return nil, err
+               return nil, nil, err
        }
 
        var rootUID, rootGID int64
@@ -5859,7 +5861,7 @@ func (c *containerLXC) Console() (*os.File, error) {
 
        master, slave, err := shared.OpenPty(rootUID, rootGID)
        if err != nil {
-               return nil, err
+               return nil, nil, err
        }
 
        cmd := exec.Cmd{}
@@ -5871,10 +5873,21 @@ func (c *containerLXC) Console() (*os.File, error) {
 
        err = cmd.Start()
        if err != nil {
-               return nil, err
+               return nil, nil, err
        }
 
-       return master, nil
+       go func() {
+               err = cmd.Wait()
+               master.Close()
+               slave.Close()
+       }()
+
+       go func() {
+               <-chDisconnect
+               cmd.Process.Kill()
+       }()
+
+       return master, chDisconnect, nil
 }
 
 func (c *containerLXC) ConsoleLog(opts lxc.ConsoleLogOptions) (string, error) {
diff --git a/lxd/instance/instance_interface.go 
b/lxd/instance/instance_interface.go
index ae0c2e3daa..9c56b0ddfe 100644
--- a/lxd/instance/instance_interface.go
+++ b/lxd/instance/instance_interface.go
@@ -51,7 +51,7 @@ type Instance interface {
        FileRemove(path string) error
 
        // Console - Allocate and run a console tty.
-       Console() (*os.File, error)
+       Console() (*os.File, chan error, error)
        Exec(command []string, env map[string]string, stdin *os.File, stdout 
*os.File, stderr *os.File, cwd string, uid uint32, gid uint32) (Cmd, error)
 
        // Status
diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go
index c68ca7e95e..2a8101575a 100644
--- a/lxd/vm_qemu.go
+++ b/lxd/vm_qemu.go
@@ -2240,23 +2240,25 @@ func (vm *vmQemu) FileRemove(path string) error {
        return fmt.Errorf("FileRemove Not implemented")
 }
 
-func (vm *vmQemu) Console() (*os.File, error) {
+func (vm *vmQemu) Console() (*os.File, chan error, error) {
+       chError := make(chan error, 1)
+
        // Connect to the monitor.
        monitor, err := qmp.NewSocketMonitor("unix", vm.getMonitorPath(), 
vmVsockTimeout)
        if err != nil {
-               return nil, err // The VM isn't running as no monitor socket 
available.
+               return nil, nil, err // The VM isn't running as no monitor 
socket available.
        }
 
        err = monitor.Connect()
        if err != nil {
-               return nil, err // The capabilities handshake failed.
+               return nil, nil, err // The capabilities handshake failed.
        }
        defer monitor.Disconnect()
 
        // Send the status command.
        respRaw, err := monitor.Run([]byte("{'execute': 'query-chardev'}"))
        if err != nil {
-               return nil, err // Status command failed.
+               return nil, nil, err // Status command failed.
        }
 
        var respDecoded struct {
@@ -2268,7 +2270,7 @@ func (vm *vmQemu) Console() (*os.File, error) {
 
        err = json.Unmarshal(respRaw, &respDecoded)
        if err != nil {
-               return nil, err // JSON decode failed.
+               return nil, nil, err // JSON decode failed.
        }
 
        var ptsPath string
@@ -2280,15 +2282,15 @@ func (vm *vmQemu) Console() (*os.File, error) {
        }
 
        if ptsPath == "" {
-               return nil, fmt.Errorf("No PTS path found")
+               return nil, nil, fmt.Errorf("No PTS path found")
        }
 
        console, err := os.OpenFile(ptsPath, os.O_RDWR, 0600)
        if err != nil {
-               return nil, err
+               return nil, nil, err
        }
 
-       return console, nil
+       return console, chError, nil
 }
 
 func (vm *vmQemu) forwardSignal(control *websocket.Conn, sig unix.Signal) 
error {

From 3065865ac24b65e610ff195e08b739c570a433a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Tue, 26 Nov 2019 20:17:08 -0500
Subject: [PATCH 4/4] lxd/vm: Add locking around console
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd/vm_qemu.go | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go
index 2a8101575a..e9002f18f9 100644
--- a/lxd/vm_qemu.go
+++ b/lxd/vm_qemu.go
@@ -13,6 +13,7 @@ import (
        "path/filepath"
        "strconv"
        "strings"
+       "sync"
        "time"
 
        "github.com/digitalocean/go-qemu/qmp"
@@ -49,6 +50,9 @@ import (
 
 var vmVsockTimeout time.Duration = time.Second
 
+var vmConsole = map[int]bool{}
+var vmConsoleLock sync.Mutex
+
 func vmQemuLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) 
(instance.Instance, error) {
        // Create the container struct.
        vm := vmQemuInstantiate(s, args)
@@ -2241,7 +2245,15 @@ func (vm *vmQemu) FileRemove(path string) error {
 }
 
 func (vm *vmQemu) Console() (*os.File, chan error, error) {
-       chError := make(chan error, 1)
+       chDisconnect := make(chan error, 1)
+
+       // Avoid duplicate connects.
+       vmConsoleLock.Lock()
+       if vmConsole[vm.id] {
+               vmConsoleLock.Unlock()
+               return nil, nil, fmt.Errorf("There is already an active console 
for this instance")
+       }
+       vmConsoleLock.Unlock()
 
        // Connect to the monitor.
        monitor, err := qmp.NewSocketMonitor("unix", vm.getMonitorPath(), 
vmVsockTimeout)
@@ -2290,7 +2302,19 @@ func (vm *vmQemu) Console() (*os.File, chan error, 
error) {
                return nil, nil, err
        }
 
-       return console, chError, nil
+       vmConsoleLock.Lock()
+       vmConsole[vm.id] = true
+       vmConsoleLock.Unlock()
+
+       go func() {
+               <-chDisconnect
+
+               vmConsoleLock.Lock()
+               vmConsole[vm.id] = false
+               vmConsoleLock.Unlock()
+       }()
+
+       return console, chDisconnect, nil
 }
 
 func (vm *vmQemu) forwardSignal(control *websocket.Conn, sig unix.Signal) 
error {
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to