The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6423
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) === This PR links the LXD VM implementation with the lxd-agent running inside the VM.
From fc6577e847ee55f0a4277e5798a980f2ea1fee5c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel