]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
portable: support vpick 32142/head
authorLuca Boccassi <bluca@debian.org>
Wed, 21 Feb 2024 20:00:29 +0000 (20:00 +0000)
committerLuca Boccassi <bluca@debian.org>
Fri, 19 Apr 2024 12:25:32 +0000 (13:25 +0100)
Resolve at attach/detach/inspect time, so that the image is pinned and requires
re-attaching on update, given files are extracted from it so just passing
img.v/ to RootImage= is not enough to get a portable image updated

man/org.freedesktop.portable1.xml
man/portablectl.xml
src/portable/portable.c
test/units/testsuite-29.sh

index c68995d95248f797e108e98071fc1d527bafb532..4de3da2905dfe9567338dc46c46fb184b273c2aa 100644 (file)
@@ -259,6 +259,9 @@ node /org/freedesktop/portable1 {
       on the system. Note that this method returns only after all the listed operations are completed,
       and due to the I/O involved it might take some time.</para>
 
+      <xi:include href="vpick.xml" xpointer="image"/>
+      <xi:include href="vpick.xml" xpointer="directory"/>
+
       <para><function>AttachImageWithExtensions()</function> attaches a portable image to the system.
       This method is a superset of <function>AttachImage()</function> with the addition of
       a list of extensions as input parameter, which will be overlaid on top of the main
index 5e88eb309dc4cc65e446090e2a60c6637821dd35..92d8ff03aa76fc7c82b84295677b399c36fe8b31 100644 (file)
         immediately started (blocking operation unless <option>--no-block</option> is passed) and/or enabled after
         attaching the image.</para>
 
+        <xi:include href="vpick.xml" xpointer="image"/>
+        <xi:include href="vpick.xml" xpointer="directory"/>
         <xi:include href="version-info.xml" xpointer="v239"/>
         </listitem>
       </varlistentry>
         <para>Note that the same extensions have to be specified, in the same order, when attaching
         and detaching.</para>
 
+        <xi:include href="vpick.xml" xpointer="image"/>
+        <xi:include href="vpick.xml" xpointer="directory"/>
         <xi:include href="version-info.xml" xpointer="v249"/></listitem>
       </varlistentry>
 
index 60dc98c5baf313feca9252a499f37ac85ab5621c..53418c417b51d072f0545906a5966534dff345f9 100644 (file)
@@ -43,6 +43,7 @@
 #include "strv.h"
 #include "tmpfile-util.h"
 #include "user-util.h"
+#include "vpick.h"
 
 /* Markers used in the first line of our 20-portable.conf unit file drop-in to determine, that a) the unit file was
  * dropped there by the portable service logic and b) for which image it was dropped there. */
@@ -564,6 +565,7 @@ static int extract_image_and_extensions(
         _cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL, *confext_level = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
+        _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
         _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_strv_free_ char **valid_prefixes = NULL;
         _cleanup_(image_unrefp) Image *image = NULL;
@@ -572,7 +574,27 @@ static int extract_image_and_extensions(
 
         assert(name_or_path);
 
-        r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
+        /* If we get a path, then check if it can be resolved with vpick. We need this as we might just
+         * get a simple image name, which would make vpick error out. */
+        if (path_is_absolute(name_or_path)) {
+                r = path_pick(/* toplevel_path= */ NULL,
+                              /* toplevel_fd= */ AT_FDCWD,
+                              name_or_path,
+                              &pick_filter_image_any,
+                              PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+                              &result);
+                if (r < 0)
+                        return r;
+                if (!result.path)
+                        return log_debug_errno(
+                                        SYNTHETIC_ERRNO(ENOENT),
+                                        "No matching entry in .v/ directory %s found.",
+                                        name_or_path);
+
+                name_or_path = result.path;
+        }
+
+        r = image_find_harder(IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
         if (r < 0)
                 return r;
 
@@ -588,9 +610,29 @@ static int extract_image_and_extensions(
                 }
 
                 STRV_FOREACH(p, extension_image_paths) {
+                        _cleanup_(pick_result_done) PickResult ext_result = PICK_RESULT_NULL;
                         _cleanup_(image_unrefp) Image *new = NULL;
+                        const char *path = *p;
+
+                        if (path_is_absolute(*p)) {
+                                r = path_pick(/* toplevel_path= */ NULL,
+                                              /* toplevel_fd= */ AT_FDCWD,
+                                              *p,
+                                              &pick_filter_image_any,
+                                              PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+                                              &ext_result);
+                                if (r < 0)
+                                        return r;
+                                if (!ext_result.path)
+                                        return log_debug_errno(
+                                                        SYNTHETIC_ERRNO(ENOENT),
+                                                        "No matching entry in .v/ directory %s found.",
+                                                        *p);
+
+                                path = ext_result.path;
+                        }
 
-                        r = image_find_harder(IMAGE_PORTABLE, *p, NULL, &new);
+                        r = image_find_harder(IMAGE_PORTABLE, path, NULL, &new);
                         if (r < 0)
                                 return r;
 
@@ -1691,6 +1733,7 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
         while (!isempty(marker))
                 STRV_FOREACH(image_name_or_path, root_and_extensions) {
                         _cleanup_free_ char *image = NULL, *base_image = NULL, *base_image_name_or_path = NULL;
+                        _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
 
                         r = extract_first_word(&marker, &image, ":", EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
                         if (r < 0)
@@ -1702,9 +1745,23 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
                         if (r < 0)
                                 return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", image);
 
-                        r = path_extract_image_name(*image_name_or_path, &base_image_name_or_path);
+                        r = path_pick(/* toplevel_path= */ NULL,
+                                      /* toplevel_fd= */ AT_FDCWD,
+                                      *image_name_or_path,
+                                      &pick_filter_image_any,
+                                      PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+                                      &result);
+                        if (r < 0)
+                                return r;
+                        if (!result.path)
+                                return log_debug_errno(
+                                                SYNTHETIC_ERRNO(ENOENT),
+                                                "No matching entry in .v/ directory %s found.",
+                                                *image_name_or_path);
+
+                        r = path_extract_image_name(result.path, &base_image_name_or_path);
                         if (r < 0)
-                                return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", *image_name_or_path);
+                                return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", result.path);
 
                         if (!streq(base_image, base_image_name_or_path)) {
                                 if (match_all)
index 977d76e22f0955e481d5c848c90810f05d5c85a2..4c0f1ba3293cf8770284534465e6bd1e0ba34fcc 100755 (executable)
@@ -183,6 +183,26 @@ status="$(portablectl is-attached --extension app1 minimal_0)"
 
 portablectl detach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1
 
+# Ensure vpick works, including reattaching to a new image
+mkdir -p /tmp/app1.v/
+cp /usr/share/app1.raw /tmp/app1.v/app1_1.0.raw
+cp /tmp/app1_2.raw /tmp/app1.v/app1_2.0.raw
+portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
+
+systemctl is-active app1.service
+status="$(portablectl is-attached --extension app1_2.0.raw minimal_1)"
+[[ "${status}" == "running-runtime" ]]
+
+rm -f /tmp/app1.v/app1_2.0.raw
+portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
+
+systemctl is-active app1.service
+status="$(portablectl is-attached --extension app1_1.0.raw minimal_1)"
+[[ "${status}" == "running-runtime" ]]
+
+portablectl detach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_0.raw app1
+rm -f /tmp/app1.v/app1_1.0.raw
+
 # 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
 # after the service is attached before the file appears.