From cbe7d0def003b1e159abe9b1caae383d602f79f7 Mon Sep 17 00:00:00 2001 From: Alberto Madonna Date: Tue, 20 Feb 2024 18:11:42 +0000 Subject: [PATCH] Added alternate local import procedure using podman's unshare and mount commands Signed-off-by: Alberto Madonna --- enroot.in | 21 +++++++++++++++++---- src/docker.sh | 44 +++++++++++++++++++++++++++++++++++--------- src/runtime.sh | 11 ++++++++--- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/enroot.in b/enroot.in index cb3dfa9..2fe8caa 100644 --- a/enroot.in +++ b/enroot.in @@ -181,8 +181,11 @@ enroot::usage() { podman://IMAGE[:TAG] Import a Docker image from a local podman repository Options: - -a, --arch Architecture of the image (defaults to host architecture) - -o, --output Name of the output image file (defaults to "URI.sqsh") + -a, --arch Architecture of the image (defaults to host architecture) + -o, --output Name of the output image file (defaults to "URI.sqsh") + -x, --extract-mode Determines the way the image is extracted from a local Podman repository. + This option is ignored when importing images from registries or the Docker daemon. + Accepted values: tar, mount. Defaults to "tar". EOF ;; digest) @@ -349,7 +352,7 @@ enroot::digest() { } enroot::import() { - local uri= filename= arch= + local uri= filename= arch= extract_mode=tar while [ $# -gt 0 ]; do case "$1" in @@ -373,6 +376,16 @@ enroot::import() { filename="${1#*=}" shift ;; + -x|--extract-mode) + [ -z "${2-}" ] && enroot::usage import 1 + extract_mode="$2" + shift 2 + ;; + --extract-mode=*) + [ -z "${1#*=}" ] && enroot::usage import 1 + extract_mode="${1#*=}" + shift + ;; -h|--help) enroot::usage import 0 ;; --) @@ -388,7 +401,7 @@ enroot::import() { fi uri="$1" - runtime::import "${uri}" "${filename}" "${arch}" + runtime::import "${uri}" "${filename}" "${extract_mode}" "${arch}" } enroot::load() { diff --git a/src/docker.sh b/src/docker.sh index 41649ec..b0e9c32 100644 --- a/src/docker.sh +++ b/src/docker.sh @@ -543,9 +543,31 @@ docker::load() ( tar --numeric-owner -C rootfs/ --mode=u-s,g-s -cpf - . | tar --numeric-owner -C '${name}/' -xpf -" ) +docker::daemon::_config_squash() { +local -r engine="$1" image="$2" arch="$3" rootfs="$4" filename="$5" + "${engine}" inspect "${image}" | common::jq '.[] | with_entries(.key|=ascii_downcase)' > config + docker::configure "${rootfs}" config "${arch}" + + # Create the final squashfs filesystem. + common::log INFO "Creating squashfs filesystem..." NL + mksquashfs "${rootfs}" "${filename}" -all-root ${TTY_OFF+-no-progress} -processors "${ENROOT_MAX_PROCESSORS}" ${ENROOT_SQUASH_OPTIONS} >&2 +} + +podman::_mount_squash() { + set -euo pipefail + shopt -s lastpipe + local -r image="$1" arch="$2" container_name="$3" filename="$4" + local rootfs= + + rootfs=$(podman mount "${container_name}") + docker::daemon::_config_squash podman "${image}" "${arch}" "${rootfs}" "${filename}" + podman unmount "${container_name}" +} + docker::daemon::import() ( local -r uri="$1" local filename="$2" arch="$3" + local -r extract_mode="$4" local image= tmpdir= engine= case "${uri}" in @@ -592,14 +614,18 @@ docker::daemon::import() ( common::log # Extract and configure the rootfs. - common::log INFO "Extracting image content..." - mkdir rootfs - "${engine}" export "${PWD##*/}" | tar -C rootfs --warning=no-timestamp --anchored --exclude='dev/*' --exclude='.dockerenv' -px - common::fixperms rootfs - "${engine}" inspect "${image}" | common::jq '.[] | with_entries(.key|=ascii_downcase)' > config - docker::configure rootfs config "${arch}" + if [[ "${engine}" == "podman" ]] && [[ "${extract_mode}" == "mount" ]]; then + common::log INFO "Mounting image from Podman container..." + printf -v cmd "source %q/docker.sh && podman::_mount_squash %q %q %q %q" "${ENROOT_LIBRARY_PATH}" "${image}" "${arch}" "${PWD##*/}" "${filename}" + podman unshare bash -c "$cmd" + else + common::log INFO "Extracting image content..." + mkdir rootfs + "${engine}" export "${PWD##*/}" | tar -C rootfs --warning=no-timestamp --anchored --exclude='dev/*' --exclude='.dockerenv' -px + common::fixperms rootfs + docker::daemon::_config_squash "${engine}" "${image}" "${arch}" rootfs "${filename}" + fi - # Create the final squashfs filesystem. - common::log INFO "Creating squashfs filesystem..." NL - mksquashfs rootfs "${filename}" -all-root ${TTY_OFF+-no-progress} -processors "${ENROOT_MAX_PROCESSORS}" ${ENROOT_SQUASH_OPTIONS} >&2 + # Cleanup the container created to extract the rootfs + "${engine}" rm "${PWD##*/}" ) diff --git a/src/runtime.sh b/src/runtime.sh index 0b65078..14a5c63 100644 --- a/src/runtime.sh +++ b/src/runtime.sh @@ -441,8 +441,13 @@ runtime::digest() { } runtime::import() { - local -r uri="$1" filename="$2" - local arch="$3" + local -r uri="$1" filename="$2" extract_mode="$3" + local arch="${4-}" + + # Check the extract mode value. + if [[ "${extract_mode}" != "tar" ]] && [[ "${extract_mode}" != "mount" ]]; then + common::err "Invalid extract mode: ${extract_mode}" + fi # Use the host architecture as the default. if [ -z "${arch}" ]; then @@ -454,7 +459,7 @@ runtime::import() { docker://*) docker::import "${uri}" "${filename}" "${arch}" ;; dockerd://* | podman://*) - docker::daemon::import "${uri}" "${filename}" "${arch}" ;; + docker::daemon::import "${uri}" "${filename}" "${arch}" "${extract_mode}" ;; *) common::err "Invalid argument: ${uri}" ;; esac