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

Fix containerd-related path cleanup on failed bootstrap/join and associated test. #910

Merged
merged 3 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 15 additions & 0 deletions src/k8s/pkg/k8sd/setup/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ func defaultContainerdConfig(
// Containerd configures configuration and arguments for containerd on the local node.
// Optionally, a number of registry mirrors and auths can be configured.
func Containerd(snap snap.Snap, extraContainerdConfig map[string]any, extraArgs map[string]*string) error {
// We create the directories here since PreInitCheck is called before this
// This ensures we only create the directories if we are going to configure containerd
for _, dir := range []string{
snap.ContainerdConfigDir(),
snap.ContainerdExtraConfigDir(),
snap.ContainerdRegistryConfigDir(),
} {
if dir == "" {
continue
}
if err := os.MkdirAll(dir, 0o700); err != nil {
return fmt.Errorf("failed to create required directory: %w", err)
}
}

configToml := defaultContainerdConfig(
snap.CNIConfDir(),
snap.CNIBinDir(),
Expand Down
3 changes: 0 additions & 3 deletions src/k8s/pkg/k8sd/setup/directories.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ func EnsureAllDirectories(snap snap.Snap) error {

for _, dir := range []string{
snap.CNIConfDir(),
snap.ContainerdConfigDir(),
snap.ContainerdExtraConfigDir(),
snap.ContainerdRegistryConfigDir(),
snap.K8sDqliteStateDir(),
snap.KubernetesConfigDir(),
snap.KubernetesPKIDir(),
Expand Down
18 changes: 18 additions & 0 deletions tests/integration/templates/bootstrap-fail.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contains the bootstrap configuration for the smoke test.
cluster-config:
network:
enabled: true
dns:
enabled: true
ingress:
enabled: true
load-balancer:
enabled: true
local-storage:
enabled: true
gateway:
enabled: true
metrics-server:
enabled: true
extra-node-kube-apiserver-args:
--foo: bar
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea, it hadn't crossed my mind to induce the failure with incorrect args!

31 changes: 7 additions & 24 deletions tests/integration/tests/test_cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,14 @@ def test_node_cleanup_new_containerd_path(instances: List[harness.Instance]):


@pytest.mark.node_count(1)
@pytest.mark.no_setup()
@pytest.mark.disable_k8s_bootstrapping()
@pytest.mark.tags(tags.NIGHTLY)
def test_containerd_path_cleanup_on_failed_init(
instances: List[harness.Instance], tmp_path
):
def test_containerd_path_cleanup_on_failed_init(instances: List[harness.Instance]):
"""Tests that a failed `bootstrap` properly cleans up any
containerd-related paths it may have created as part of the
failed `bootstrap`.

It introduces a bootstrap failure by pre-creating the containerd socket
path before running `k8s-bootstrap`.
It introduces a bootstrap failure by supplying an incorrect argument to the kube-apiserver.

The bootstrap/join-cluster aborting behavior was added in this PR:
https://github.com/canonical/k8s-snap/pull/772
Expand All @@ -132,33 +129,19 @@ def test_containerd_path_cleanup_on_failed_init(
"""
instance = instances[0]
expected_code = 1
expected_message = "containerd socket already exists"

util.setup_k8s_snap(instance, tmp_path, config.SNAP, connect_interfaces=False)

# Pre-create the containerd socket directory in the test instance:
instance.exec(["mkdir", "-p", CONTAINERD_SOCKET_DIRECTORY_CLASSIC], check=True)
fail_bootstrap_config = (config.MANIFESTS_DIR / "bootstrap-fail.yaml").read_text()

proc = instance.exec(
["k8s", "bootstrap"], capture_output=True, text=True, check=False
["k8s", "bootstrap", "--file", "-"],
input=str.encode(fail_bootstrap_config),
check=False,
)

if proc.returncode != expected_code:
raise AssertionError(
f"Expected `k8s bootstrap` to exit with code {expected_code}, "
f"but it exited with {proc.returncode}.\n"
f"Stdout was: \n{proc.stdout}.\nStderr was: \n{proc.stderr}"
)

if expected_message not in proc.stderr:
raise AssertionError(
f"Expected to find socket-related warning '{expected_message}' in "
"stderr of the `k8s bootstrap` command.\n"
f"Stdout was: \n{proc.stdout}.\nStderr was: \n{proc.stderr}"
)

_assert_paths_not_exist(instance, CONTAINERD_PATHS)

# Remove the directory and ensure the bootstrap succeeds:
instance.exec(["rmdir", CONTAINERD_SOCKET_DIRECTORY_CLASSIC], check=True)
instance.exec(["k8s", "bootstrap"])
Loading