]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vmspawn: introduce --notify-ready= switch
authorLennart Poettering <lennart@poettering.net>
Mon, 16 Jun 2025 08:49:25 +0000 (10:49 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 11 Jul 2025 16:17:04 +0000 (18:17 +0200)
This mimics the switch of the same name from nspawn: it controls whether
we expect a READY=1 message from the payload or not. Previously we'd
always expect that. This makes it configurable, just like it is in
nspawn.

There's one fundamental difference in behaviour though: in nspawn it
defaults to off, in vmspawn it defaults to on. (for historical reasons,
ideally we'd default to on in both cases, but changing is quite a compat
break both directly and indirectly: since timeouts might get triggered).

man/systemd-nspawn.xml
man/systemd-vmspawn.xml
src/vmspawn/vmspawn.c

index d9d0de918bae6f20c73cd6997d173d34c2e6d103..d7d7d17f663146aeca4d3f2a5cd174ab9786bce9 100644 (file)
         <term><option>--notify-ready=</option></term>
 
         <listitem><para>Configures support for notifications from the container's init process.
-        <option>--notify-ready=</option> takes a boolean (<option>no</option> and  <option>yes</option>).
-        With option <option>no</option> systemd-nspawn notifies systemd
-        with a <literal>READY=1</literal> message when the init process is created.
-        With option <option>yes</option> systemd-nspawn waits for the
-        <literal>READY=1</literal> message from the init process in the container
-        before sending its own to systemd. For more details about notifications
-        see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+        <option>--notify-ready=</option> takes a boolean. If false <command>systemd-vmpawn</command>
+        notifies the calling service manager with a <literal>READY=1</literal> message when the init process is
+        created. If true it waits for a <literal>READY=1</literal> message from the init process in the VM
+        before sending its own to the service manager. For more details about notifications see
+        <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
+        <para>Defaults to false. (Note that this is unlike the option of the same name to
+        <citerefentry><refentrytitle>systemd-vmspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        that defaults to true.)</para>
 
         <xi:include href="version-info.xml" xpointer="v231"/></listitem>
       </varlistentry>
index 304bbb44a387be43fdda7a5d5715c5899fc4c10d..03a2da649b610fd6906a3a6b2d38ab09e88a3d6c 100644 (file)
 
           <xi:include href="version-info.xml" xpointer="v258"/></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><option>--notify-ready=</option></term>
+
+          <listitem><para>Configures support for notifications from the VM's init process to
+          <command>systemd-vmspawn</command>.  If true, <command>systemd-vmspawn</command> will consider the
+          machine as ready only when it has received a <literal>READY=1</literal> message from the init
+          process in the VM. If false, <command>systemd-vmspawn</command> will consider the machine as ready
+          immediately after creation.  In either case, <command>systemd-vmspawn</command> sends its own
+          readiness notification to its manager after the spawned VM is ready. For more details about
+          notifications see
+          <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
+          <para>Defaults to true. (Note that this is unlike the option of the same name to
+          <citerefentry><refentrytitle>systemd-vmspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+          that defaults to false.)</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
index ce623cfd99bd1da92df76140a1be0c70c2d95bc3..6889734e9c76d34e96eae2e0aa6695d2a37a6620 100644 (file)
@@ -139,6 +139,7 @@ static uint64_t arg_grow_image = 0;
 static char *arg_tpm_state_path = NULL;
 static TpmStateMode arg_tpm_state_mode = TPM_STATE_AUTO;
 static bool arg_ask_password = true;
+static bool arg_notify_ready = true;
 
 STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@@ -196,7 +197,9 @@ static int help(void) {
                "     --firmware=PATH|list  Select firmware definition file (or list available)\n"
                "     --discard-disk=BOOL   Control processing of discard requests\n"
                "  -G --grow-image=BYTES    Grow image file to specified size in bytes\n"
+               "\n%3$sExecution:%4$s\n"
                "  -s --smbios11=STRING     Pass an arbitrary SMBIOS Type #11 string to the VM\n"
+               "     --notify-ready=BOOL   Wait for ready notification from the VM\n"
                "\n%3$sSystem Identity:%4$s\n"
                "  -M --machine=NAME        Set the machine name for the VM\n"
                "     --uuid=UUID           Set a specific machine UUID for the VM\n"
@@ -289,6 +292,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_TPM_STATE,
                 ARG_NO_ASK_PASSWORD,
                 ARG_PROPERTY,
+                ARG_NOTIFY_READY,
         };
 
         static const struct option options[] = {
@@ -337,6 +341,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "tpm-state",         required_argument, NULL, ARG_TPM_STATE         },
                 { "no-ask-password",   no_argument,       NULL, ARG_NO_ASK_PASSWORD   },
                 { "property",          required_argument, NULL, ARG_PROPERTY          },
+                { "notify-ready",      required_argument, NULL, ARG_NOTIFY_READY      },
                 {}
         };
 
@@ -673,6 +678,13 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_NOTIFY_READY:
+                        r = parse_boolean_argument("--notify-ready=", optarg, &arg_notify_ready);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -755,17 +767,20 @@ static int read_vsock_notify(NotifyConnectionData *d, int fd) {
                 log_debug("Received notification message with tags: %s", strnull(j));
         }
 
+        const char *status = strv_find_startswith(tags, "STATUS=");
+        if (status)
+                (void) sd_notifyf(/* unset_environment= */ false, "STATUS=VM running: %s", status);
+
         if (strv_contains(tags, "READY=1")) {
-                r = sd_notify(false, "READY=1");
+                r = sd_notify(/* unset_environment= */ false, "READY=1");
                 if (r < 0)
                         log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
-        }
 
-        const char *p = strv_find_startswith(tags, "STATUS=");
-        if (p)
-                (void) sd_notifyf(false, "STATUS=VM running: %s", p);
+                if (!status)
+                        (void) sd_notifyf(/* unset_environment= */ false, "STATUS=VM running.");
+        }
 
-        p = strv_find_startswith(tags, "EXIT_STATUS=");
+        const char *p = strv_find_startswith(tags, "EXIT_STATUS=");
         if (p) {
                 uint8_t k = 0;
                 r = safe_atou8(p, &k);
@@ -2669,6 +2684,16 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
         child_vsock_fd = safe_close(child_vsock_fd);
         tap_fd = safe_close(tap_fd);
 
+        /* Report that the VM is now set up */
+        (void) sd_notifyf(/* unset_environment= */ false,
+                          "STATUS=VM started.\n"
+                          "X_VMSPAWN_LEADER_PID=" PID_FMT, child_pidref.pid);
+        if (!arg_notify_ready) {
+                r = sd_notify(/* unset_environment= */ false, "READY=1\n");
+                if (r < 0)
+                        log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
+        }
+
         /* All operations that might need Polkit authorizations (i.e. machine registration, netif
          * acquisition, …) are complete now, get rid of the agent again, so that we retain exclusive control
          * of the TTY from now on. */