Skip to content

Commit

Permalink
Merge pull request #12404 from tomponline/tp-vm-vsockid
Browse files Browse the repository at this point in the history
lxd-agent: Fixes vsock listener restart on boot due to vsock module not being fully initialised
  • Loading branch information
monstermunchkin authored Oct 18, 2023
2 parents b6ec0f2 + 0e62d0e commit 2a7a67f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 17 deletions.
33 changes: 31 additions & 2 deletions lxd-agent/api_1.0.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"time"

"github.com/mdlayher/vsock"

Expand Down Expand Up @@ -191,14 +193,41 @@ func getClient(CID uint32, port int, serverCertificate string) (*http.Client, er
return client, nil
}

// waitVsockContextID checks for valid local context ID and returns it.
// If no valid context ID has been ascertained when the context is cancelled, the last error is returned.
func waitVsockContextID(ctx context.Context) (uint32, error) {
const CIDAny uint32 = 4294967295 // Equivalent to VMADDR_CID_ANY.

for {
cid, err := vsock.ContextID()
if cid == CIDAny {
// Ignore VMADDR_CID_ANY as this seems to indicate the vsock module is still initialising.
err = fmt.Errorf("Invalid context ID %d", cid)
} else if err == nil {
return cid, nil
}

ctxErr := ctx.Err()
if ctxErr != nil {
if err != nil {
return 0, err
}

return 0, ctxErr
}

time.Sleep(time.Second)
}
}

func startHTTPServer(d *Daemon, debug bool) error {
// Setup the listener on VM's context ID for inbound connections from LXD.
l, err := vsock.Listen(shared.HTTPSDefaultPort, nil)
l, err := vsock.ListenContextID(d.localCID, shared.HTTPSDefaultPort, nil)
if err != nil {
return fmt.Errorf("Failed to listen on vsock: %w", err)
}

logger.Info("Started vsock listener")
logger.Info("Started vsock listener", logger.Ctx{"contextID": d.localCID})

// Load the expected server certificate.
cert, err := shared.ReadCert("server.crt")
Expand Down
4 changes: 0 additions & 4 deletions lxd-agent/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"sync"

"github.com/canonical/lxd/lxd/events"
"github.com/canonical/lxd/lxd/vsock"
)

// A Daemon can respond to requests from a shared client.
Expand All @@ -31,11 +30,8 @@ type Daemon struct {
func newDaemon(debug, verbose bool) *Daemon {
lxdEvents := events.NewServer(debug, verbose, nil)

cid, _ := vsock.ContextID()

return &Daemon{
events: lxdEvents,
chConnected: make(chan struct{}),
localCID: cid,
}
}
29 changes: 18 additions & 11 deletions lxd-agent/main_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/canonical/lxd/lxd/instance/instancetype"
"github.com/canonical/lxd/lxd/storage/filesystem"
"github.com/canonical/lxd/lxd/util"
"github.com/canonical/lxd/lxd/vsock"
"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/logger"
)
Expand Down Expand Up @@ -130,6 +129,16 @@ func (c *cmdAgent) Run(cmd *cobra.Command, args []string) error {

d := newDaemon(c.global.flagLogDebug, c.global.flagLogVerbose)

// Wait up to 30s to get a valid local vsock context ID.
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
d.localCID, err = waitVsockContextID(ctx)
if err != nil {
cancel()
return fmt.Errorf("Failed getting vsock context ID: %w", err)
}

cancel()

// Start the server.
err = startHTTPServer(d, c.global.flagLogDebug)
if err != nil {
Expand All @@ -138,26 +147,24 @@ func (c *cmdAgent) Run(cmd *cobra.Command, args []string) error {

// Check context ID periodically, and restart the HTTP server if needed.
go func() {
for range time.Tick(30 * time.Second) {
cid, err := vsock.ContextID()
if err != nil {
continue
}

if d.localCID == cid {
for {
time.Sleep(30 * time.Second)
cid, err := waitVsockContextID(context.Background())
if err != nil || d.localCID == cid {
continue
}

// Restart server
logger.Warn("Restarting the vsock server due to context ID change", logger.Ctx{"oldID": d.localCID, "newID": cid})
servers["http"].Close()

// Update context ID.
d.localCID = cid

err = startHTTPServer(d, c.global.flagLogDebug)
if err != nil {
errChan <- err
}

// Update context ID.
d.localCID = cid
}
}()

Expand Down

0 comments on commit 2a7a67f

Please sign in to comment.