diff --git a/.github/workflows/tests_scripts.yml b/.github/workflows/tests_scripts.yml index 7a8f5fa..7a3682c 100644 --- a/.github/workflows/tests_scripts.yml +++ b/.github/workflows/tests_scripts.yml @@ -45,13 +45,14 @@ jobs: - name: test load_easybuild_module.sh script run: | + export SINGULARITY_CACHEDIR=$PWD # bind current directory into container as /software-layer-scripts export SINGULARITY_BIND="${PWD}:/software-layer-scripts" # can't test with EasyBuild versions older than v4.5.2 when using EESSI 2023.06, # since Python in compat layer is Python 3.11.x; # testing with a single EasyBuild version takes a while in GitHub Actions, so stick to a single sensible version - for EB_VERSION in '4.6.0'; do + for EB_VERSION in '5.1.0'; do # Create script that uses load_easybuild_module.sh which we can run in compat layer environment # note: Be careful with single vs double quotes below! # ${EB_VERSION} should be expanded, so use double quotes; @@ -91,6 +92,7 @@ jobs: - name: test install_software_layer.sh script run: | + export SINGULARITY_CACHEDIR=$PWD # bind current directory into container as /software-layer-scripts export SINGULARITY_BIND="${PWD}:/software-layer-scripts" # force using x86_64/generic, to avoid triggering an installation from scratch @@ -105,6 +107,7 @@ jobs: - name: test create_directory_tarballs.sh script run: | + export SINGULARITY_CACHEDIR=$PWD # bind current directory into container as /software-layer-scripts export SINGULARITY_BIND="${PWD}:/software-layer-scripts" @@ -113,12 +116,13 @@ jobs: # scripts need to be copied to /tmp, # since create_directory_tarballs.sh must be accessible from within build container - ./eessi_container.sh --mode run --verbose /software-layer-scripts/create_directory_tarballs.sh 2023.06 + ./eessi_container.sh --mode run --verbose /software-layer-scripts/create_directory_tarballs.sh "${{matrix.EESSI_VERSION}}" # check if tarballs have been produced ls -l *.tar.gz - name: test create_lmodsitepackage.py script run: | + export SINGULARITY_CACHEDIR=$PWD # bind current directory into container as /software-layer-scripts export SINGULARITY_BIND="${PWD}:/software-layer-scripts" @@ -140,3 +144,22 @@ jobs: for pattern in "^Site Pkg location.*/software-layer-scripts/.lmod/SitePackage.lua" "LMOD_SITEPACKAGE_LOCATION.*/software-layer-scripts/.lmod/SitePackage.lua"; do grep "${pattern}" ${out} || (echo "Pattern '${pattern}' not found in output!" && exit 1) done + + - name: Mount EESSI CernVM-FS repository + uses: eessi/github-action-eessi@v3 + with: + eessi_stack_version: ${{matrix.EESSI_VERSION}} + use_eessi_module: true + + - name: Verify that mounted repositories are passed through directly + run: | + export SINGULARITY_CACHEDIR=$PWD + # run wrapper script + capture & check output + export SINGULARITY_BIND="${PWD}:/software-layer-scripts" + # make sure that correct EESSI version is used (required because default is a placeholder version) + export EESSI_VERSION_OVERRIDE="${{matrix.EESSI_VERSION}}" + + out="${PWD}/eb-${EB_VERSION}.out" + ./eessi_container.sh --access rw --mode run --verbose /software-layer-scripts/run_in_compat_layer_env.sh ls 2>&1 | tee ${out} + echo $(grep "SINGULARITY_BIND" ${out}) + grep "SINGULARITY_BIND" ${out} | grep "software.eessi.io" || (echo "software.eessi.io did not seem to be bind mounted!" && exit 1) diff --git a/eessi_container.sh b/eessi_container.sh index 00a0322..6b16d03 100755 --- a/eessi_container.sh +++ b/eessi_container.sh @@ -97,8 +97,8 @@ display_help() { echo " container; can be given multiple times [default: not set]" echo " -r | --repository CFG - configuration file or identifier defining the" echo " repository to use; can be given multiple times;" - echo " CFG may include a suffix ',access={ro,rw}' to" - echo " overwrite the global access mode for this repository" + echo " CFG may include suffixes ',access={ro,rw},mode={bind,fuse}' to" + echo " overwrite the global access and/or mount mode for this repository" echo " [default: software.eessi.io via CVMFS config available" echo " via default container, see --container]" echo " -u | --resume DIR/TGZ - resume a previous run from a directory or tarball," @@ -756,14 +756,40 @@ for cvmfs_repo in "${REPOSITORIES[@]}" do unset cfg_repo_id [[ ${VERBOSE} -eq 1 ]] && echo "add fusemount options for CVMFS repo '${cvmfs_repo}'" - # split into name and access mode if ',access=' in $cvmfs_repo - if [[ ${cvmfs_repo} == *",access="* ]] ; then - cvmfs_repo_name=${cvmfs_repo/,access=*/} # remove access mode specification - cvmfs_repo_access=${cvmfs_repo/*,access=/} # remove repo name part - else - cvmfs_repo_name="${cvmfs_repo}" - cvmfs_repo_access="${ACCESS}" # use globally defined access mode + # split into name, access mode, and mount mode + readarray -td, cvmfs_repo_args <<<"$cvmfs_repo" + cvmfs_repo_name=${cvmfs_repo_args[0]} + cvmfs_repo_access="${ACCESS}" # initialize to the default access mode + for arg in ${cvmfs_repo_args[@]:1}; do + if [[ $arg == "access="* ]]; then + cvmfs_repo_access=${arg/access=} + fi + if [[ $arg == "mount="* ]]; then + cvmfs_repo_mount=${arg/mount=} + # check if the specified mount mode is a valid one + if [[ ${cvmfs_repo_mount} != "bind" ]] && [[ ${cvmfs_repo_mount} != "fuse" ]]; then + echo -e "ERROR: mount mode '${cvmfs_repo_mount}' for CVMFS repository\n '${cvmfs_repo_name}' is not known" + exit ${REPOSITORY_ERROR_EXITCODE} + fi + fi + done + # if a mount mode was not specified, we use a bind mount if the repository is available on the host, + # and otherwise we use a fuse mount + if [[ -z ${cvmfs_repo_mount} ]]; then + cvmfs_repo_mount="fuse" + if [[ -x $(command -v cvmfs_config) ]] && cvmfs_config probe ${cvmfs_repo_name} >& /dev/null; then + cvmfs_repo_mount="bind" + fi + fi + [[ ${VERBOSE} -eq 1 ]] && echo "Using a ${cvmfs_repo_mount} mount for /cvmfs/${cvmfs_repo_name}" + # if a bind mount was requested, check if the repository is really available on the host + if [[ ${cvmfs_repo_mount} == "bind" ]]; then + if [[ ! -x $(command -v cvmfs_config) ]] || ! cvmfs_config probe ${cvmfs_repo_name} >& /dev/null; then + echo -e "ERROR: bind mount requested for CVMFS repository\n '${cvmfs_repo_name}', but it cannot be probed on the host" + exit ${REPOSITORY_ERROR_EXITCODE} + fi fi + # obtain cvmfs_repo_name from EESSI_REPOS_CFG_FILE if cvmfs_repo is in cfg_cvmfs_repos if [[ ${cfg_cvmfs_repos[${cvmfs_repo_name}]} ]]; then [[ ${VERBOSE} -eq 1 ]] && echo "repo '${cvmfs_repo_name}' is not an EESSI CVMFS repository..." @@ -795,9 +821,12 @@ do echo " session. Will use it as left-most directory in 'lowerdir' argument for fuse-overlayfs." # make the target CernVM-FS repository available under /cvmfs_ro - export EESSI_READONLY="container:cvmfs2 ${cvmfs_repo_name} /cvmfs_ro/${cvmfs_repo_name}" - - EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") + if [[ ${cvmfs_repo_mount} == "fuse" ]]; then + export EESSI_READONLY="container:cvmfs2 ${cvmfs_repo_name} /cvmfs_ro/${cvmfs_repo_name}" + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") + elif [[ ${cvmfs_repo_mount} == "bind" ]]; then + BIND_PATHS="/cvmfs/${cvmfs_repo_name}:/cvmfs_ro/${cvmfs_repo_name},${BIND_PATHS}" + fi # now, put the overlay-upper read-only on top of the repo and make it available under the usual prefix /cvmfs if [[ "${OVERLAY_TOOL}" == "fuse-overlayfs" ]]; then @@ -827,10 +856,14 @@ do # basic "ro" access that doesn't require any fuseoverlay-fs echo "Mounting '${cvmfs_repo_name}' 'read-only' without fuse-overlayfs." - export EESSI_READONLY="container:cvmfs2 ${cvmfs_repo_name} /cvmfs/${cvmfs_repo_name}" + if [[ ${cvmfs_repo_mount} == "fuse" ]]; then + export EESSI_READONLY="container:cvmfs2 ${cvmfs_repo_name} /cvmfs/${cvmfs_repo_name}" + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") + export EESSI_FUSE_MOUNTS + elif [[ ${cvmfs_repo_mount} == "bind" ]]; then + BIND_PATHS="/cvmfs/${cvmfs_repo_name},${BIND_PATHS}" + fi - EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") - export EESSI_FUSE_MOUNTS fi elif [[ ${cvmfs_repo_access} == "rw" ]] ; then # use repo-specific overlay directories @@ -840,9 +873,12 @@ do [[ ${VERBOSE} -eq 1 ]] && echo -e "TMP directory contents:\n$(ls -l ${EESSI_TMPDIR})" # set environment variables for fuse mounts in Singularity container - export EESSI_READONLY="container:cvmfs2 ${cvmfs_repo_name} /cvmfs_ro/${cvmfs_repo_name}" - - EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") + if [[ ${cvmfs_repo_mount} == "fuse" ]]; then + export EESSI_READONLY="container:cvmfs2 ${cvmfs_repo_name} /cvmfs_ro/${cvmfs_repo_name}" + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") + elif [[ ${cvmfs_repo_mount} == "bind" ]]; then + BIND_PATHS="/cvmfs/${cvmfs_repo_name}:/cvmfs_ro/${cvmfs_repo_name},${BIND_PATHS}" + fi if [[ "${OVERLAY_TOOL}" == "fuse-overlayfs" ]]; then EESSI_WRITABLE_OVERLAY="container:fuse-overlayfs"