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: Revert server config if it cannot be set #12264

Merged
merged 1 commit into from
Sep 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions lxd/api_1.0.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/canonical/lxd/lxd/project"
"github.com/canonical/lxd/lxd/request"
"github.com/canonical/lxd/lxd/response"
"github.com/canonical/lxd/lxd/revert"
scriptletLoad "github.com/canonical/lxd/lxd/scriptlet/load"
"github.com/canonical/lxd/lxd/util"
"github.com/canonical/lxd/shared"
Expand Down Expand Up @@ -574,13 +575,20 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re

nodeChanged := map[string]string{}
var newNodeConfig *node.Config
oldNodeConfig := make(map[string]any)

err = s.DB.Node.Transaction(r.Context(), func(ctx context.Context, tx *db.NodeTx) error {
var err error
newNodeConfig, err = node.ConfigLoad(ctx, tx)
if err != nil {
return fmt.Errorf("Failed to load node config: %w", err)
}

// Keep old config around in case something goes wrong. In that case the config will be reverted.
for k, v := range newNodeConfig.Dump() {
oldNodeConfig[k] = v
}

// We currently don't allow changing the cluster.https_address once it's set.
if clustered {
curConfig, err := tx.Config(ctx)
Expand Down Expand Up @@ -632,6 +640,38 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re
}
}

revert := revert.New()
defer revert.Fail()

revert.Add(func() {
for key := range nodeValues {
val, ok := oldNodeConfig[key]
if !ok {
nodeValues[key] = nil
} else {
nodeValues[key] = val
}
}

err = s.DB.Node.Transaction(r.Context(), func(ctx context.Context, tx *db.NodeTx) error {
newNodeConfig, err := node.ConfigLoad(ctx, tx)
if err != nil {
return fmt.Errorf("Failed to load node config: %w", err)
}

_, err = newNodeConfig.Replace(nodeValues)
if err != nil {
return fmt.Errorf("Failed updating node config: %w", err)
}

return nil
})

if err != nil {
logger.Warn("Failed reverting node config", logger.Ctx{"err": err})
}
})

// Validate global configuration
hasRBAC := false
hasCandid := false
Expand All @@ -654,13 +694,20 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re
// Then deal with cluster wide configuration
var clusterChanged map[string]string
var newClusterConfig *clusterConfig.Config
oldClusterConfig := make(map[string]any)

err = s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error {
var err error
newClusterConfig, err = clusterConfig.Load(ctx, tx)
if err != nil {
return fmt.Errorf("Failed to load cluster config: %w", err)
}

// Keep old config around in case something goes wrong. In that case the config will be reverted.
for k, v := range newClusterConfig.Dump() {
oldClusterConfig[k] = v
}

if patch {
clusterChanged, err = newClusterConfig.Patch(req.Config)
} else {
Expand All @@ -678,6 +725,35 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re
}
}

revert.Add(func() {
for key := range req.Config {
val, ok := oldClusterConfig[key]
if !ok {
req.Config[key] = nil
} else {
req.Config[key] = val
}
}

err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error {
newClusterConfig, err = clusterConfig.Load(ctx, tx)
if err != nil {
return fmt.Errorf("Failed to load cluster config: %w", err)
}

_, err = newClusterConfig.Replace(req.Config)
if err != nil {
return fmt.Errorf("Failed updating cluster config: %w", err)
}

return nil
})

if err != nil {
logger.Warn("Failed reverting cluster config", logger.Ctx{"err": err})
}
})

// Notify the other nodes about changes
notifier, err := cluster.NewNotifier(s, s.Endpoints.NetworkCert(), s.ServerCert(), cluster.NotifyAlive)
if err != nil {
Expand Down Expand Up @@ -716,6 +792,8 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re
return response.SmartError(err)
}

revert.Success()

s.Events.SendLifecycle(project.Default, lifecycle.ConfigUpdated.Event(request.CreateRequestor(r), nil))

return response.EmptySyncResponse
Expand Down
Loading