[lxc-devel] [lxd/master] VM Agent Link

tomponline on Github lxc-bot at linuxcontainers.org
Fri Nov 8 22:52:50 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 382 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191108/9dd28671/attachment.bin>
-------------- next part --------------
From fc6577e847ee55f0a4277e5798a980f2ea1fee5c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 8 Nov 2019 22:46:48 +0000
Subject: [PATCH 1/3] client/connection: Simplifies ConnectLXDHTTP

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/connection.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/client/connection.go b/client/connection.go
index 13ab844d6e..dde3e327a1 100644
--- a/client/connection.go
+++ b/client/connection.go
@@ -68,7 +68,7 @@ func ConnectLXD(url string, args *ConnectionArgs) (InstanceServer, error) {
 }
 
 // ConnectLXDHTTP lets you connect to a VM agent over a VM socket.
-func ConnectLXDHTTP(vsockID int, args *ConnectionArgs, client *http.Client) (InstanceServer, error) {
+func ConnectLXDHTTP(args *ConnectionArgs, client *http.Client) (InstanceServer, error) {
 	logger.Debugf("Connecting to a VM agent over a VM socket")
 
 	// Use empty args if not specified

From 87b276bed527d6d24111dc5bdee41641ff26c890 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 8 Nov 2019 22:51:14 +0000
Subject: [PATCH 2/3] lxd/vm/qemu: Adds agent connection setup

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/vm_qemu.go | 83 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 63 insertions(+), 20 deletions(-)

diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go
index b6b7d8e427..cef9508ddc 100644
--- a/lxd/vm_qemu.go
+++ b/lxd/vm_qemu.go
@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
-	"net"
 	"net/http"
 	"os"
 	"os/exec"
@@ -15,11 +14,11 @@ import (
 	"time"
 
 	"github.com/digitalocean/go-qemu/qmp"
-	"github.com/linuxkit/virtsock/pkg/vsock"
 	"github.com/pborman/uuid"
 	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 
+	lxdClient "github.com/lxc/lxd/client"
 	"github.com/lxc/lxd/lxd/backup"
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
@@ -33,6 +32,7 @@ import (
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/lxd/util"
+	"github.com/lxc/lxd/lxd/vsock"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 	log "github.com/lxc/lxd/shared/log15"
@@ -58,6 +58,11 @@ func vmQemuLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) (I
 		return nil, err
 	}
 
+	err = vm.initAgentClient()
+	if err != nil {
+		return nil, err
+	}
+
 	return vm, nil
 }
 
@@ -259,6 +264,55 @@ type vmQemu struct {
 	op *operations.Operation
 
 	expiryDate time.Time
+
+	agentClient *http.Client
+}
+
+func (vm *vmQemu) initAgentClient() error {
+	agentCertFile, _, err := vm.generateAgentCert()
+	if err != nil {
+		return err
+	}
+
+	agentCert, err := ioutil.ReadFile(agentCertFile)
+	if err != nil {
+		return err
+	}
+
+	// The connection uses mutual authentication, so use the LXD server's key & cert for client.
+	clientCertFile := shared.VarPath("server.crt")
+	clientKeyFile := shared.VarPath("server.key")
+
+	clientCert, err := ioutil.ReadFile(clientCertFile)
+	if err != nil {
+		return err
+	}
+
+	clientKey, err := ioutil.ReadFile(clientKeyFile)
+	if err != nil {
+		return err
+	}
+
+	vm.agentClient, err = vsock.HTTPClient(vm.vsockID(), string(clientCert), string(clientKey), string(agentCert))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// generateAgentCert creates the necessary server key and certificate if needed.
+func (vm *vmQemu) generateAgentCert() (agentCertFile string, agentKeyFile string, err error) {
+	agentCertFile = filepath.Join(vm.Path(), "agent.crt")
+	agentKeyFile = filepath.Join(vm.Path(), "agent.key")
+
+	// Create server certificate.
+	err = shared.FindOrGenCert(agentCertFile, agentKeyFile, true)
+	if err != nil {
+		return
+	}
+
+	return
 }
 
 func (vm *vmQemu) Freeze() error {
@@ -660,9 +714,7 @@ WantedBy=multi-user.target
 	}
 
 	// Check if we have both agent.crt and agent.key and if not generate a new set.
-	agentCertFile := filepath.Join(vm.Path(), "agent.cert")
-	agentKeyFile := filepath.Join(vm.Path(), "agent.key")
-	err = shared.FindOrGenCert(agentCertFile, agentKeyFile, true)
+	agentCertFile, agentKeyFile, err := vm.generateAgentCert()
 	if err != nil {
 		return "", err
 	}
@@ -1967,7 +2019,9 @@ func (vm *vmQemu) RenderState() (*api.InstanceState, error) {
 	pid, _ := vm.pid()
 
 	status, err := vm.agentGetState()
-	if err == nil {
+	if err != nil {
+		logger.Warn("Could not get VM state from agent", log.Ctx{"project": vm.Project(), "instance": vm.Name(), "err": err})
+	} else {
 		status.Pid = int64(pid)
 		status.Status = statusCode.String()
 		status.StatusCode = statusCode
@@ -1987,34 +2041,23 @@ func (vm *vmQemu) RenderState() (*api.InstanceState, error) {
 // agentGetState connects to the agent inside of the VM and does
 // an API call to get the current state.
 func (vm *vmQemu) agentGetState() (*api.InstanceState, error) {
-	var status api.InstanceState
-
 	// Ensure the correct vhost_vsock kernel module is loaded before establishing the vsock.
 	err := util.LoadModule("vhost_vsock")
 	if err != nil {
 		return nil, err
 	}
 
-	client := http.Client{
-		Transport: &http.Transport{
-			Dial: func(network, addr string) (net.Conn, error) {
-				return vsock.Dial(uint32(vm.vsockID()), 8443)
-			},
-		},
-	}
-
-	resp, err := client.Get("http://vm.socket/state")
+	agent, err := lxdClient.ConnectLXDHTTP(nil, vm.agentClient)
 	if err != nil {
 		return nil, err
 	}
-	defer resp.Body.Close()
 
-	err = json.NewDecoder(resp.Body).Decode(&status)
+	status, _, err := agent.GetInstanceState("")
 	if err != nil {
 		return nil, err
 	}
 
-	return &status, nil
+	return status, nil
 }
 
 func (vm *vmQemu) IsRunning() bool {

From c62e95009c98908bf55c472d91bf582b8a7432da Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 8 Nov 2019 22:51:39 +0000
Subject: [PATCH 3/3] lxd/vsock: Simplifies HTTPClient

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/vsock/vsock.go | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/lxd/vsock/vsock.go b/lxd/vsock/vsock.go
index 2e3d0a5ecd..1a590738b4 100644
--- a/lxd/vsock/vsock.go
+++ b/lxd/vsock/vsock.go
@@ -8,18 +8,20 @@ import (
 	"github.com/lxc/lxd/shared"
 )
 
-func vsockHTTPClient(vsockID int, tlsClientCert string, tlsClientKey string, tlsCA string, tlsServerCert string, insecureSkipVerify bool) (*http.Client, error) {
+// HTTPClient provides an HTTP client for using over vsock.
+func HTTPClient(vsockID int, tlsClientCert string, tlsClientKey string, tlsServerCert string) (*http.Client, error) {
 	client := &http.Client{}
 
-	// Get the TLS configuration
-	tlsConfig, err := shared.GetTLSConfigMem(tlsClientCert, tlsClientKey, tlsCA, tlsServerCert, insecureSkipVerify)
+	// Get the TLS configuration.
+	// tomp TODO remove insecure skip verify.
+	tlsConfig, err := shared.GetTLSConfigMem(tlsClientCert, tlsClientKey, "", tlsServerCert, true)
 	if err != nil {
 		return nil, err
 	}
 
 	client.Transport = &http.Transport{
 		TLSClientConfig: tlsConfig,
-		// Setup a VM socket dialer
+		// Setup a VM socket dialer.
 		Dial: func(network, addr string) (net.Conn, error) {
 			conn, err := dial(uint32(vsockID), 8443)
 			if err != nil {
@@ -28,7 +30,7 @@ func vsockHTTPClient(vsockID int, tlsClientCert string, tlsClientKey string, tls
 
 			tlsConn := tls.Client(conn, tlsConfig)
 
-			// Validate the connection
+			// Validate the connection.
 			err = tlsConn.Handshake()
 			if err != nil {
 				conn.Close()
@@ -40,9 +42,9 @@ func vsockHTTPClient(vsockID int, tlsClientCert string, tlsClientKey string, tls
 		DisableKeepAlives: true,
 	}
 
-	// Setup redirect policy
+	// Setup redirect policy.
 	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
-		// Replicate the headers
+		// Replicate the headers.
 		req.Header = via[len(via)-1].Header
 
 		return nil


More information about the lxc-devel mailing list