[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