-
Notifications
You must be signed in to change notification settings - Fork 14
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
fix: ensure containerd-related directories removed on failed bootstrap/join-cluster
.
#863
base: main
Are you sure you want to change the base?
Changes from all commits
fa16a12
9303487
83763de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
|
||
"dario.cat/mergo" | ||
"github.com/canonical/k8s/pkg/k8sd/images" | ||
"github.com/canonical/k8s/pkg/log" | ||
"github.com/canonical/k8s/pkg/snap" | ||
snaputil "github.com/canonical/k8s/pkg/snap/util" | ||
"github.com/canonical/k8s/pkg/utils" | ||
|
@@ -166,23 +167,79 @@ func Containerd(snap snap.Snap, extraContainerdConfig map[string]any, extraArgs | |
return nil | ||
} | ||
|
||
func saveSnapContainerdPaths(s snap.Snap) error { | ||
// Write the containerd-related paths to files to properly clean-up on removal. | ||
// Returns a mapping between the absolute paths of the lockfiles within the | ||
// k8s snap and the absolute paths of the containerd directory they lock. | ||
func containerdLockPathsForSnap(s snap.Snap) map[string]string { | ||
m := map[string]string{ | ||
"containerd-socket-path": s.ContainerdSocketDir(), | ||
"containerd-config-dir": s.ContainerdConfigDir(), | ||
"containerd-root-dir": s.ContainerdRootDir(), | ||
"containerd-cni-bin-dir": s.CNIBinDir(), | ||
} | ||
|
||
for filename, content := range m { | ||
if err := utils.WriteFile(filepath.Join(s.LockFilesDir(), filename), []byte(content), 0o600); err != nil { | ||
return fmt.Errorf("failed to write %s: %w", filename, err) | ||
prefixed := map[string]string{} | ||
for k, v := range m { | ||
prefixed[filepath.Join(s.LockFilesDir(), k)] = v | ||
} | ||
|
||
return prefixed | ||
} | ||
|
||
// Creates the lock files for the containerd directory paths to be used for later cleanup. | ||
func saveSnapContainerdPaths(s snap.Snap) error { | ||
for lockpath, dirpath := range containerdLockPathsForSnap(s) { | ||
if err := utils.WriteFile(lockpath, []byte(dirpath), 0o600); err != nil { | ||
return fmt.Errorf("failed to write %s: %w", lockpath, err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Attempts to clean up all containerd directories which were created | ||
// by the k8s-snap based on the existence of their respective lockfiles | ||
// located in the directory returned by `s.LockFilesDir()`. | ||
func TryCleanupContainerdPaths(s snap.Snap) error { | ||
log := log.L() | ||
|
||
for lockpath, dirpath := range containerdLockPathsForSnap(s) { | ||
// Ensure lockfile exists: | ||
if _, err := os.Stat(lockpath); os.IsNotExist(err) { | ||
log.Info("WARN: failed to find containerd lockfile, no cleanup will be perfomed", "lockfile", lockpath, "directory", dirpath) | ||
continue | ||
} | ||
|
||
// Ensure lockfile's contents is the one we expect: | ||
lockfile_contents := "" | ||
if contents, err := os.ReadFile(lockpath); err != nil { | ||
log.Info("WARN: failed to read contents of lockfile", "lockfile", lockpath, "error", err) | ||
continue | ||
} else { | ||
lockfile_contents = string(contents) | ||
} | ||
|
||
if lockfile_contents != dirpath { | ||
log.Info("WARN: lockfile points to different path than expected", "lockfile", lockpath, "expected", dirpath, "actual", lockfile_contents) | ||
continue | ||
} | ||
|
||
// Check directory exists before attempting to remove: | ||
if _, err := os.Stat(dirpath); os.IsNotExist(err) { | ||
log.Info("Containerd directory doesn't exist; skipping cleanup", "directory", dirpath) | ||
} else { | ||
if err := os.RemoveAll(dirpath); err != nil { | ||
log.Info("WARN: failed to remove containerd data directory", "directory", dirpath, "error", err) | ||
continue // Avoid removing the lockfile path. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't cleanup done on a best effort basis? Do we check the lockfile later on at bootstrap time? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is, but IMO it would have been "incorrect" for this code to remove the lockfile path if it had failed to remove the actual path it was pointing too. (IMO either both should be deleted; or none)
AFAIK the These contents of the lockfiles are only read by the |
||
} | ||
} | ||
|
||
if err := os.Remove(lockpath); err != nil { | ||
log.Info("WARN: Failed to remove containerd lockfile", "lockfile", lockpath) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func init() { | ||
images.Register(defaultPauseImage) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this check ensure for us? Is it to check someone else did not create the locks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I admit I have no concrete usecase where this check would ever be relevant, it just "felt right" to double-check in case someone changed their contents from what the k8s-snap expects.
Note that, as far as I can tell, the k8s-snap does NOT use the paths written within the lockfiles (considering they're hardcoded/derived within the k8s-snap itself, it has no need for them).
The only place I've seen the actual file contents read is in the
remove
hook of the snap.I could gladly remove it if it's "too redundant" or switch the k8s-snap to always clean up the paths which are written within the file, instead of what the
k8s-snap
expects that file lock to be for...