[lxc-devel] [lxd/master] Console on Windows

stgraber on Github lxc-bot at linuxcontainers.org
Thu Aug 20 18:35:11 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200820/4c663286/attachment.bin>
-------------- next part --------------
From f73f82bc3ce2d25c0bce1b3a657d8255ecff01ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 20 Aug 2020 12:13:43 -0400
Subject: [PATCH 1/2] shared/cert: Fix on Windows
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/cert.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/shared/cert.go b/shared/cert.go
index a1e923e0d8..55e4d4dabf 100644
--- a/shared/cert.go
+++ b/shared/cert.go
@@ -22,7 +22,6 @@ import (
 	"net/http"
 	"os"
 	"os/user"
-	"path"
 	"path/filepath"
 	"time"
 )
@@ -230,12 +229,13 @@ func FindOrGenCert(certf string, keyf string, certtype bool, addHosts bool) erro
 // GenCert will create and populate a certificate file and a key file
 func GenCert(certf string, keyf string, certtype bool, addHosts bool) error {
 	/* Create the basenames if needed */
-	dir := path.Dir(certf)
+	dir := filepath.Dir(certf)
 	err := os.MkdirAll(dir, 0750)
 	if err != nil {
 		return err
 	}
-	dir = path.Dir(keyf)
+
+	dir = filepath.Dir(keyf)
 	err = os.MkdirAll(dir, 0750)
 	if err != nil {
 		return err

From 37e9f82978aa695af20ee88c99cc600393b986b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 20 Aug 2020 14:34:49 -0400
Subject: [PATCH 2/2] lxc/console: Support remote-viewer on Windows
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/console.go         | 65 +++++++++++++++++++++++++++---------------
 lxc/console_unix.go    |  6 ++++
 lxc/console_windows.go | 23 +++++++++++++++
 3 files changed, 71 insertions(+), 23 deletions(-)

diff --git a/lxc/console.go b/lxc/console.go
index cfc134311b..02e4ae114e 100644
--- a/lxc/console.go
+++ b/lxc/console.go
@@ -7,6 +7,7 @@ import (
 	"net"
 	"os"
 	"os/exec"
+	"runtime"
 	"strconv"
 
 	"github.com/gorilla/websocket"
@@ -218,6 +219,7 @@ func (c *cmdConsole) console(d lxd.InstanceServer, name string) error {
 }
 
 func (c *cmdConsole) vga(d lxd.InstanceServer, name string) error {
+	var err error
 	conf := c.global.conf
 
 	// We currently use the control websocket just to abort in case of errors.
@@ -247,31 +249,48 @@ func (c *cmdConsole) vga(d lxd.InstanceServer, name string) error {
 		close(consoleDisconnect)
 	}()
 
-	// Create a temporary unix socket mirroring the instance's spice socket.
-	if !shared.PathExists(conf.ConfigPath("sockets")) {
-		err := os.MkdirAll(conf.ConfigPath("sockets"), 0700)
+	var socket string
+	var listener net.Listener
+	if runtime.GOOS != "windows" {
+		// Create a temporary unix socket mirroring the instance's spice socket.
+		if !shared.PathExists(conf.ConfigPath("sockets")) {
+			err := os.MkdirAll(conf.ConfigPath("sockets"), 0700)
+			if err != nil {
+				return err
+			}
+		}
+
+		// Generate a random file name.
+		path, err := ioutil.TempFile(conf.ConfigPath("sockets"), "*.spice")
 		if err != nil {
 			return err
 		}
-	}
+		path.Close()
 
-	path, err := ioutil.TempFile(conf.ConfigPath("sockets"), "*.spice")
-	if err != nil {
-		return err
-	}
-	err = os.Remove(path.Name())
-	if err != nil {
-		return err
-	}
-	path.Close()
+		err = os.Remove(path.Name())
+		if err != nil {
+			return err
+		}
 
-	socket := path.Name()
-	listener, err := net.Listen("unix", socket)
-	if err != nil {
-		return err
+		// Listen on the socket.
+		listener, err = net.Listen("unix", path.Name())
+		if err != nil {
+			return err
+		}
+		defer listener.Close()
+		defer os.Remove(path.Name())
+
+		socket = fmt.Sprintf("spice+unix://%s", path.Name())
+	} else {
+		listener, err = net.Listen("tcp", "127.0.0.1:0")
+		if err != nil {
+			return err
+		}
+		defer listener.Close()
+
+		addr := listener.Addr().(*net.TCPAddr)
+		socket = fmt.Sprintf("spice://127.0.0.1:%d", addr.Port)
 	}
-	defer listener.Close()
-	defer os.Remove(path.Name())
 
 	op, connect, err := d.ConsoleInstanceDynamic(name, req, &consoleArgs)
 	if err != nil {
@@ -304,15 +323,15 @@ func (c *cmdConsole) vga(d lxd.InstanceServer, name string) error {
 	}()
 
 	// Use either spicy or remote-viewer if available.
-	remoteViewer, _ := exec.LookPath("remote-viewer")
-	spicy, _ := exec.LookPath("spicy")
+	remoteViewer := c.findCommand("remote-viewer")
+	spicy := c.findCommand("spicy")
 
 	if remoteViewer != "" || spicy != "" {
 		var cmd *exec.Cmd
 		if remoteViewer != "" {
-			cmd = exec.Command(remoteViewer, fmt.Sprintf("spice+unix://%s", socket))
+			cmd = exec.Command(remoteViewer, socket)
 		} else {
-			cmd = exec.Command(spicy, fmt.Sprintf("--uri=spice+unix://%s", socket))
+			cmd = exec.Command(spicy, fmt.Sprintf("--uri=%s", socket))
 		}
 
 		// Start the command.
diff --git a/lxc/console_unix.go b/lxc/console_unix.go
index 0edba5d521..44c7ee672d 100644
--- a/lxc/console_unix.go
+++ b/lxc/console_unix.go
@@ -4,6 +4,7 @@ package main
 
 import (
 	"os"
+	"os/exec"
 	"os/signal"
 
 	"github.com/gorilla/websocket"
@@ -29,3 +30,8 @@ func (c *cmdConsole) controlSocketHandler(control *websocket.Conn) {
 	closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
 	control.WriteMessage(websocket.CloseMessage, closeMsg)
 }
+
+func (c *cmdConsole) findCommand(name string) string {
+	path, _ := exec.LookPath(name)
+	return path
+}
diff --git a/lxc/console_windows.go b/lxc/console_windows.go
index 74649d6e73..422e6113b2 100644
--- a/lxc/console_windows.go
+++ b/lxc/console_windows.go
@@ -4,6 +4,10 @@ package main
 
 import (
 	"fmt"
+	"io/ioutil"
+	"os/exec"
+	"path/filepath"
+	"strings"
 
 	"github.com/gorilla/websocket"
 )
@@ -21,3 +25,22 @@ func (c *cmdConsole) controlSocketHandler(control *websocket.Conn) {
 		fmt.Printf("error setting term size %s\n", err)
 	}
 }
+
+func (c *cmdConsole) findCommand(name string) string {
+	path, _ := exec.LookPath(name)
+	if path == "" {
+		// Let's see if it's not in the usual location.
+		programs, err := ioutil.ReadDir("\\Program Files")
+		if err != nil {
+			return ""
+		}
+
+		for _, entry := range programs {
+			if strings.HasPrefix(entry.Name(), "VirtViewer") {
+				return filepath.Join("\\Program Files", entry.Name(), "bin", "remote-viewer.exe")
+			}
+		}
+	}
+
+	return path
+}


More information about the lxc-devel mailing list