From 35bccdbe2fb425671089164e4b8bebb73cf6fd23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eric=20M=C3=BCller?= <mueller@kip.uni-heidelberg.de>
Date: Thu, 1 Aug 2024 20:27:38 +0200
Subject: [PATCH] feat: use skopeo and proot to create base image sandbox
 [DO-NOT-MERGE]

Change-Id: Id28e2d75c3e0cc7a399f4c7a01bf57b88b2e3e2d
---
 bin/yashchiki                       |  12 ++--
 lib/yashchiki/build_base_sandbox.sh |  47 ++++++++++++-
 lib/yashchiki/build_image.sh        |   7 +-
 lib/yashchiki/build_sandbox.sh      | 104 +++++++++++++++++++++++++---
 lib/yashchiki/update_build_cache.sh |  18 +++--
 5 files changed, 170 insertions(+), 18 deletions(-)

diff --git a/bin/yashchiki b/bin/yashchiki
index 2f24443c..77477526 100755
--- a/bin/yashchiki
+++ b/bin/yashchiki
@@ -348,10 +348,14 @@ env.update({"YASHCHIKI_META_DIR": meta_dir})
 run("lib/yashchiki/create_caches.sh", env)
 run("lib/yashchiki/fetch.sh", env)
 if config.get("docker_base_image", False):
-    run("lib/yashchiki/build_base_sandbox.sh", env, [base_sandbox_recipe])
-run(str(pathlib.Path("share", "yashchiki", "styles", args.style,
-                     "create_recipe.sh")),
-    env)
+    run("lib/yashchiki/build_base_sandbox.sh", env)# FIXME: , [base_sandbox_recipe])
+# FIXME: dispatch to apptainer-based build or proot via style config?
+#        (for proot we don't use a apptainer recipe)
+create_recipe_script = pathlib.Path("share", "yashchiki", "styles", args.style,
+        "create_recipe.sh")
+if create_recipe_script.exists():
+    run(str(create_recipe_script), env)
+
 run("lib/yashchiki/build_sandbox.sh", env)
 run("lib/yashchiki/build_image.sh", env)
 
diff --git a/lib/yashchiki/build_base_sandbox.sh b/lib/yashchiki/build_base_sandbox.sh
index 38c049e5..b6d79f00 100755
--- a/lib/yashchiki/build_base_sandbox.sh
+++ b/lib/yashchiki/build_base_sandbox.sh
@@ -23,4 +23,49 @@ TARGET_FOLDER="${YASHCHIKI_SANDBOXES}/${CONTAINER_STYLE}"
 
 mkdir -p ${YASHCHIKI_SANDBOXES}
 
