From: Yu Watanabe Date: Tue, 15 Oct 2024 08:25:09 +0000 (+0900) Subject: nspawn: introduce --cleanup option to clear propagation and unix-export directories X-Git-Tag: v258-rc1~1069^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c06a630f0c7d2396d47dbde93784c670791805fb;p=thirdparty%2Fsystemd.git nspawn: introduce --cleanup option to clear propagation and unix-export directories This is useful when the previous invocation is unexpectedly killed. Otherwise, if systemd-nspawn is killed forcibly, then unix-export directory is not cleared and unmounted, and the subsequent invocation will fail. E.g. === [ 18.895515] TEST-13-NSPAWN.sh[645]: + machinectl start long-running [ 18.945703] systemd-nspawn[1387]: Mount point '/run/systemd/nspawn/unix-export/long-running' exists already, refusing. [ 18.949236] systemd[1]: systemd-nspawn@long-running.service: Failed with result 'exit-code'. [ 18.949743] systemd[1]: Failed to start systemd-nspawn@long-running.service. === --- diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 213f434fe77..1ade5483a8f 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -223,6 +223,20 @@ + + + + + Clean up left-over mounts and underlying mount points used by the container, and exit without + invoking any containers. This may be useful when the previous invocation of + systemd-nspawn was unexpectedly terminated. This requires at least one of + , , or + to determine the mounts to be cleaned up. + + + + + diff --git a/shell-completion/bash/systemd-nspawn b/shell-completion/bash/systemd-nspawn index e1829287f45..5d54fca3346 100644 --- a/shell-completion/bash/systemd-nspawn +++ b/shell-completion/bash/systemd-nspawn @@ -66,7 +66,8 @@ _systemd_nspawn() { local -A OPTS=( [STANDALONE]='-h --help --version --private-network -b --boot --read-only -q --quiet --share-system - --keep-unit -n --network-veth -j -x --ephemeral -a --as-pid2 -U --suppress-sync=yes' + --keep-unit -n --network-veth -j -x --ephemeral -a --as-pid2 -U --suppress-sync=yes + --cleanup' [ARG]='-D --directory -u --user --uuid --capability --drop-capability --link-journal --bind --bind-ro -M --machine -S --slice -E --setenv -Z --selinux-context -L --selinux-apifs-context --register --network-interface --network-bridge --personality -i --image --image-policy --tmpfs diff --git a/shell-completion/zsh/_systemd-nspawn b/shell-completion/zsh/_systemd-nspawn index a9856b50083..5f081700644 100644 --- a/shell-completion/zsh/_systemd-nspawn +++ b/shell-completion/zsh/_systemd-nspawn @@ -16,6 +16,7 @@ _arguments \ '(- *)'{-h,--help}'[Show this help.]' \ '(- *)--version[Print a short version string and exit.]' \ '(--quiet -q)'{--quiet,-q}'[Turns off any status output by the tool itself.]' \ + '--cleanup[Cleanup left-over mounts and underlying mount points used by the container.]' \ '(--directory -D)'{--directory=,-D+}'[Directory to use as file system root for the namespace container. If omitted the current directory will be used.]:directories:_directories' \ '--template=[Initialize root directory from template directory, if missing.]:template:_directories' \ '(--ephemeral -x)'{--ephemeral,-x}'[Run container with snapshot of root directory, and remove it after exit.]' \ diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 1916e441d8f..f19014016f8 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -236,6 +236,7 @@ static Architecture arg_architecture = _ARCHITECTURE_INVALID; static ImagePolicy *arg_image_policy = NULL; static char *arg_background = NULL; static bool arg_privileged = false; +static bool arg_cleanup = false; STATIC_DESTRUCTOR_REGISTER(arg_directory, freep); STATIC_DESTRUCTOR_REGISTER(arg_template, freep); @@ -327,6 +328,8 @@ static int help(void) { " -q --quiet Do not show status information\n" " --no-pager Do not pipe output into a pager\n" " --settings=BOOLEAN Load additional settings from .nspawn file\n" + " --cleanup Clean up left-over mounts and underlying mount\n" + " points used by the container\n" "\n%3$sImage:%4$s\n" " -D --directory=PATH Root directory for the container\n" " --template=PATH Initialize root directory from template directory,\n" @@ -751,6 +754,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SUPPRESS_SYNC, ARG_IMAGE_POLICY, ARG_BACKGROUND, + ARG_CLEANUP, }; static const struct option options[] = { @@ -826,6 +830,7 @@ static int parse_argv(int argc, char *argv[]) { { "suppress-sync", required_argument, NULL, ARG_SUPPRESS_SYNC }, { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, { "background", required_argument, NULL, ARG_BACKGROUND }, + { "cleanup", no_argument, NULL, ARG_CLEANUP }, {} }; @@ -1609,6 +1614,10 @@ static int parse_argv(int argc, char *argv[]) { return r; break; + case ARG_CLEANUP: + arg_cleanup = true; + break; + case '?': return -EINVAL; @@ -5919,6 +5928,34 @@ static void initialize_defaults(void) { arg_private_network = !arg_privileged; } +static void cleanup_propagation_and_export_directories(void) { + const char *p; + + if (!arg_machine || !arg_privileged) + return; + + p = strjoina("/run/systemd/nspawn/propagate/", arg_machine); + (void) rm_rf(p, REMOVE_ROOT); + + p = strjoina("/run/systemd/nspawn/unix-export/", arg_machine); + (void) umount2(p, MNT_DETACH|UMOUNT_NOFOLLOW); + (void) rmdir(p); +} + +static int do_cleanup(void) { + int r; + + if (arg_ephemeral) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot specify --ephemeral with --cleanup."); + + r = determine_names(); + if (r < 0) + return r; + + cleanup_propagation_and_export_directories(); + return 0; +} + static int run(int argc, char *argv[]) { bool remove_directory = false, remove_image = false, veth_created = false; _cleanup_close_ int master = -EBADF, userns_fd = -EBADF, mount_fd = -EBADF; @@ -5941,6 +5978,9 @@ static int run(int argc, char *argv[]) { if (r <= 0) goto finish; + if (arg_cleanup) + return do_cleanup(); + r = cant_be_in_netns(); if (r < 0) goto finish; @@ -6476,6 +6516,8 @@ finish: (void) rmdir(p); } + cleanup_propagation_and_export_directories(); + expose_port_flush(&fw_ctx, arg_expose_ports, AF_INET, &expose_args.address4); expose_port_flush(&fw_ctx, arg_expose_ports, AF_INET6, &expose_args.address6); diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in index 0dec0e04785..c1426e673bd 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -19,6 +19,7 @@ RequiresMountsFor=/var/lib/machines/%i [Service] # Make sure the DeviceAllow= lines below can properly resolve the 'block-loop' expression (and others) ExecStart=systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth -U --settings=override --machine=%i +ExecStopPost=systemd-nspawn --cleanup --machine=%i KillMode=mixed Type=notify RestartForceExitStatus=133