From: Luca Boccassi Date: Thu, 29 Sep 2022 21:41:55 +0000 (+0100) Subject: portablectl: add --force attach/detach X-Git-Tag: v252-rc1~57 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ace212f577572bcbab5a464d13bf09418a6e7fa4;p=thirdparty%2Fsystemd.git portablectl: add --force attach/detach Allows to skip check that ensures units must not be running. I have a use case that would use reattach, except the orchestrator is using a non-standard versioning scheme, so image matching cannot work. As a workaround, need to be able to detach and then attach manually, without stopping the units to avoid extended downtimes and loss of FD store. --- diff --git a/man/org.freedesktop.portable1.xml b/man/org.freedesktop.portable1.xml index 0007e0c2ded..0e926fe850f 100644 --- a/man/org.freedesktop.portable1.xml +++ b/man/org.freedesktop.portable1.xml @@ -307,10 +307,13 @@ node /org/freedesktop/portable1 { The AttachImageWithExtensions(), DetachImageWithExtensions() and ReattachImageWithExtensions() methods take in options as flags instead of - booleans to allow for extendability, defined as follows: + booleans to allow for extendability. SD_SYSTEMD_PORTABLE_FORCE will cause + safety checks that ensure the units are not running while the new image is attached or detached + to be skipped. They are defined as follows: #define SD_SYSTEMD_PORTABLE_RUNTIME (UINT64_C(1) << 0) +#define SD_SYSTEMD_PORTABLE_FORCE (UINT64_C(1) << 1) diff --git a/man/portablectl.xml b/man/portablectl.xml index ed2089c63a3..64927a2fe67 100644 --- a/man/portablectl.xml +++ b/man/portablectl.xml @@ -374,6 +374,13 @@ and detaching. + + + + Skip safety checks and attach or detach images (with extensions) without first ensuring + that the units are not running. + + diff --git a/src/portable/portable.c b/src/portable/portable.c index 5d0a965db5f..202442903f3 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -1357,19 +1357,20 @@ int portable_attach( if (r < 0) return r; - HASHMAP_FOREACH(item, unit_files) { - r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, &paths, item->name); - if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name); - if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' exists on the host already, refusing.", item->name); + if (!FLAGS_SET(flags, PORTABLE_REATTACH) && !FLAGS_SET(flags, PORTABLE_FORCE)) + HASHMAP_FOREACH(item, unit_files) { + r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, &paths, item->name); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name); + if (r > 0) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' exists on the host already, refusing.", item->name); - r = unit_file_is_active(bus, item->name, error); - if (r < 0) - return r; - if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active already, refusing.", item->name); - } + r = unit_file_is_active(bus, item->name, error); + if (r < 0) + return r; + if (r > 0) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active already, refusing.", item->name); + } HASHMAP_FOREACH(item, unit_files) { r = attach_unit_file(&paths, image->path, image->type, extension_images, @@ -1599,11 +1600,13 @@ int portable_detach( if (r == 0) continue; - r = unit_file_is_active(bus, unit_name, error); - if (r < 0) - return r; - if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active, can't detach.", unit_name); + if (!FLAGS_SET(flags, PORTABLE_REATTACH) && !FLAGS_SET(flags, PORTABLE_FORCE)) { + r = unit_file_is_active(bus, unit_name, error); + if (r < 0) + return r; + if (r > 0) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active, can't detach.", unit_name); + } r = set_ensure_consume(&unit_files, &string_hash_ops_free, TAKE_PTR(unit_name)); if (r < 0) diff --git a/src/portable/portable.h b/src/portable/portable.h index c6061cc589f..dc2f8781b77 100644 --- a/src/portable/portable.h +++ b/src/portable/portable.h @@ -22,10 +22,11 @@ typedef struct PortableMetadata { typedef enum PortableFlags { PORTABLE_RUNTIME = 1 << 0, /* Public API via DBUS, do not change */ - PORTABLE_PREFER_COPY = 1 << 1, - PORTABLE_PREFER_SYMLINK = 1 << 2, - PORTABLE_REATTACH = 1 << 3, - _PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME, + PORTABLE_FORCE = 1 << 1, /* Public API via DBUS, do not change */ + PORTABLE_PREFER_COPY = 1 << 2, + PORTABLE_PREFER_SYMLINK = 1 << 3, + PORTABLE_REATTACH = 1 << 4, + _PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME | PORTABLE_FORCE, _PORTABLE_TYPE_MAX, _PORTABLE_TYPE_INVALID = -EINVAL, } PortableFlags; diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index c3c22220c22..7e3627d1daf 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -48,6 +48,7 @@ static bool arg_enable = false; static bool arg_now = false; static bool arg_no_block = false; static char **arg_extension_images = NULL; +static bool arg_force = false; STATIC_DESTRUCTOR_REGISTER(arg_extension_images, strv_freep); @@ -868,7 +869,7 @@ static int attach_reattach_image(int argc, char *argv[], const char *method) { return bus_log_create_error(r); if (STR_IN_SET(method, "AttachImageWithExtensions", "ReattachImageWithExtensions")) { - uint64_t flags = arg_runtime ? PORTABLE_RUNTIME : 0; + uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE : 0); r = sd_bus_message_append(m, "st", arg_copy_mode, flags); } else @@ -940,7 +941,7 @@ static int detach_image(int argc, char *argv[], void *userdata) { if (strv_isempty(arg_extension_images)) r = sd_bus_message_append(m, "b", arg_runtime); else { - uint64_t flags = arg_runtime ? PORTABLE_RUNTIME : 0; + uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE : 0); r = sd_bus_message_append(m, "t", flags); } @@ -1241,6 +1242,8 @@ static int help(int argc, char *argv[], void *userdata) { " attach/before detach\n" " --no-block Don't block waiting for attach --now to complete\n" " --extension=PATH Extend the image with an overlay\n" + " --force Skip 'already active' check when attaching or\n" + " detaching an image (with extensions)\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -1266,6 +1269,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NOW, ARG_NO_BLOCK, ARG_EXTENSION, + ARG_FORCE, }; static const struct option options[] = { @@ -1286,6 +1290,7 @@ static int parse_argv(int argc, char *argv[]) { { "now", no_argument, NULL, ARG_NOW }, { "no-block", no_argument, NULL, ARG_NO_BLOCK }, { "extension", required_argument, NULL, ARG_EXTENSION }, + { "force", no_argument, NULL, ARG_FORCE }, {} }; @@ -1390,6 +1395,10 @@ static int parse_argv(int argc, char *argv[]) { return log_oom(); break; + case ARG_FORCE: + arg_force = true; + break; + case '?': return -EINVAL; diff --git a/test/units/testsuite-29.sh b/test/units/testsuite-29.sh index 4b32161e5f9..072ca921b36 100755 --- a/test/units/testsuite-29.sh +++ b/test/units/testsuite-29.sh @@ -124,7 +124,16 @@ systemctl is-active app1.service status="$(portablectl is-attached --extension app1 minimal_1)" [[ "${status}" == "running-runtime" ]] -portablectl detach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_1.raw app1 +portablectl detach --force --no-reload --runtime --extension /usr/share/app1.raw /usr/share/minimal_1.raw app1 +portablectl "${ARGS[@]}" attach --force --no-reload --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1 +systemctl daemon-reload +systemctl restart app1.service + +systemctl is-active app1.service +status="$(portablectl is-attached --extension app1 minimal_0)" +[[ "${status}" == "running-runtime" ]] + +portablectl detach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1 # Ensure that the combination of read-only images, state directory and dynamic user works, and that # state is retained. Check after detaching, as on slow systems (eg: sanitizers) it might take a while