mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
nspawn: introduce --cleanup option (#34776)
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. ```
This commit is contained in:
@@ -223,6 +223,20 @@
|
||||
<xi:include href="version-info.xml" xpointer="v226"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--cleanup</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>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
|
||||
<command>systemd-nspawn</command> was unexpectedly terminated. This requires at least one of
|
||||
<option>-M/--machine=</option>, <option>-D/--directory=</option>, or <option>-i/--image=</option>
|
||||
to determine the mounts to be cleaned up.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<refsect2>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.]' \
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -287,6 +287,10 @@ rm -f /var/lib/machines/long-running/trap
|
||||
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "whom": "leader", "signal": 5}'
|
||||
timeout 120 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
|
||||
|
||||
# sending KILL signal
|
||||
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "signal": 9}'
|
||||
timeout 30 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{\"name\":\"long-running\"}'; do sleep 0.5; done"
|
||||
|
||||
# test io.systemd.Machine.Terminate
|
||||
long_running_machine_start
|
||||
rm -f /var/lib/machines/long-running/terminate
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user