]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Add suppport for PuzzleFS images in the oci template 4483/head
authorAriel Miculas-Trif <amiculas@cisco.com>
Wed, 18 Sep 2024 10:07:46 +0000 (13:07 +0300)
committerAriel Miculas-Trif <amiculas@cisco.com>
Fri, 4 Oct 2024 18:51:03 +0000 (21:51 +0300)
PuzzleFS images (media type 'application/vnd.puzzlefs.image.rootfs.v1')
can be mounted in a similar way to squashfs images, we just have to
detect the type and reuse the existing code for providing a mount
helper. PuzzleFS is a next-generation container filesystem [1] with
several benefits, such as  reduced duplication, reproducible image
builds, direct mounting support and memory safety guarantees.

Since PuzzleFS currently doesn't provide an image config, also add
support for empty image configs, they are supported by the OCI spec [2].

The MOUNT_HELPER is now passed a `--persist <upperdir>` flag, so it
knows that it needs to create an overlay. This is needed because LXC
expects a writable rootfs and both atomfs and puzzlefs are read-only
filesystems.

Example:
```
$ sudo env PATH=$PATH build/src/lxc/tools/lxc-create --name mycontainer -t \
oci -- --url oci:/$HOME/.local/share/puzzlefs/pfs_ubuntu:eg --no-cache

$ sudo build/src/lxc/tools/lxc-start --name mycontainer --foreground /bin/bash
```

--no-cache is needed for puzzlefs until [3] is solved

[1] https://github.com/project-machine/puzzlefs
[2] https://github.com/opencontainers/image-spec/blob/main/manifest.md#image-manifest
[3] https://github.com/project-machine/puzzlefs/issues/131

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
templates/lxc-oci.in

index 298d3e06ed461b3d8c84a63e522ab6e84e4505da..425ddd0d7e5be1600eb99d4b123ee6631bf35aa8 100755 (executable)
@@ -36,7 +36,7 @@ done
 LOCALSTATEDIR=@LOCALSTATEDIR@
 LXC_TEMPLATE_CONFIG=@LXCTEMPLATECONFIG@
 LXC_HOOK_DIR=@LXCHOOKDIR@
-MOUNT_HELPER="atomfs"
+MOUNT_HELPER=""
 MOUNTED_WORKDIR=""
 
 # Some useful functions