-apptainer build --fakeroot --force ${YASHCHIKI_BASEIMAGE_NAME} $1
+#apptainer -d build --fakeroot --force ${YASHCHIKI_BASEIMAGE_NAME} $1
+
+set -x
+skopeo copy docker://${DOCKER_BASE_IMAGE} docker-archive:archive-file.tar:${DOCKER_BASE_IMAGE}
+ARCHIVE_FILE=$(realpath archive-file.tar)
+mkdir -p ${YASHCHIKI_SANDBOXES}/tmp
+pushd ${YASHCHIKI_SANDBOXES}/tmp >/dev/null
+tar xf ${ARCHIVE_FILE}
+ls
+popd >/dev/null
+rm -f ${ARCHIVE_FILE}
+
+mkdir -p ${YASHCHIKI_SANDBOXES}/base_image
+pushd ${YASHCHIKI_SANDBOXES}/base_image >/dev/null
+find ${YASHCHIKI_SANDBOXES}/tmp -name "*.tar" -exec tar xf {} \;
+rm -rf ${YASHCHIKI_SANDBOXES}/tmp
+ls
+popd >/dev/null
+
+mkdir -p "${YASHCHIKI_SANDBOXES}/base_image/opt/spack_install_scripts"
+rsync -aLv --chmod 0755 "${ROOT_DIR}"/share/yashchiki/styles/${CONTAINER_STYLE}/*.sh "${YASHCHIKI_SANDBOXES}/base_image/opt/spack_install_scripts"
+rsync -aLv --chmod 0755 "${ROOT_DIR}"/lib/yashchiki/*.sh "${YASHCHIKI_SANDBOXES}/base_image/opt/spack_install_scripts"
+rsync -aLv "${ROOT_DIR}"/lib/yashchiki/*.awk "${YASHCHIKI_SANDBOXES}/base_image/opt/spack_install_scripts"
+rsync -aLv "${ROOT_DIR}"/share/yashchiki/patches "${YASHCHIKI_SANDBOXES}/base_image/opt/spack_install_scripts"
+
+# create a fingerprint by which we can identify the container from within
+cat /proc/sys/kernel/random/uuid > "${YASHCHIKI_SANDBOXES}/base_image/opt/fingerprint"
+
+cat <<EOF > ${YASHCHIKI_SANDBOXES}/base_image/prepare.sh
+# prerequisites
+ls /opt/spack_install_scripts
+RUNLEVEL=1 /opt/spack_install_scripts/install_prerequisites.sh || exit 1
+# cannot specify permissions in files-section
+chmod 440 /etc/sudoers
+chown root:root /etc/sudoers
+# install locales
+/usr/sbin/locale-gen
+EOF
+
+pushd /
+echo proot -S ${YASHCHIKI_SANDBOXES}/base_image -w /root /bin/dash ${YASHCHIKI_SANDBOXES}/base_image/prepare.sh
+PROOT_NO_SECCOMP=1 TMPDIR=/tmp proot -S ${YASHCHIKI_SANDBOXES}/base_image -w /root /bin/dash ${YASHCHIKI_SANDBOXES}/base_image/prepare.sh
+popd
+echo apptainer -d build --fakeroot --force ${YASHCHIKI_BASEIMAGE_NAME} ${YASHCHIKI_SANDBOXES}/base_image
+TMPDIR=/tmp apptainer -d build --fakeroot --force ${YASHCHIKI_BASEIMAGE_NAME} ${YASHCHIKI_SANDBOXES}/base_image
+rm -rf ${YASHCHIKI_SANDBOXES}/base_image
diff --git a/lib/yashchiki/build_image.sh b/lib/yashchiki/build_image.sh
index 6b7578c4..a8251730 100755
--- a/lib/yashchiki/build_image.sh
+++ b/lib/yashchiki/build_image.sh
@@ -3,6 +3,10 @@
 set -euo pipefail
 shopt -s inherit_errexit 2>/dev/null || true
 
+# for env vars
+SOURCE_DIR="$(dirname "$(readlink -m "${BASH_SOURCE[0]}")")"
+source "${SOURCE_DIR}/commons.sh"
+
 if [ -z "${YASHCHIKI_ENABLE_STAGE_IMAGE:-}" ]; then
     echo "Skipping stage build-base-sandbox."
     exit 0
@@ -15,4 +19,5 @@ if test -f "${YASHCHIKI_IMAGE_NAME}"; then
     exit 1
 fi
 
-apptainer build --fakeroot ${YASHCHIKI_IMAGE_NAME} "${TARGET_FOLDER}"
+set -x
+TMPDIR=/tmp apptainer -d build --fakeroot --bind ${YASHCHIKI_SPACK_PATH}:/opt/spack,ro ${YASHCHIKI_IMAGE_NAME} "${TARGET_FOLDER}"
diff --git a/lib/yashchiki/build_sandbox.sh b/lib/yashchiki/build_sandbox.sh
index 17a80b5f..14723b1e 100755
--- a/lib/yashchiki/build_sandbox.sh
+++ b/lib/yashchiki/build_sandbox.sh
@@ -3,6 +3,10 @@
 set -euo pipefail
 shopt -s inherit_errexit 2>/dev/null || true
 
+# for env vars
+SOURCE_DIR="$(dirname "$(readlink -m "${BASH_SOURCE[0]}")")"
+source "${SOURCE_DIR}/commons.sh"
+
 if [ -z "${YASHCHIKI_ENABLE_STAGE_BUILD_BASE:-}" ]; then
     echo "Skipping stage build-base."
     exit 0
@@ -23,11 +27,95 @@ TARGET_FOLDER="${YASHCHIKI_SANDBOXES}/${CONTAINER_STYLE}"
 
 mkdir -p ${YASHCHIKI_SANDBOXES}
 
-apptainer build \
-    --bind ${YASHCHIKI_CACHES_ROOT}/download_cache:/opt/spack/var/spack/cache \
-    --bind ${YASHCHIKI_CACHES_ROOT}/spack_ccache:/opt/ccache \
-    --bind ${YASHCHIKI_CACHES_ROOT}/build_caches:/opt/build_cache \
-    --bind ${YASHCHIKI_CACHES_ROOT}/preserved_packages:/opt/preserved_packages \
-    --bind ${JOB_TMP_SPACK}:/tmp/spack \
-    --bind ${YASHCHIKI_SPACK_CONFIG}:/tmp/spack_config \
-    --fakeroot --sandbox "${TARGET_FOLDER}" "${YASHCHIKI_RECIPE_PATH}" | tee out_singularity_build_recipe.txt
+set -x
+skopeo copy sif:${YASHCHIKI_BASEIMAGE_NAME} docker-archive:archive-file.tar
+ARCHIVE_FILE=$(realpath archive-file.tar)
+mkdir -p ${YASHCHIKI_SANDBOXES}/tmp
+pushd ${YASHCHIKI_SANDBOXES}/tmp >/dev/null
+tar xf ${ARCHIVE_FILE}
+ls
+popd >/dev/null
+rm -f ${ARCHIVE_FILE}
+
+mkdir -p ${TARGET_FOLDER}
+pushd ${TARGET_FOLDER} >/dev/null
+find ${YASHCHIKI_SANDBOXES}/tmp -name "*.tar" -exec tar xf {} \;
+rm -rf ${YASHCHIKI_SANDBOXES}/tmp
+ls
+popd >/dev/null
+
+ls ${TARGET_FOLDER}
+
+# FIXME: from recipe
+# location to bind-mount spack-folder
+mkdir ${TARGET_FOLDER}/opt/spack
+# location to bind-mount spack-source-cache-folder
+mkdir -p ${TARGET_FOLDER}/opt/spack/var/spack/cache/
+# copy spack repo
+rsync -a ${YASHCHIKI_SPACK_PATH}/ ${TARGET_FOLDER}/opt/spack
+# location to bind-mount ccache
+mkdir ${TARGET_FOLDER}/opt/ccache
+# location to bind-mount build_cache
+mkdir -p "${TARGET_FOLDER}${BUILD_CACHE_INSIDE}"
+# # create buildcache directory if it does not exist
+[ ! -d "${BUILD_CACHE_OUTSIDE}" ] && mkdir -p "${BUILD_CACHE_OUTSIDE}"
+# location to mount the full build cache folder into container because some files might be symlinked to other buildcaches
+# mount --no-mtab --bind "${BASE_BUILD_CACHE_OUTSIDE}" "\${APPTAINER_ROOTFS}${BASE_BUILD_CACHE_INSIDE}"
+# location to bind-mount preserved packages in case the build fails
+mkdir -p "${TARGET_FOLDER}${PRESERVED_PACKAGES_INSIDE}"
+# location to bind-mount tmp-folder
+mkdir -p "${TARGET_FOLDER}/tmp/spack"
+# location to bind-mount spack config tmp-folder
+mkdir -p "${TARGET_FOLDER}/tmp/spack_config"
+# copy install scripts
+#mkdir "\${APPTAINER_ROOTFS}/${SPACK_INSTALL_SCRIPTS}"
+rsync -a --chmod 0755 "${ROOT_DIR}"/share/yashchiki/styles/${CONTAINER_STYLE}/*.sh "${TARGET_FOLDER}${SPACK_INSTALL_SCRIPTS}"
+rsync -a --chmod 0755 "${ROOT_DIR}"/lib/yashchiki/*.sh "${TARGET_FOLDER}${SPACK_INSTALL_SCRIPTS}"
+rsync -a "${ROOT_DIR}"/lib/yashchiki/*.awk "${TARGET_FOLDER}${SPACK_INSTALL_SCRIPTS}"
+rsync -a "${ROOT_DIR}"/share/yashchiki/patches "${TARGET_FOLDER}/${SPACK_INSTALL_SCRIPTS}"
+mkdir -p "${TARGET_FOLDER}/${META_DIR_INSIDE}"
+rsync -a "${META_DIR_OUTSIDE}/" "${TARGET_FOLDER}/${META_DIR_INSIDE}"
+# init scripts for user convenience
+mkdir -p "${TARGET_FOLDER}/opt/init"
+rsync -a "${ROOT_DIR}"/share/yashchiki/misc-files/init/*.sh "${TARGET_FOLDER}/opt/init"
+
+rsync -a ${ROOT_DIR}/share/yashchiki/misc-files/setup-spack.sh ${TARGET_FOLDER}/etc/profile.d/setup-spack.sh
+rsync -a ${ROOT_DIR}/share/yashchiki/misc-files/locale.gen ${TARGET_FOLDER}/etc/locale.gen
+rsync -a ${ROOT_DIR}/share/yashchiki/misc-files/locale.alias ${TARGET_FOLDER}/etc/locale.alias
+#rsync -a ${ROOT_DIR}/share/yashchiki/misc-files/sudoers ${TARGET_FOLDER}/etc/sudoers # FIXME: permission denied?
+
+
+cat <<EOF > ${TARGET_FOLDER}/build.sh
+# propagate environment variables to container recipe
+export DEPENDENCY_PYTHON="${DEPENDENCY_PYTHON}"
+export YASHCHIKI_BUILD_SPACK_GCC="${YASHCHIKI_BUILD_SPACK_GCC}"
+export YASHCHIKI_SPACK_GCC="${YASHCHIKI_SPACK_GCC}"
+export YASHCHIKI_SPACK_GCC_VERSION="${YASHCHIKI_SPACK_GCC_VERSION}"
+export YASHCHIKI_JOBS="${YASHCHIKI_JOBS}"
+export YASHCHIKI_SPACK_CONFIG="/tmp/spack_config"
+export YASHCHIKI_CACHES_ROOT="${YASHCHIKI_CACHES_ROOT}"
+export YASHCHIKI_BUILD_CACHE_NAME="${YASHCHIKI_BUILD_CACHE_NAME}"
+export YASHCHIKI_BUILD_CACHE_ON_FAILURE_NAME="${YASHCHIKI_BUILD_CACHE_ON_FAILURE_NAME:-}"
+export YASHCHIKI_SPACK_VERBOSE="${YASHCHIKI_SPACK_VERBOSE}"
+export YASHCHIKI_DEBUG=${YASHCHIKI_DEBUG}
+export CONTAINER_STYLE="${CONTAINER_STYLE}"
+"${SPACK_INSTALL_SCRIPTS}/complete_spack_install_routine_called_in_post.sh"
+EOF
+
+PROOT_NO_SECCOMP=1 proot -w / -S ${TARGET_FOLDER} \
+    --bind=${YASHCHIKI_CACHES_ROOT}/download_cache:/opt/spack/var/spack/cache \
+    --bind=${YASHCHIKI_CACHES_ROOT}/spack_ccache:/opt/ccache \
+    --bind=${YASHCHIKI_CACHES_ROOT}/build_caches:/opt/build_cache \
+    --bind=${YASHCHIKI_CACHES_ROOT}/preserved_packages:/opt/preserved_packages \
+    --bind=${JOB_TMP_SPACK}:/tmp/spack \
+    --bind=${YASHCHIKI_SPACK_CONFIG}:/tmp/spack_config \
+    /bin/dash /build.sh
+
+#apptainer -d build --fakeroot \
+#    --bind ${YASHCHIKI_CACHES_ROOT}/download_cache:/opt/spack/var/spack/cache \
+#    --bind ${YASHCHIKI_CACHES_ROOT}/spack_ccache:/opt/ccache \
+#    --bind ${YASHCHIKI_CACHES_ROOT}/build_caches:/opt/build_cache \
+#    --bind ${YASHCHIKI_CACHES_ROOT}/preserved_packages:/opt/preserved_packages \
+#    --bind ${JOB_TMP_SPACK}:/tmp/spack \
+#    --bind ${YASHCHIKI_SPACK_CONFIG}:/tmp/spack_config \
+#    --sandbox "${TARGET_FOLDER}" "${YASHCHIKI_RECIPE_PATH}" | tee out_singularity_build_recipe.txt
diff --git a/lib/yashchiki/update_build_cache.sh b/lib/yashchiki/update_build_cache.sh
index 76d3bbc5..a0345e4b 100755
--- a/lib/yashchiki/update_build_cache.sh
+++ b/lib/yashchiki/update_build_cache.sh
@@ -3,6 +3,10 @@
 set -euo pipefail
 shopt -s inherit_errexit 2>/dev/null || true
 
+# for env vars
+SOURCE_DIR="$(dirname "$(readlink -m "${BASH_SOURCE[0]}")")"
+source "${SOURCE_DIR}/commons.sh"
+
 usage() { echo "Usage: ${0} -c <container>" 1>&2; exit 1; }
 
 while getopts ":c:" opts; do
@@ -29,10 +33,16 @@ source "${SOURCE_DIR}/commons.sh"
 # update script inside the container
 set +e
 # Arguments needed once we switch to singularity3: --writable-tmpfs
-apptainer exec\
-    -B "${BUILD_CACHE_OUTSIDE}:${BUILD_CACHE_INSIDE}:rw"\
-    "${IMAGE_NAME}" \
-    /opt/spack_install_scripts/update_build_cache_in_container.sh -j ${YASHCHIKI_JOBS} -q || exit 0
+#apptainer exec\
+#    -B "${BUILD_CACHE_OUTSIDE}:${BUILD_CACHE_INSIDE}:rw"\
+#    "${IMAGE_NAME}" \
+#    /opt/spack_install_scripts/update_build_cache_in_container.sh -j ${YASHCHIKI_JOBS} -q || exit 0
+
+TARGET_FOLDER="${YASHCHIKI_SANDBOXES}/${CONTAINER_STYLE}"
+
+proot -w / -S ${TARGET_FOLDER} \
+    --bind="${BUILD_CACHE_OUTSIDE}:${BUILD_CACHE_INSIDE}" \
+    /opt/spack_install_scripts/update_build_cache_in_container.sh -q || exit 0
 
 if [ -n "${CACHE_BUILD_TYPE:-}" ]; then
     if [ ${CACHE_SOURCE_TYPE} != "oci" ]; then
-- 
GitLab