From: Ariel Miculas-Trif Date: Wed, 18 Sep 2024 10:07:46 +0000 (+0300) Subject: Add suppport for PuzzleFS images in the oci template X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3764c19967286a9cb193485fadec3181c62fe241;p=thirdparty%2Flxc.git Add suppport for PuzzleFS images in the oci template 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 ` 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 --- diff --git a/templates/lxc-oci.in b/templates/lxc-oci.in index 298d3e06e..425ddd0d7 100755 --- a/templates/lxc-oci.in +++ b/templates/lxc-oci.in @@ -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 ]: The username for the registry [ --password ]: The password for the registry -[ --mount-helper ]: program that will be used to mount. default is 'atomfs' +[ --mount-helper ]: 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:: + mount-helper mount --persist : mount-helper umount + The --persist flag tells the mount helper to create a writable overlay, with a read-only + filesystem as lowerdir and as upperdir, where is a filesystem path + LXC internal arguments (do not pass manually!): [ --name ]: The container name [ --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