@@ -76,6 +76,12 @@ in_userns() {
 
 getconfigpath() {
   local basedir="$1" mfpath="$2" cdigest=""
+  mtdigest=$(jq -c -r '.config.mediaType' < "$mfpath")
+  if [ "$mtdigest" = "application/vnd.oci.empty.v1+json" ]; then
+    echo ""
+    return 0
+  fi
+
   # Ok we have the image config digest, now get the config ref from the manifest.
   # shellcheck disable=SC2039
   cdigest=$(jq -c -r '.config.digest' < "$mfpath")
@@ -129,6 +135,10 @@ getep() {
   fi
 
   configpath="$1"
+  if [ "${configpath}" = "" ]; then
+    echo "/bin/sh"
+    return
+  fi
 
   ep=$(jq -c '.config.Entrypoint[]?'< "${configpath}" | tr '\n' ' ')
   cmd=$(jq -c '.config.Cmd[]?'< "${configpath}" | tr '\n' ' ')
@@ -152,6 +162,9 @@ getenv() {
   fi
 
   configpath="$1"
+  if [ "${configpath}" = "" ]; then
+    return
+  fi
 
   env=$(jq -c -r '.config.Env[]'< "${configpath}")
 
@@ -176,6 +189,12 @@ getuidgid() {
   passwdpath="${rootpath}/etc/passwd"
   grouppath="${rootpath}/etc/group"
 
+  if [ "${configpath}" = "" ]; then
+    user=0
+    group=0
+    echo "${user:-0} ${group:-0}"
+    return
+  fi
   usergroup=$(jq -c -r '.config.User' < "${configpath}")
   # shellcheck disable=SC2039
   usergroup=(${usergroup//:/ })
@@ -216,6 +235,10 @@ getcwd() {
   fi
 
   configpath="$1"
+  if [ "${configpath}" = "" ]; then
+    echo "/"
+    return
+  fi
 
   cwd=$(jq -c -r '.config.WorkingDir // "/"' < "${configpath}")
 
@@ -236,14 +259,17 @@ Required arguments:
 Optional arguments:
 [ --username <username> ]: The username for the registry
 [ --password <password> ]: The password for the registry
-[ --mount-helper <command> ]: program that will be used to mount. default is 'atomfs'
+[ --mount-helper <command> ]: program that will be used to mount. default will be detected from mediatype
 
      mount-helper is expected to support being called with 'mount'
      and 'umount' subcommands as below:
 
-        mount-helper mount oci:<oci_dir>:<oci_name> <mountpoint>
+        mount-helper mount --persist <upperdir> <oci_dir>:<oci_name> <mountpoint>
         mount-helper umount <mountpoint>
 
+     The --persist <upperdir> flag tells the mount helper to create a writable overlay, with a read-only
+     filesystem as lowerdir and <upperdir> as upperdir, where <upperdir> is a filesystem path
+
 LXC internal arguments (do not pass manually!):
 [ --name <name> ]: The container name
 [ --path <path> ]: The path to the container
@@ -366,6 +392,15 @@ mediatype=$(getlayermediatype "$mfpath")
 echo "mfpath=$mfpath conf=$OCI_CONF_FILE" 1>&2
 echo "mediatype=$mediatype" >&2
 
+case "$mediatype" in
+  application/vnd.*.image.layer.squashfs*)
+    MOUNT_HELPER="atomfs"
+    ;;
+  application/vnd.puzzlefs.image.rootfs.*)
+    MOUNT_HELPER="puzzlefs"
+    ;;
+esac
+
 case "$mediatype" in
   #application/vnd.oci.image.layer.v1.tar+gzip
   application/vnd.oci.image.layer.v1.tar*)
@@ -382,13 +417,18 @@ case "$mediatype" in
     find "${LXC_ROOTFS}.tmp/rootfs" -mindepth 1 -maxdepth 1 -exec mv '{}' "${LXC_ROOTFS}/" \;
     ;;
   #application/vnd.stacker.image.layer.squashfs+zstd+verity
-  application/vnd.*.image.layer.squashfs*)
+  application/vnd.*.image.layer.squashfs*|application/vnd.puzzlefs.image.rootfs.*)
+    if [ -z "${MOUNT_HELPER}" ]; then
+      echo "MOUNT_HELPER not detected for $mediatype"
+      exit 1
+    fi
     if ! command -v "${MOUNT_HELPER}" >/dev/null 2>&1; then
       echo "media type $mediatype requires $MOUNT_HELPER" >&2
       exit 1
     fi
-    echo "$MOUNT_HELPER mount ${OCI_DIR}:${OCI_NAME} $LXC_ROOTFS" >&2
-    "$MOUNT_HELPER" mount "${OCI_DIR}:${OCI_NAME}" "$LXC_ROOTFS"
+    MOUNT_HELPER_UPPERDIR="$LXC_PATH/upper"
+    echo "$MOUNT_HELPER mount --persist ${MOUNT_HELPER_UPPERDIR} ${OCI_DIR}:${OCI_NAME} $LXC_ROOTFS" >&2
+    "$MOUNT_HELPER" mount --persist "${MOUNT_HELPER_UPPERDIR}" "${OCI_DIR}:${OCI_NAME}" "$LXC_ROOTFS"
     MOUNTED_WORKDIR="$LXC_ROOTFS"
     ;;
   *)
@@ -403,10 +443,10 @@ echo "lxc.execute.cmd = '${entrypoint}'" >> "${LXC_CONF_FILE}"
 echo "lxc.mount.auto = proc:mixed sys:mixed cgroup:mixed" >> "${LXC_CONF_FILE}"
 
 case "$mediatype" in
-  application/vnd.*.image.layer.squashfs*)
+  application/vnd.*.image.layer.squashfs*|application/vnd.puzzlefs.image.rootfs.*)
     echo "lxc.hook.version = 1" >> "${LXC_CONF_FILE}"
     # shellcheck disable=SC2016
-    echo "lxc.hook.pre-mount = $MOUNT_HELPER mount" \
+    echo "lxc.hook.pre-mount = $MOUNT_HELPER mount --persist ${MOUNT_HELPER_UPPERDIR}" \
         '${LXC_ROOTFS_PATH}/../oci:${LXC_NAME} ${LXC_ROOTFS_PATH}' \
         >> "${LXC_CONF_FILE}";;
 esac