diff --git a/.github/workflows/tests_readme.yml b/.github/workflows/tests_readme.yml new file mode 100644 index 0000000000..5c6d0318d4 --- /dev/null +++ b/.github/workflows/tests_readme.yml @@ -0,0 +1,32 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +name: Tests for consistency of README.md +on: + push: + paths: + - README.md + - init/eessi_defaults + + pull_request: + branches: + - main + paths: + - README.md + - init/eessi_defaults +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - name: Check out software-layer repository + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + + - name: verify if README.md is consistent with EESSI_PILOT_VERSION from init/eessi_defaults + run: | + source init/eessi_defaults + grep "${EESSI_PILOT_VERSION}" README.md + + - name: verify if README.md is consistent with EESSI_CVMFS_REPO from init/eessi_defaults + run: | + source init/eessi_defaults + grep "${EESSI_CVMFS_REPO}" README.md diff --git a/EESSI-pilot-install-software.sh b/EESSI-pilot-install-software.sh index e1b4089e2d..87a6f59b75 100755 --- a/EESSI-pilot-install-software.sh +++ b/EESSI-pilot-install-software.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Script to install EESSI pilot software stack (version 2021.12) +# Script to install EESSI pilot software stack (version set through init/eessi_defaults) # see example parsing of command line arguments at # https://wiki.bash-hackers.org/scripting/posparams#using_a_while_loop @@ -125,6 +125,13 @@ fi echo ">> Configuring EasyBuild..." source $TOPDIR/configure_easybuild +echo "@@ Check if installpath '${EASYBUILD_INSTALLPATH}' is writable @@" +touch ${EASYBUILD_INSTALLPATH}/foo +ls -l ${EASYBUILD_INSTALLPATH} + +echo "@@ Check contents of /tmp @@" +ls -l /tmp + echo ">> Setting up \$MODULEPATH..." # make sure no modules are loaded module --force purge @@ -137,7 +144,7 @@ else echo_green ">> MODULEPATH set up: ${MODULEPATH}" fi -REQ_EB_VERSION='4.5.0' +REQ_EB_VERSION='4.6.2' echo ">> Checking for EasyBuild module..." ml_av_easybuild_out=$TMPDIR/ml_av_easybuild.out @@ -206,230 +213,238 @@ fi echo_green "All set, let's start installing some software in ${EASYBUILD_INSTALLPATH}..." -# install Java with fixed custom easyblock that uses patchelf to ensure right glibc is picked up, -# see https://github.com/EESSI/software-layer/issues/123 -# and https://github.com/easybuilders/easybuild-easyblocks/pull/2557 -ok_msg="Java installed, off to a good (?) start!" -fail_msg="Failed to install Java, woopsie..." -$EB Java-11.eb --robot --include-easyblocks-from-pr 2557 -check_exit_code $? "${ok_msg}" "${fail_msg}" - -# install GCC for foss/2020a -export GCC_EC="GCC-9.3.0.eb" -echo ">> Starting slow with ${GCC_EC}..." -ok_msg="${GCC_EC} installed, yippy! Off to a good start..." -fail_msg="Installation of ${GCC_EC} failed!" -# pull in easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/14453, -# which includes patch to fix build of GCC 9.3 when recent kernel headers are in place -$EB ${GCC_EC} --robot --from-pr 14453 GCCcore-9.3.0.eb -check_exit_code $? "${ok_msg}" "${fail_msg}" - -# install CMake with custom easyblock that patches CMake when --sysroot is used -echo ">> Install CMake with fixed easyblock to take into account --sysroot" -ok_msg="CMake installed!" -fail_msg="Installation of CMake failed, what the ..." -$EB CMake-3.16.4-GCCcore-9.3.0.eb --robot --include-easyblocks-from-pr 2248 -check_exit_code $? "${ok_msg}" "${fail_msg}" - -# If we're building OpenBLAS for GENERIC, we need https://github.com/easybuilders/easybuild-easyblocks/pull/1946 -echo ">> Installing OpenBLAS..." -ok_msg="Done with OpenBLAS!" -fail_msg="Installation of OpenBLAS failed!" -if [[ $GENERIC -eq 1 ]]; then - echo_yellow ">> Using https://github.com/easybuilders/easybuild-easyblocks/pull/1946 to build generic OpenBLAS." - openblas_include_easyblocks_from_pr="--include-easyblocks-from-pr 1946" -else - openblas_include_easyblocks_from_pr='' -fi -$EB $openblas_include_easyblocks_from_pr OpenBLAS-0.3.9-GCC-9.3.0.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing OpenMPI..." -ok_msg="OpenMPI installed, w00!" -fail_msg="Installation of OpenMPI failed, that's not good..." -$EB OpenMPI-4.0.3-GCC-9.3.0.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -# install Python -echo ">> Install Python 2.7.18 and Python 3.8.2..." -ok_msg="Python 2.7.18 and 3.8.2 installed, yaay!" -fail_msg="Installation of Python failed, oh no..." -$EB Python-2.7.18-GCCcore-9.3.0.eb Python-3.8.2-GCCcore-9.3.0.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing Perl..." -ok_msg="Perl installed, making progress..." -fail_msg="Installation of Perl failed, this never happens..." -# use enhanced Perl easyblock from https://github.com/easybuilders/easybuild-easyblocks/pull/2640 -# to avoid trouble when using long installation prefix (for example with EESSI pilot 2021.12 on skylake_avx512...) -$EB Perl-5.30.2-GCCcore-9.3.0.eb --robot --include-easyblocks-from-pr 2640 -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing Qt5..." -ok_msg="Qt5 installed, phieuw, that was a big one!" -fail_msg="Installation of Qt5 failed, that's frustrating..." -$EB Qt5-5.14.1-GCCcore-9.3.0.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -# skip test step when installing SciPy-bundle on aarch64, -# to dance around problem with broken numpy tests; -# cfr. https://github.com/easybuilders/easybuild-easyconfigs/issues/11959 -echo ">> Installing SciPy-bundle" -ok_msg="SciPy-bundle installed, yihaa!" -fail_msg="SciPy-bundle installation failed, bummer..." -SCIPY_EC=SciPy-bundle-2020.03-foss-2020a-Python-3.8.2.eb -if [[ "$(uname -m)" == "aarch64" ]]; then - $EB $SCIPY_EC --robot --skip-test-step -else - $EB $SCIPY_EC --robot -fi -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing GROMACS..." -ok_msg="GROMACS installed, wow!" -fail_msg="Installation of GROMACS failed, damned..." -$EB GROMACS-2020.1-foss-2020a-Python-3.8.2.eb GROMACS-2020.4-foss-2020a-Python-3.8.2.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -# note: compiling OpenFOAM is memory hungry (16GB is not enough with 8 cores)! -# 32GB is sufficient to build with 16 cores -echo ">> Installing OpenFOAM (twice!)..." -ok_msg="OpenFOAM installed, now we're talking!" -fail_msg="Installation of OpenFOAM failed, we were so close..." -$EB OpenFOAM-8-foss-2020a.eb OpenFOAM-v2006-foss-2020a.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -if [ ! "${EESSI_CPU_FAMILY}" = "ppc64le" ]; then - echo ">> Installing QuantumESPRESSO..." - ok_msg="QuantumESPRESSO installed, let's go quantum!" - fail_msg="Installation of QuantumESPRESSO failed, did somebody observe it?!" - $EB QuantumESPRESSO-6.6-foss-2020a.eb --robot - check_exit_code $? "${ok_msg}" "${fail_msg}" -fi - -echo ">> Installing R 4.0.0 (better be patient)..." -ok_msg="R installed, wow!" -fail_msg="Installation of R failed, so sad..." -$EB R-4.0.0-foss-2020a.eb --robot --parallel-extensions-install --experimental -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing Bioconductor 3.11 bundle..." -ok_msg="Bioconductor installed, enjoy!" -fail_msg="Installation of Bioconductor failed, that's annoying..." -$EB R-bundle-Bioconductor-3.11-foss-2020a-R-4.0.0.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing TensorFlow 2.3.1..." -ok_msg="TensorFlow 2.3.1 installed, w00!" -fail_msg="Installation of TensorFlow failed, why am I not surprised..." -$EB TensorFlow-2.3.1-foss-2020a-Python-3.8.2.eb --robot --include-easyblocks-from-pr 2218 -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing Horovod 0.21.3..." -ok_msg="Horovod installed! Go do some parallel training!" -fail_msg="Horovod installation failed. There comes the headache..." -$EB Horovod-0.21.3-foss-2020a-TensorFlow-2.3.1-Python-3.8.2.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -if [ ! "${EESSI_CPU_FAMILY}" = "ppc64le" ]; then - - echo ">> Installing code-server 3.7.3..." - ok_msg="code-server 3.7.3 installed, now you can use VS Code!" - fail_msg="Installation of code-server failed, that's going to be hard to fix..." - $EB code-server-3.7.3.eb --robot - check_exit_code $? "${ok_msg}" "${fail_msg}" -fi - -echo ">> Installing RStudio-Server 1.3.1093..." -ok_msg="RStudio-Server installed, enjoy!" -fail_msg="Installation of RStudio-Server failed, might be OS deps..." -$EB RStudio-Server-1.3.1093-foss-2020a-Java-11-R-4.0.0.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing OSU-Micro-Benchmarks 5.6.3..." -ok_msg="OSU-Micro-Benchmarks installed, yihaa!" -fail_msg="Installation of OSU-Micro-Benchmarks failed, that's unexpected..." -$EB OSU-Micro-Benchmarks-5.6.3-gompi-2020a.eb -r -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing Spark 3.1.1..." -ok_msg="Spark installed, set off the fireworks!" -fail_msg="Installation of Spark failed, no fireworks this time..." -$EB Spark-3.1.1-foss-2020a-Python-3.8.2.eb -r -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing IPython 7.15.0..." -ok_msg="IPython installed, launch your Jupyter Notebooks!" -fail_msg="Installation of IPython failed, that's unexpected..." -$EB IPython-7.15.0-foss-2020a-Python-3.8.2.eb -r -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing WRF 3.9.1.1..." -ok_msg="WRF installed, it's getting hot in here!" -fail_msg="Installation of WRF failed, that's unexpected..." -OMPI_MCA_pml=ucx UCX_TLS=tcp $EB WRF-3.9.1.1-foss-2020a-dmpar.eb -r --include-easyblocks-from-pr 2648 -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing R 4.1.0 (better be patient)..." -ok_msg="R installed, wow!" -fail_msg="Installation of R failed, so sad..." -$EB --from-pr 14821 X11-20210518-GCCcore-10.3.0.eb -r && $EB --from-pr 16011 R-4.1.0-foss-2021a.eb --robot --parallel-extensions-install --experimental -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing Nextflow 22.10.1..." -ok_msg="Nextflow installed, the work must flow..." -fail_msg="Installation of Nextflow failed, that's unexpected..." -$EB -r --from-pr 16531 Nextflow-22.10.1.eb -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing OSU-Micro-Benchmarks/5.7.1-gompi-2021a..." -ok_msg="OSU-Micro-Benchmarks installed, yihaa!" -fail_msg="Installation of OSU-Micro-Benchmarks failed, that's unexpected..." -$EB OSU-Micro-Benchmarks-5.7.1-gompi-2021a.eb -r -check_exit_code $? "${ok_msg}" "${fail_msg}" - -echo ">> Installing EasyBuild 4.5.1..." -ok_msg="EasyBuild v4.5.1 installed" -fail_msg="EasyBuild v4.5.1 failed to install" -$EB --from-pr 14545 --include-easyblocks-from-pr 2805 -check_exit_code $? "${ok_msg}" "${fail_msg}" - -LMOD_IGNORE_CACHE=1 module swap EasyBuild/4.5.1 -check_exit_code $? "Swapped to EasyBuild/4.5.1" "Couldn't swap to EasyBuild/4.5.1" - -echo ">> Installing SciPy-bundle with foss/2021a..." -ok_msg="SciPy-bundle with foss/2021a installed, welcome to the modern age" -fail_msg="Installation of SciPy-bundle with foss/2021a failed, back to the stone age..." -# use GCCcore easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/14454 -# which includes patch to fix installation with recent Linux kernel headers -$EB --from-pr 14454 GCCcore-10.3.0.eb --robot -# use enhanced Perl easyblock from https://github.com/easybuilders/easybuild-easyblocks/pull/2640 -# to avoid trouble when using long installation prefix (for example with EESSI pilot 2021.12 on skylake_avx512...) -$EB Perl-5.32.1-GCCcore-10.3.0.eb --robot --include-easyblocks-from-pr 2640 -# use enhanced CMake easyblock to patch CMake's UnixPaths.cmake script if --sysroot is set -# from https://github.com/easybuilders/easybuild-easyblocks/pull/2248 -$EB CMake-3.20.1-GCCcore-10.3.0.eb --robot --include-easyblocks-from-pr 2248 -# use Rust easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/14584 -# that includes patch to fix bootstrap problem when using alternate sysroot -$EB --from-pr 14584 Rust-1.52.1-GCCcore-10.3.0.eb --robot -# use OpenBLAS easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/15885 -# which includes a patch to fix installation on POWER -$EB $openblas_include_easyblocks_from_pr --from-pr 15885 OpenBLAS-0.3.15-GCC-10.3.0.eb --robot -# ignore failing FlexiBLAS tests when building on POWER; -# some tests are failing due to a segmentation fault due to "invalid memory reference", -# see also https://github.com/easybuilders/easybuild-easyconfigs/pull/12476; -# using -fstack-protector-strong -fstack-clash-protection should fix that, -# but it doesn't for some reason when building for ppc64le/generic... -if [ "${EESSI_SOFTWARE_SUBDIR}" = "ppc64le/generic" ]; then - $EB FlexiBLAS-3.0.4-GCC-10.3.0.eb --ignore-test-failure -else - $EB FlexiBLAS-3.0.4-GCC-10.3.0.eb -fi - -$EB SciPy-bundle-2021.05-foss-2021a.eb --robot -check_exit_code $? "${ok_msg}" "${fail_msg}" +##### install Java with fixed custom easyblock that uses patchelf to ensure right glibc is picked up, +##### see https://github.com/EESSI/software-layer/issues/123 +##### and https://github.com/easybuilders/easybuild-easyblocks/pull/2557 +####ok_msg="Java installed, off to a good (?) start!" +####fail_msg="Failed to install Java, woopsie..." +####$EB Java-11.eb --robot --include-easyblocks-from-pr 2557 +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +##### install GCC for foss/2020a +####export GCC_EC="GCC-9.3.0.eb" +####echo ">> Starting slow with ${GCC_EC}..." +####ok_msg="${GCC_EC} installed, yippy! Off to a good start..." +####fail_msg="Installation of ${GCC_EC} failed!" +##### pull in easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/14453, +##### which includes patch to fix build of GCC 9.3 when recent kernel headers are in place +####$EB ${GCC_EC} --robot --from-pr 14453 GCCcore-9.3.0.eb +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +##### install CMake with custom easyblock that patches CMake when --sysroot is used +####echo ">> Install CMake with fixed easyblock to take into account --sysroot" +####ok_msg="CMake installed!" +####fail_msg="Installation of CMake failed, what the ..." +####$EB CMake-3.16.4-GCCcore-9.3.0.eb --robot --include-easyblocks-from-pr 2248 +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +##### If we're building OpenBLAS for GENERIC, we need https://github.com/easybuilders/easybuild-easyblocks/pull/1946 +####echo ">> Installing OpenBLAS..." +####ok_msg="Done with OpenBLAS!" +####fail_msg="Installation of OpenBLAS failed!" +####if [[ $GENERIC -eq 1 ]]; then +#### echo_yellow ">> Using https://github.com/easybuilders/easybuild-easyblocks/pull/1946 to build generic OpenBLAS." +#### openblas_include_easyblocks_from_pr="--include-easyblocks-from-pr 1946" +####else +#### openblas_include_easyblocks_from_pr='' +####fi +####$EB $openblas_include_easyblocks_from_pr OpenBLAS-0.3.9-GCC-9.3.0.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing OpenMPI..." +####ok_msg="OpenMPI installed, w00!" +####fail_msg="Installation of OpenMPI failed, that's not good..." +####$EB OpenMPI-4.0.3-GCC-9.3.0.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +##### install Python +####echo ">> Install Python 2.7.18 and Python 3.8.2..." +####ok_msg="Python 2.7.18 and 3.8.2 installed, yaay!" +####fail_msg="Installation of Python failed, oh no..." +####$EB Python-2.7.18-GCCcore-9.3.0.eb Python-3.8.2-GCCcore-9.3.0.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing Perl..." +####ok_msg="Perl installed, making progress..." +####fail_msg="Installation of Perl failed, this never happens..." +##### use enhanced Perl easyblock from https://github.com/easybuilders/easybuild-easyblocks/pull/2640 +##### to avoid trouble when using long installation prefix (for example with EESSI pilot 2021.12 on skylake_avx512...) +####$EB Perl-5.30.2-GCCcore-9.3.0.eb --robot --include-easyblocks-from-pr 2640 +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing Qt5..." +####ok_msg="Qt5 installed, phieuw, that was a big one!" +####fail_msg="Installation of Qt5 failed, that's frustrating..." +####$EB Qt5-5.14.1-GCCcore-9.3.0.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +##### skip test step when installing SciPy-bundle on aarch64, +##### to dance around problem with broken numpy tests; +##### cfr. https://github.com/easybuilders/easybuild-easyconfigs/issues/11959 +####echo ">> Installing SciPy-bundle" +####ok_msg="SciPy-bundle installed, yihaa!" +####fail_msg="SciPy-bundle installation failed, bummer..." +####SCIPY_EC=SciPy-bundle-2020.03-foss-2020a-Python-3.8.2.eb +####if [[ "$(uname -m)" == "aarch64" ]]; then +#### $EB $SCIPY_EC --robot --skip-test-step +####else +#### $EB $SCIPY_EC --robot +####fi +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing GROMACS..." +####ok_msg="GROMACS installed, wow!" +####fail_msg="Installation of GROMACS failed, damned..." +####$EB GROMACS-2020.1-foss-2020a-Python-3.8.2.eb GROMACS-2020.4-foss-2020a-Python-3.8.2.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +##### note: compiling OpenFOAM is memory hungry (16GB is not enough with 8 cores)! +##### 32GB is sufficient to build with 16 cores +####echo ">> Installing OpenFOAM (twice!)..." +####ok_msg="OpenFOAM installed, now we're talking!" +####fail_msg="Installation of OpenFOAM failed, we were so close..." +####$EB OpenFOAM-8-foss-2020a.eb OpenFOAM-v2006-foss-2020a.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####if [ ! "${EESSI_CPU_FAMILY}" = "ppc64le" ]; then +#### echo ">> Installing QuantumESPRESSO..." +#### ok_msg="QuantumESPRESSO installed, let's go quantum!" +#### fail_msg="Installation of QuantumESPRESSO failed, did somebody observe it?!" +#### $EB QuantumESPRESSO-6.6-foss-2020a.eb --robot +#### check_exit_code $? "${ok_msg}" "${fail_msg}" +####fi +#### +####echo ">> Installing R 4.0.0 (better be patient)..." +####ok_msg="R installed, wow!" +####fail_msg="Installation of R failed, so sad..." +####$EB R-4.0.0-foss-2020a.eb --robot --parallel-extensions-install --experimental +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing Bioconductor 3.11 bundle..." +####ok_msg="Bioconductor installed, enjoy!" +####fail_msg="Installation of Bioconductor failed, that's annoying..." +####$EB R-bundle-Bioconductor-3.11-foss-2020a-R-4.0.0.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing TensorFlow 2.3.1..." +####ok_msg="TensorFlow 2.3.1 installed, w00!" +####fail_msg="Installation of TensorFlow failed, why am I not surprised..." +####$EB TensorFlow-2.3.1-foss-2020a-Python-3.8.2.eb --robot --include-easyblocks-from-pr 2218 +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing Horovod 0.21.3..." +####ok_msg="Horovod installed! Go do some parallel training!" +####fail_msg="Horovod installation failed. There comes the headache..." +####$EB Horovod-0.21.3-foss-2020a-TensorFlow-2.3.1-Python-3.8.2.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####if [ ! "${EESSI_CPU_FAMILY}" = "ppc64le" ]; then +#### +#### echo ">> Installing code-server 3.7.3..." +#### ok_msg="code-server 3.7.3 installed, now you can use VS Code!" +#### fail_msg="Installation of code-server failed, that's going to be hard to fix..." +#### $EB code-server-3.7.3.eb --robot +#### check_exit_code $? "${ok_msg}" "${fail_msg}" +####fi +#### +####echo ">> Installing RStudio-Server 1.3.1093..." +####ok_msg="RStudio-Server installed, enjoy!" +####fail_msg="Installation of RStudio-Server failed, might be OS deps..." +####$EB RStudio-Server-1.3.1093-foss-2020a-Java-11-R-4.0.0.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing OSU-Micro-Benchmarks 5.6.3..." +####ok_msg="OSU-Micro-Benchmarks installed, yihaa!" +####fail_msg="Installation of OSU-Micro-Benchmarks failed, that's unexpected..." +####$EB OSU-Micro-Benchmarks-5.6.3-gompi-2020a.eb -r +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing Spark 3.1.1..." +####ok_msg="Spark installed, set off the fireworks!" +####fail_msg="Installation of Spark failed, no fireworks this time..." +####$EB Spark-3.1.1-foss-2020a-Python-3.8.2.eb -r +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing IPython 7.15.0..." +####ok_msg="IPython installed, launch your Jupyter Notebooks!" +####fail_msg="Installation of IPython failed, that's unexpected..." +####$EB IPython-7.15.0-foss-2020a-Python-3.8.2.eb -r +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing WRF 3.9.1.1..." +####ok_msg="WRF installed, it's getting hot in here!" +####fail_msg="Installation of WRF failed, that's unexpected..." +####OMPI_MCA_pml=ucx UCX_TLS=tcp $EB WRF-3.9.1.1-foss-2020a-dmpar.eb -r --include-easyblocks-from-pr 2648 +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing R 4.1.0 (better be patient)..." +####ok_msg="R installed, wow!" +####fail_msg="Installation of R failed, so sad..." +####$EB --from-pr 14821 X11-20210518-GCCcore-10.3.0.eb -r && $EB --from-pr 16011 R-4.1.0-foss-2021a.eb --robot --parallel-extensions-install --experimental +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing Nextflow 22.10.1..." +####ok_msg="Nextflow installed, the work must flow..." +####fail_msg="Installation of Nextflow failed, that's unexpected..." +####$EB -r --from-pr 16531 Nextflow-22.10.1.eb +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing OSU-Micro-Benchmarks/5.7.1-gompi-2021a..." +####ok_msg="OSU-Micro-Benchmarks installed, yihaa!" +####fail_msg="Installation of OSU-Micro-Benchmarks failed, that's unexpected..." +####$EB OSU-Micro-Benchmarks-5.7.1-gompi-2021a.eb -r +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####echo ">> Installing EasyBuild 4.5.1..." +####ok_msg="EasyBuild v4.5.1 installed" +####fail_msg="EasyBuild v4.5.1 failed to install" +####$EB --from-pr 14545 --include-easyblocks-from-pr 2805 +####check_exit_code $? "${ok_msg}" "${fail_msg}" +#### +####LMOD_IGNORE_CACHE=1 module swap EasyBuild/4.5.1 +####check_exit_code $? "Swapped to EasyBuild/4.5.1" "Couldn't swap to EasyBuild/4.5.1" +#### +####echo ">> Installing SciPy-bundle with foss/2021a..." +####ok_msg="SciPy-bundle with foss/2021a installed, welcome to the modern age" +####fail_msg="Installation of SciPy-bundle with foss/2021a failed, back to the stone age..." +##### use GCCcore easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/14454 +##### which includes patch to fix installation with recent Linux kernel headers +####$EB --from-pr 14454 GCCcore-10.3.0.eb --robot +##### use enhanced Perl easyblock from https://github.com/easybuilders/easybuild-easyblocks/pull/2640 +##### to avoid trouble when using long installation prefix (for example with EESSI pilot 2021.12 on skylake_avx512...) +####$EB Perl-5.32.1-GCCcore-10.3.0.eb --robot --include-easyblocks-from-pr 2640 +##### use enhanced CMake easyblock to patch CMake's UnixPaths.cmake script if --sysroot is set +##### from https://github.com/easybuilders/easybuild-easyblocks/pull/2248 +####$EB CMake-3.20.1-GCCcore-10.3.0.eb --robot --include-easyblocks-from-pr 2248 +##### use Rust easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/14584 +##### that includes patch to fix bootstrap problem when using alternate sysroot +####$EB --from-pr 14584 Rust-1.52.1-GCCcore-10.3.0.eb --robot +##### use OpenBLAS easyconfig from https://github.com/easybuilders/easybuild-easyconfigs/pull/15885 +##### which includes a patch to fix installation on POWER +####$EB $openblas_include_easyblocks_from_pr --from-pr 15885 OpenBLAS-0.3.15-GCC-10.3.0.eb --robot +##### ignore failing FlexiBLAS tests when building on POWER; +##### some tests are failing due to a segmentation fault due to "invalid memory reference", +##### see also https://github.com/easybuilders/easybuild-easyconfigs/pull/12476; +##### using -fstack-protector-strong -fstack-clash-protection should fix that, +##### but it doesn't for some reason when building for ppc64le/generic... +####if [ "${EESSI_SOFTWARE_SUBDIR}" = "ppc64le/generic" ]; then +#### $EB FlexiBLAS-3.0.4-GCC-10.3.0.eb --ignore-test-failure +####else +#### $EB FlexiBLAS-3.0.4-GCC-10.3.0.eb +####fi +#### +####$EB SciPy-bundle-2021.05-foss-2021a.eb --robot +####check_exit_code $? "${ok_msg}" "${fail_msg}" ### add packages here +echo "Installing CaDiCaL/1.3.0 for GCC/9.3.0..." +ok_msg="CaDiCaL installed. Nice!" +fail_msg="Installation of CaDiCaL failed, that's unexpected..." +$EB CaDiCaL-1.3.0-GCC-9.3.0.eb --robot --disable-cleanup-tmpdir +exit_code=$? +$EB --last-log +cat $($EB --last-log) +check_exit_code $exit_code "${ok_msg}" "${fail_msg}" echo ">> Creating/updating Lmod cache..." export LMOD_RC="${EASYBUILD_INSTALLPATH}/.lmod/lmodrc.lua" @@ -442,5 +457,9 @@ $TOPDIR/update_lmod_cache.sh ${EPREFIX} ${EASYBUILD_INSTALLPATH} $TOPDIR/check_missing_installations.sh +# TODO do not clean up by default (or provide a cmd line arg and when run +# from bot, do not clean up) echo ">> Cleaning up ${TMPDIR}..." rm -r ${TMPDIR} + +exit 0 diff --git a/README.md b/README.md index 4d463b1c5b..daf02eebc2 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,22 @@ Environment set up to use EESSI pilot software stack, have fun! [EESSI pilot 2021.12] $ ``` +### Accessing EESSI via a container + +You need Singularity version 3.7 or newer. Then, simply run + +``` +$ ./eessi_container.sh +``` +Once you get presented the prompt `Singularity>` run the above `source` command. + +If you want to build a package for the software repository, simply add the arguments `--access rw`, e.g., full command would be + +``` +$ ./eessi_container.sh --access rw +``` +Note, not all features/arguments listed via `./eessi_container.sh --help` are implemented. + # License The software in this repository is distributed under the terms of the diff --git a/bot/build.sh b/bot/build.sh new file mode 100755 index 0000000000..54ea46bc37 --- /dev/null +++ b/bot/build.sh @@ -0,0 +1,209 @@ +#!/usr/bin/env bash +# +# script to build the EESSI software layer. Intended use is that it is called +# by a (batch) job running on a compute node. +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Thomas Roeblitz (@trz42) +# +# license: GPLv2 +# + +# ASSUMPTIONs: +# - working directory has been prepared by the bot with a checkout of a +# pull request (OR by some other means) +# - the working directory contains a directory 'cfg' where the main config +# file 'job.cfg' has been deposited +# - the directory may contain any additional files references in job.cfg +# - the tool 'yq' for working with json files is available via the PATH or +# the environment variable BOT_YQ (see https://github.com/mikefarah/yq) + +echo "###################################################################" +env +echo "###################################################################" +echo + +# defaults +export JOB_CFG_FILE="${JOB_CFG_FILE_OVERRIDE:=./cfg/job.cfg}" + +# source utils.sh +source utils.sh + +# check setup / define key variables +# get path for 'yq' (if not found, an empty string is returned) +YQ=$(get_path_for_tool "yq" "BOT_YQ") +exit_code=$? +if [[ ${exit_code} -ne 0 ]]; then + fatal_error "could not find path to 'yq'; exiting" +else + echo_green "found yq (${YQ})" +fi + +# check if './cfg/job.cfg' exists +if [[ ! -r "${JOB_CFG_FILE}" ]]; then + fatal_error "job config file (JOB_CFG_FILE=${JOB_CFG_FILE}) does not exist or not readable" +fi +echo "obtaining configuration settings from '${JOB_CFG_FILE}'" + +# if http_proxy is in cfg/job.cfg use it, if not use env var $http_proxy +HTTP_PROXY=$(${YQ} '.site_config.http_proxy // ""' ${JOB_CFG_FILE}) +HTTP_PROXY=${HTTP_PROXY:-${http_proxy}} +echo "HTTP_PROXY='${HTTP_PROXY}'" + +# if https_proxy is in cfg/job.cfg use it, if not use env var $https_proxy +HTTPS_PROXY=$(${YQ} '.site_config.https_proxy // ""' ${JOB_CFG_FILE}) +HTTPS_PROXY=${HTTPS_PROXY:-${https_proxy}} +echo "HTTPS_PROXY='${HTTPS_PROXY}'" + +LOCAL_TMP=$(${YQ} '.site_config.local_tmp // ""' ${JOB_CFG_FILE}) +echo "LOCAL_TMP='${LOCAL_TMP}'" +# TODO should local_tmp be mandatory? --> then we check here and exit if it is not provided + +echo -n "setting \$STORAGE by replacing any var in '${LOCAL_TMP}' -> " +# replace any env variable in ${LOCAL_TMP} with its +# current value (e.g., a value that is local to the job) +STORAGE=$(envsubst <<< ${LOCAL_TMP}) +echo "'${STORAGE}'" + +# obtain list of modules to be loaded +LOAD_MODULES=$(${YQ} '.site_config.load_modules // ""' ${JOB_CFG_FILE}) +echo "LOAD_MODULES='${LOAD_MODULES}'" + +# singularity/apptainer settings: CONTAINER, HOME, TMPDIR, BIND +CONTAINER=$(${YQ} '.repository.container // ""' ${JOB_CFG_FILE}) +export SINGULARITY_HOME="$(pwd):/eessi_bot_job" +export SINGULARITY_TMPDIR="$(pwd)/singularity_tmpdir" +mkdir -p ${SINGULARITY_TMPDIR} + +# load modules if LOAD_MODULES is not empty +if [[ ! -z ${LOAD_MODULES} ]]; then + for mod in $(echo ${LOAD_MODULES} | tr ',' '\n') + do + echo "bot/build.sh: loading module '${mod}'" + module load ${mod} + done +else + echo "bot/build.sh: no modules to be loaded" +fi + +# determine repository to be used from entry .repository in cfg/job.cfg +REPOSITORY=$(${YQ} '.repository.repo_id // ""' ${JOB_CFG_FILE}) +EESSI_REPOS_CFG_DIR_OVERRIDE=$(${YQ} '.repository.repos_cfg_dir // ""' ${JOB_CFG_FILE}) +export EESSI_REPOS_CFG_DIR_OVERRIDE=${EESSI_REPOS_CFG_DIR_OVERRIDE:-${PWD}/cfg} + +# determine pilot version to be used from .repository.repo_version in cfg/job.cfg +# TODO better? set EESSI_PILOT_VERSION_OVERRIDE and "source init/eessi_defaults" +EESSI_PILOT_VERSION=$(${YQ} '.repository.repo_version // ""' ${JOB_CFG_FILE}) +export EESSI_PILOT_VERSION=${EESSI_PILOT_VERSION:-2021.12} + +# determine architecture to be used from entry .architecture in cfg/job.cfg +# default: leave empty to let downstream script(s) determine subdir to be used +if [[ ! -z "${CPU_TARGET}" ]]; then + EESSI_SOFTWARE_SUBDIR_OVERRIDE=${CPU_TARGET} +else + EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(${YQ} '.architecture.software_subdir // ""' ${JOB_CFG_FILE}) +fi + +# get EESSI_OS_TYPE from cfg/job.cfg (default: linux) +EESSI_OS_TYPE=$(${YQ} '.architecture.os_type // ""' ${JOB_CFG_FILE}) +export EESSI_OS_TYPE=${EESSI_OS_TYPE:-linux} + +#echo "environment BEFORE sourcing '${PWD}/init/minimal_eessi_env'" +#env | grep EESSI_ +#source init/minimal_eessi_env +#echo "environment AFTER sourcing '${PWD}/init/minimal_eessi_env'" +#env | grep EESSI_ + +# TODO +# - CODED add handling of EESSI_SOFTWARE_SUBDIR_OVERRIDE to eessi_container.sh +# TODO ensure that the bot makes use of that. (currently sets env var +# CPU_TARGET & adds --export=ALL,CPU_TARGET=val to sbatch command ... also +# add it to cfg/job.cfg - .architecture.software_subdir) +# - CODED add handling of http(s)_proxy to eessi_container.sh, in there needs the +# CVMFS_HTTP_PROXY added to /etc/cvmfs/default.local (this needs a robust +# way to determine the IP address of a proxy) +# - bot needs to make repos.cfg and cfg_bundle available to job (likely, by copying +# files into './cfg/.' and defining '.repository.repos_cfg_dir' in './cfg/job.cfg') + +# prepare options and directories for calling eessi_container.sh +CONTAINER_OPT= +if [[ ! -z ${CONTAINER} ]]; then + CONTAINER_OPT="--container ${CONTAINER}" +fi +HTTP_PROXY_OPT= +if [[ ! -z ${HTTP_PROXY} ]]; then + HTTP_PROXY_OPT="--http-proxy ${HTTP_PROXY}" +fi +HTTPS_PROXY_OPT= +if [[ ! -z ${HTTPS_PROXY} ]]; then + HTTPS_PROXY_OPT="--https-proxy ${HTTPS_PROXY}" +fi +REPOSITORY_OPT= +if [[ ! -z ${REPOSITORY} ]]; then + REPOSITORY_OPT="--repository ${REPOSITORY}" +fi +echo "###################################################################" +env +echo "###################################################################" +echo +mkdir -p previous_tmp +build_outerr=$(mktemp build.outerr.XXXX) +echo "Executing command to build software:" +echo "./eessi_container.sh --access rw" +echo " ${CONTAINER_OPT}" +echo " ${HTTP_PROXY_OPT}" +echo " ${HTTPS_PROXY_OPT}" +echo " --info" +echo " --mode run" +echo " ${REPOSITORY_OPT}" +echo " --save ${PWD}/previous_tmp" +echo " --storage ${STORAGE}" +echo " ./install_software_layer.sh \"$@\" 2>&1 | tee -a ${build_outerr}" +./eessi_container.sh --access rw \ + ${CONTAINER_OPT} \ + ${HTTP_PROXY_OPT} \ + ${HTTPS_PROXY_OPT} \ + --info \ + --mode run \ + ${REPOSITORY_OPT} \ + --save ${PWD}/previous_tmp \ + --storage ${STORAGE} \ + ./install_software_layer.sh \"$@\" 2>&1 | tee -a ${build_outerr} + +# determine temporary directory to resume from +BUILD_TMPDIR=$(grep 'RESUME_FROM_DIR' ${build_outerr} | sed -e "s/^RESUME_FROM_DIR //") + +tar_outerr=$(mktemp tar.outerr.XXXX) +timestamp=$(date +%s) +export TGZ=$(printf "eessi-%s-software-%s-%s-%d.tar.gz" ${EESSI_PILOT_VERSION} ${EESSI_OS_TYPE} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE//\//-} ${timestamp}) + +# value of first parameter to create_tarball.sh TMP_IN_CONTAINER needs to be +# synchronised with setting of TMP_IN_CONTAINER in eessi_container.sh +# TODO should we make this a configurable parameter of eessi_container.sh using +# /tmp as default? +TMP_IN_CONTAINER=/tmp +echo "Executing command to create tarball:" +echo "./eessi_container.sh --access rw" +echo " ${CONTAINER_OPT}" +echo " ${HTTP_PROXY_OPT}" +echo " ${HTTPS_PROXY_OPT}" +echo " --info" +echo " --mode run" +echo " ${REPOSITORY_OPT}" +echo " --resume ${BUILD_TMPDIR}" +echo " --save ${PWD}/previous_tmp" +echo " ./create_tarball.sh ${TMP_IN_CONTAINER} ${EESSI_PILOT_VERSION} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} /eessi_bot_job/${TGZ} 2>&1 | tee -a ${tar_outerr}" +./eessi_container.sh --access rw \ + ${CONTAINER_OPT} \ + ${HTTP_PROXY_OPT} \ + ${HTTPS_PROXY_OPT} \ + --info \ + --mode run \ + ${REPOSITORY_OPT} \ + --resume ${BUILD_TMPDIR} \ + --save ${PWD}/previous_tmp \ + ./create_tarball.sh ${TMP_IN_CONTAINER} ${EESSI_PILOT_VERSION} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} /eessi_bot_job/${TGZ} 2>&1 | tee -a ${tar_outerr} + +exit 0 diff --git a/build_container.sh b/build_container.sh index bddd3dfffc..23a9e665c9 100755 --- a/build_container.sh +++ b/build_container.sh @@ -1,5 +1,7 @@ #!/bin/bash +base_dir=$(dirname $(realpath $0)) + BUILD_CONTAINER="docker://ghcr.io/eessi/build-node:debian11" if [ $# -lt 2 ]; then @@ -39,9 +41,13 @@ if [ -z $SINGULARITY_HOME ]; then export SINGULARITY_HOME="$EESSI_TMPDIR/home:/home/$USER" fi +source ${base_dir}/init/eessi_defaults +# strip "/cvmfs/" from default setting +repo_name=${EESSI_CVMFS_REPO/\/cvmfs\//} + # set environment variables for fuse mounts in Singularity container -export EESSI_PILOT_READONLY="container:cvmfs2 pilot.eessi-hpc.org /cvmfs_ro/pilot.eessi-hpc.org" -export EESSI_PILOT_WRITABLE_OVERLAY="container:fuse-overlayfs -o lowerdir=/cvmfs_ro/pilot.eessi-hpc.org -o upperdir=$EESSI_TMPDIR/overlay-upper -o workdir=$EESSI_TMPDIR/overlay-work /cvmfs/pilot.eessi-hpc.org" +export EESSI_PILOT_READONLY="container:cvmfs2 ${repo_name} /cvmfs_ro/${repo_name}" +export EESSI_PILOT_WRITABLE_OVERLAY="container:fuse-overlayfs -o lowerdir=/cvmfs_ro/${repo_name} -o upperdir=$EESSI_TMPDIR/overlay-upper -o workdir=$EESSI_TMPDIR/overlay-work ${EESSI_CVMFS_REPO}" # pass $EESSI_SOFTWARE_SUBDIR_OVERRIDE into build container (if set) if [ ! -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then diff --git a/cfg_files.sh b/cfg_files.sh new file mode 100644 index 0000000000..57ea2f7c03 --- /dev/null +++ b/cfg_files.sh @@ -0,0 +1,167 @@ +# functions for working with ini/cfg files +# +# This file is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Thomas Roeblitz (@trz42) +# +# license: GPLv2 +# + + +# global variables +# -a -> indexed array +# -A -> associative array +declare -A cfg_repos +declare -A cfg_file_map + + +# functions +function cfg_get_section { + if [[ "$1" =~ ^(\[)(.*)(\])$ ]]; then + echo ${BASH_REMATCH[2]} + else + echo "" + fi +} + +function cfg_get_key_value { + if [[ "$1" =~ ^([^=]+)=([^=]+)$ ]]; then + echo "${BASH_REMATCH[1]}=${BASH_REMATCH[2]}" + else + echo "" + fi +} + +function cfg_load { + local cur_section="" + local cur_key="" + local cur_val="" + IFS= + while read -r line; do + new_section=$(cfg_get_section $line) + # got a new section + if [[ -n "$new_section" ]]; then + cur_section=$new_section + # not a section, try a key value + else + val=$(cfg_get_key_value $line) + # trim leading and trailing spaces as well + cur_key=$(echo $val | cut -f1 -d'=' | cfg_trim_spaces) + cur_val=$(echo $val | cut -f2 -d'=' | cfg_trim_spaces) + if [[ -n "$cur_key" ]]; then + # section + key is the associative in bash array, the field separator is space + cfg_repos[${cur_section} ${cur_key}]=$cur_val + fi + fi + done <$1 +} + +function cfg_print { + for index in "${!cfg_repos[@]}" + do + # split the associative key in to section and key + echo -n "section : $(echo $index | cut -f1 -d ' ');" + echo -n "key : $(echo $index | cut -f2 -d ' ');" + echo "value: ${cfg_repos[$index]}" + done +} + +function cfg_sections { + declare -A sections + for key in "${!cfg_repos[@]}" + do + # extract section from the associative key + section=$(echo $key | cut -f1 -d ' ') + sections[${section}]=1 + done + for repo in "${!sections[@]}" + do + echo "${repo}" + done +} + +function cfg_get_value { + section=$1 + key=$2 + echo "${cfg_repos[$section $key]}" +} + +function cfg_trim_spaces { + # reads from argument $1 or stdin + if [[ $# -gt 0 ]]; then + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< ${1} + else + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' < /dev/stdin + fi +} + +function cfg_trim_quotes { + # reads from argument $1 or stdin + if [[ $# -gt 0 ]]; then + sed -e 's/^"*//' -e 's/"*$//' <<< ${1} + else + sed -e 's/^"*//' -e 's/"*$//' < /dev/stdin + fi +} + +function cfg_trim_curly_brackets { + # reads from argument $1 or stdin + if [[ $# -gt 0 ]]; then + sed -e 's/^{*//' -e 's/}*$//' <<< ${1} + else + sed -e 's/^{*//' -e 's/}*$//' < /dev/stdin + fi +} + +function cfg_get_all_sections { + # first field in keys + # 1. get first field in all keys, 2. filter duplicates, 3. return them as string + declare -A all_sections + for key in "${!cfg_repos[@]}" + do + section=$(echo "$key" | cut -f1 -d' ') + all_sections[${section}]=1 + done + sections= + for sec_key in "${!all_sections[@]}" + do + sections="${sections} ${sec_key}" + done + echo "${sections}" | cfg_trim_spaces +} + +function cfg_init_file_map { + # strip '{' and '}' from config_map + # split config_map at ',' + # for each item: split at ':' use first as key, second as value + + # reset global variable + cfg_file_map=() + + # expects a string containing the config_map from the cfg file + # trim leading and trailing curly brackets + cm_trimmed=$(cfg_trim_curly_brackets "$1") + + # split into elements along ',' + declare -a cm_mappings + IFS=',' read -r -a cm_mappings <<< "${cm_trimmed}" + + for index in "${!cm_mappings[@]}" + do + # split mapping into key and value + map_key=$(echo ${cm_mappings[index]} | cut -f1 -d':') + map_value=$(echo ${cm_mappings[index]} | cut -f2 -d':') + # trim spaces and double quotes at start and end + tr_key=$(cfg_trim_spaces "${map_key}" | cfg_trim_quotes) + tr_value=$(cfg_trim_spaces "${map_value}" | cfg_trim_quotes) + cfg_file_map[${tr_key}]=${tr_value} + done +} + +function cfg_print_map { + for index in "${!cfg_file_map[@]}" + do + echo "${index} --> ${cfg_file_map[${index}]}" + done +} diff --git a/create_tarball.sh b/create_tarball.sh index f2643ccfc5..c8ede057d3 100755 --- a/create_tarball.sh +++ b/create_tarball.sh @@ -2,6 +2,8 @@ set -e +base_dir=$(dirname $(realpath $0)) + if [ $# -ne 4 ]; then echo "ERROR: Usage: $0 " >&2 exit 1 @@ -11,21 +13,40 @@ pilot_version=$2 cpu_arch_subdir=$3 target_tgz=$4 +echo eessi_tmpdir=$1 +echo pilot_version=$2 +echo cpu_arch_subdir=$3 +echo target_tgz=$4 + tmpdir=`mktemp -d` echo ">> tmpdir: $tmpdir" os="linux" -cvmfs_repo="/cvmfs/pilot.eessi-hpc.org" +source ${base_dir}/init/eessi_defaults +cvmfs_repo=${EESSI_CVMFS_REPO} +# overwrite what we get from command line +# pilot_version=${EESSI_PILOT_VERSION} software_dir="${cvmfs_repo}/versions/${pilot_version}/software/${os}/${cpu_arch_subdir}" if [ ! -d ${software_dir} ]; then echo "Software directory ${software_dir} does not exist?!" >&2 exit 2 +else + echo "Software directory ${software_dir} does exist! GOOD!" >&2 fi overlay_upper_dir="${eessi_tmpdir}/overlay-upper" +echo overlay_upper_dir="${eessi_tmpdir}/overlay-upper" +#overlay_upper_dir="/tmp/overlay-upper" +#echo overlay_upper_dir="/tmp/overlay-upper" +echo "ls ${overlay_upper_dir}" +ls ${overlay_upper_dir} software_dir_overlay="${overlay_upper_dir}/versions/${pilot_version}/software/${os}/${cpu_arch_subdir}" +echo software_dir_overlay="${overlay_upper_dir}/versions/${pilot_version}/software/${os}/${cpu_arch_subdir}" +echo "find ${overlay_upper_dir} -type d" +find ${overlay_upper_dir} -type d + if [ ! -d ${software_dir_overlay} ]; then echo "Software directory overlay ${software_dir_overlay} does not exist?!" >&2 exit 3 diff --git a/eessi-2021.12.yml b/eessi-2021.12.yml index 210bbb2845..25ea2f0f7a 100644 --- a/eessi-2021.12.yml +++ b/eessi-2021.12.yml @@ -67,3 +67,7 @@ software: versions: '3.9.1.1': versionsuffix: -dmpar + CaDiCaL: + toolchains: + GCC-9.3.0: + versions: ['1.3.0'] diff --git a/eessi-2022.11.yml b/eessi-2022.11.yml new file mode 100644 index 0000000000..b4d9001de8 --- /dev/null +++ b/eessi-2022.11.yml @@ -0,0 +1,5 @@ +software: + CaDiCaL: + toolchains: + GCC-9.3.0: + versions: ['1.3.0'] diff --git a/eessi_container.sh b/eessi_container.sh new file mode 100755 index 0000000000..277e83aade --- /dev/null +++ b/eessi_container.sh @@ -0,0 +1,529 @@ +#!/bin/bash +# +# unified script to access EESSI in different scenarios: read-only +# for just using EESSI, read & write for building software to be +# added to the software stack +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Thomas Roeblitz (@trz42) +# +# license: GPLv2 +# + +# script overview +# -. initial settings & exit codes +# 0. parse args +# 1. check if argument values are valid +# 2. set up host storage/tmp +# 3. set up common vars and directories +# 4. set up vars specific to a scenario +# 5. run container +# 6. save tmp (if requested) + +# -. initial settings & exit codes +base_dir=$(dirname $(realpath $0)) + +source ${base_dir}/utils.sh +source ${base_dir}/cfg_files.sh + +# exit codes: bitwise shift codes to allow for combination of exit codes +# ANY_ERROR_EXITCODE is sourced from ${base_dir}/utils.sh +CMDLINE_ARG_UNKNOWN_EXITCODE=$((${ANY_ERROR_EXITCODE} << 1)) +ACCESS_UNKNOWN_EXITCODE=$((${ANY_ERROR_EXITCODE} << 2)) +CONTAINER_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 3)) +HOST_STORAGE_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 4)) +MODE_UNKNOWN_EXITCODE=$((${ANY_ERROR_EXITCODE} << 5)) +REPOSITORY_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 6)) +RESUME_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 7)) +SAVE_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 8)) +HTTP_PROXY_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 9)) +HTTPS_PROXY_ERROR_EXITCODE=$((${ANY_ERROR_EXITCODE} << 10)) +RUN_SCRIPT_MISSING_EXITCODE=$((${ANY_ERROR_EXITCODE} << 11)) + +# CernVM-FS settings +CVMFS_VAR_LIB="var-lib-cvmfs" +CVMFS_VAR_RUN="var-run-cvmfs" + +# target for tmp used inside container +export TMP_IN_CONTAINER=/tmp + +# repository cfg file, default name (default location: $PWD) +# can be overwritten by setting env var EESSI_REPOS_CFG_DIR_OVERRIDE +export EESSI_REPOS_CFG_FILE="${EESSI_REPOS_CFG_DIR_OVERRIDE:=${PWD}}/repos.cfg" +# other repository cfg files in directory, default location: $PWD +# can be overwritten by setting env var EESSI_REPOS_CFG_DIR_OVERRIDE +export EESSI_REPOS_CFG_DIR="${EESSI_REPOS_CFG_DIR_OVERRIDE:=${PWD}}" + + +# 0. parse args +# see example parsing of command line arguments at +# https://wiki.bash-hackers.org/scripting/posparams#using_a_while_loop +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash + +display_help() { + echo "usage: $0 [OPTIONS] [SCRIPT]" + echo " OPTIONS:" + echo " -a | --access {ro,rw} - ro (read-only), rw (read & write) [default: ro]" + echo " -c | --container IMG - image file or URL defining the container to use" + echo " [default: docker://ghcr.io/eessi/build-node:debian11]" + echo " -h | --help - display this usage information [default: false]" + echo " -i | --info - display configuration information [default: false]" + echo " -g | --storage DIR - directory space on host machine (used for" + echo " temporary data) [default: 1. TMPDIR, 2. /tmp]" + echo " -l | --list-repos - list available repository identifiers [default: false]" + echo " -m | --mode MODE - with MODE==shell (launch interactive shell) or" + echo " MODE==run (run a script) [default: shell]" + echo " -r | --repository CFG - configuration file or identifier defining the" + echo " repository to use [default: EESSI-pilot]" + echo " -u | --resume DIR/TGZ - resume a previous run from a directory or tarball," + echo " where DIR points to a previously used tmp directory" + echo " (check for output 'Using DIR as tmp ...' of a previous" + echo " run) and TGZ is the path to a tarball which is" + echo " unpacked the tmp dir stored on the local storage space" + echo " (see option --storage above) [default: not set]" + echo " -s | --save DIR/TGZ - save contents of tmp directory to a tarball in" + echo " directory DIR or provided with the fixed full path TGZ" + echo " when a directory is provided, the format of the" + echo " tarball's name will be {REPO_ID}-{TIMESTAMP}.tgz" + echo " [default: not set]" + echo " -x | --http-proxy URL - provides URL for the env variable http_proxy" + echo " [default: not set]; uses env var \$http_proxy if set" + echo " -y | --https-proxy URL - provides URL for the env variable https_proxy" + echo " [default: not set]; uses env var \$https_proxy if set" + echo + echo " If value for --mode is 'run', the SCRIPT provided is executed." + echo + echo " FEATURES/OPTIONS to be implemented:" + echo " -d | --dry-run - run script except for executing the container," + echo " print information about setup [default: false]" +} + +# set defaults for command line arguments +ACCESS="ro" +CONTAINER="docker://ghcr.io/eessi/build-node:debian11" +DRY_RUN=0 +INFO=0 +STORAGE= +LIST_REPOS=0 +MODE="shell" +REPOSITORY="EESSI-pilot" +RESUME= +SAVE= +HTTP_PROXY=${http_proxy:-} +HTTPS_PROXY=${https_proxy:-} + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -a|--access) + ACCESS="$2" + shift 2 + ;; + -c|--container) + CONTAINER="$2" + shift 2 + ;; + -d|--dry-run) + DRY_RUN=1 + shift 1 + ;; + -g|--storage) + STORAGE="$2" + shift 2 + ;; + -h|--help) + display_help + exit 0 + ;; + -i|--info) + INFO=1 + shift 1 + ;; + -l|--list-repos) + LIST_REPOS=1 + shift 1 + ;; + -m|--mode) + MODE="$2" + shift 2 + ;; + -r|--repository) + REPOSITORY="$2" + shift 2 + ;; + -s|--save) + SAVE="$2" + shift 2 + ;; + -u|--resume) + RESUME="$2" + shift 2 + ;; + -x|--http-proxy) + HTTP_PROXY="$2" + export http_proxy=${HTTP_PROXY} + shift 2 + ;; + -y|--https-proxy) + HTTPS_PROXY="$2" + export https_proxy=${HTTPS_PROXY} + shift 2 + ;; + -*|--*) + fatal_error "Unknown option: $1" "${CMDLINE_ARG_UNKNOWN_EXITCODE}" + ;; + *) # No more options + POSITIONAL_ARGS+=("$1") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +if [[ ${LIST_REPOS} -eq 1 ]]; then + echo "Repositories defined in the config file '${EESSI_REPOS_CFG_FILE}':" + echo " EESSI-pilot [default]" + cfg_load ${EESSI_REPOS_CFG_FILE} + sections=$(cfg_sections) + while IFS= read -r repo_id + do + echo " ${repo_id}" + done <<< "${sections}" + exit 0 +fi + +# 1. check if argument values are valid +# (arg -a|--access) check if ACCESS is supported +if [[ "${ACCESS}" != "ro" && "${ACCESS}" != "rw" ]]; then + fatal_error "unknown access method '${ACCESS}'" "${ACCESS_UNKNOWN_EXITCODE}" +fi + +# TODO (arg -c|--container) check container (is it a file or URL & access those) +# CONTAINER_ERROR_EXITCODE + +# TODO (arg -g|--storage) check if it exists, if user has write permission, +# if it contains no data, etc. +# HOST_STORAGE_ERROR_EXITCODE + +# (arg -m|--mode) check if MODE is known +if [[ "${MODE}" != "shell" && "${MODE}" != "run" ]]; then + fatal_error "unknown execution mode '${MODE}'" "${MODE_UNKNOWN_EXITCODE}" +fi + +# TODO (arg -r|--repository) check if repository is known +# REPOSITORY_ERROR_EXITCODE +if [[ ! -z "${REPOSITORY}" && "${REPOSITORY}" != "EESSI-pilot" && ! -r ${EESSI_REPOS_CFG_FILE} ]]; then + fatal_error "arg '--repository ${REPOSITORY}' requires a cfg file at '${EESSI_REPOS_CFG_FILE}'" "${REPOSITORY_ERROR_EXITCODE}" +fi + + +# TODO (arg -u|--resume) check if it exists, if user has read permission, +# if it contains data from a previous run +# RESUME_ERROR_EXITCODE + +# TODO (arg -s|--save) check if DIR exists, if user has write permission, +# if TGZ already exists, if user has write permission to directory to which +# TGZ should be written +# SAVE_ERROR_EXITCODE + +# TODO (arg -x|--http-proxy) check if http proxy is accessible +# HTTP_PROXY_ERROR_EXITCODE + +# TODO (arg -y|--https-proxy) check if https proxy is accessible +# HTTPS_PROXY_ERROR_EXITCODE + +# check if a script is provided if mode is 'run' +if [[ "${MODE}" == "run" ]]; then + if [[ $# -eq 0 ]]; then + fatal_error "no command specified to run?!" "${RUN_SCRIPT_MISSING_EXITCODE}" + fi +fi + + +# 2. set up host storage/tmp if necessary +# if session to be resumed from a previous one (--resume ARG) and ARG is a directory +# just reuse ARG, define environment variables accordingly and skip creating a new +# tmp storage +if [[ ! -z ${RESUME} && -d ${RESUME} ]]; then + # resume from directory ${RESUME} + # skip creating a new tmp directory, just set environment variables + echo "Resuming from previous run using temporary storage at ${RESUME}" + EESSI_HOST_STORAGE=${RESUME} +else + # we need a tmp location (and possibly init it with ${RESUME} if it was not + # a directory + + # as location for temporary data use in the following order + # a. command line argument -l|--host-storage + # b. env var TMPDIR + # c. /tmp + # note, we ensure that (a) takes precedence by setting TMPDIR to STORAGE + # if STORAGE is not empty + # note, (b) & (c) are automatically ensured by using 'mktemp -d --tmpdir' to + # create a temporary directory + if [[ ! -z ${STORAGE} ]]; then + export TMPDIR=${STORAGE} + # mktemp fails if TMPDIR does not exist, so let's create it + mkdir -p ${TMPDIR} + fi + if [[ ! -z ${TMPDIR} ]]; then + # TODO check if TMPDIR already exists + # mktemp fails if TMPDIR does not exist, so let's create it + mkdir -p ${TMPDIR} + fi + if [[ -z ${TMPDIR} ]]; then + # mktemp falls back to using /tmp if TMPDIR is empty + # TODO check if /tmp is writable, large enough and usable (different + # features for ro-access and rw-access) + [[ ${INFO} -eq 1 ]] && echo "skipping sanity checks for /tmp" + fi + EESSI_HOST_STORAGE=$(mktemp -d --tmpdir eessi.XXXXXXXXXX) + echo "Using ${EESSI_HOST_STORAGE} as tmp storage (add '--resume ${EESSI_HOST_STORAGE}' to resume where this session ended)." + echo "RESUME_FROM_DIR ${EESSI_HOST_STORAGE}" +fi + +# if ${RESUME} is a file (assume a tgz), unpack it into ${EESSI_HOST_STORAGE} +if [[ ! -z ${RESUME} && -f ${RESUME} ]]; then + tar xf ${RESUME} -C ${EESSI_HOST_STORAGE} + echo "Resuming from previous run using temporary storage ${RESUME} unpacked into ${EESSI_HOST_STORAGE}" +fi + +# 3. set up common vars and directories +# directory structure should be: +# ${EESSI_HOST_STORAGE} +# |-singularity_cache +# |-${CVMFS_VAR_LIB} +# |-${CVMFS_VAR_RUN} +# |-overlay-upper +# |-overlay-work +# |-home +# |-repos_cfg + +# tmp dir for EESSI +EESSI_TMPDIR=${EESSI_HOST_STORAGE} +mkdir -p ${EESSI_TMPDIR} +[[ ${INFO} -eq 1 ]] && echo "EESSI_TMPDIR='${EESSI_TMPDIR}'" + +# configure Singularity +export SINGULARITY_CACHEDIR=${EESSI_TMPDIR}/singularity_cache +mkdir -p ${SINGULARITY_CACHEDIR} +[[ ${INFO} -eq 1 ]] && echo "SINGULARITY_CACHEDIR='${SINGULARITY_CACHEDIR}'" + +# set env vars and create directories for CernVM-FS +EESSI_CVMFS_VAR_LIB=${EESSI_TMPDIR}/${CVMFS_VAR_LIB} +EESSI_CVMFS_VAR_RUN=${EESSI_TMPDIR}/${CVMFS_VAR_RUN} +mkdir -p ${EESSI_CVMFS_VAR_LIB} +mkdir -p ${EESSI_CVMFS_VAR_RUN} +[[ ${INFO} -eq 1 ]] && echo "EESSI_CVMFS_VAR_LIB='${EESSI_CVMFS_VAR_LIB}'" +[[ ${INFO} -eq 1 ]] && echo "EESSI_CVMFS_VAR_RUN='${EESSI_CVMFS_VAR_RUN}'" + +# allow that SINGULARITY_HOME is defined before script is run +if [[ -z ${SINGULARITY_HOME} ]]; then + export SINGULARITY_HOME="${EESSI_TMPDIR}/home:/home/${USER}" + mkdir -p ${EESSI_TMPDIR}/home + [[ ${INFO} -eq 1 ]] && echo "SINGULARITY_HOME='${SINGULARITY_HOME}'" +fi + +# define paths to add to SINGULARITY_BIND (added later when all BIND mounts are defined) +BIND_PATHS="${EESSI_CVMFS_VAR_LIB}:/var/lib/cvmfs,${EESSI_CVMFS_VAR_RUN}:/var/run/cvmfs" +# provide a '/tmp' inside the container +BIND_PATHS="${BIND_PATHS},${EESSI_TMPDIR}:${TMP_IN_CONTAINER}" +#if [[ ${EESSI_TMPDIR} != /tmp* ]] ; +#then +# mkdir -p ${EESSI_TMPDIR}/tmp +# BIND_PATHS="${BIND_PATHS},${EESSI_TMPDIR}/tmp:/tmp" +#fi + +[[ ${INFO} -eq 1 ]] && echo "BIND_PATHS=${BIND_PATHS}" + +# set up repository config (always create directory repos_cfg and populate it with info when +# arg -r|--repository is used) +echo "environment BEFORE setting up repository" +env | grep EESSI_ +mkdir -p ${EESSI_TMPDIR}/repos_cfg +if [[ "${REPOSITORY}" == "EESSI-pilot" ]]; then + # need to source defaults as late as possible (see other sourcing below) + source ${base_dir}/init/eessi_defaults + + # strip "/cvmfs/" from default setting + repo_name=${EESSI_CVMFS_REPO/\/cvmfs\//} +else + # TODO implement more flexible specification of repo cfgs + # REPOSITORY => repo-id OR repo-cfg-file (with a single section) OR + # repo-cfg-file:repo-id (repo-id defined in repo-cfg-file) + # + # for now, assuming repo-id is defined in config file pointed to + # EESSI_REPOS_CFG_FILE, which is to be copied into the working directory + # (could also become part of the software layer to define multiple + # standard EESSI repositories) + cfg_load ${EESSI_REPOS_CFG_FILE} + + # cfg file should include: repo_name, repo_version, config_bundle, + # map { local_filepath -> container_filepath } + # + # repo_name_domain is the domain part of the repo_name, e.g., + # eessi-hpc.org for pilot.eessi-hpc.org + # + # where config bundle includes the files (-> target location in container) + # - default.local -> /etc/cvmfs/default.local + # contains CVMFS settings, e.g., CVMFS_HTTP_PROXY, CVMFS_QUOTA_LIMIT, ... + # - ${repo_name_domain}.conf -> /etc/cvmfs/domain.d/${repo_name_domain}.conf + # contains CVMFS settings, e.g., CVMFS_SERVER_URL (Stratum 1s), + # CVMFS_KEYS_DIR, CVMFS_USE_GEOAPI, ... + # - ${repo_name_domain}/ -> /etc/cvmfs/keys/${repo_name_domain} + # a directory that contains the public key to access the repository, key + # itself then doesn't need to be BIND mounted + # - ${repo_name_domain}/${repo_name}.pub + # (-> /etc/cvmfs/keys/${repo_name_domain}/${repo_name}.pub + # the public key to access the repository, key itself is BIND mounted + # via directory ${repo_name_domain} + repo_name=$(cfg_get_value ${REPOSITORY} "repo_name") + # derive domain part from repo_name (everything after first '.') + repo_name_domain=${repo_name#*.} + repo_version=$(cfg_get_value ${REPOSITORY} "repo_version") + config_bundle=$(cfg_get_value ${REPOSITORY} "config_bundle") + config_map=$(cfg_get_value ${REPOSITORY} "config_map") + + # convert config_map into associative array cfg_file_map + cfg_init_file_map "${config_map}" + [[ ${INFO} -eq 1 ]] && cfg_print_map + + # use information to set up dir ${EESSI_TMPDIR}/repos_cfg, + # define BIND mounts and override repo name and version + # check if config_bundle exists, if so, unpack it into ${EESSI_TMPDIR}/repos_cfg + # if config_bundle is relative path (no '/' at start) prepend it with + # EESSI_REPOS_CFG_DIR + config_bundle_path= + if [[ ! "${config_bundle}" =~ ^/ ]]; then + config_bundle_path=${EESSI_REPOS_CFG_DIR}/${config_bundle} + else + config_bundle_path=${config_bundle} + fi + + if [[ ! -r ${config_bundle_path} ]]; then + fatal_error "config bundle '${config_bundle_path}' is not readable" ${REPOSITORY_ERROR_EXITCODE} + fi + + # only unpack config_bundle if we're not resuming from a previous run + if [[ -z ${RESUME} ]]; then + tar xf ${config_bundle_path} -C ${EESSI_TMPDIR}/repos_cfg + fi + + for src in "${!cfg_file_map[@]}" + do + target=${cfg_file_map[${src}]} + BIND_PATHS="${BIND_PATHS},${EESSI_TMPDIR}/repos_cfg/${src}:${target}" + done + export EESSI_PILOT_VERSION_OVERRIDE=${repo_version} + export EESSI_CVMFS_REPO_OVERRIDE="/cvmfs/${repo_name}" + # need to source defaults as late as possible (after *_OVERRIDEs) + source ${base_dir}/init/eessi_defaults +fi +echo "environment AFTER setting up repository" +env | grep EESSI_ + +# if http_proxy is not empty, we assume that the machine accesses internet +# via a proxy. then we need to add CVMFS_HTTP_PROXY to +# ${EESSI_TMPDIR}/repos_cfg/default.local on host (and possibly add a BIND +# MOUNT if it was not yet in BIND_PATHS) +if [[ ! -z ${http_proxy} ]]; then + # TODO tolerate other formats for proxy URLs, for now assume format is + # http://SOME_HOSTNAME:SOME_PORT/ + [[ ${INFO} -eq 1 ]] && echo "http_proxy='${http_proxy}'" + PROXY_HOST=$(get_host_from_url ${http_proxy}) + [[ ${INFO} -eq 1 ]] && echo "PROXY_HOST='${PROXY_HOST}'" + PROXY_PORT=$(get_port_from_url ${http_proxy}) + [[ ${INFO} -eq 1 ]] && echo "PROXY_PORT='${PROXY_PORT}'" + HTTP_PROXY_IPV4=$(get_ipv4_address ${PROXY_HOST}) + [[ ${INFO} -eq 1 ]] && echo "HTTP_PROXY_IPV4='${HTTP_PROXY_IPV4}'" + echo "CVMFS_HTTP_PROXY=\"${http_proxy}|http://${HTTP_PROXY_IPV4}:${PROXY_PORT}\"" \ + >> ${EESSI_TMPDIR}/repos_cfg/default.local + cat ${EESSI_TMPDIR}/repos_cfg/default.local + + # if default.local is not BIND mounted into container, add it to BIND_PATHS + if [[ ! ${BIND_PATHS} =~ "${EESSI_TMPDIR}/repos_cfg/default.local:/etc/cvmfs/default.local" ]]; then + export BIND_PATHS="${BIND_PATHS},${EESSI_TMPDIR}/repos_cfg/default.local:/etc/cvmfs/default.local" + fi +fi + +# 4. set up vars and dirs specific to a scenario + +declare -a EESSI_FUSE_MOUNTS=() +if [[ "${ACCESS}" == "ro" ]]; then + export EESSI_PILOT_READONLY="container:cvmfs2 ${repo_name} /cvmfs/${repo_name}" + + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_PILOT_READONLY}") + export EESSI_FUSE_MOUNTS +fi + +if [[ "${ACCESS}" == "rw" ]]; then + mkdir -p ${EESSI_TMPDIR}/overlay-upper + mkdir -p ${EESSI_TMPDIR}/overlay-work + + # set environment variables for fuse mounts in Singularity container + export EESSI_PILOT_READONLY="container:cvmfs2 ${repo_name} /cvmfs_ro/${repo_name}" + + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_PILOT_READONLY}") + + EESSI_PILOT_WRITABLE_OVERLAY="container:fuse-overlayfs" + EESSI_PILOT_WRITABLE_OVERLAY+=" -o lowerdir=/cvmfs_ro/${repo_name}" + EESSI_PILOT_WRITABLE_OVERLAY+=" -o upperdir=${TMP_IN_CONTAINER}/overlay-upper" + EESSI_PILOT_WRITABLE_OVERLAY+=" -o workdir=${TMP_IN_CONTAINER}/overlay-work" + EESSI_PILOT_WRITABLE_OVERLAY+=" ${EESSI_CVMFS_REPO}" + export EESSI_PILOT_WRITABLE_OVERLAY + + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_PILOT_WRITABLE_OVERLAY}") + export EESSI_FUSE_MOUNTS +fi + + +# 5. run container +# final settings +if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${BIND_PATHS}" +else + export SINGULARITY_BIND="${SINGULARITY_BIND},${BIND_PATHS}" +fi +[[ ${INFO} -eq 1 ]] && echo "SINGULARITY_BIND='${SINGULARITY_BIND}'" + +# pass $EESSI_SOFTWARE_SUBDIR_OVERRIDE into build container (if set) +if [ ! -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then + export SINGULARITYENV_EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE} + # also specify via $APPTAINERENV_* (future proof, cfr. https://apptainer.org/docs/user/latest/singularity_compatibility.html#singularity-environment-variable-compatibility) + export APPTAINERENV_EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE} +fi + +echo "Show contents of EESSI_TMPDIR='${EESSI_TMPDIR}'" +find ${EESSI_TMPDIR} -type d + +echo "Launching container with command (next line):" +echo "singularity -q ${MODE} ${EESSI_FUSE_MOUNTS[@]} ${CONTAINER} $@" +# TODO for now we run singularity with '-q' (quiet), later adjust this to the log level +# provided to the script +singularity ${MODE} "${EESSI_FUSE_MOUNTS[@]}" ${CONTAINER} "$@" + +# 6. save tmp if requested (arg -s|--save) +if [[ ! -z ${SAVE} ]]; then + # Note, for now we don't try to be smart and record in any way the OS and + # ARCH which might have been used internally, eg, when software packages + # were built ... we rather keep the script here "stupid" and leave the handling + # of these aspects to where the script is used + if [[ -d ${SAVE} ]]; then + # assume SAVE is name of a directory to which tarball shall be written to + # name format: {REPO_ID}-{TIMESTAMP}.tgz + ts=$(date +%s) + TGZ=${SAVE}/${REPOSITORY}-${ts}.tgz + else + # assume SAVE is the full path to a tarball's name + TGZ=${SAVE} + fi + tar cf ${TGZ} -C ${EESSI_TMPDIR} . + echo "Saved contents of '${EESSI_TMPDIR}' to '${TGZ}' (to resume, add '--resume ${TGZ}')" + echo "RESUME_FROM_TGZ ${TGZ}" +fi + +# TODO clean up tmp by default? only retain if another option provided (--retain-tmp) diff --git a/init/eessi_defaults b/init/eessi_defaults new file mode 100644 index 0000000000..f482cbc269 --- /dev/null +++ b/init/eessi_defaults @@ -0,0 +1,12 @@ +# define default values for some EESSI_* environment variables +# +# This file is part of the EESSI software layer, +# see https://github.com/EESSI/software-layer +# +# author: Thomas Roeblitz (@trz42) +# +# license: GPLv2 +# + +export EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO_OVERRIDE:=/cvmfs/pilot.eessi-hpc.org}" +export EESSI_PILOT_VERSION="${EESSI_PILOT_VERSION_OVERRIDE:=2021.12}" diff --git a/init/minimal_eessi_env b/init/minimal_eessi_env index 39478d5c4c..97a3729a88 100644 --- a/init/minimal_eessi_env +++ b/init/minimal_eessi_env @@ -1,7 +1,22 @@ # define minimal EESSI environment, without relying on external scripts +# +# this script is *sourced*, not executed, so can't rely on $0 to determine path to self +# $BASH_SOURCE points to correct path, see also http://mywiki.wooledge.org/BashFAQ/028 +EESSI_INIT_DIR_PATH=$(dirname $(realpath $BASH_SOURCE)) +echo "init/minimal_eessi_env: BASH_SOURCE='${BASH_SOURCE}'" +echo "init/minimal_eessi_env: realpath BASH_SOURCE='$(realpath ${BASH_SOURCE})'" +echo "init/minimal_eessi_env: EESSI_INIT_DIR_PATH='${EESSI_INIT_DIR_PATH}'" + +echo "EESSI_ settings BEFORE sourcing eessi_defaults" +env | grep EESSI_ + +# set up defaults: EESSI_CVMFS_REPO, EESSI_PILOT_VERSION +# script takes *_OVERRIDEs into account +source ${EESSI_INIT_DIR_PATH}/eessi_defaults + +echo "EESSI_ settings AFTER sourcing eessi_defaults" +env | grep EESSI_ -export EESSI_CVMFS_REPO="/cvmfs/pilot.eessi-hpc.org" -export EESSI_PILOT_VERSION="${EESSI_PILOT_VERSION_OVERRIDE:=2021.12}" export EESSI_PREFIX=$EESSI_CVMFS_REPO/versions/$EESSI_PILOT_VERSION if [[ $(uname -s) == 'Linux' ]]; then diff --git a/install_software_layer.sh b/install_software_layer.sh index e0b2f785d5..bf3006a4a0 100755 --- a/install_software_layer.sh +++ b/install_software_layer.sh @@ -1,3 +1,4 @@ #!/bin/bash -export EESSI_PILOT_VERSION='2021.12' +base_dir=$(dirname $(realpath $0)) +source ${base_dir}/init/eessi_defaults ./run_in_compat_layer_env.sh ./EESSI-pilot-install-software.sh "$@" diff --git a/run_in_compat_layer_env.sh b/run_in_compat_layer_env.sh index 561a311588..37f2587de4 100755 --- a/run_in_compat_layer_env.sh +++ b/run_in_compat_layer_env.sh @@ -1,9 +1,20 @@ #!/bin/bash + +base_dir=$(dirname $(realpath $0)) +echo "script '$0' before sourcing '${base_dir}/init/eessi_defaults'" +env | grep EESSI_ +source ${base_dir}/init/eessi_defaults + +echo "script '$0' after sourcing '${base_dir}/init/eessi_defaults'" +env | grep EESSI_ + +BUILD_CONTAINER="docker://ghcr.io/eessi/build-node:debian11" if [ -z $EESSI_PILOT_VERSION ]; then echo "ERROR: \$EESSI_PILOT_VERSION must be set!" >&2 exit 1 fi -EESSI_COMPAT_LAYER_DIR="/cvmfs/pilot.eessi-hpc.org/versions/${EESSI_PILOT_VERSION}/compat/linux/$(uname -m)" +EESSI_COMPAT_LAYER_DIR="${EESSI_CVMFS_REPO}/versions/${EESSI_PILOT_VERSION}/compat/linux/$(uname -m)" +echo "script '$0' compat layer '${EESSI_COMPAT_LAYER_DIR}'" if [ ! -d ${EESSI_COMPAT_LAYER_DIR} ]; then echo "ERROR: ${EESSI_COMPAT_LAYER_DIR} does not exist!" >&2 exit 1 @@ -13,6 +24,18 @@ INPUT=$(echo "$@") if [ ! -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then INPUT="export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE}; ${INPUT}" fi +if [ ! -z ${EESSI_CVMFS_REPO_OVERRIDE} ]; then + INPUT="export EESSI_CVMFS_REPO_OVERRIDE=${EESSI_CVMFS_REPO_OVERRIDE}; ${INPUT}" +fi +if [ ! -z ${EESSI_PILOT_VERSION_OVERRIDE} ]; then + INPUT="export EESSI_PILOT_VERSION_OVERRIDE=${EESSI_PILOT_VERSION_OVERRIDE}; ${INPUT}" +fi +if [ ! -z ${http_proxy} ]; then + INPUT="export http_proxy=${http_proxy}; ${INPUT}" +fi +if [ ! -z ${https_proxy} ]; then + INPUT="export https_proxy=${https_proxy}; ${INPUT}" +fi -echo "Running '${INPUT}' in EESSI ${EESSI_PILOT_VERSION} compatibility layer environment..." +echo "Running '${INPUT}' in EESSI (${EESSI_CVMFS_REPO}) ${EESSI_PILOT_VERSION} compatibility layer environment..." ${EESSI_COMPAT_LAYER_DIR}/startprefix <<< "${INPUT}" diff --git a/utils.sh b/utils.sh index 0c98c86ec4..d0da95e87f 100644 --- a/utils.sh +++ b/utils.sh @@ -10,9 +10,14 @@ function echo_yellow() { echo -e "\e[33m$1\e[0m" } +ANY_ERROR_EXITCODE=1 function fatal_error() { echo_red "ERROR: $1" >&2 - exit 1 + if [[ $# -gt 1 ]]; then + exit $2 + else + exit "${ANY_ERROR_EXITCODE}" + fi } function check_exit_code { @@ -26,3 +31,68 @@ function check_exit_code { fatal_error "${fail_msg}" fi } + +function get_path_for_tool { + tool_name=$1 + tool_envvar_name=$2 + + which_out=$(which ${tool_name} 2>&1) + exit_code=$? + if [[ ${exit_code} -eq 0 ]]; then + echo "INFO: found tool ${tool_name} in PATH (${which_out})" >&2 + echo "${which_out}" + return 0 + fi + if [[ -z "${tool_envvar_name}" ]]; then + msg="no env var holding the full path to tool '${tool_name}' provided" + echo "${msg}" >&2 + return 1 + else + tool_envvar_value=${!tool_envvar_name} + if [[ -x "${tool_envvar_value}" ]]; then + msg="INFO: found tool ${tool_envvar_value} via env var ${tool_envvar_name}" + echo "${msg}" >&2 + echo "${tool_envvar_value}" + return 0 + else + msg="ERROR: tool '${tool_name}' not in PATH\n" + msg+="ERROR: tool '${tool_envvar_value}' via '${tool_envvar_name}' not in PATH" + echo "${msg}" >&2 + echo "" + return 2 + fi + fi +} + +function get_host_from_url { + url=$1 + re="(http|https)://([^/:]+)" + if [[ $url =~ $re ]]; then + echo ${BASH_REMATCH[2]} + return 0 + else + echo "" + return 1 + fi +} + +function get_port_from_url { + url=$1 + re="(http|https)://[^:]+:([0-9]+)" + if [[ $url =~ $re ]]; then + echo ${BASH_REMATCH[2]} + return 0 + else + echo "" + return 1 + fi +} + +function get_ipv4_address { + hname=$1 + hipv4=$(grep ${hname} /etc/hosts | grep -v '^[[:space:]]*#' | cut -d ' ' -f 1) + # TODO try other methods if the one above does not work --> tool that verifies + # what method can be used? + echo "${hipv4}" + return 0 +}