Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lxd-agent: Retry VM hotplug directory share mounts #13674

Merged
merged 9 commits into from
Jun 27, 2024
18 changes: 13 additions & 5 deletions lxd-agent/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"os"
"strings"
"time"

"github.com/canonical/lxd/lxd/events"
"github.com/canonical/lxd/lxd/instance/instancetype"
Expand Down Expand Up @@ -150,12 +151,19 @@ func eventsProcess(event api.Event) {
mntSource = e.Mount.Source
}

l := logger.AddContext(logger.Ctx{"type": "virtiofs", "source": mntSource, "path": e.Config["path"]})

_ = os.MkdirAll(e.Config["path"], 0755)
_, err = shared.RunCommand("mount", "-t", "virtiofs", mntSource, e.Config["path"])
if err != nil {
logger.Infof("Failed to mount hotplug %q (Type: %q) to %q", mntSource, "virtiofs", e.Config["path"])
return

for i := 0; i < 5; i++ {
_, err = shared.RunCommand("mount", "-t", "virtiofs", mntSource, e.Config["path"])
if err == nil {
l.Info("Mounted hotplug")
return
}

time.Sleep(500 * time.Millisecond)
}

logger.Infof("Mounted hotplug %q (Type: %q) to %q", mntSource, "virtiofs", e.Config["path"])
l.Info("Failed to mount hotplug", logger.Ctx{"err": err})
}
3 changes: 2 additions & 1 deletion lxd-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func main() {
// Run the main command and handle errors
err := app.Execute()
if err != nil {
os.Exit(1)
// Ensure we exit with a non-zero exit code.
os.Exit(1) //nolint:revive
}
}
18 changes: 11 additions & 7 deletions lxd-agent/main_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ func (c *cmdAgent) Command() *cobra.Command {
// Run executes the agent command.
func (c *cmdAgent) Run(cmd *cobra.Command, args []string) error {
// Setup logger.
err := logger.InitLogger("", "", c.global.flagLogVerbose, c.global.flagLogDebug, nil)
err := logger.InitLogger("", "lxd-agent", c.global.flagLogVerbose, c.global.flagLogDebug, nil)
if err != nil {
os.Exit(1)
// Ensure we exit with a non-zero exit code.
os.Exit(1) //nolint:revive
}

logger.Info("Starting")
Expand Down Expand Up @@ -196,7 +197,8 @@ func (c *cmdAgent) Run(cmd *cobra.Command, args []string) error {
cancelStatusNotifier() // Ensure STOPPED status is written to QEMU status ringbuffer.
cancelFunc()

os.Exit(exitStatus)
// Ensure we exit with a relevant exit code.
os.Exit(exitStatus) //nolint:revive

return nil
}
Expand Down Expand Up @@ -281,10 +283,12 @@ func (c *cmdAgent) mountHostShares() {
mount.Target = fmt.Sprintf("/%s", mount.Target)
}

l := logger.AddContext(logger.Ctx{"source": mount.Source, "path": mount.Target})

if !shared.PathExists(mount.Target) {
err := os.MkdirAll(mount.Target, 0755)
if err != nil {
logger.Errorf("Failed to create mount target %q", mount.Target)
l.Error("Failed to create mount target", logger.Ctx{"err": err})
continue // Don't try to mount if mount point can't be created.
}
} else if filesystem.IsMountPoint(mount.Target) {
Expand All @@ -307,7 +311,7 @@ func (c *cmdAgent) mountHostShares() {

_, err = shared.RunCommand("mount", args...)
if err == nil {
logger.Infof("Mounted %q (Type: %q, Options: %v) to %q", mount.Source, "virtiofs", mount.Options, mount.Target)
l.Info("Mounted", logger.Ctx{"type": "virtiofs"})
continue
}
}
Expand All @@ -320,10 +324,10 @@ func (c *cmdAgent) mountHostShares() {

_, err = shared.RunCommand("mount", args...)
if err != nil {
logger.Errorf("Failed mount %q (Type: %q, Options: %v) to %q: %v", mount.Source, mount.FSType, mount.Options, mount.Target, err)
l.Error("Failed to mount", logger.Ctx{"err": err, "args": args})
continue
}

logger.Infof("Mounted %q (Type: %q, Options: %v) to %q", mount.Source, mount.FSType, mount.Options, mount.Target)
l.Info("Mounted", logger.Ctx{"type": mount.FSType})
}
}
2 changes: 1 addition & 1 deletion lxd-agent/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func createCmd(restAPI *mux.Router, version string, c APIEndpoint, cert *x509.Ce
if err != nil {
writeErr := response.InternalError(err).Render(w)
if writeErr != nil {
logger.Error("Failed writing error for HTTP response", logger.Ctx{"url": uri, "error": err, "writeErr": writeErr})
logger.Error("Failed writing error for HTTP response", logger.Ctx{"url": uri, "err": err, "writeErr": writeErr})
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion lxd/auth/drivers/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func (t *tls) GetPermissionChecker(ctx context.Context, r *http.Request, entitle
return func(entityURL *api.URL) bool {
eType, project, _, pathArgs, err := entity.ParseURL(entityURL.URL)
if err != nil {
logger.Warn("Permission checker failed to parse entity URL", logger.Ctx{"entity_url": entityURL, "error": err})
logger.Warn("Permission checker failed to parse entity URL", logger.Ctx{"entity_url": entityURL, "err": err})
return false
}

Expand Down
2 changes: 1 addition & 1 deletion lxd/auth/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ scan:
curType = entity.Type(submatch[1])
err := curType.Validate()
if err != nil {
logger.Warn("Entity type not defined for OpenFGA model type", logger.Ctx{"model_type": submatch[1], "error": err})
logger.Warn("Entity type not defined for OpenFGA model type", logger.Ctx{"model_type": submatch[1], "err": err})
continue scan
}

Expand Down
12 changes: 6 additions & 6 deletions lxd/cluster/membership.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ func Join(state *state.State, gateway *Gateway, networkCert *shared.CertInfo, se
return nil
})
if err != nil {
logger.Error("Failed to unlock global database after cluster join error", logger.Ctx{"error": err})
logger.Error("Failed to unlock global database after cluster join error", logger.Ctx{"err": err})
}
})

Expand Down Expand Up @@ -437,32 +437,32 @@ func Join(state *state.State, gateway *Gateway, networkCert *shared.CertInfo, se
return tx.ReplaceRaftNodes([]db.RaftNode{})
})
if err != nil {
logger.Error("Failed to clear local raft node records after cluster join error", logger.Ctx{"error": err})
logger.Error("Failed to clear local raft node records after cluster join error", logger.Ctx{"err": err})
return
}

err = gateway.Shutdown()
if err != nil {
logger.Error("Failed to shutdown gateway after cluster join error", logger.Ctx{"error": err})
logger.Error("Failed to shutdown gateway after cluster join error", logger.Ctx{"err": err})
return
}

err = os.RemoveAll(state.OS.GlobalDatabaseDir())
if err != nil {
logger.Error("Failed to remove raft data after cluster join error", logger.Ctx{"error": err})
logger.Error("Failed to remove raft data after cluster join error", logger.Ctx{"err": err})
return
}

gateway.networkCert = oldCert
err = gateway.init(false)
if err != nil {
logger.Error("Failed to re-initialize gateway after cluster join error", logger.Ctx{"error": err})
logger.Error("Failed to re-initialize gateway after cluster join error", logger.Ctx{"err": err})
return
}

_, err = cluster.EnsureSchema(state.DB.Cluster.DB(), localClusterAddress, state.OS.GlobalDatabaseDir())
if err != nil {
logger.Error("Failed to reload schema after cluster join error", logger.Ctx{"error": err})
logger.Error("Failed to reload schema after cluster join error", logger.Ctx{"err": err})
return
}
})
Expand Down
2 changes: 1 addition & 1 deletion lxd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ func (d *Daemon) createCmd(restAPI *mux.Router, version string, c APIEndpoint) {
var forwardedIdentityProviderGroups []string
err = json.Unmarshal([]byte(forwardedIdentityProviderGroupsJSON), &forwardedIdentityProviderGroups)
if err != nil {
logger.Error("Failed unmarshalling identity provider groups from forwarded request header", logger.Ctx{"error": err})
logger.Error("Failed unmarshalling identity provider groups from forwarded request header", logger.Ctx{"err": err})
} else {
ctx = context.WithValue(ctx, request.CtxForwardedIdentityProviderGroups, forwardedIdentityProviderGroups)
}
Expand Down
2 changes: 1 addition & 1 deletion lxd/firewall/drivers/drivers_xtables.go
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,7 @@ func (d Xtables) NetworkApplyForwards(networkName string, rules []AddressForward
reverter.Add(func() {
err := clearNetworkForwards()
if err != nil {
logger.Error("Failed to clear firewall rules after failing to apply network forwards", logger.Ctx{"network_name": networkName, "error": err})
logger.Error("Failed to clear firewall rules after failing to apply network forwards", logger.Ctx{"network_name": networkName, "err": err})
}
})

Expand Down
10 changes: 5 additions & 5 deletions lxd/identities.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,15 +832,15 @@ func updateIdentityCache(d *Daemon) {
if cacheEntry.AuthenticationMethod == api.AuthenticationMethodTLS {
cert, err := id.X509()
if err != nil {
logger.Warn("Failed to extract x509 certificate from TLS identity metadata", logger.Ctx{"error": err})
logger.Warn("Failed to extract x509 certificate from TLS identity metadata", logger.Ctx{"err": err})
continue
}

cacheEntry.Certificate = cert
} else if cacheEntry.AuthenticationMethod == api.AuthenticationMethodOIDC {
subject, err := id.Subject()
if err != nil {
logger.Warn("Failed to extract OIDC subject from OIDC identity metadata", logger.Ctx{"error": err})
logger.Warn("Failed to extract OIDC subject from OIDC identity metadata", logger.Ctx{"err": err})
continue
}

Expand All @@ -853,7 +853,7 @@ func updateIdentityCache(d *Daemon) {
if id.Type == api.IdentityTypeCertificateServer {
cert, err := id.ToCertificate()
if err != nil {
logger.Warn("Failed to convert TLS identity to server certificate", logger.Ctx{"error": err})
logger.Warn("Failed to convert TLS identity to server certificate", logger.Ctx{"err": err})
}

localServerCerts = append(localServerCerts, *cert)
Expand All @@ -872,7 +872,7 @@ func updateIdentityCache(d *Daemon) {

err = d.identityCache.ReplaceAll(identityCacheEntries, idpGroupMapping)
if err != nil {
logger.Warn("Failed to update identity cache", logger.Ctx{"error": err})
logger.Warn("Failed to update identity cache", logger.Ctx{"err": err})
}
}

Expand Down Expand Up @@ -907,7 +907,7 @@ func updateIdentityCacheFromLocal(d *Daemon) error {

id, err := dbCert.ToIdentity()
if err != nil {
logger.Warn("Failed to convert node certificate into identity entry", logger.Ctx{"error": err})
logger.Warn("Failed to convert node certificate into identity entry", logger.Ctx{"err": err})
continue
}

Expand Down
8 changes: 4 additions & 4 deletions lxd/project/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1474,19 +1474,19 @@ func FilterUsedBy(authorizer auth.Authorizer, r *http.Request, entries []string)
for _, entry := range entries {
u, err := url.Parse(entry)
if err != nil {
logger.Warn("Failed to parse project used-by entity URL", logger.Ctx{"url": entry, "error": err})
logger.Warn("Failed to parse project used-by entity URL", logger.Ctx{"url": entry, "err": err})
continue
}

entityType, projectName, location, pathArguments, err := entity.ParseURL(*u)
if err != nil {
logger.Warn("Failed to parse project used-by entity URL", logger.Ctx{"url": entry, "error": err})
logger.Warn("Failed to parse project used-by entity URL", logger.Ctx{"url": entry, "err": err})
continue
}

entityURL, err := entityType.URL(projectName, location, pathArguments...)
if err != nil {
logger.Warn("Failed to create canonical entity URL for project used-by filtering", logger.Ctx{"url": entry, "error": err})
logger.Warn("Failed to create canonical entity URL for project used-by filtering", logger.Ctx{"url": entry, "err": err})
continue
}

Expand Down Expand Up @@ -1522,7 +1522,7 @@ func FilterUsedBy(authorizer auth.Authorizer, r *http.Request, entries []string)
// Otherwise get a permission checker for the entity type.
canViewEntity, err := authorizer.GetPermissionChecker(r.Context(), r, auth.EntitlementCanView, entityType)
if err != nil {
logger.Error("Failed to get permission checker for project used-by filtering", logger.Ctx{"entity_type": entityType, "error": err})
logger.Error("Failed to get permission checker for project used-by filtering", logger.Ctx{"entity_type": entityType, "err": err})
continue
}

Expand Down
Loading