diff --git a/.github/workflows/modules/fake_module.lua b/.github/workflows/modules/fake_module.lua new file mode 100644 index 0000000000..e45cb640d6 --- /dev/null +++ b/.github/workflows/modules/fake_module.lua @@ -0,0 +1,3 @@ +setenv("INSIDE_GITHUB_ACTIONS", "true") +-- Interfere with PATH so Lmod keeps a record +prepend_path("PATH", "/snap/bin") diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index ec018bd049..d761d5f1ff 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -4,26 +4,22 @@ name: Scorecards supply-chain security on: - # For Branch-Protection check. Only the default branch is supported. See - # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection - branch_protection_rule: # To guarantee Maintained check is occasionally updated. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained schedule: - cron: '25 15 * * 3' push: - branches: [ "main" ] - pull_request: - branches: - - main + branches: + - '*-software.eessi.io' # Declare default permissions as read only. permissions: read-all jobs: analysis: + if: github.repository_owner == 'EESSI' # Prevent running on forks name: Scorecards analysis - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: # Needed to upload the results to code-scanning dashboard. security-events: write @@ -35,12 +31,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@99c53751e09b9529366343771cc321ec74e9bd3d # v2.0.6 + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 with: results_file: results.sarif results_format: sarif @@ -62,7 +58,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: SARIF file path: results.sarif @@ -70,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@807578363a7869ca324a79039e6db9c843e0e100 # v2.1.27 + uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6 with: sarif_file: results.sarif diff --git a/.github/workflows/scripts/only_latest_easystacks.sh b/.github/workflows/scripts/only_latest_easystacks.sh new file mode 100755 index 0000000000..acc9d3279a --- /dev/null +++ b/.github/workflows/scripts/only_latest_easystacks.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# +# This script figures out the latest version of EasyBuild being used for the installation of easystack +# files. +# +# This file is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Alan O'Cais (CECAM) +# +# license: GPLv2 +# + +EESSI_VERSION=${EESSI_VERSION:-"2023.06"} + +directory="easystacks/software.eessi.io/${EESSI_VERSION}" +# List of example filenames +files=($(find "$directory" -name "*.yml" | grep -e '-eb-')) +[ -n "$DEBUG" ] && echo "${files[@]}" + +versions=() +# Loop over each filename +for filename in "${files[@]}"; do + # Extract the semantic version using grep + version=$(echo "$filename" | grep -oP '(?<=eb-)\d+\.\d+\.\d+?(?=-)') + + # Output the result + [ -n "$DEBUG" ] && echo "Filename: $filename" + [ -n "$DEBUG" ] && echo "Extracted version: $version" + [ -n "$DEBUG" ] && echo + versions+=("$version") +done +highest_version=$(printf "%s\n" "${versions[@]}" | sort -V | tail -n 1) + +[ -n "$DEBUG" ] && echo "Highest version: $highest_version" +[ -n "$DEBUG" ] && echo +[ -n "$DEBUG" ] && echo "Matching files:" +all_latest_easystacks=($(find $directory -type f -name "*eb-$highest_version*.yml")) + +accel_latest_easystacks=() +cpu_latest_easystacks=() + +# Loop through the array and split based on partial matching of string +accel="/accel/" +for item in "${all_latest_easystacks[@]}"; do + if [[ "$item" == *"$accel"* ]]; then + accel_latest_easystacks+=("$item") + else + cpu_latest_easystacks+=("$item") + fi +done + +# Output the results +if [ -n "$ACCEL_EASYSTACKS" ]; then + echo "${accel_latest_easystacks[@]}" +else + echo "${cpu_latest_easystacks[@]}" +fi diff --git a/.github/workflows/scripts/test_init_scripts.sh b/.github/workflows/scripts/test_init_scripts.sh new file mode 100755 index 0000000000..048fba81f5 --- /dev/null +++ b/.github/workflows/scripts/test_init_scripts.sh @@ -0,0 +1,50 @@ +#!/bin/bash +EESSI_VERSION="2023.06" +export LMOD_PAGER=cat + +# initialize assert framework +if [ ! -d assert.sh ]; then + echo "assert.sh not cloned." + echo "" + echo "run \`git clone https://github.com/lehmannro/assert.sh.git\`" + exit 1 +fi +. assert.sh/assert.sh + +TEST_SHELLS=("bash" "zsh" "fish" "ksh") +SHELLS=$@ + +for shell in ${SHELLS[@]}; do + echo = | awk 'NF += (OFS = $_) + 100' + echo RUNNING TESTS FOR SHELL: $shell + echo = | awk 'NF += (OFS = $_) + 100' + if [[ ! " ${TEST_SHELLS[*]} " =~ [[:space:]]${shell}[[:space:]] ]]; then + ### EXCEPTION FOR CSH ### + echo -e "\033[33mWe don't now how to test the shell '$shell', PRs are Welcome.\033[0m" + else + # TEST 1: Source Script and check Module Output + assert "$shell -c 'source init/lmod/$shell' 2>&1 " "EESSI/$EESSI_VERSION loaded successfully" + # TEST 2: Check if module overviews first section is the loaded EESSI module + MODULE_SECTIONS=($($shell -c "source init/lmod/$shell 2>/dev/null; module ov 2>&1 | grep -e '---'")) + PATTERN="/cvmfs/software\.eessi\.io/versions/$EESSI_VERSION/software/linux/x86_64/(intel/haswell|amd/zen3)/modules/all" + assert_raises 'echo "${MODULE_SECTIONS[1]}" | grep -E "$PATTERN"' + # TEST 3: Check if module overviews second section is the EESSI init module + assert "echo ${MODULE_SECTIONS[4]}" "/cvmfs/software.eessi.io/versions/$EESSI_VERSION/init/modules" + # Test 4: Load Python module and check version + command="$shell -c 'source init/lmod/$shell 2>/dev/null; module load Python/3.10.8-GCCcore-12.2.0; python --version'" + expected="Python 3.10.8" + assert "$command" "$expected" + # Test 5: Load Python module and check path + PYTHON_PATH=$($shell -c "source init/lmod/$shell 2>/dev/null; module load Python/3.10.8-GCCcore-12.2.0; which python") + PATTERN="/cvmfs/software\.eessi\.io/versions/$EESSI_VERSION/software/linux/x86_64/(intel/haswell|amd/zen3)/software/Python/3\.10\.8-GCCcore-12\.2\.0/bin/python" + echo "$PYTHON_PATH" | grep -E "$PATTERN" + assert_raises 'echo "$PYTHON_PATH" | grep -E "$PATTERN"' + + #End Test Suite + assert_end "source_eessi_$shell" + fi +done + + +# RESET PAGER +export LMOD_PAGER= diff --git a/.github/workflows/test-software.eessi.io.yml b/.github/workflows/test-software.eessi.io.yml new file mode 100644 index 0000000000..b8104a543f --- /dev/null +++ b/.github/workflows/test-software.eessi.io.yml @@ -0,0 +1,116 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +name: Check for missing software installations in software.eessi.io +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: + workflow_dispatch: +permissions: + contents: read # to fetch code (actions/checkout) +env: + EESSI_ACCELERATOR_TARGETS: | + x86_64/amd/zen2: + - nvidia/cc80 + x86_64/amd/zen3: + - nvidia/cc80 +jobs: + check_missing: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + EESSI_VERSION: + - 2023.06 + EESSI_SOFTWARE_SUBDIR_OVERRIDE: + - aarch64/generic + - aarch64/neoverse_n1 + - aarch64/neoverse_v1 + - x86_64/amd/zen2 + - x86_64/amd/zen3 + - x86_64/amd/zen4 + - x86_64/intel/haswell + - x86_64/intel/skylake_avx512 + - x86_64/generic + steps: + - name: Check out software-layer repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Mount EESSI CernVM-FS pilot repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + + - name: Test check_missing_installations.sh script + run: | + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}} + source /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/init/bash + # set $EESSI_CPU_FAMILY to the CPU architecture that corresponds to $EESSI_SOFTWARE_SUBDIR_OVERRIDE (part before the first slash), + # to prevent issues with checks in the Easybuild configuration that use this variable + export EESSI_CPU_FAMILY=${EESSI_SOFTWARE_SUBDIR_OVERRIDE%%/*} + module load EasyBuild + which eb + eb --version + export EESSI_PREFIX=/cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}} + export EESSI_OS_TYPE=linux + env | grep ^EESSI | sort + + # first check the CPU-only builds for this CPU target + echo "just run check_missing_installations.sh (should use easystacks/software.eessi.io/${{matrix.EESSI_VERSION}}/eessi-${{matrix.EESSI_VERSION}}-*.yml with latest EasyBuild release)" + for easystack_file in $(EESSI_VERSION=${{matrix.EESSI_VERSION}} .github/workflows/scripts/only_latest_easystacks.sh); do + echo "check missing installations for ${easystack_file}..." + ./check_missing_installations.sh ${easystack_file} + ec=$? + if [[ ${ec} -ne 0 ]]; then echo "missing installations found for ${easystack_file}!" >&2; exit ${ec}; fi + done + + # now check the accelerator builds for this CPU target + accelerators=$(echo "${EESSI_ACCELERATOR_TARGETS}" | yq ".${EESSI_SOFTWARE_SUBDIR_OVERRIDE}[]") + if [ -z ${accelerators} ]; then + echo "no accelerator targets defined for ${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" + else + for accel in ${accelerators}; do + module use ${EESSI_SOFTWARE_PATH}/accel/${accel}/modules/all + echo "checking missing installations for accelerator ${accel} using modulepath: ${MODULEPATH}" + for easystack_file in $(EESSI_VERSION=${{matrix.EESSI_VERSION}} ACCEL_EASYSTACKS=1 .github/workflows/scripts/only_latest_easystacks.sh); do + echo "check missing installations for ${easystack_file}..." + ./check_missing_installations.sh ${easystack_file} + ec=$? + if [[ ${ec} -ne 0 ]]; then echo "missing installations found for ${easystack_file}!" >&2; exit ${ec}; fi + done + module unuse ${EESSI_SOFTWARE_PATH}/accel/${accel}/modules/all + done + fi + + - name: Test check_missing_installations.sh with missing package (GCC/8.3.0) + run: | + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}} + source /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/init/bash + # set $EESSI_CPU_FAMILY to the CPU architecture that corresponds to $EESSI_SOFTWARE_SUBDIR_OVERRIDE (part before the first slash), + # to prevent issues with checks in the Easybuild configuration that use this variable + export EESSI_CPU_FAMILY=${EESSI_SOFTWARE_SUBDIR_OVERRIDE%%/*} + module load EasyBuild + which eb + eb --version + export EESSI_PREFIX=/cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}} + export EESSI_OS_TYPE=linux + env | grep ^EESSI | sort + # create dummy easystack file with a single entry (something that is not installed in EESSI) + easystack_file="test.yml" + echo "easyconfigs:" > ${easystack_file} + echo " - GCC-8.3.0:" >> ${easystack_file} + echo "created easystack file '${easystack_file}' with a missing installation (GCC/8.3.0):" + cat ${easystack_file} + # note, check_missing_installations.sh exits 1 if a package was + # missing, which is intepreted as false (exit code based, not + # boolean logic), hence when the script exits 0 if no package was + # missing it is interpreted as true, thus the test did not capture + # the missing package + if ./check_missing_installations.sh ${easystack_file}; then + echo "did NOT capture missing package; test FAILED" + exit 1 + else + echo "captured missing package; test PASSED" + exit 0 + fi diff --git a/.github/workflows/test_eessi.yml b/.github/workflows/test_eessi.yml deleted file mode 100644 index 04195dd619..0000000000 --- a/.github/workflows/test_eessi.yml +++ /dev/null @@ -1,72 +0,0 @@ -# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions -name: Tests relying on having EESSI pilot repo mounted -on: [push, pull_request, workflow_dispatch] -permissions: - contents: read # to fetch code (actions/checkout) -jobs: - eessi_pilot_repo: - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - EESSI_VERSION: - - 2021.12 - EESSI_SOFTWARE_SUBDIR: - - aarch64/generic - - aarch64/graviton2 - - aarch64/graviton3 - - x86_64/amd/zen2 - - x86_64/amd/zen3 - - x86_64/intel/haswell - - x86_64/intel/skylake_avx512 - - x86_64/generic - steps: - - name: Check out software-layer repository - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - - - name: Mount EESSI CernVM-FS pilot repository - uses: cvmfs-contrib/github-action-cvmfs@d4641d0d591c9a5c3be23835ced2fb648b44c04b # v3.1 - with: - cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb - cvmfs_http_proxy: DIRECT - cvmfs_repositories: pilot.eessi-hpc.org - - - name: Test check_missing_installations.sh script - run: | - source /cvmfs/pilot.eessi-hpc.org/versions/${{matrix.EESSI_VERSION}}/init/bash - module load EasyBuild - eb --version - export EESSI_PREFIX=/cvmfs/pilot.eessi-hpc.org/versions/${{matrix.EESSI_VERSION}} - export EESSI_OS_TYPE=linux - export EESSI_SOFTWARE_SUBDIR=${{matrix.EESSI_SOFTWARE_SUBDIR}} - env | grep ^EESSI | sort - echo "just run check_missing_installations.sh (should use eessi-${{matrix.EESSI_VERSION}}.yml)" - ./check_missing_installations.sh - - - name: Test check_missing_installations.sh with missing package (GCC/8.3.0) - run: | - source /cvmfs/pilot.eessi-hpc.org/versions/${{matrix.EESSI_VERSION}}/init/bash - module load EasyBuild - eb --version - export EESSI_PREFIX=/cvmfs/pilot.eessi-hpc.org/versions/${{matrix.EESSI_VERSION}} - export EESSI_OS_TYPE=linux - export EESSI_SOFTWARE_SUBDIR=${{matrix.EESSI_SOFTWARE_SUBDIR}} - env | grep ^EESSI | sort - echo "modify eessi-${{matrix.EESSI_VERSION}}.yml by adding a missing package (GCC/8.3.0)" - echo " GCC:" >> eessi-${{matrix.EESSI_VERSION}}.yml - echo " toolchains:" >> eessi-${{matrix.EESSI_VERSION}}.yml - echo " SYSTEM:" >> eessi-${{matrix.EESSI_VERSION}}.yml - echo " versions: '8.3.0'" >> eessi-${{matrix.EESSI_VERSION}}.yml - tail -n 4 eessi-${{matrix.EESSI_VERSION}}.yml - # note, check_missing_installations.sh exits 1 if a package was - # missing, which is intepreted as false (exit code based, not - # boolean logic), hence when the script exits 0 if no package was - # missing it is interpreted as true, thus the test did not capture - # the missing package - if ./check_missing_installations.sh; then - echo "did NOT capture missing package; test FAILED" - exit 1 - else - echo "captured missing package; test PASSED" - exit 0 - fi diff --git a/.github/workflows/test_eessi_container_script.yml b/.github/workflows/test_eessi_container_script.yml index 929fb22cec..6f7055a546 100644 --- a/.github/workflows/test_eessi_container_script.yml +++ b/.github/workflows/test_eessi_container_script.yml @@ -1,11 +1,15 @@ # documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions name: Tests for eessi_container.sh script -on: [push, pull_request, workflow_dispatch] +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: + workflow_dispatch: permissions: contents: read # to fetch code (actions/checkout) jobs: eessi_container_script: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -22,7 +26,7 @@ jobs: #- save steps: - name: Check out software-layer repository - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: install Apptainer run: | @@ -45,7 +49,8 @@ jobs: elif [[ ${{matrix.SCRIPT_TEST}} == 'listrepos_default' ]]; then outfile=out_listrepos.txt ./eessi_container.sh --verbose --list-repos | tee ${outfile} - grep "EESSI-pilot" ${outfile} + # make sure that the default EESSI software repository is available + grep "software.eessi.io" ${outfile} # test use of --list-repos with custom repos.cfg elif [[ ${{matrix.SCRIPT_TEST}} == 'listrepos_custom' ]]; then @@ -57,11 +62,12 @@ jobs: echo "[EESSI/20HT.TP]" >> cfg/repos.cfg echo "repo_version = 20HT.TP" >> cfg/repos.cfg ./eessi_container.sh --verbose --list-repos | tee ${outfile} - grep "EESSI-pilot" ${outfile} + # make sure that the default EESSI software repository is available + grep "software.eessi.io" ${outfile} export EESSI_REPOS_CFG_DIR_OVERRIDE=${PWD}/cfg ./eessi_container.sh --verbose --list-repos | tee ${outfile2} - grep "[EESSI/2023.02]" ${outfile2} + grep "EESSI/20AB.CD" ${outfile2} # test use of --mode run elif [[ ${{matrix.SCRIPT_TEST}} == 'run' ]]; then @@ -90,15 +96,15 @@ jobs: elif [[ ${{matrix.SCRIPT_TEST}} == 'readwrite' ]]; then outfile=out_readwrite.txt fn="test_${RANDOM}.txt" - echo "touch /cvmfs/pilot.eessi-hpc.org/${fn}" > test_script.sh + echo "touch /cvmfs/software.eessi.io/${fn}" > test_script.sh chmod u+x test_script.sh export SINGULARITY_BIND="$PWD:/test" ./eessi_container.sh --verbose --access rw --mode run /test/test_script.sh > ${outfile} tmpdir=$(grep "\-\-resume" ${outfile} | sed "s/.*--resume \([^']*\).*/\1/g") # note: must use '--access rw' again here, since touched file is in overlay upper dir - ./eessi_container.sh --verbose --resume ${tmpdir} --access rw --mode shell <<< "ls -l /cvmfs/pilot.eessi-hpc.org/${fn}" > ${outfile} - grep "/cvmfs/pilot.eessi-hpc.org/${fn}$" $outfile + ./eessi_container.sh --verbose --resume ${tmpdir} --access rw --mode shell <<< "ls -l /cvmfs/software.eessi.io/${fn}" > ${outfile} + grep "/cvmfs/software.eessi.io/${fn}$" $outfile # test use of --resume elif [[ ${{matrix.SCRIPT_TEST}} == 'resume' ]]; then @@ -120,12 +126,12 @@ jobs: elif [[ ${{matrix.SCRIPT_TEST}} == 'save' ]]; then outfile=out_save.txt fn="test_${RANDOM}.txt" - test_cmd="touch /cvmfs/pilot.eessi-hpc.org/${fn}" + test_cmd="touch /cvmfs/software.eessi.io/${fn}" ./eessi_container.sh --verbose --mode shell --access rw --save test-save.tar <<< "${test_cmd}" 2>&1 | tee ${outfile} rm -f ${outfile} - ./eessi_container.sh --verbose --mode shell --access rw --resume test-save.tar <<< "ls -l /cvmfs/pilot.eessi-hpc.org/${fn}" > ${outfile} - grep "/cvmfs/pilot.eessi-hpc.org/${fn}$" $outfile + ./eessi_container.sh --verbose --mode shell --access rw --resume test-save.tar <<< "ls -l /cvmfs/software.eessi.io/${fn}" > ${outfile} + grep "/cvmfs/software.eessi.io/${fn}$" $outfile tar tfv test-save.tar | grep "overlay-upper/${fn}" diff --git a/.github/workflows/test_licenses.yml b/.github/workflows/test_licenses.yml new file mode 100644 index 0000000000..1770d8719a --- /dev/null +++ b/.github/workflows/test_licenses.yml @@ -0,0 +1,23 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +name: Test software licenses +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: set up Python + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 + with: + python-version: '3.9' + + - name: Check software licenses + run: | + python licenses/spdx.py licenses/licenses.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cc00685a40..ecfa9a7ba5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,28 +1,31 @@ # documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions name: Tests -on: [push, pull_request] +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: permissions: contents: read # to fetch code (actions/checkout) jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: - python: [3.6, 3.7, 3.8, 3.9, '3.10'] + python: [3.8, 3.9, '3.10'] fail-fast: false steps: - name: checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: set up Python - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # v4.3.0 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: python-version: ${{matrix.python}} architecture: x64 - name: install Python packages run: | - pip install archspec + pip install archspec==0.2.2 - name: test eessi_software_subdir.py script run: | diff --git a/.github/workflows/tests_archdetect.yml b/.github/workflows/tests_archdetect.yml index 37338693c5..82438d8e92 100644 --- a/.github/workflows/tests_archdetect.yml +++ b/.github/workflows/tests_archdetect.yml @@ -1,11 +1,14 @@ # documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions name: Tests for eessi_archdetect.sh -on: [push, pull_request] +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: permissions: contents: read # to fetch code (actions/checkout) jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: proc_cpuinfo: @@ -13,37 +16,62 @@ jobs: - x86_64/intel/skylake_avx512/archspec-linux-6132 - x86_64/amd/zen2/Azure-CentOS7-7V12 - x86_64/amd/zen3/Azure-CentOS7-7V73X - - ppc64le/power9le/unknown-power9le + - x86_64/amd/zen4/Azure-Alma8-9V33X + - x86_64/amd/zen4/Shinx-RHEL8-9654 + - aarch64/a64fx/Deucalion-Rocky85 - aarch64/neoverse_n1/Azure-Ubuntu20-Altra - aarch64/neoverse_n1/AWS-awslinux-graviton2 - aarch64/neoverse_v1/AWS-awslinux-graviton3 + # commented out since these targets are currently not supported in software.eessi.io repo + # (and some tests assume that the corresponding subdirectory in software layer is there) + # - ppc64le/power9le/unknown-power9le fail-fast: false steps: - name: checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - - name: Enable EESSI - uses: eessi/github-action-eessi@58b50fd2eead2162c2b9ac258d4fb60cc9f30503 # v2.0.13 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Mount EESSI CernVM-FS pilot repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + - name: test eessi_archdetect.sh run: | export EESSI_MACHINE_TYPE=${{matrix.proc_cpuinfo}} export EESSI_MACHINE_TYPE=${EESSI_MACHINE_TYPE%%/*} export EESSI_PROC_CPUINFO=./tests/archdetect/${{matrix.proc_cpuinfo}}.cpuinfo + # check that printing of best match works correctly CPU_ARCH=$(./init/eessi_archdetect.sh cpupath) if [[ $CPU_ARCH == "$( cat ./tests/archdetect/${{matrix.proc_cpuinfo}}.output )" ]]; then - echo "Test for ${{matrix.proc_cpuinfo}} PASSED: $CPU_ARCH" >&2 + echo "Test for ${{matrix.proc_cpuinfo}} PASSED: $CPU_ARCH" else echo "Test for ${{matrix.proc_cpuinfo}} FAILED: $CPU_ARCH" >&2 exit 1 fi + # check that $EESSI_SOFTWARE_SUBDIR_OVERRIDE is honored + export EESSI_SOFTWARE_SUBDIR_OVERRIDE='dummy/cpu' + CPU_ARCH=$(./init/eessi_archdetect.sh cpupath) + if [[ $CPU_ARCH == "${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" ]]; then + echo "Test for picking up on \$EESSI_SOFTWARE_SUBDIR_OVERRIDE PASSED" + else + echo "Test for picking up on \$EESSI_SOFTWARE_SUBDIR_OVERRIDE FAILED" >&2 + exit 1 + fi + unset EESSI_SOFTWARE_SUBDIR_OVERRIDE + # check that printing of all matches works correctly (-a option for cpupath action) CPU_ARCHES=$(./init/eessi_archdetect.sh -a cpupath) if [[ $CPU_ARCHES == "$( cat ./tests/archdetect/${{matrix.proc_cpuinfo}}.all.output )" ]]; then - echo "Test for ${{matrix.proc_cpuinfo}} PASSED: $CPU_ARCHES" >&2 + echo "Test for ${{matrix.proc_cpuinfo}} PASSED: $CPU_ARCHES" else echo "Test for ${{matrix.proc_cpuinfo}} FAILED: $CPU_ARCHES" >&2 exit 1 fi - # Check all those architectures actually exist - for dir in $(echo "$CPU_ARCHES" | tr ':' '\n'); do - # Search all EESSI versions as we may drop support at some point - ls -d "$EESSI_PREFIX"/../*/software/linux/"$dir" - done + # Check all those architectures actually exist (if this EESSI version has been populated already) + if [ -d ${EESSI_PREFIX}/software/linux ]; then + for dir in $(echo "$CPU_ARCHES" | tr ':' '\n'); do + # Search all EESSI versions as we may drop support at some point + ls -d ${EESSI_PREFIX}/software/linux/${dir} + done + fi diff --git a/.github/workflows/tests_archdetect_nvidia_gpu.yml b/.github/workflows/tests_archdetect_nvidia_gpu.yml new file mode 100644 index 0000000000..54827eccad --- /dev/null +++ b/.github/workflows/tests_archdetect_nvidia_gpu.yml @@ -0,0 +1,124 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +name: Tests for accelerator detection (NVIDIA GPU) +on: + push: + pull_request: +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + build: + runs-on: ubuntu-24.04 + strategy: + matrix: + fake_nvidia_smi_script: + - none # no nvidia-smi command + - no_devices # nvidia-smi command works, but no GPUs available + - 1xa100 # cc80, supported with (atleast) zen2 CPU + - 2xa100 # cc80, supported with (atleast) zen2 CPU + - 4xa100 # cc80, supported with (atleast) zen2 CPU + - cc01 # non-existing GPU + fail-fast: false + steps: + - name: checkout + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + # we deliberately do not use the eessi/github-action-eessi action, + # because we want to control when the EESSI environment is initialized + - name: Mount EESSI CernVM-FS repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + + - name: test accelerator detection + run: | + export EESSI_SOFTWARE_SUBDIR_OVERRIDE='x86_64/amd/zen2' + + # put fake nvidia-smi command in place (unless we don't want to) + if [[ "${{matrix.fake_nvidia_smi_script}}" != "none" ]]; then + tmpdir=$(mktemp -d) + ln -s $PWD/tests/archdetect/nvidia-smi/${{matrix.fake_nvidia_smi_script}}.sh $tmpdir/nvidia-smi + export PATH=$tmpdir:$PATH + fi + + # first run with debugging enabled, just to show the output + ./init/eessi_archdetect.sh -d accelpath || echo "non-zero exit code: $?" + + # verify output (or exit code if non-zero) + out=$(./init/eessi_archdetect.sh accelpath || echo "non-zero exit code: $?") + + if [[ $out == "$( cat ./tests/archdetect/nvidia-smi/${{matrix.fake_nvidia_smi_script}}.output )" ]]; then + + echo "Test for '${{matrix.fake_nvidia_smi_script}}' PASSED: '$out'" + + # run full EESSI init script, which pick up on the accelerator (if available) + echo + . init/bash 2>&1 | tee init.out + echo "-----------------------------------------------------------------------------" + + if [[ "${{matrix.fake_nvidia_smi_script}}" == "none" ]] || [[ "${{matrix.fake_nvidia_smi_script}}" == "no_devices" ]]; then + + pattern="archdetect could not detect any accelerators" + echo ">>> checking for pattern '${pattern}' in init output..." + grep "${pattern}" init.out || (echo "FAILED 1" || exit 1) + + pattern="archdetect found supported accelerator" + echo ">>> checking for lack of pattern '${pattern}' in init output..." + match=$(grep "${pattern}" init.out || true) + test "x${match}" = "x" || (echo "unexpected match found for '${pattern}' in init output" && exit 1) + + pattern="Prepending /cvmfs/software.eessi.io/versions/2023.06/software/linux/.*/accel/.*/modules/all to \$MODULEPATH" + echo ">>> checking for lack of pattern '${pattern}' in init output..." + match=$(grep "${pattern}" init.out || true) + test "x${match}" = "x" || (echo "unexpected match found for '${pattern}' in init output" && exit 1) + + elif [[ "${{matrix.fake_nvidia_smi_script}}" == "cc01" ]]; then + + pattern="No matching path found in x86_64/amd/zen2 for accelerator detected by archdetect (accel/nvidia/cc01)" + echo ">>> checking for pattern '${pattern}' in init output..." + grep "${pattern}" init.out || (echo "FAILED 1" || exit 1) + + pattern="Prepending /cvmfs/software.eessi.io/versions/2023.06/software/linux/.*/accel/.*/modules/all to \$MODULEPATH" + echo ">>> checking for lack of pattern '${pattern}' in init output..." + match=$(grep "${pattern}" init.out || true) + test "x${match}" = "x" || (echo "unexpected match found for '${pattern}' in init output" && exit 1) + + else + echo ">>> checking for 'accel/nvidia/cc80' in init output..." + grep "archdetect found supported accelerator for CPU target x86_64/amd/zen2: accel/nvidia/cc80" init.out || (echo "FAILED 2" && exit 1) + grep "Prepending /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen2/accel/nvidia/cc80/modules/all to \$MODULEPATH" init.out || (echo "FAILED 3" && exit 1) + fi + + echo ">>> checking last line of init output..." + tail -1 init.out | grep "Environment set up to use EESSI (2023.06), have fun!" || (echo "FAILED, full init utput:" && cat init.out && exit 1) + + echo "All checks on init output PASSED" + else + echo "Test for '${{matrix.fake_nvidia_smi_script}}' FAILED: '$out'" >&2 + exit 1 + fi + + - name: test accelerator detection under $EESSI_ACCEL_SOFTWARE_SUBDIR_OVERRIDE + $EESSI_ACCELERATOR_TARGET_OVERRIDE + run: | + export EESSI_SOFTWARE_SUBDIR_OVERRIDE='x86_64/amd/zen2' + export EESSI_ACCEL_SOFTWARE_SUBDIR_OVERRIDE='x86_64/amd/zen3' + export EESSI_ACCELERATOR_TARGET_OVERRIDE='accel/nvidia/cc80' + + # first run with debugging enabled, just to show the output + ./init/eessi_archdetect.sh -d accelpath || echo "non-zero exit code: $?" + + # verify output (or exit code if non-zero) + out=$(./init/eessi_archdetect.sh accelpath || echo "non-zero exit code: $?") + + echo + . init/bash 2>&1 | tee init.out + echo "-----------------------------------------------------------------------------" + + echo ">>> checking for 'accel/nvidia/cc80' in init output..." + grep "archdetect found supported accelerator for CPU target x86_64/amd/zen3: accel/nvidia/cc80" init.out || (echo "FAILED 1" && exit 1) + grep "Using x86_64/amd/zen2 as software subdirectory" init.out || (echo "FAILED 2" && exit 1) + grep "Prepending /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen2/modules/all to \$MODULEPATH" init.out || (echo "FAILED 3" && exit 1) + grep "Prepending /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen3/accel/nvidia/cc80/modules/all to \$MODULEPATH" init.out || (echo "FAILED 4" && exit 1) + + echo "All checks on init output PASSED" diff --git a/.github/workflows/tests_eessi_module.yml b/.github/workflows/tests_eessi_module.yml new file mode 100644 index 0000000000..a7b38e2205 --- /dev/null +++ b/.github/workflows/tests_eessi_module.yml @@ -0,0 +1,207 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +name: Tests for eessi_module_functionality in software.eessi.io +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + basic_checks: + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + EESSI_VERSION: + - 2023.06 + steps: + - name: Check out software-layer repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Mount EESSI CernVM-FS pilot repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + + - name: Test for making sure spider cache is being used and not being rebuilt + run: | + . /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash # Initialise Lmod + export MODULEPATH=init/modules + configfile="configfile.txt" + module -T load EESSI/${{matrix.EESSI_VERSION}} + module --config > "${configfile}" 2>&1 + grep cache "${configfile}" | grep software | grep -v compat + if timeout 10s bash -c "LMOD_PAGER=none module --terse avail" && grep cache "${configfile}" | grep software | grep -v compat; then + echo "EESSI spider cache is being used" + else + echo "EESSI spider cache is being rebuilt" >&2 + exit 1 + fi + env | grep LMOD + module purge + unset MODULEPATH + + - name: Test for archdetect_cpu functionality with invalid path + run: | + # Initialise Lmod + . /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash + export MODULEPATH=init/modules + set +e # Do not exit immediately if a command exits with a non-zero status + export EESSI_ARCHDETECT_OPTIONS_OVERRIDE="dummy/cpu" + outfile="outfile.txt" + module load EESSI/${{matrix.EESSI_VERSION}} > "${outfile}" 2>&1 + cat "${outfile}" + if grep -q "Software directory check" "${outfile}"; then + echo "Test for picking up invalid path on \${archdetect_cpu} PASSED" + else + echo "Test for picking up invalid path on \${archdetect_cpu} FAILED" >&2 + exit 1 + fi + unset EESSI_ARCHDETECT_OPTIONS_OVERRIDE + set -e # Re-enable exit on non-zero status + + lmod_and_init_script_comparison: + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + EESSI_VERSION: + - 2023.06 + EESSI_SOFTWARE_SUBDIR_OVERRIDE: + - x86_64/amd/zen3 + - x86_64/amd/zen4 + EESSI_ACCELERATOR_TARGET_OVERRIDE: + - accel/nvidia/cc80 + steps: + - name: Check out software-layer repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Mount EESSI CernVM-FS pilot repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + + - name: Test for expected variables match between Lmod init script and original bash script + run: | + # Initialise Lmod + . /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash + + # Set our path overrides according to our matrix + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}} + export EESSI_ACCELERATOR_TARGET_OVERRIDE=${{matrix.EESSI_ACCELERATOR_TARGET_OVERRIDE}} + + moduleoutfile="moduleout.txt" + sourceoutfile="sourceout.txt" + + # First do (and undo) the Lmod initialisation + export MODULEPATH=init/modules + # Turn on debug output in case we want to take a look + export EESSI_DEBUG_INIT=true + CPU_ARCH=$(./init/eessi_archdetect.sh -a cpupath) + export EESSI_ARCHDETECT_OPTIONS_OVERRIDE="dummy/cpu:${CPU_ARCH}:dummy1/cpu1" + module load EESSI/${{matrix.EESSI_VERSION}} + # EESSI_ARCHDETECT_OPTIONS_OVERRIDE/EESSI_DEBUG_INIT only relevant for Lmod init + unset EESSI_ARCHDETECT_OPTIONS_OVERRIDE + unset EESSI_DEBUG_INIT + # Store all relevant environment variables + env | grep -E '(^EESSI_|^LMOD_RC|^LMOD_PACKAGE_PATH)' | sort > "${moduleoutfile}" + module unload EESSI/${{matrix.EESSI_VERSION}} + + # Now do the init script initialisation + source ./init/bash + # source script version sets environment variables to force archdetect, ignore these + unset EESSI_USE_ARCHSPEC + unset EESSI_USE_ARCHDETECT + env | grep -E '(^EESSI_|^LMOD_RC|^LMOD_PACKAGE_PATH)' | sort > "${sourceoutfile}" + + # Now compare the two results + echo "" + echo "Lmod initialisation:" + cat "${moduleoutfile}" + echo "" + echo "Source script initialisation:" + cat "${sourceoutfile}" + echo "" + echo "" + if (diff "${moduleoutfile}" "${sourceoutfile}" > /dev/null); then + echo "Test for checking env variables PASSED" + else + echo "Test for checking env variables FAILED" >&2 + diff --unified=0 "${moduleoutfile}" "${sourceoutfile}" + exit 1 + fi + + make_sure_load_and_unload_work: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + EESSI_VERSION: + - 2023.06 + EESSI_SOFTWARE_SUBDIR_OVERRIDE: + - none + - x86_64/amd/zen2 + - x86_64/amd/zen4 + EESSI_ACCELERATOR_TARGET_OVERRIDE: + - none + - accel/nvidia/cc80 + steps: + - name: Check out software-layer repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Mount EESSI CernVM-FS pilot repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + + - name: Test for identical environment after loading and unloading the EESSI module + run: | + # Initialise Lmod + . /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash + + # Set our cpu path overrides according to our matrix + if [[ "${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}}" != "none" ]]; then + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}} + fi + + # Set our accelerator path overrides according to our matrix + if [[ "${{matrix.EESSI_ACCELERATOR_TARGET_OVERRIDE}}" != "none" ]]; then + export EESSI_ACCELERATOR_TARGET_OVERRIDE=${{matrix.EESSI_ACCELERATOR_TARGET_OVERRIDE}} + fi + + # Turn on debug output in case we want to take a look + export EESSI_DEBUG_INIT=true + + initial_env_file="initial_env.txt" + module_cycled_file="load_unload_cycle.txt" + + # prepare Lmod, resetting it in a roundabout given we don't want defaults set + export MODULEPATH=init/modules:.github/workflows/modules + module load fake_module + module purge + module unuse .github/workflows/modules + module avail + + # Store the initial environment (ignoring Lmod tables) + env | grep -v _ModuleTable | sort > "${initial_env_file}" + + # Do (and undo) loading the EESSI module + CPU_ARCH=$(./init/eessi_archdetect.sh -a cpupath) + module load EESSI/${{matrix.EESSI_VERSION}} + module unload EESSI/${{matrix.EESSI_VERSION}} + env | grep -v _ModuleTable | sort > "${module_cycled_file}" + + # Now compare the two results (do not expose the files, as they contain the full environment!) + if (diff "${initial_env_file}" "${module_cycled_file}" > /dev/null); then + echo "Test for checking env variables PASSED" + else + echo "Test for checking env variables FAILED" >&2 + diff --unified=0 "${initial_env_file}" "${module_cycled_file}" + exit 1 + fi diff --git a/.github/workflows/tests_init.yml b/.github/workflows/tests_init.yml index 417b7851f1..9ab373eec0 100644 --- a/.github/workflows/tests_init.yml +++ b/.github/workflows/tests_init.yml @@ -1,28 +1,31 @@ # documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions name: Tests for init scripts -on: [push, pull_request] +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: permissions: contents: read # to fetch code (actions/checkout) jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: - python: [3.6, 3.7, 3.8, 3.9, '3.10'] + python: [3.8, 3.9, '3.10'] fail-fast: false steps: - name: checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: set up Python - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # v4.3.0 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: python-version: ${{matrix.python}} architecture: x64 - name: install Python packages run: | - pip install archspec pytest + pip install archspec==0.2.2 pytest - name: unit tests for eessi_software_subdir_for_host.py script run: diff --git a/.github/workflows/tests_init_module.yml b/.github/workflows/tests_init_module.yml new file mode 100644 index 0000000000..d30da61c84 --- /dev/null +++ b/.github/workflows/tests_init_module.yml @@ -0,0 +1,43 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +name: Check for EESSI init shell scripts to load eessi software module in software.eessi.io +on: + push: + branches: [ "*-software.eessi.io" ] + pull_request: + workflow_dispatch: +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + build: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + EESSI_VERSION: + - 2023.06 + EESSI_SOFTWARE_SUBDIR_OVERRIDE: + - x86_64/intel/haswell + steps: + - name: Check out software-layer repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Mount EESSI CernVM-FS pilot repository + uses: cvmfs-contrib/github-action-cvmfs@55899ca74cf78ab874bdf47f5a804e47c198743c # v4.0 + with: + cvmfs_config_package: https://github.com/EESSI/filesystem-layer/releases/download/latest/cvmfs-config-eessi_latest_all.deb + cvmfs_http_proxy: DIRECT + cvmfs_repositories: software.eessi.io + + - name: Clone assert.sh script + run: git clone https://github.com/lehmannro/assert.sh.git + + - name: Install missing shells + run: | + sudo apt update + sudo apt install zsh ksh fish + echo "# INIT ZSH" > ~/.zshrc + + - name: Run tests for available shells + run: | + .github/workflows/scripts/test_init_scripts.sh "bash" "zsh" "ksh" "fish" "csh" + diff --git a/.github/workflows/tests_readme.yml b/.github/workflows/tests_readme.yml index 5c6d0318d4..1a838e06d6 100644 --- a/.github/workflows/tests_readme.yml +++ b/.github/workflows/tests_readme.yml @@ -7,8 +7,6 @@ on: - init/eessi_defaults pull_request: - branches: - - main paths: - README.md - init/eessi_defaults @@ -16,15 +14,15 @@ permissions: contents: read # to fetch code (actions/checkout) jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Check out software-layer repository - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: verify if README.md is consistent with EESSI_PILOT_VERSION from init/eessi_defaults + - name: verify if README.md is consistent with EESSI_VERSION from init/eessi_defaults run: | source init/eessi_defaults - grep "${EESSI_PILOT_VERSION}" README.md + grep "${EESSI_VERSION}" README.md - name: verify if README.md is consistent with EESSI_CVMFS_REPO from init/eessi_defaults run: | diff --git a/.github/workflows/tests_scripts.yml b/.github/workflows/tests_scripts.yml index 5c0b3893ae..de227dfc25 100644 --- a/.github/workflows/tests_scripts.yml +++ b/.github/workflows/tests_scripts.yml @@ -3,9 +3,10 @@ name: Tests for scripts on: push: paths: - - build_container.sh - create_directory_tarballs.sh - - EESSI-pilot-install-software.sh + - create_lmodsitepackage.py + - eessi_container.sh + - EESSI-install-software.sh - install_software_layer.sh - load_easybuild_module.sh - run_in_compat_layer_env.sh @@ -13,12 +14,11 @@ on: - update_lmod_cache.sh pull_request: - branches: - - main paths: - - build_container.sh - create_directory_tarballs.sh - - EESSI-pilot-install-software.sh + - create_lmodsitepackage.py + - eessi_container.sh + - EESSI-install-software.sh - install_software_layer.sh - load_easybuild_module.sh - run_in_compat_layer_env.sh @@ -28,10 +28,10 @@ permissions: contents: read # to fetch code (actions/checkout) jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: install Apptainer run: | @@ -42,7 +42,10 @@ jobs: # bind current directory into container as /software-layer export SINGULARITY_BIND="${PWD}:/software-layer" - for EB_VERSION in '4.5.0' '4.5.1' '4.7.2'; do + # 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 # 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; @@ -78,20 +81,41 @@ jobs: - name: test install_software_layer.sh script run: | - # scripts need to be copied to /tmp, - # since install_software_layer.sh must be accessible from within build container - cp -a * /tmp/ - cd /tmp + # bind current directory into container as /software-layer + export SINGULARITY_BIND="${PWD}:/software-layer" # force using x86_64/generic, to avoid triggering an installation from scratch - sed -i "s@./EESSI-pilot-install-software.sh@\"export EESSI_SOFTWARE_SUBDIR_OVERRIDE='x86_64/generic'; ./EESSI-pilot-install-software.sh\"@g" install_software_layer.sh - ./build_container.sh run /tmp/$USER/EESSI /tmp/install_software_layer.sh + sed -i "s@./EESSI-install-software.sh@\"export EESSI_SOFTWARE_SUBDIR_OVERRIDE='x86_64/generic'; ./EESSI-install-software.sh\"@g" install_software_layer.sh + # skip installation of CUDA SDKs, since this is too heavy for CI + sed -i "s@./EESSI-install-software.sh@./EESSI-install-software.sh --skip-cuda-install@g" install_software_layer.sh + ./eessi_container.sh --mode run --verbose /software-layer/install_software_layer.sh - name: test create_directory_tarballs.sh script run: | + # bind current directory into container as /software-layer + export SINGULARITY_BIND="${PWD}:/software-layer" # scripts need to be copied to /tmp, # since create_directory_tarballs.sh must be accessible from within build container - cp -a * /tmp/ - cd /tmp - ./build_container.sh run /tmp/$USER/EESSI /tmp/create_directory_tarballs.sh 2021.12 + ./eessi_container.sh --mode run --verbose /software-layer/create_directory_tarballs.sh 2023.06 # check if tarballs have been produced ls -l *.tar.gz + + - name: test create_lmodsitepackage.py script + run: | + # bind current directory into container as /software-layer + export SINGULARITY_BIND="${PWD}:/software-layer" + + # Creates .lmod/SitePackage.lua in current dir, which then gets bind-mounted into /software-layer + python3 create_lmodsitepackage.py . + # run some commands to make sure that generated Lmod SitePackage file works + test_script="${PWD}/test_lmod_sitepackage.sh" + echo '#!/bin/bash' > ${test_script} + echo 'export LMOD_PACKAGE_PATH="/software-layer/.lmod"' > ${test_script} + echo 'ml --config' >> ${test_script} + + chmod u+x ${test_script} + + out="${PWD}/test_create_lmodsitepackage.out" + ./eessi_container.sh --mode run --verbose /software-layer/run_in_compat_layer_env.sh /software-layer/test_lmod_sitepackage.sh 2>&1 | tee ${out} + for pattern in "^Site Pkg location.*/software-layer/.lmod/SitePackage.lua" "LMOD_SITEPACKAGE_LOCATION.*/software-layer/.lmod/SitePackage.lua"; do + grep "${pattern}" ${out} || (echo "Pattern '${pattern}' not found in output!" && exit 1) + done diff --git a/EESSI-extend-easybuild.eb b/EESSI-extend-easybuild.eb new file mode 100644 index 0000000000..f74f36aca7 --- /dev/null +++ b/EESSI-extend-easybuild.eb @@ -0,0 +1,189 @@ +easyblock = 'Bundle' + +name = 'EESSI-extend' +import os +version = os.getenv('EESSI_VERSION', '2023.06') +# May have different ways to extend EESSI in future (manually, other tools,...) +versionsuffix = '-easybuild' + +homepage = 'https://eessi.io/docs/' + +description = """ + The goal of the European Environment for Scientific Software Installations + (EESSI, pronounced as "easy") is to build a common stack of scientific + software installations for HPC systems and beyond, including laptops, + personal workstations and cloud infrastructure. + + This module allows you to extend EESSI using the same configuration for + EasyBuild as EESSI itself uses. A number of environment variables control the + behaviour of the module: + - EESSI_USER_INSTALL can be set to a location to install modules for use by + the user only. The location must already exist on the filesystem. + - EESSI_PROJECT_INSTALL can be set to a location to install modules for use by + a project. The location must already exist on the filesystem and you should + ensure that the location has the correct Linux group and the SGID permission + is set on that directory (`chmod g+s $EESSI_PROJECT_INSTALL`) so that all + members of the group have permission to read and write installations. + - EESSI_SITE_INSTALL is either defined or not and cannot be used with another + environment variable. A site installation is done in a defined location and + any installations there are (by default) world readable. + - EESSI_CVMFS_INSTALL is either defined or not and cannot be used with another + environment variable. A CVMFS installation targets a defined location which + will be ingested into CVMFS and is only useful for CVMFS administrators. + - If none of the environment variables above are defined, an EESSI_USER_INSTALL + is assumed with a value of $HOME/EESSI + If both EESSI_USER_INSTALL and EESSI_PROJECT_INSTALL are defined, both sets of + installations are exposed, but new installations are created as user + installations. +""" + +toolchain = SYSTEM + +# All the dependencies we filter in EESSI +local_deps_to_filter = "Autoconf,Automake,Autotools,binutils,bzip2,DBus,flex,gettext,gperf,help2man,intltool,libreadline,libtool,M4,makeinfo,ncurses,util-linux,XZ,zlib" +local_arch_specific_deps_to_filter = {'aarch64': ',Yasm', 'riscv64': ',Yasm', 'x86_64': ''} +local_deps_to_filter += local_arch_specific_deps_to_filter[ARCH] + +# Set the universal EasyBuild variables +modextravars = { + 'EASYBUILD_FILTER_DEPS': local_deps_to_filter, + 'EASYBUILD_IGNORE_OSDEPS': '1', + 'EASYBUILD_DEBUG': '1', + 'EASYBUILD_TRACE': '1', + 'EASYBUILD_ZIP_LOGS': 'bzip2', + 'EASYBUILD_RPATH': '1', + 'EASYBUILD_FILTER_ENV_VARS': 'LD_LIBRARY_PATH', + 'EASYBUILD_READ_ONLY_INSTALLDIR': '1', + 'EASYBUILD_MODULE_EXTENSIONS': '1', + 'EASYBUILD_EXPERIMENTAL': '1', +} + +# Need a few other variables, but they are more dynamic +# EASYBUILD_SYSROOT=${EPREFIX} +# EASYBUILD_PREFIX=${WORKDIR}/easybuild +# EASYBUILD_HOOKS=${EESSI_PREFIX}/init/easybuild/eb_hooks.py +# EASYBUILD_INSTALLPATH=${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR} +# EASYBUILD_SOURCEPATH=${WORKDIR}/easybuild/sources:${EESSI_SOURCEPATH} +# +# And also some optional ones based on the kind of installation +# EASYBUILD_SET_GID_BIT +# EASYBUILD_GROUP_WRITABLE_INSTALLDIR +# EASYBUILD_UMASK +# EASYBUILD_STICKY_BIT +modluafooter = """ +if (mode() == "load") then + -- Use a working directory for temporary build files + if (os.getenv("WORKING_DIR") == nil) then + LmodMessage("-- Using /tmp/$USER as a temporary working directory for installations, you can override this by setting the environment variable WORKING_DIR and reloading the module (e.g., /dev/shm is a common option)") + end +end +working_dir = os.getenv("WORKING_DIR") or pathJoin("/tmp", os.getenv("USER")) +-- Gather the EPREFIX to use as a sysroot +sysroot = os.getenv("EESSI_EPREFIX") +-- Use an installation prefix that we _should_ have write access to +if (os.getenv("EESSI_CVMFS_INSTALL") ~= nil) then + -- Make sure no other EESSI install environment variables are set + if ((os.getenv("EESSI_SITE_INSTALL") ~= nil) or (os.getenv("EESSI_PROJECT_INSTALL") ~= nil) or (os.getenv("EESSI_USER_INSTALL") ~= nil)) then + LmodError("You cannot use EESSI_CVMFS_INSTALL in combination with any other EESSI_*_INSTALL environment variables") + end + eessi_cvmfs_install = true + easybuild_installpath = os.getenv("EESSI_SOFTWARE_PATH") + eessi_accelerator_target = os.getenv("EESSI_ACCELERATOR_TARGET") + if (eessi_accelerator_target ~= nil) then + cuda_compute_capability = string.match(eessi_accelerator_target, "^nvidia/cc([0-9][0-9])$") + if (cuda_compute_capability ~= nil) then + easybuild_installpath = pathJoin(easybuild_installpath, 'accel', eessi_accelerator_target) + easybuild_cuda_compute_capabilities = cuda_compute_capability:sub(1, 1) .. "." .. cuda_compute_capability:sub(2, 2) + else + LmodError("Incorrect value for $EESSI_ACCELERATOR_TARGET: " .. eessi_accelerator_target) + end + end +elseif (os.getenv("EESSI_SITE_INSTALL") ~= nil) then + -- Make sure no other EESSI install environment variables are set + if ((os.getenv("EESSI_PROJECT_INSTALL") ~= nil) or (os.getenv("EESSI_USER_INSTALL") ~= nil)) then + LmodError("You cannot use EESSI_SITE_INSTALL in combination with any other EESSI_*_INSTALL environment variables") + end + easybuild_installpath = os.getenv("EESSI_SITE_SOFTWARE_PATH") +else + -- Deal with user and project installs + project_install = os.getenv("EESSI_PROJECT_INSTALL") + project_modulepath = nil + if (project_install ~= nil) then + -- Check the folder exists + if not isDir(project_install) then + LmodError("The location of EESSI_PROJECT_INSTALL (" .. project_install .. ") does not exist or is not a folder") + end + if (mode() == "load") then + LmodMessage("Configuring for use of EESSI_PROJECT_INSTALL under " .. project_install) + end + easybuild_installpath = string.gsub(os.getenv("EESSI_SOFTWARE_PATH"), os.getenv("EESSI_CVMFS_REPO"), project_install) + project_modulepath = pathJoin(easybuild_installpath, 'modules', 'all') + end + user_install = os.getenv("EESSI_USER_INSTALL") + user_modulepath = nil + if (user_install ~= nil) then + -- Check the folder exists + if not isDir(user_install) then + LmodError("The location of EESSI_USER_INSTALL (" .. user_install .. ") does not exist or is not a folder") + end + elseif (user_install == nil) and (project_install == nil) then + -- No need to check for existence when we use a HOME subdir + user_install = pathJoin(os.getenv("HOME"), "eessi") + end + if (user_install ~= nil) then + if (mode() == "load") then + LmodMessage("Configuring for use of EESSI_USER_INSTALL under " .. user_install) + end + easybuild_installpath = string.gsub(os.getenv("EESSI_SOFTWARE_PATH"), os.getenv("EESSI_CVMFS_REPO"), user_install) + user_modulepath = pathJoin(easybuild_installpath, 'modules', 'all') + end +end +if (mode() == "load") then + LmodMessage("-- To create installations for EESSI, you _must_ have write permissions to " .. easybuild_installpath) + -- Advise them to reuse sources + if (os.getenv("EASYBUILD_SOURCEPATH") == nil) then + LmodMessage("-- You may wish to configure a sources directory for EasyBuild (for example, via setting the environment variable EASYBUILD_SOURCEPATH) to allow you to reuse existing sources for packages.") + end +end +-- Set the relevant universal environment variables for EasyBuild +setenv ("EASYBUILD_SYSROOT", sysroot) +setenv ("EASYBUILD_PREFIX", pathJoin(working_dir, "easybuild")) +setenv ("EASYBUILD_INSTALLPATH", easybuild_installpath) +setenv ("EASYBUILD_HOOKS", pathJoin(os.getenv("EESSI_PREFIX"), "init", "easybuild", "eb_hooks.py")) + +-- Make sure to use the general umask that allows a global read +setenv ("EASYBUILD_UMASK", "022") + +-- Allow this module to be loaded when running EasyBuild +setenv ("EASYBUILD_ALLOW_LOADED_MODULES", "EasyBuild,EESSI-extend") + +-- Set environment variables if building for CUDA compute capabilities +if (easybuild_cuda_compute_capabilities ~= nil) then + setenv ("EASYBUILD_CUDA_COMPUTE_CAPABILITIES", easybuild_cuda_compute_capabilities) +end + +-- Set all related environment variables if we have project or user installations (including extending MODULEPATH) +if (user_modulepath ~= nil) then + -- Use a more restrictive umask for this case + setenv ("EASYBUILD_UMASK", "077") + setenv ("EASYBUILD_STICKY_BIT", "1") + -- configure MODULEPATH + if (project_modulepath ~= nil) then + prepend_path("MODULEPATH", project_modulepath) + end + prepend_path("MODULEPATH", user_modulepath) +elseif (project_modulepath ~= nil) then + setenv ("EASYBUILD_SET_GID_BIT", "1") + setenv ("EASYBUILD_GROUP_WRITABLE_INSTALLDIR", "1") + setenv ("EASYBUILD_STICKY_BIT", "0") + setenv ("EASYBUILD_UMASK", "002") + -- configure MODULEPATH + prepend_path("MODULEPATH", project_modulepath) +end +-- Make sure EasyBuild itself is loaded +if not ( isloaded("EasyBuild") ) then + load(latest("EasyBuild")) +end +""" + +moduleclass = 'devel' diff --git a/EESSI-install-software.sh b/EESSI-install-software.sh new file mode 100755 index 0000000000..3a9ba175c9 --- /dev/null +++ b/EESSI-install-software.sh @@ -0,0 +1,397 @@ +#!/bin/bash +# +# Script to install EESSI 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 +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash + +display_help() { + echo "usage: $0 [OPTIONS]" + echo " --build-logs-dir - location to copy EasyBuild logs to for failed builds" + echo " -g | --generic - instructs script to build for generic architecture target" + echo " -h | --help - display this usage information" + echo " -x | --http-proxy URL - provides URL for the environment variable http_proxy" + echo " -y | --https-proxy URL - provides URL for the environment variable https_proxy" + echo " --shared-fs-path - path to directory on shared filesystem that can be used" + echo " --skip-cuda-install - disable installing a full CUDA SDK in the host_injections prefix (e.g. in CI)" +} + +# Function to check if a command exists +function command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +function copy_build_log() { + # copy specified build log to specified directory, with some context added + build_log=${1} + build_logs_dir=${2} + + # also copy to build logs directory, if specified + if [ ! -z "${build_logs_dir}" ]; then + log_filename="$(basename ${build_log})" + if [ ! -z "${SLURM_JOB_ID}" ]; then + # use subdirectory for build log in context of a Slurm job + build_log_path="${build_logs_dir}/jobs/${SLURM_JOB_ID}/${log_filename}" + else + build_log_path="${build_logs_dir}/non-jobs/${log_filename}" + fi + mkdir -p $(dirname ${build_log_path}) + cp -a ${build_log} ${build_log_path} + chmod 0644 ${build_log_path} + + # add context to end of copied log file + echo >> ${build_log_path} + echo "Context from which build log was copied:" >> ${build_log_path} + echo "- original path of build log: ${build_log}" >> ${build_log_path} + echo "- working directory: ${PWD}" >> ${build_log_path} + echo "- Slurm job ID: ${SLURM_OUT}" >> ${build_log_path} + echo "- EasyBuild version: ${eb_version}" >> ${build_log_path} + echo "- easystack file: ${easystack_file}" >> ${build_log_path} + + echo "EasyBuild log file ${build_log} copied to ${build_log_path} (with context appended)" + fi +} + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -g|--generic) + EASYBUILD_OPTARCH="GENERIC" + shift + ;; + -h|--help) + display_help # Call your function + # no shifting needed here, we're done. + exit 0 + ;; + -x|--http-proxy) + export http_proxy="$2" + shift 2 + ;; + -y|--https-proxy) + export https_proxy="$2" + shift 2 + ;; + --build-logs-dir) + export build_logs_dir="${2}" + shift 2 + ;; + --shared-fs-path) + export shared_fs_path="${2}" + shift 2 + ;; + --skip-cuda-install) + export skip_cuda_install=True + shift 1 + ;; + -*|--*) + echo "Error: Unknown option: $1" >&2 + exit 1 + ;; + *) # No more options + POSITIONAL_ARGS+=("$1") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +TOPDIR=$(dirname $(realpath $0)) + +source $TOPDIR/scripts/utils.sh + +# honor $TMPDIR if it is already defined, use /tmp otherwise +if [ -z $TMPDIR ]; then + export WORKDIR=/tmp/$USER +else + export WORKDIR=$TMPDIR/$USER +fi + +TMPDIR=$(mktemp -d) + + +# Get override subdir +DETECTION_PARAMETERS='' +GENERIC=0 +EB='eb' +if [[ "$EASYBUILD_OPTARCH" == "GENERIC" ]]; then + echo_yellow ">> GENERIC build requested, taking appropriate measures!" + DETECTION_PARAMETERS="$DETECTION_PARAMETERS --generic" + GENERIC=1 + EB='eb --optarch=GENERIC' +fi + +echo ">> Determining software subdirectory to use for current build host..." +if [ -z $EESSI_SOFTWARE_SUBDIR_OVERRIDE ]; then + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(python3 $TOPDIR/eessi_software_subdir.py $DETECTION_PARAMETERS) + echo ">> Determined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE via 'eessi_software_subdir.py $DETECTION_PARAMETERS' script" +else + echo ">> Picking up pre-defined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE: ${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" + # Run in a subshell, so that minimal_eessi_env doesn't change the shell environment for the rest of this script + ( + # Make sure EESSI_PREFIX and EESSI_OS_TYPE are set + source $TOPDIR/init/minimal_eessi_env + + # make sure the the software and modules directory exist + # (since it's expected by init/eessi_environment_variables when using archdetect and by the EESSI module) + mkdir -p ${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR_OVERRIDE}/{modules,software} + ) +fi + +echo ">> Setting up environment..." + +# If EESSI_VERSION is not set, source the defaults script to set it +if [ -z ${EESSI_VERSION} ]; then + source $TOPDIR/init/eessi_defaults +fi + +# If module command does not exist, use the one from the compat layer +command -v module +module_cmd_exists=$? +if [[ "$module_cmd_exists" -ne 0 ]]; then + echo_green "No module command found, initializing lmod from the compatibility layer" + # Minimal initalization of the lmod from the compat layer + source $TOPDIR/init/lmod/bash +else + echo_green "Module command found" +fi +ml_version_out=$TMPDIR/ml.out +ml --version &> $ml_version_out +if [[ $? -eq 0 ]]; then + echo_green ">> Found Lmod ${LMOD_VERSION}" +else + fatal_error "Failed to initialize Lmod?! (see output in ${ml_version_out}" +fi + +# Make sure we start with no modules and clean $MODULEPATH +echo ">> Setting up \$MODULEPATH..." +module --force purge +module unuse $MODULEPATH + +# Initialize the EESSI environment +module use $TOPDIR/init/modules +module load EESSI/$EESSI_VERSION + +# make sure we're in Prefix environment by checking $SHELL +# We can only do this after loading the EESSI module, as we need ${EPREFIX} +if [[ ${SHELL} = ${EPREFIX}/bin/bash ]]; then + echo_green ">> It looks like we're in a Gentoo Prefix environment, good!" +else + fatal_error "Not running in Gentoo Prefix environment, run '${EPREFIX}/startprefix' first!" +fi + +if [ -d $EESSI_CVMFS_REPO ]; then + echo_green "$EESSI_CVMFS_REPO available, OK!" +else + fatal_error "$EESSI_CVMFS_REPO is not available!" +fi + +# Check that EESSI_SOFTWARE_SUBDIR now matches EESSI_SOFTWARE_SUBDIR_OVERRIDE +if [[ -z ${EESSI_SOFTWARE_SUBDIR} ]]; then + fatal_error "Failed to determine software subdirectory?!" +elif [[ "${EESSI_SOFTWARE_SUBDIR}" != "${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" ]]; then + fatal_error "Values for EESSI_SOFTWARE_SUBDIR_OVERRIDE (${EESSI_SOFTWARE_SUBDIR_OVERRIDE}) and EESSI_SOFTWARE_SUBDIR (${EESSI_SOFTWARE_SUBDIR}) differ!" +else + echo_green ">> Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory!" +fi + +# avoid that pyc files for EasyBuild are stored in EasyBuild installation directory +export PYTHONPYCACHEPREFIX=$TMPDIR/pycache + +# if we run the script for the first time, e.g., to start building for a new +# stack, we need to ensure certain files are present in +# ${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR_OVERRIDE} +# - .lmod/lmodrc.lua +# - .lmod/SitePackage.lua +_eessi_software_path=${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR_OVERRIDE} +_lmod_cfg_dir=${_eessi_software_path}/.lmod +_lmod_rc_file=${_lmod_cfg_dir}/lmodrc.lua +if [ ! -f ${_lmod_rc_file} ]; then + echo "Lmod file '${_lmod_rc_file}' does not exist yet; creating it..." + command -V python3 + python3 ${TOPDIR}/create_lmodrc.py ${_eessi_software_path} +fi +_lmod_sitepackage_file=${_lmod_cfg_dir}/SitePackage.lua +if [ ! -f ${_lmod_sitepackage_file} ]; then + echo "Lmod file '${_lmod_sitepackage_file}' does not exist yet; creating it..." + command -V python3 + python3 ${TOPDIR}/create_lmodsitepackage.py ${_eessi_software_path} +fi + +# install any additional required scripts +# order is important: these are needed to install a full CUDA SDK in host_injections +# for now, this just reinstalls all scripts. Note the most elegant, but works + +# Only run install_scripts.sh if not dev.eessi.io for security +if [[ "${EESSI_CVMFS_REPO}" != /cvmfs/dev.eessi.io ]]; then + ${TOPDIR}/install_scripts.sh --prefix ${EESSI_PREFIX} +fi + +echo ">> Configuring EasyBuild..." + +# Make sure EESSI-extend is not loaded, and configure location variables for a +# CVMFS installation +module unload EESSI-extend +unset EESSI_USER_INSTALL +unset EESSI_PROJECT_INSTALL +unset EESSI_SITE_INSTALL +export EESSI_CVMFS_INSTALL=1 + +# We now run 'source load_eessi_extend_module.sh' to load or install and load the +# EESSI-extend module which sets up all build environment settings. +# The script requires the EESSI_VERSION given as argument, a couple of +# environment variables set (TMPDIR, EB and EASYBUILD_INSTALLPATH) and the +# function check_exit_code defined. +# NOTE 1, the script exits if those variables/functions are undefined. +# NOTE 2, loading the EESSI-extend module may adjust the value of EASYBUILD_INSTALLPATH, +# e.g., to point to the installation directory for accelerators. +# NOTE 3, we have to set a default for EASYBUILD_INSTALLPATH here in cases the +# EESSI-extend module itself needs to be installed. +export EASYBUILD_INSTALLPATH=${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR_OVERRIDE} +source load_eessi_extend_module.sh ${EESSI_VERSION} + +# Install full CUDA SDK and cu* libraries in host_injections +# Hardcode this for now, see if it works +# TODO: We should make a nice yaml and loop over all CUDA versions in that yaml to figure out what to install +# Allow skipping CUDA SDK install in e.g. CI environments +echo "Going to install full CUDA SDK and cu* libraries under host_injections if necessary" +temp_install_storage=${TMPDIR}/temp_install_storage +mkdir -p ${temp_install_storage} +if [ -z "${skip_cuda_install}" ] || [ ! "${skip_cuda_install}" ]; then + ${EESSI_PREFIX}/scripts/gpu_support/nvidia/install_cuda_and_libraries.sh \ + -t ${temp_install_storage} \ + --accept-cuda-eula \ + --accept-cudnn-eula +else + echo "Skipping installation of CUDA SDK and cu* libraries in host_injections, since the --skip-cuda-install flag was passed" +fi + +# Install NVIDIA drivers in host_injections (if they exist) +if command_exists "nvidia-smi"; then + echo "Command 'nvidia-smi' found. Installing NVIDIA drivers for use in prefix shell..." + ${EESSI_PREFIX}/scripts/gpu_support/nvidia/link_nvidia_host_libraries.sh +fi + + +if [ ! -z "${shared_fs_path}" ]; then + shared_eb_sourcepath=${shared_fs_path}/easybuild/sources + echo ">> Using ${shared_eb_sourcepath} as shared EasyBuild source path" + export EASYBUILD_SOURCEPATH=${shared_eb_sourcepath}:${EASYBUILD_SOURCEPATH} +fi + +# if an accelerator target is specified, we need to make sure that the CPU-only modules are also still available +if [ ! -z ${EESSI_ACCELERATOR_TARGET} ]; then + CPU_ONLY_MODULES_PATH=$(echo $EASYBUILD_INSTALLPATH | sed "s@/accel/${EESSI_ACCELERATOR_TARGET}@@g")/modules/all + if [ -d ${CPU_ONLY_MODULES_PATH} ]; then + module use ${CPU_ONLY_MODULES_PATH} + else + fatal_error "Derived path to CPU-only modules does not exist: ${CPU_ONLY_MODULES_PATH}" + fi +fi + +# If in dev.eessi.io, allow building on top of software.eessi.io +if [[ "${EESSI_CVMFS_REPO}" == /cvmfs/dev.eessi.io ]]; then + module use /cvmfs/software.eessi.io/versions/$EESSI_VERSION/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR_OVERRIDE}/modules/all +fi + +module use $EASYBUILD_INSTALLPATH/modules/all + +if [[ -z ${MODULEPATH} ]]; then + fatal_error "Failed to set up \$MODULEPATH?!" +else + echo_green ">> MODULEPATH set up: ${MODULEPATH}" +fi + +# assume there's only one diff file that corresponds to the PR patch file +pr_diff=$(ls [0-9]*.diff | head -1) + + +# use PR patch file to determine in which easystack files stuff was added +changed_easystacks=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep 'easystacks/.*yml$' | egrep -v 'known-issues|missing') +if [ -z "${changed_easystacks}" ]; then + echo "No missing installations, party time!" # Ensure the bot report success, as there was nothing to be build here +else + + # first process rebuilds, if any, then easystack files for new installations + # "|| true" is used to make sure that the grep command always returns success + rebuild_easystacks=$(echo "${changed_easystacks}" | (grep "/rebuilds/" || true)) + new_easystacks=$(echo "${changed_easystacks}" | (grep -v "/rebuilds/" || true)) + for easystack_file in ${rebuild_easystacks} ${new_easystacks}; do + + echo -e "Processing easystack file ${easystack_file}...\n\n" + + # determine version of EasyBuild module to load based on EasyBuild version included in name of easystack file + eb_version=$(echo ${easystack_file} | sed 's/.*eb-\([0-9.]*\).*/\1/g') + + # load EasyBuild module (will be installed if it's not available yet) + source ${TOPDIR}/load_easybuild_module.sh ${eb_version} + + ${EB} --show-config + + echo_green "All set, let's start installing some software with EasyBuild v${eb_version} in ${EASYBUILD_INSTALLPATH}..." + + if [ -f ${easystack_file} ]; then + echo_green "Feeding easystack file ${easystack_file} to EasyBuild..." + + if [[ ${easystack_file} == *"/rebuilds/"* ]]; then + # the removal script should have removed the original directory and created a new and empty one + # to work around permission issues: + # https://github.com/EESSI/software-layer/issues/556 + echo_yellow "This is a rebuild, so using --try-amend=keeppreviousinstall=True to reuse the already created directory" + ${EB} --easystack ${easystack_file} --robot --try-amend=keeppreviousinstall=True + else + ${EB} --easystack ${easystack_file} --robot + fi + ec=$? + + # copy EasyBuild log file if EasyBuild exited with an error + if [ ${ec} -ne 0 ]; then + eb_last_log=$(unset EB_VERBOSE; eb --last-log) + # copy to current working directory + cp -a ${eb_last_log} . + echo "Last EasyBuild log file copied from ${eb_last_log} to ${PWD}" + # copy to build logs dir (with context added) + copy_build_log "${eb_last_log}" "${build_logs_dir}" + fi + + $TOPDIR/check_missing_installations.sh ${easystack_file} ${pr_diff} + else + fatal_error "Easystack file ${easystack_file} not found!" + fi + + done +fi + +export LMOD_CONFIG_DIR="${EASYBUILD_INSTALLPATH}/.lmod" +lmod_rc_file="$LMOD_CONFIG_DIR/lmodrc.lua" +if [[ ! -z ${EESSI_ACCELERATOR_TARGET} ]]; then + # EESSI_ACCELERATOR_TARGET is set, so let's remove the accelerator path from $lmod_rc_file + lmod_rc_file=$(echo ${lmod_rc_file} | sed "s@/accel/${EESSI_ACCELERATOR_TARGET}@@") + echo "Path to lmodrc.lua changed to '${lmod_rc_file}'" +fi +lmodrc_changed=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep '^create_lmodrc.py$' > /dev/null; echo $?) +if [ ! -f $lmod_rc_file ] || [ ${lmodrc_changed} == '0' ]; then + echo ">> Creating/updating Lmod RC file (${lmod_rc_file})..." + python3 $TOPDIR/create_lmodrc.py ${EASYBUILD_INSTALLPATH} + check_exit_code $? "$lmod_rc_file created" "Failed to create $lmod_rc_file" +fi + +export LMOD_PACKAGE_PATH="${EASYBUILD_INSTALLPATH}/.lmod" +lmod_sitepackage_file="$LMOD_PACKAGE_PATH/SitePackage.lua" +if [[ ! -z ${EESSI_ACCELERATOR_TARGET} ]]; then + # EESSI_ACCELERATOR_TARGET is set, so let's remove the accelerator path from $lmod_sitepackage_file + lmod_sitepackage_file=$(echo ${lmod_sitepackage_file} | sed "s@/accel/${EESSI_ACCELERATOR_TARGET}@@") + echo "Path to SitePackage.lua changed to '${lmod_sitepackage_file}'" +fi +sitepackage_changed=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep '^create_lmodsitepackage.py$' > /dev/null; echo $?) +if [ ! -f "$lmod_sitepackage_file" ] || [ "${sitepackage_changed}" == '0' ]; then + echo ">> Creating/updating Lmod SitePackage.lua (${lmod_sitepackage_file})..." + python3 $TOPDIR/create_lmodsitepackage.py ${EASYBUILD_INSTALLPATH} + check_exit_code $? "$lmod_sitepackage_file created" "Failed to create $lmod_sitepackage_file" +fi + +echo ">> Cleaning up ${TMPDIR}..." +rm -r ${TMPDIR} diff --git a/EESSI-pilot-install-software.sh b/EESSI-pilot-install-software.sh deleted file mode 100755 index d9bcf20231..0000000000 --- a/EESSI-pilot-install-software.sh +++ /dev/null @@ -1,384 +0,0 @@ -#!/bin/bash -# -# 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 -# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash - -display_help() { - echo "usage: $0 [OPTIONS]" - echo " -g | --generic - instructs script to build for generic architecture target" - echo " -h | --help - display this usage information" - echo " -x | --http-proxy URL - provides URL for the environment variable http_proxy" - echo " -y | --https-proxy URL - provides URL for the environment variable https_proxy" -} - -POSITIONAL_ARGS=() - -while [[ $# -gt 0 ]]; do - case $1 in - -g|--generic) - EASYBUILD_OPTARCH="GENERIC" - shift - ;; - -h|--help) - display_help # Call your function - # no shifting needed here, we're done. - exit 0 - ;; - -x|--http-proxy) - export http_proxy="$2" - shift 2 - ;; - -y|--https-proxy) - export https_proxy="$2" - shift 2 - ;; - -*|--*) - echo "Error: Unknown option: $1" >&2 - exit 1 - ;; - *) # No more options - POSITIONAL_ARGS+=("$1") # save positional arg - shift - ;; - esac -done - -set -- "${POSITIONAL_ARGS[@]}" - -TOPDIR=$(dirname $(realpath $0)) - -source $TOPDIR/scripts/utils.sh - -# honor $TMPDIR if it is already defined, use /tmp otherwise -if [ -z $TMPDIR ]; then - export WORKDIR=/tmp/$USER -else - export WORKDIR=$TMPDIR/$USER -fi - -TMPDIR=$(mktemp -d) - -echo ">> Setting up environment..." - -source $TOPDIR/init/minimal_eessi_env - -if [ -d $EESSI_CVMFS_REPO ]; then - echo_green "$EESSI_CVMFS_REPO available, OK!" -else - fatal_error "$EESSI_CVMFS_REPO is not available!" -fi - -# make sure we're in Prefix environment by checking $SHELL -if [[ ${SHELL} = ${EPREFIX}/bin/bash ]]; then - echo_green ">> It looks like we're in a Gentoo Prefix environment, good!" -else - fatal_error "Not running in Gentoo Prefix environment, run '${EPREFIX}/startprefix' first!" -fi - -# avoid that pyc files for EasyBuild are stored in EasyBuild installation directory -export PYTHONPYCACHEPREFIX=$TMPDIR/pycache - -DETECTION_PARAMETERS='' -GENERIC=0 -EB='eb' -if [[ "$EASYBUILD_OPTARCH" == "GENERIC" ]]; then - echo_yellow ">> GENERIC build requested, taking appropriate measures!" - DETECTION_PARAMETERS="$DETECTION_PARAMETERS --generic" - GENERIC=1 - EB='eb --optarch=GENERIC' -fi - -echo ">> Determining software subdirectory to use for current build host..." -if [ -z $EESSI_SOFTWARE_SUBDIR_OVERRIDE ]; then - export EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(python3 $TOPDIR/eessi_software_subdir.py $DETECTION_PARAMETERS) - echo ">> Determined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE via 'eessi_software_subdir.py $DETECTION_PARAMETERS' script" -else - echo ">> Picking up pre-defined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE: ${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" -fi - -# Set all the EESSI environment variables (respecting $EESSI_SOFTWARE_SUBDIR_OVERRIDE) -# $EESSI_SILENT - don't print any messages -# $EESSI_BASIC_ENV - give a basic set of environment variables -EESSI_SILENT=1 EESSI_BASIC_ENV=1 source $TOPDIR/init/eessi_environment_variables - -if [[ -z ${EESSI_SOFTWARE_SUBDIR} ]]; then - fatal_error "Failed to determine software subdirectory?!" -elif [[ "${EESSI_SOFTWARE_SUBDIR}" != "${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" ]]; then - fatal_error "Values for EESSI_SOFTWARE_SUBDIR_OVERRIDE (${EESSI_SOFTWARE_SUBDIR_OVERRIDE}) and EESSI_SOFTWARE_SUBDIR (${EESSI_SOFTWARE_SUBDIR}) differ!" -else - echo_green ">> Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory!" -fi - -echo ">> Initializing Lmod..." -source $EPREFIX/usr/share/Lmod/init/bash -ml_version_out=$TMPDIR/ml.out -ml --version &> $ml_version_out -if [[ $? -eq 0 ]]; then - echo_green ">> Found Lmod ${LMOD_VERSION}" -else - fatal_error "Failed to initialize Lmod?! (see output in ${ml_version_out}" -fi - -echo ">> Configuring EasyBuild..." -source $TOPDIR/configure_easybuild - -echo ">> Setting up \$MODULEPATH..." -# make sure no modules are loaded -module --force purge -# ignore current $MODULEPATH entirely -module unuse $MODULEPATH -module use $EASYBUILD_INSTALLPATH/modules/all -if [[ -z ${MODULEPATH} ]]; then - fatal_error "Failed to set up \$MODULEPATH?!" -else - echo_green ">> MODULEPATH set up: ${MODULEPATH}" -fi - -REQ_EB_VERSION='4.5.0' - -# load EasyBuild module (will be installed if it's not available yet) -source ${TOPDIR}/load_easybuild_module.sh ${REQ_EB_VERSION} - -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}" - -### add packages here - -echo ">> Creating/updating Lmod cache..." -export LMOD_RC="${EASYBUILD_INSTALLPATH}/.lmod/lmodrc.lua" -if [ ! -f $LMOD_RC ]; then - python3 $TOPDIR/create_lmodrc.py ${EASYBUILD_INSTALLPATH} - check_exit_code $? "$LMOD_RC created" "Failed to create $LMOD_RC" -fi - -$TOPDIR/update_lmod_cache.sh ${EPREFIX} ${EASYBUILD_INSTALLPATH} - -$TOPDIR/check_missing_installations.sh - -echo ">> Cleaning up ${TMPDIR}..." -rm -r ${TMPDIR} diff --git a/EESSI-remove-software.sh b/EESSI-remove-software.sh new file mode 100755 index 0000000000..c35c7bc469 --- /dev/null +++ b/EESSI-remove-software.sh @@ -0,0 +1,148 @@ +#!/bin/bash +# +# Script to remove part of the EESSI 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 +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash + +display_help() { + echo "usage: $0 [OPTIONS]" + echo " -g | --generic - instructs script to build for generic architecture target" + echo " -h | --help - display this usage information" +} + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -g|--generic) + DETECTION_PARAMETERS="--generic" + shift + ;; + -h|--help) + display_help # Call your function + # no shifting needed here, we're done. + exit 0 + ;; + -*|--*) + echo "Error: Unknown option: $1" >&2 + exit 1 + ;; + *) # No more options + POSITIONAL_ARGS+=("$1") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +TOPDIR=$(dirname $(realpath $0)) + +export TMPDIR=$(mktemp -d /tmp/eessi-remove.XXXXXXXX) + +source $TOPDIR/scripts/utils.sh + +echo ">> Determining software subdirectory to use for current build host..." +if [ -z $EESSI_SOFTWARE_SUBDIR_OVERRIDE ]; then + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(python3 $TOPDIR/eessi_software_subdir.py $DETECTION_PARAMETERS) + echo ">> Determined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE via 'eessi_software_subdir.py $DETECTION_PARAMETERS' script" +else + echo ">> Picking up pre-defined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE: ${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" +fi + +echo ">> Setting up environment..." + +source $TOPDIR/init/bash + +if [ -d $EESSI_CVMFS_REPO ]; then + echo_green "$EESSI_CVMFS_REPO available, OK!" +else + fatal_error "$EESSI_CVMFS_REPO is not available!" +fi + +if [[ -z ${EESSI_SOFTWARE_SUBDIR} ]]; then + fatal_error "Failed to determine software subdirectory?!" +elif [[ "${EESSI_SOFTWARE_SUBDIR}" != "${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" ]]; then + fatal_error "Values for EESSI_SOFTWARE_SUBDIR_OVERRIDE (${EESSI_SOFTWARE_SUBDIR_OVERRIDE}) and EESSI_SOFTWARE_SUBDIR (${EESSI_SOFTWARE_SUBDIR}) differ!" +else + echo_green ">> Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory!" +fi + +echo ">> Configuring EasyBuild..." +EB="eb" +source $TOPDIR/configure_easybuild + +echo ">> Setting up \$MODULEPATH..." +# make sure no modules are loaded +module --force purge +# ignore current $MODULEPATH entirely +module unuse $MODULEPATH + +# if an accelerator target is specified, we need to make sure that the CPU-only modules are also still available +if [ ! -z ${EESSI_ACCELERATOR_TARGET} ]; then + CPU_ONLY_MODULES_PATH=$(echo $EASYBUILD_INSTALLPATH | sed "s@/accel/${EESSI_ACCELERATOR_TARGET}@@g")/modules/all + if [ -d ${CPU_ONLY_MODULES_PATH} ]; then + module use ${CPU_ONLY_MODULES_PATH} + else + fatal_error "Derived path to CPU-only modules does not exist: ${CPU_ONLY_MODULES_PATH}" + fi +fi + +module use $EASYBUILD_INSTALLPATH/modules/all +if [[ -z ${MODULEPATH} ]]; then + fatal_error "Failed to set up \$MODULEPATH?!" +else + echo_green ">> MODULEPATH set up: ${MODULEPATH}" +fi + +# assume there's only one diff file that corresponds to the PR patch file +pr_diff=$(ls [0-9]*.diff | head -1) + +# if this script is run as root, use PR patch file to determine if software needs to be removed first +if [ $EUID -eq 0 ]; then + changed_easystacks_rebuilds=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep 'easystacks/.*yml$' | egrep -v 'known-issues|missing' | grep "/rebuilds/") + if [ -z ${changed_easystacks_rebuilds} ]; then + echo "No software needs to be removed." + else + for easystack_file in ${changed_easystacks_rebuilds}; do + # determine version of EasyBuild module to load based on EasyBuild version included in name of easystack file + eb_version=$(echo ${easystack_file} | sed 's/.*eb-\([0-9.]*\).*/\1/g') + + # load EasyBuild module (will be installed if it's not available yet) + source ${TOPDIR}/load_easybuild_module.sh ${eb_version} + + if [ -f ${easystack_file} ]; then + echo_green "Software rebuild(s) requested in ${easystack_file}, so determining which existing installation have to be removed..." + # we need to remove existing installation directories first, + # so let's figure out which modules have to be rebuilt by doing a dry-run and grepping "someapp/someversion" for the relevant lines (with [R]) + # * [R] $CFGS/s/someapp/someapp-someversion.eb (module: someapp/someversion) + rebuild_apps=$(eb --allow-use-as-root-and-accept-consequences --dry-run-short --rebuild --easystack ${easystack_file} | grep "^ \* \[R\]" | grep -o "module: .*[^)]" | awk '{print $2}') + for app in ${rebuild_apps}; do + # Returns e.g. /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen2/modules/all: + app_modulepath=$(module --terse av ${app} 2>&1 | head -n 1 | sed 's/://') + # Two dirname invocations, so returns e.g. /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen2 + app_installprefix=$(dirname $(dirname ${app_modulepath})) + app_dir=${app_installprefix}/software/${app} + app_subdirs=$(find ${app_dir} -mindepth 1 -maxdepth 1 -type d) + app_module=${app_installprefix}/modules/all/${app}.lua + echo_yellow "Removing ${app_dir} and ${app_module}..." + rm -rf ${app_dir} + rm -rf ${app_module} + # recreate the installation directory and do an ls on the first-level subdirectories to work around + # permission issues when reinstalling the application (see https://github.com/EESSI/software-layer/issues/556) + echo_yellow "Recreating an empty ${app_dir}..." + mkdir -p ${app_dir} + # these subdirs don't (and shouldn't) exist, but we need to do the ls anyway as a workaround, + # so redirect to /dev/null and ignore the exit code + ls ${app_subdirs} >& /dev/null || true + done + else + fatal_error "Easystack file ${easystack_file} not found!" + fi + done + fi +else + fatal_error "This script can only be run by root!" +fi diff --git a/README.md b/README.md index daf02eebc2..ab73ad7579 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,22 @@ # Software layer -The software layer of the EESSI project uses [EasyBuild](https://easybuild.readthedocs.io), [Lmod](https://lmod.readthedocs.io) and [archspec](https://archspec.readthedocs.io). +The software layer of the EESSI project uses [EasyBuild](https://docs.easybuild.io), [Lmod](https://lmod.readthedocs.io) and [archspec](https://archspec.readthedocs.io). -See also https://eessi.github.io/docs/software_layer. +See also https://www.eessi.io/docs/software_layer . ## Pilot software stack You can set up your environment by sourcing the init script: ``` -$ source /cvmfs/pilot.eessi-hpc.org/versions/2021.12/init/bash -Found EESSI pilot repo @ /cvmfs/pilot.eessi-hpc.org/versions/2021.12! +$ source /cvmfs/software.eessi.io/versions/2023.06/init/bash +Found EESSI repo @ /cvmfs/software.eessi.io/versions/2023.06! Derived subdirectory for software layer: x86_64/intel/haswell -Using x86_64/intel/haswell subdirectory for software layer (HARDCODED) +Using x86_64/intel/haswell subdirectory for software layer Initializing Lmod... -Prepending /cvmfs/pilot.eessi-hpc.org/versions/2021.12/software/x86_64/intel/haswell/modules/all to $MODULEPATH... -Environment set up to use EESSI pilot software stack, have fun! -[EESSI pilot 2021.12] $ +Prepending /cvmfs/software.eessi.io/versions/2023.06/software/x86_64/intel/haswell/modules/all to $MODULEPATH... +Environment set up to use EESSI (2023.06), have fun! +[EESSI 2023.06] $ ``` ### Accessing EESSI via a container diff --git a/bot/build.sh b/bot/build.sh index c8def2cdd3..5c6ac8c185 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -21,12 +21,14 @@ # stop as soon as something fails set -e +# Make sure we are referring to software-layer as working directory +software_layer_dir=$(dirname $(dirname $(realpath $0))) # source utils.sh and cfg_files.sh -source scripts/utils.sh -source scripts/cfg_files.sh +source $software_layer_dir/scripts/utils.sh +source $software_layer_dir/scripts/cfg_files.sh # defaults -export JOB_CFG_FILE="${JOB_CFG_FILE_OVERRIDE:=./cfg/job.cfg}" +export JOB_CFG_FILE="${JOB_CFG_FILE_OVERRIDE:=cfg/job.cfg}" HOST_ARCH=$(uname -m) # check if ${JOB_CFG_FILE} exists @@ -53,6 +55,33 @@ LOCAL_TMP=$(cfg_get_value "site_config" "local_tmp") echo "bot/build.sh: LOCAL_TMP='${LOCAL_TMP}'" # TODO should local_tmp be mandatory? --> then we check here and exit if it is not provided +# check if path to copy build logs to is specified, so we can copy build logs for failing builds there +BUILD_LOGS_DIR=$(cfg_get_value "site_config" "build_logs_dir") +echo "bot/build.sh: BUILD_LOGS_DIR='${BUILD_LOGS_DIR}'" +# if $BUILD_LOGS_DIR is set, add it to $SINGULARITY_BIND so the path is available in the build container +if [[ ! -z ${BUILD_LOGS_DIR} ]]; then + mkdir -p ${BUILD_LOGS_DIR} + if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${BUILD_LOGS_DIR}" + else + export SINGULARITY_BIND="${SINGULARITY_BIND},${BUILD_LOGS_DIR}" + fi +fi + +# check if path to directory on shared filesystem is specified, +# and use it as location for source tarballs used by EasyBuild if so +SHARED_FS_PATH=$(cfg_get_value "site_config" "shared_fs_path") +echo "bot/build.sh: SHARED_FS_PATH='${SHARED_FS_PATH}'" +# if $SHARED_FS_PATH is set, add it to $SINGULARITY_BIND so the path is available in the build container +if [[ ! -z ${SHARED_FS_PATH} ]]; then + mkdir -p ${SHARED_FS_PATH} + if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${SHARED_FS_PATH}" + else + export SINGULARITY_BIND="${SINGULARITY_BIND},${SHARED_FS_PATH}" + fi +fi + SINGULARITY_CACHEDIR=$(cfg_get_value "site_config" "container_cachedir") echo "bot/build.sh: SINGULARITY_CACHEDIR='${SINGULARITY_CACHEDIR}'" if [[ ! -z ${SINGULARITY_CACHEDIR} ]]; then @@ -64,7 +93,19 @@ fi 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}) +#STORAGE=$(envsubst <<< ${LOCAL_TMP}) +# We should have set TMPDIR via $LOCAL_TMP already in the bot's slurm script. +# To be sure, we test if TMPDIR is set and simply use that, otherwise we expand +# it here. +if [[ -n ${TMPDIR} && -d ${TMPDIR} ]]; then + # TMPDIR defined and directory exists + STORAGE=${TMPDIR} +else + if [[ -z ${TMPDIR} ]]; then + # TMPDIR not defined + STORAGE=$(envsubst <<< ${LOCAL_TMP}) + fi +fi echo "'${STORAGE}'" # make sure ${STORAGE} exists @@ -81,7 +122,7 @@ echo "bot/build.sh: LOAD_MODULES='${LOAD_MODULES}'" # singularity/apptainer settings: CONTAINER, HOME, TMPDIR, BIND CONTAINER=$(cfg_get_value "repository" "container") export SINGULARITY_HOME="${PWD}:/eessi_bot_job" -export SINGULARITY_TMPDIR="${PWD}/singularity_tmpdir" +export SINGULARITY_TMPDIR="${JOB_STORAGE}/singularity_tmpdir" mkdir -p ${SINGULARITY_TMPDIR} # load modules if LOAD_MODULES is not empty @@ -96,25 +137,27 @@ else fi # determine repository to be used from entry .repository in ${JOB_CFG_FILE} -REPOSITORY=$(cfg_get_value "repository" "repo_id") +REPOSITORY_ID=$(cfg_get_value "repository" "repo_id") +REPOSITORY_NAME=$(cfg_get_value "repository" "repo_name") +REPOSITORY_VERSION=$(cfg_get_value "repository" "repo_version") EESSI_REPOS_CFG_DIR_OVERRIDE=$(cfg_get_value "repository" "repos_cfg_dir") export EESSI_REPOS_CFG_DIR_OVERRIDE=${EESSI_REPOS_CFG_DIR_OVERRIDE:-${PWD}/cfg} echo "bot/build.sh: EESSI_REPOS_CFG_DIR_OVERRIDE='${EESSI_REPOS_CFG_DIR_OVERRIDE}'" -# determine pilot version to be used from .repository.repo_version in ${JOB_CFG_FILE} -# here, just set & export EESSI_PILOT_VERSION_OVERRIDE +# determine EESSI version to be used from .repository.repo_version in ${JOB_CFG_FILE} +# here, just set & export EESSI_VERSION_OVERRIDE # next script (eessi_container.sh) makes use of it via sourcing init scripts # (e.g., init/eessi_defaults or init/minimal_eessi_env) -export EESSI_PILOT_VERSION_OVERRIDE=$(cfg_get_value "repository" "repo_version") -echo "bot/build.sh: EESSI_PILOT_VERSION_OVERRIDE='${EESSI_PILOT_VERSION_OVERRIDE}'" +export EESSI_VERSION_OVERRIDE=${REPOSITORY_VERSION} +echo "bot/build.sh: EESSI_VERSION_OVERRIDE='${EESSI_VERSION_OVERRIDE}'" # determine CVMFS repo to be used from .repository.repo_name in ${JOB_CFG_FILE} # here, just set EESSI_CVMFS_REPO_OVERRIDE, a bit further down # "source init/eessi_defaults" via sourcing init/minimal_eessi_env -export EESSI_CVMFS_REPO_OVERRIDE=$(cfg_get_value "repository" "repo_name") +export EESSI_CVMFS_REPO_OVERRIDE=/cvmfs/${REPOSITORY_NAME} echo "bot/build.sh: EESSI_CVMFS_REPO_OVERRIDE='${EESSI_CVMFS_REPO_OVERRIDE}'" -# determine architecture to be used from entry .architecture in ${JOB_CFG_FILE} +# determine CPU architecture to be used from entry .architecture in ${JOB_CFG_FILE} # fallbacks: # - ${CPU_TARGET} handed over from bot # - left empty to let downstream script(s) determine subdir to be used @@ -123,6 +166,10 @@ EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE:-${CPU_TARGET}} export EESSI_SOFTWARE_SUBDIR_OVERRIDE echo "bot/build.sh: EESSI_SOFTWARE_SUBDIR_OVERRIDE='${EESSI_SOFTWARE_SUBDIR_OVERRIDE}'" +# determine accelerator target (if any) from .architecture in ${JOB_CFG_FILE} +export EESSI_ACCELERATOR_TARGET=$(cfg_get_value "architecture" "accelerator") +echo "bot/build.sh: EESSI_ACCELERATOR_TARGET='${EESSI_ACCELERATOR_TARGET}'" + # get EESSI_OS_TYPE from .architecture.os_type in ${JOB_CFG_FILE} (default: linux) EESSI_OS_TYPE=$(cfg_get_value "architecture" "os_type") export EESSI_OS_TYPE=${EESSI_OS_TYPE:-linux} @@ -136,34 +183,100 @@ COMMON_ARGS+=("--mode" "run") [[ ! -z ${CONTAINER} ]] && COMMON_ARGS+=("--container" "${CONTAINER}") [[ ! -z ${HTTP_PROXY} ]] && COMMON_ARGS+=("--http-proxy" "${HTTP_PROXY}") [[ ! -z ${HTTPS_PROXY} ]] && COMMON_ARGS+=("--https-proxy" "${HTTPS_PROXY}") -[[ ! -z ${REPOSITORY} ]] && COMMON_ARGS+=("--repository" "${REPOSITORY}") +[[ ! -z ${REPOSITORY_ID} ]] && COMMON_ARGS+=("--repository" "${REPOSITORY_ID}") + +# Also expose software.eessi.io when configured for dev.eessi.io +# Need software.eessi.io for the compat layer +if [[ "${REPOSITORY_NAME}" == "dev.eessi.io" ]]; then + COMMON_ARGS+=("--repository" "software.eessi.io,access=ro") +fi # make sure to use the same parent dir for storing tarballs of tmp PREVIOUS_TMP_DIR=${PWD}/previous_tmp +# prepare arguments to install_software_layer.sh (specific to build step) +declare -a BUILD_STEP_ARGS=() +declare -a INSTALL_SCRIPT_ARGS=() +declare -a REMOVAL_SCRIPT_ARGS=() +if [[ ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} =~ .*/generic$ ]]; then + INSTALL_SCRIPT_ARGS+=("--generic") + REMOVAL_SCRIPT_ARGS+=("--generic") +fi +[[ ! -z ${BUILD_LOGS_DIR} ]] && INSTALL_SCRIPT_ARGS+=("--build-logs-dir" "${BUILD_LOGS_DIR}") +[[ ! -z ${SHARED_FS_PATH} ]] && INSTALL_SCRIPT_ARGS+=("--shared-fs-path" "${SHARED_FS_PATH}") + +# Skip CUDA installation for riscv.eessi.io +if [[ "${REPOSITORY_NAME}" == "riscv.eessi.io" ]]; then + echo "bot/build.sh: disabling CUDA installation for RISC-V repository (${REPOSITORY_NAME})" + INSTALL_SCRIPT_ARGS+=("--skip-cuda-install") +fi + +# determine if the removal step has to be run +# assume there's only one diff file that corresponds to the PR patch file +pr_diff=$(ls [0-9]*.diff | head -1) +# the true at the end of the next command is important: grep will expectedly return 1 if there is no easystack file being added under rebuilds, +# but due to "set -e" the entire script would otherwise fail +changed_easystacks_rebuilds=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep 'easystacks/.*yml$' | (grep "/rebuilds/" || true)) +if [[ -z "${changed_easystacks_rebuilds}" ]]; then + echo "This PR does not add any easystack files in a rebuilds subdirectory, so let's skip the removal step." +else + # prepare directory to store tarball of tmp for removal and build steps + TARBALL_TMP_REMOVAL_STEP_DIR=${PREVIOUS_TMP_DIR}/removal_step + mkdir -p ${TARBALL_TMP_REMOVAL_STEP_DIR} + + # prepare arguments to eessi_container.sh specific to remove step + declare -a REMOVAL_STEP_ARGS=() + REMOVAL_STEP_ARGS+=("--save" "${TARBALL_TMP_REMOVAL_STEP_DIR}") + REMOVAL_STEP_ARGS+=("--storage" "${STORAGE}") + + # add fakeroot option in order to be able to remove software, see: + # https://github.com/EESSI/software-layer/issues/312 + REMOVAL_STEP_ARGS+=("--fakeroot") + + # create tmp file for output of removal step + removal_outerr=$(mktemp remove.outerr.XXXX) + + echo "Executing command to remove software:" + echo "$software_layer_dir/eessi_container.sh ${COMMON_ARGS[@]} ${REMOVAL_STEP_ARGS[@]}" + echo " -- $software_layer_dir/EESSI-remove-software.sh \"${REMOVAL_SCRIPT_ARGS[@]}\" \"$@\" 2>&1 | tee -a ${removal_outerr}" + $software_layer_dir/eessi_container.sh "${COMMON_ARGS[@]}" "${REMOVAL_STEP_ARGS[@]}" \ + -- $software_layer_dir/EESSI-remove-software.sh "${REMOVAL_SCRIPT_ARGS[@]}" "$@" 2>&1 | tee -a ${removal_outerr} + + # make sure that the build step resumes from the same temporary directory + # this is important, as otherwise the removed software will still be there + REMOVAL_TMPDIR=$(grep ' as tmp directory ' ${removal_outerr} | cut -d ' ' -f 2) + BUILD_STEP_ARGS+=("--resume" "${REMOVAL_TMPDIR}") +fi + # prepare directory to store tarball of tmp for build step TARBALL_TMP_BUILD_STEP_DIR=${PREVIOUS_TMP_DIR}/build_step mkdir -p ${TARBALL_TMP_BUILD_STEP_DIR} # prepare arguments to eessi_container.sh specific to build step -declare -a BUILD_STEP_ARGS=() BUILD_STEP_ARGS+=("--save" "${TARBALL_TMP_BUILD_STEP_DIR}") BUILD_STEP_ARGS+=("--storage" "${STORAGE}") - -# prepare arguments to install_software_layer.sh (specific to build step) -GENERIC_OPT= -if [[ ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} =~ .*/generic$ ]]; then - GENERIC_OPT="--generic" +# add options required to handle NVIDIA support +if command_exists "nvidia-smi"; then + echo "Command 'nvidia-smi' found, using available GPU" + BUILD_STEP_ARGS+=("--nvidia" "all") +else + echo "No 'nvidia-smi' found, no available GPU but allowing overriding this check" + BUILD_STEP_ARGS+=("--nvidia" "install") +fi +# Retain location for host injections so we don't reinstall CUDA +# (Always need to run the driver installation as available driver may change) +if [[ ! -z ${SHARED_FS_PATH} ]]; then + BUILD_STEP_ARGS+=("--host-injections" "${SHARED_FS_PATH}/host-injections") fi # create tmp file for output of build step build_outerr=$(mktemp build.outerr.XXXX) echo "Executing command to build software:" -echo "./eessi_container.sh ${COMMON_ARGS[@]} ${BUILD_STEP_ARGS[@]}" -echo " -- ./install_software_layer.sh ${GENERIC_OPT} \"$@\" 2>&1 | tee -a ${build_outerr}" -./eessi_container.sh "${COMMON_ARGS[@]}" "${BUILD_STEP_ARGS[@]}" \ - -- ./install_software_layer.sh ${GENERIC_OPT} "$@" 2>&1 | tee -a ${build_outerr} +echo "$software_layer_dir/eessi_container.sh ${COMMON_ARGS[@]} ${BUILD_STEP_ARGS[@]}" +echo " -- $software_layer_dir/install_software_layer.sh \"${INSTALL_SCRIPT_ARGS[@]}\" \"$@\" 2>&1 | tee -a ${build_outerr}" +$software_layer_dir/eessi_container.sh "${COMMON_ARGS[@]}" "${BUILD_STEP_ARGS[@]}" \ + -- $software_layer_dir/install_software_layer.sh "${INSTALL_SCRIPT_ARGS[@]}" "$@" 2>&1 | tee -a ${build_outerr} # prepare directory to store tarball of tmp for tarball step TARBALL_TMP_TARBALL_STEP_DIR=${PREVIOUS_TMP_DIR}/tarball_step @@ -177,13 +290,19 @@ declare -a TARBALL_STEP_ARGS=() TARBALL_STEP_ARGS+=("--save" "${TARBALL_TMP_TARBALL_STEP_DIR}") # determine temporary directory to resume from -BUILD_TMPDIR=$(grep ' as tmp directory ' ${build_outerr} | cut -d ' ' -f 2) -TARBALL_STEP_ARGS+=("--resume" "${BUILD_TMPDIR}") +if [[ -z ${REMOVAL_TMPDIR} ]]; then + # no rebuild step was done, so the tarball step should resume from the build directory + BUILD_TMPDIR=$(grep ' as tmp directory ' ${build_outerr} | cut -d ' ' -f 2) + TARBALL_STEP_ARGS+=("--resume" "${BUILD_TMPDIR}") +else + # a removal step was done, so resume from its temporary directory (which was also used for the build step) + TARBALL_STEP_ARGS+=("--resume" "${REMOVAL_TMPDIR}") +fi timestamp=$(date +%s) -# to set EESSI_PILOT_VERSION we need to source init/eessi_defaults now -source init/eessi_defaults -export TGZ=$(printf "eessi-%s-software-%s-%s-%d.tar.gz" ${EESSI_PILOT_VERSION} ${EESSI_OS_TYPE} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE//\//-} ${timestamp}) +# to set EESSI_VERSION we need to source init/eessi_defaults now +source $software_layer_dir/init/eessi_defaults +export TGZ=$(printf "eessi-%s-software-%s-%s-%d.tar.gz" ${EESSI_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 @@ -191,9 +310,9 @@ export TGZ=$(printf "eessi-%s-software-%s-%s-%d.tar.gz" ${EESSI_PILOT_VERSION} $ # /tmp as default? TMP_IN_CONTAINER=/tmp echo "Executing command to create tarball:" -echo "./eessi_container.sh ${COMMON_ARGS[@]} ${TARBALL_STEP_ARGS[@]}" -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 "${COMMON_ARGS[@]}" "${TARBALL_STEP_ARGS[@]}" \ - -- ./create_tarball.sh ${TMP_IN_CONTAINER} ${EESSI_PILOT_VERSION} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} /eessi_bot_job/${TGZ} 2>&1 | tee -a ${tar_outerr} +echo "$software_layer_dir/eessi_container.sh ${COMMON_ARGS[@]} ${TARBALL_STEP_ARGS[@]}" +echo " -- $software_layer_dir/create_tarball.sh ${TMP_IN_CONTAINER} ${EESSI_VERSION} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} \"${EESSI_ACCELERATOR_TARGET}\" /eessi_bot_job/${TGZ} 2>&1 | tee -a ${tar_outerr}" +$software_layer_dir/eessi_container.sh "${COMMON_ARGS[@]}" "${TARBALL_STEP_ARGS[@]}" \ + -- $software_layer_dir/create_tarball.sh ${TMP_IN_CONTAINER} ${EESSI_VERSION} ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} "${EESSI_ACCELERATOR_TARGET}" /eessi_bot_job/${TGZ} 2>&1 | tee -a ${tar_outerr} exit 0 diff --git a/bot/check-build.sh b/bot/check-build.sh index ec1ca56bba..a3c3a3a1d2 100755 --- a/bot/check-build.sh +++ b/bot/check-build.sh @@ -8,6 +8,7 @@ # https://github.com/EESSI/software-layer.git # # author: Thomas Roeblitz (@trz42) +# author: Samuel Moors (@smoors) # # license: GPLv2 # @@ -17,6 +18,7 @@ # - SUCCESS (all of) # - working directory contains slurm-JOBID.out file # - working directory contains eessi*tar.gz +# - no message FATAL # - no message ERROR # - no message FAILED # - no message ' required modules missing:' @@ -25,6 +27,7 @@ # - FAILED (one of ... implemented as NOT SUCCESS) # - no slurm-JOBID.out file # - no tarball +# - message with FATAL # - message with ERROR # - message with FAILED # - message with ' required modules missing:' @@ -57,10 +60,12 @@ display_help() { echo " OPTIONS:" echo " -h | --help - display this usage information [default: false]" echo " -v | --verbose - display more information [default: false]" + echo " --use-check-build-artefacts-script - alternative build artefacts check (sources file check-build-artefacts.sh if exists) [default: false]" } # set defaults for command line arguments VERBOSE=0 +USE_CHECK_BUILD_ARTEFACTS_SCRIPT=0 POSITIONAL_ARGS=() @@ -74,6 +79,10 @@ while [[ $# -gt 0 ]]; do VERBOSE=1 shift 1 ;; + --use-check-build-artefacts-script) + USE_CHECK_BUILD_ARTEFACTS_SCRIPT=1 + shift 1 + ;; --) shift POSITIONAL_ARGS+=("$@") # save positional args @@ -98,15 +107,25 @@ job_dir=${PWD} job_out="slurm-${SLURM_JOB_ID}.out" [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for job output file(s) matching '"${job_out}"'" if [[ -f ${job_out} ]]; then - SLURM=1 + SLURM_OUTPUT_FOUND=1 [[ ${VERBOSE} -ne 0 ]] && echo " found slurm output file '"${job_out}"'" else - SLURM=0 + SLURM_OUTPUT_FOUND=0 [[ ${VERBOSE} -ne 0 ]] && echo " Slurm output file '"${job_out}"' NOT found" fi +FATAL=-1 +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then + GP_fatal='FATAL: ' + grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_fatal}") + [[ $? -eq 0 ]] && FATAL=1 || FATAL=0 + # have to be careful to not add searched for pattern into slurm out file + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_fatal}"'" + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_out}" +fi + ERROR=-1 -if [[ ${SLURM} -eq 1 ]]; then +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then GP_error='ERROR: ' grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_error}") [[ $? -eq 0 ]] && ERROR=1 || ERROR=0 @@ -116,7 +135,7 @@ if [[ ${SLURM} -eq 1 ]]; then fi FAILED=-1 -if [[ ${SLURM} -eq 1 ]]; then +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then GP_failed='FAILED: ' grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_failed}") [[ $? -eq 0 ]] && FAILED=1 || FAILED=0 @@ -126,7 +145,7 @@ if [[ ${SLURM} -eq 1 ]]; then fi MISSING=-1 -if [[ ${SLURM} -eq 1 ]]; then +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then GP_req_missing=' required modules missing:' grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_req_missing}") [[ $? -eq 0 ]] && MISSING=1 || MISSING=0 @@ -136,7 +155,7 @@ if [[ ${SLURM} -eq 1 ]]; then fi NO_MISSING=-1 -if [[ ${SLURM} -eq 1 ]]; then +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then GP_no_missing='No missing installations' grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_no_missing}") [[ $? -eq 0 ]] && NO_MISSING=1 || NO_MISSING=0 @@ -145,45 +164,76 @@ if [[ ${SLURM} -eq 1 ]]; then [[ ${VERBOSE} -ne 0 ]] && echo "${grep_out}" fi -TGZ=-1 -TARBALL= -if [[ ${SLURM} -eq 1 ]]; then - GP_tgz_created="\.tar\.gz created!" - grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_tgz_created}" | sort -u) - if [[ $? -eq 0 ]]; then - TGZ=1 - TARBALL=$(echo ${grep_out} | sed -e 's@^.*/\(eessi[^/ ]*\) .*$@\1@') - else - TGZ=0 - fi - # have to be careful to not add searched for pattern into slurm out file - [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_tgz_created}"'" - [[ ${VERBOSE} -ne 0 ]] && echo "${grep_out}" +if [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -eq 0 ]]; then + TGZ=-1 + TARBALL= + if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then + GP_tgz_created="\.tar\.gz created!" + grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_tgz_created}" | sort -u) + if [[ $? -eq 0 ]]; then + TGZ=1 + TARBALL=$(echo ${grep_out} | sed -e 's@^.*/\(eessi[^/ ]*\) .*$@\1@') + else + TGZ=0 + fi + # have to be careful to not add searched for pattern into slurm out file + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_tgz_created}"'" + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_out}" + fi fi [[ ${VERBOSE} -ne 0 ]] && echo "SUMMARY: ${job_dir}/${job_out}" [[ ${VERBOSE} -ne 0 ]] && echo " : ()" +[[ ${VERBOSE} -ne 0 ]] && echo " FATAL......: $([[ $FATAL -eq 1 ]] && echo 'yes' || echo 'no') (no)" [[ ${VERBOSE} -ne 0 ]] && echo " ERROR......: $([[ $ERROR -eq 1 ]] && echo 'yes' || echo 'no') (no)" [[ ${VERBOSE} -ne 0 ]] && echo " FAILED.....: $([[ $FAILED -eq 1 ]] && echo 'yes' || echo 'no') (no)" [[ ${VERBOSE} -ne 0 ]] && echo " REQ_MISSING: $([[ $MISSING -eq 1 ]] && echo 'yes' || echo 'no') (no)" [[ ${VERBOSE} -ne 0 ]] && echo " NO_MISSING.: $([[ $NO_MISSING -eq 1 ]] && echo 'yes' || echo 'no') (yes)" -[[ ${VERBOSE} -ne 0 ]] && echo " TGZ_CREATED: $([[ $TGZ -eq 1 ]] && echo 'yes' || echo 'no') (yes)" +if [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -eq 0 ]]; then + [[ ${VERBOSE} -ne 0 ]] && echo " TGZ_CREATED: $([[ $TGZ -eq 1 ]] && echo 'yes' || echo 'no') (yes)" +fi + +# Here, we try to do some additional analysis on the output file +# to see if we can print a more clear 'reason' for the failure +# For now, we only analyse unmerged EasyConfigs as potential cause, but we can easily add checks for other +# specific scenarios below + +# Check for the pattern being added here by check_missing_installations.sh to the output to +# see if EasyConfigs might have been unmerged, and that's causing a failure +UNMERGED_EASYCONFIG=-1 +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then + gp_unmerged="are you sure all PRs referenced have been merged in EasyBuild" + grep_unmerged=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${gp_unmerged}") + [[ $? -eq 0 ]] && UNMERGED_EASYCONFIG=1 || UNMERGED_EASYCONFIG=0 + # have to be careful to not add searched for pattern into slurm out file + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${gp_unmerged}"'" + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_unmerged}" +fi job_result_file=_bot_job${SLURM_JOB_ID}.result -if [[ ${SLURM} -eq 1 ]] && \ +# Default reason: +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]] && \ + [[ ${FATAL} -eq 0 ]] && \ [[ ${ERROR} -eq 0 ]] && \ [[ ${FAILED} -eq 0 ]] && \ [[ ${MISSING} -eq 0 ]] && \ [[ ${NO_MISSING} -eq 1 ]] && \ - [[ ${TGZ} -eq 1 ]] && \ - [[ ! -z ${TARBALL} ]]; then + [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -ne 0 || ${TGZ} -eq 1 ]] && \ + [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -ne 0 || -n ${TARBALL} ]]; then # SUCCESS status="SUCCESS" + reason="" summary=":grin: SUCCESS" +elif [[ ${UNMERGED_EASYCONFIG} -eq 1 ]]; then + status="FAILURE" + reason="EasyConfig not found during missing installation check. Are you sure all PRs referenced have been merged in EasyBuild?" + summary=":cry: FAILURE" else # FAILURE status="FAILURE" + # General failure, we don't know a more specific reason + reason="" summary=":cry: FAILURE" fi @@ -198,6 +248,7 @@ fi #
_Details_
#
# :white_check_mark: job output file slurm-4682.out
+# :white_check_mark: no message matching FATAL:
# :white_check_mark: no message matching ERROR:
# :white_check_mark: no message matching FAILED:
# :white_check_mark: no message matching required modules missing:
@@ -239,6 +290,7 @@ fi #
_Details_
#
# :white_check_mark: job output file slurm-4682.out
+# :x: no message matching FATAL:
# :x: no message matching ERROR:
# :white_check_mark: no message matching FAILED:
# :x: no message matching required modules missing:
@@ -253,14 +305,6 @@ fi # ### -# construct and write complete PR comment details: implements third alternative -comment_template="
__SUMMARY_FMT__
__DETAILS_FMT____ARTEFACTS_FMT__
" -comment_summary_fmt="__SUMMARY__ _(click triangle for details)_" -comment_details_fmt="
_Details_
__DETAILS_LIST__
" -comment_success_item_fmt=":white_check_mark: __ITEM__" -comment_failure_item_fmt=":x: __ITEM__" -comment_artefacts_fmt="
_Artefacts_
__ARTEFACTS_LIST__
" -comment_artefact_details_fmt="
__ARTEFACT_SUMMARY____ARTEFACT_DETAILS__
" function print_br_item() { format="${1}" @@ -332,159 +376,202 @@ echo -n "comment_description = " >> ${job_result_file} # - __DETAILS_FMT__ -> variable $comment_details # - __ARTEFACTS_FMT__ -> variable $comment_artefacts +# construct and write complete PR comment details: implements third alternative +comment_template="
__SUMMARY_FMT__
__REASON_FMT____DETAILS_FMT____ARTEFACTS_FMT__
" +comment_success_item_fmt=":white_check_mark: __ITEM__" +comment_failure_item_fmt=":x: __ITEM__" + +# Initialize comment_description +comment_description=${comment_template} + +# Now, start replacing template items one by one +# Replace the summary template (__SUMMARY_FMT__) +comment_summary_fmt="__SUMMARY__ _(click triangle for details)_" comment_summary="${comment_summary_fmt/__SUMMARY__/${summary}}" +comment_description=${comment_template/__SUMMARY_FMT__/${comment_summary}} + +# Only add if there is a reason (e.g. no reason for successful runs) +if [[ ! -z ${reason} ]]; then + comment_reason_fmt="
_Reason_
__REASONS__
" + reason_details="${comment_reason_fmt/__REASONS__/${reason}}" + comment_description=${comment_description/__REASON_FMT__/${reason_details}} +else + comment_description=${comment_description/__REASON_FMT__/""} +fi -# first construct comment_details_list, abbreviated CoDeList +# Replace the details template (__DETAILS_FMT__) +# first construct comment_details_list, abbreviated comment_details_list # then use it to set comment_details -CoDeList="" +comment_details_list="" success_msg="job output file ${job_out}" failure_msg="no job output file ${job_out}" -CoDeList=${CoDeList}$(add_detail ${SLURM} 1 "${success_msg}" "${failure_msg}") +comment_details_list=${comment_details_list}$(add_detail ${SLURM_OUTPUT_FOUND} 1 "${success_msg}" "${failure_msg}") + +success_msg="no message matching ${GP_fatal}" +failure_msg="found message matching ${GP_fatal}" +comment_details_list=${comment_details_list}$(add_detail ${FATAL} 0 "${success_msg}" "${failure_msg}") success_msg="no message matching ${GP_error}" failure_msg="found message matching ${GP_error}" -CoDeList=${CoDeList}$(add_detail ${ERROR} 0 "${success_msg}" "${failure_msg}") +comment_details_list=${comment_details_list}$(add_detail ${ERROR} 0 "${success_msg}" "${failure_msg}") success_msg="no message matching ${GP_failed}" failure_msg="found message matching ${GP_failed}" -CoDeList=${CoDeList}$(add_detail ${FAILED} 0 "${success_msg}" "${failure_msg}") +comment_details_list=${comment_details_list}$(add_detail ${FAILED} 0 "${success_msg}" "${failure_msg}") success_msg="no message matching ${GP_req_missing}" failure_msg="found message matching ${GP_req_missing}" -CoDeList=${CoDeList}$(add_detail ${MISSING} 0 "${success_msg}" "${failure_msg}") +comment_details_list=${comment_details_list}$(add_detail ${MISSING} 0 "${success_msg}" "${failure_msg}") success_msg="found message(s) matching ${GP_no_missing}" failure_msg="no message matching ${GP_no_missing}" -CoDeList=${CoDeList}$(add_detail ${NO_MISSING} 1 "${success_msg}" "${failure_msg}") - -success_msg="found message matching ${GP_tgz_created}" -failure_msg="no message matching ${GP_tgz_created}" -CoDeList=${CoDeList}$(add_detail ${TGZ} 1 "${success_msg}" "${failure_msg}") - -comment_details="${comment_details_fmt/__DETAILS_LIST__/${CoDeList}}" - - -# first construct comment_artefacts_list, abbreviated CoArList -# then use it to set comment_artefacts -CoArList="" - -# TARBALL should only contain a single tarball -if [[ ! -z ${TARBALL} ]]; then - # Example of the detailed information for a tarball. The actual result MUST be a - # single line (no '\n') or it would break the structure of the markdown table - # that holds status updates of a bot job. - # - #
- #
- # eessi-2023.06-software-linux-x86_64-generic-1682696567.tar.gz - # size: 234 MiB (245366784 bytes)
- # entries: 1234
- # modules under _2023.06/software/linux/x86_64/intel/cascadelake/modules/all/_
- #
-    #       GCC/9.3.0.lua
- # GCC/10.3.0.lua
- # OpenSSL/1.1.lua - #
- # software under _2023.06/software/linux/x86_64/intel/cascadelake/software/_ - #
-    #       GCC/9.3.0/
- # CMake/3.20.1-GCCcore-10.3.0/
- # OpenMPI/4.1.1-GCC-10.3.0/ - #
- # other under _2023.06/software/linux/x86_64/intel/cascadelake/_ - #
-    #       .lmod/cache/spiderT.lua
- # .lmod/cache/spiderT.luac_5.1
- # .lmod/cache/timestamp - #
- #
- #
- size="$(stat --dereference --printf=%s ${TARBALL})" - size_mib=$((${size} >> 20)) - tmpfile=$(mktemp --tmpdir=. tarfiles.XXXX) - tar tf ${TARBALL} > ${tmpfile} - entries=$(cat ${tmpfile} | wc -l) - # determine prefix from job config: VERSION/software/OS_TYPE/CPU_FAMILY/ARCHITECTURE - # e.g., 2023.06/software/linux/x86_64/intel/skylake_avx512 - # cfg/job.cfg contains (only the attributes to be used are shown below): - # [repository] - # repo_version = 2023.06 - # [architecture] - # os_type = linux - # software_subdir = x86_64/intel/skylake_avx512 - repo_version=$(cfg_get_value "repository" "repo_version") - os_type=$(cfg_get_value "architecture" "os_type") - software_subdir=$(cfg_get_value "architecture" "software_subdir") - prefix="${repo_version}/software/${os_type}/${software_subdir}" - - # extract directories/entries from tarball content - modules_entries=$(grep "${prefix}/modules" ${tmpfile}) - software_entries=$(grep "${prefix}/software" ${tmpfile}) - other_entries=$(cat ${tmpfile} | grep -v "${prefix}/modules" | grep -v "${prefix}/software") - other_shortened=$(echo "${other_entries}" | sed -e "s@^.*${prefix}/@@" | sort -u) - modules=$(echo "${modules_entries}" | grep "/all/.*/.*lua$" | sed -e 's@^.*/\([^/]*/[^/]*.lua\)$@\1@' | sort -u) - software_pkgs=$(echo "${software_entries}" | sed -e "s@${prefix}/software/@@" | awk -F/ '{if (NR >= 2) {print $1 "/" $2}}' | sort -u) - - artefact_summary="$(print_code_item '__ITEM__' ${TARBALL})" - CoArList="" - CoArList="${CoArList}$(print_br_item2 'size: __ITEM__ MiB (__ITEM2__ bytes)' ${size_mib} ${size})" - CoArList="${CoArList}$(print_br_item 'entries: __ITEM__' ${entries})" - CoArList="${CoArList}$(print_br_item 'modules under ___ITEM___' ${prefix}/modules/all)" - CoArList="${CoArList}
"
-    if [[ ! -z ${modules} ]]; then
-        while IFS= read -r mod ; do
-            CoArList="${CoArList}$(print_br_item '__ITEM__' ${mod})"
-        done <<< "${modules}"
-    else
-        CoArList="${CoArList}$(print_br_item '__ITEM__' 'no module files in tarball')"
-    fi
-    CoArList="${CoArList}
" - CoArList="${CoArList}$(print_br_item 'software under ___ITEM___' ${prefix}/software)" - CoArList="${CoArList}
"
-    if [[ ! -z ${software_pkgs} ]]; then
-        while IFS= read -r sw_pkg ; do
-            CoArList="${CoArList}$(print_br_item '__ITEM__' ${sw_pkg})"
-        done <<< "${software_pkgs}"
-    else
-        CoArList="${CoArList}$(print_br_item '__ITEM__' 'no software packages in tarball')"
-    fi
-    CoArList="${CoArList}
" - CoArList="${CoArList}$(print_br_item 'other under ___ITEM___' ${prefix})" - CoArList="${CoArList}
"
-    if [[ ! -z ${other_shortened} ]]; then
-        while IFS= read -r other ; do
-            CoArList="${CoArList}$(print_br_item '__ITEM__' ${other})"
-        done <<< "${other_shortened}"
+comment_details_list=${comment_details_list}$(add_detail ${NO_MISSING} 1 "${success_msg}" "${failure_msg}")
+
+if [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -eq 0 ]]; then
+    success_msg="found message matching ${GP_tgz_created}"
+    failure_msg="no message matching ${GP_tgz_created}"
+    comment_details_list=${comment_details_list}$(add_detail ${TGZ} 1 "${success_msg}" "${failure_msg}")
+fi
+
+# Now, do the actual replacement of __DETAILS_FMT__
+comment_details_fmt="
_Details_
__DETAILS_LIST__
" +comment_details="${comment_details_fmt/__DETAILS_LIST__/${comment_details_list}}" +comment_description=${comment_description/__DETAILS_FMT__/${comment_details}} + +if [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -eq 0 ]]; then + # first construct comment_artefacts_list + # then use it to set comment_artefacts + comment_artifacts_list="" + + # TARBALL should only contain a single tarball + if [[ ! -z ${TARBALL} ]]; then + # Example of the detailed information for a tarball. The actual result MUST be a + # single line (no '\n') or it would break the structure of the markdown table + # that holds status updates of a bot job. + # + #
+ #
+ # eessi-2023.06-software-linux-x86_64-generic-1682696567.tar.gz + # size: 234 MiB (245366784 bytes)
+ # entries: 1234
+ # modules under _2023.06/software/linux/x86_64/intel/cascadelake/modules/all/_
+ #
+        #       GCC/9.3.0.lua
+ # GCC/10.3.0.lua
+ # OpenSSL/1.1.lua + #
+ # software under _2023.06/software/linux/x86_64/intel/cascadelake/software/_ + #
+        #       GCC/9.3.0/
+ # CMake/3.20.1-GCCcore-10.3.0/
+ # OpenMPI/4.1.1-GCC-10.3.0/ + #
+ # other under _2023.06/software/linux/x86_64/intel/cascadelake/_ + #
+        #       .lmod/cache/spiderT.lua
+ # .lmod/cache/spiderT.luac_5.1
+ # .lmod/cache/timestamp + #
+ #
+ #
+ size="$(stat --dereference --printf=%s ${TARBALL})" + size_mib=$((${size} >> 20)) + tmpfile=$(mktemp --tmpdir=. tarfiles.XXXX) + tar tf ${TARBALL} > ${tmpfile} + entries=$(cat ${tmpfile} | wc -l) + # determine prefix from job config: VERSION/software/OS_TYPE/CPU_FAMILY/ARCHITECTURE + # e.g., 2023.06/software/linux/x86_64/intel/skylake_avx512 + # cfg/job.cfg contains (only the attributes to be used are shown below): + # [repository] + # repo_version = 2023.06 + # [architecture] + # os_type = linux + # software_subdir = x86_64/intel/skylake_avx512 + repo_version=$(cfg_get_value "repository" "repo_version") + os_type=$(cfg_get_value "architecture" "os_type") + software_subdir=$(cfg_get_value "architecture" "software_subdir") + accelerator=$(cfg_get_value "architecture" "accelerator") + prefix="${repo_version}/software/${os_type}/${software_subdir}" + + # if we build for an accelerator, the prefix is different + if [[ ! -z ${accelerator} ]]; then + prefix="${prefix}/accel/${accelerator}" + fi + + # extract directories/entries from tarball content + modules_entries=$(grep "${prefix}/modules" ${tmpfile}) + software_entries=$(grep "${prefix}/software" ${tmpfile}) + other_entries=$(cat ${tmpfile} | grep -v "${prefix}/modules" | grep -v "${prefix}/software") + other_shortened=$(echo "${other_entries}" | sed -e "s@^.*${prefix}/@@" | sort -u) + modules=$(echo "${modules_entries}" | grep "/all/.*/.*lua$" | sed -e 's@^.*/\([^/]*/[^/]*.lua\)$@\1@' | sort -u) + software_pkgs=$(echo "${software_entries}" | sed -e "s@${prefix}/software/@@" | awk -F/ '{if (NR >= 2) {print $1 "/" $2}}' | sort -u) + + artefact_summary="$(print_code_item '__ITEM__' ${TARBALL})" + comment_artifacts_list="" + comment_artifacts_list="${comment_artifacts_list}$(print_br_item2 'size: __ITEM__ MiB (__ITEM2__ bytes)' ${size_mib} ${size})" + comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'entries: __ITEM__' ${entries})" + comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'modules under ___ITEM___' ${prefix}/modules/all)" + comment_artifacts_list="${comment_artifacts_list}
"
+        if [[ ! -z ${modules} ]]; then
+            while IFS= read -r mod ; do
+                comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' ${mod})"
+            done <<< "${modules}"
+        else
+            comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no module files in tarball')"
+        fi
+        comment_artifacts_list="${comment_artifacts_list}
" + comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'software under ___ITEM___' ${prefix}/software)" + comment_artifacts_list="${comment_artifacts_list}
"
+        if [[ ! -z ${software_pkgs} ]]; then
+            while IFS= read -r sw_pkg ; do
+                comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' ${sw_pkg})"
+            done <<< "${software_pkgs}"
+        else
+            comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no software packages in tarball')"
+        fi
+        comment_artifacts_list="${comment_artifacts_list}
" + comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'other under ___ITEM___' ${prefix})" + comment_artifacts_list="${comment_artifacts_list}
"
+        if [[ ! -z ${other_shortened} ]]; then
+            while IFS= read -r other ; do
+                comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' ${other})"
+            done <<< "${other_shortened}"
+        else
+            comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no other files in tarball')"
+        fi
+        comment_artifacts_list="${comment_artifacts_list}
" else - CoArList="${CoArList}$(print_br_item '__ITEM__' 'no other files in tarball')" + comment_artifacts_list="${comment_artifacts_list}$(print_dd_item 'No artefacts were created or found.' '')" fi - CoArList="${CoArList}
" -else - CoArList="${CoArList}$(print_dd_item 'No artefacts were created or found.' '')" -fi -comment_artefacts_details="${comment_artefact_details_fmt/__ARTEFACT_SUMMARY__/${artefact_summary}}" -comment_artefacts_details="${comment_artefacts_details/__ARTEFACT_DETAILS__/${CoArList}}" -comment_artefacts="${comment_artefacts_fmt/__ARTEFACTS_LIST__/${comment_artefacts_details}}" + comment_artefact_details_fmt="
__ARTEFACT_SUMMARY____ARTEFACT_DETAILS__
" + comment_artefacts_details="${comment_artefact_details_fmt/__ARTEFACT_SUMMARY__/${artefact_summary}}" + comment_artefacts_details="${comment_artefacts_details/__ARTEFACT_DETAILS__/${comment_artifacts_list}}" -# now put all pieces together creating comment_details from comment_template -comment_description=${comment_template/__SUMMARY_FMT__/${comment_summary}} -comment_description=${comment_description/__DETAILS_FMT__/${comment_details}} -comment_description=${comment_description/__ARTEFACTS_FMT__/${comment_artefacts}} + comment_artefacts_fmt="
_Artefacts_
__ARTEFACTS_LIST__
" + comment_artefacts="${comment_artefacts_fmt/__ARTEFACTS_LIST__/${comment_artefacts_details}}" + comment_description=${comment_description/__ARTEFACTS_FMT__/${comment_artefacts}} -echo "${comment_description}" >> ${job_result_file} + echo "${comment_description}" >> ${job_result_file} -# add overall result: SUCCESS, FAILURE, UNKNOWN + artefacts -# - this should make use of subsequent steps such as deploying a tarball more -# efficient -echo "status = ${status}" >> ${job_result_file} -echo "artefacts = " >> ${job_result_file} -echo "${TARBALL}" | sed -e 's/^/ /g' >> ${job_result_file} + # add overall result: SUCCESS, FAILURE, UNKNOWN + artefacts + # - this should make use of subsequent steps such as deploying a tarball more + # efficient + echo "status = ${status}" >> ${job_result_file} + echo "artefacts = " >> ${job_result_file} + echo "${TARBALL}" | sed -e 's/^/ /g' >> ${job_result_file} -# remove tmpfile -if [[ -f ${tmpfile} ]]; then - rm ${tmpfile} + # remove tmpfile + if [[ -f ${tmpfile} ]]; then + rm ${tmpfile} + fi + +elif [[ -f "$TOPDIR/check-build-artefacts.sh" ]]; then + source "$TOPDIR/check-build-artefacts.sh" +else + echo "ERROR: Required script $TOPDIR/check-build-artefacts.sh not found!" >&2 + exit 1 fi # exit script with value that reflects overall job result: SUCCESS (0), FAILURE (1) diff --git a/bot/check-test.sh b/bot/check-test.sh new file mode 100755 index 0000000000..2731e75464 --- /dev/null +++ b/bot/check-test.sh @@ -0,0 +1,238 @@ +#!/bin/bash +# +# Dummy script that only creates test result file for the bot, without actually checking anything +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Kenneth Hoste (HPC-UGent) +# +# license: GPLv2 +# +job_dir=${PWD} +job_out="slurm-${SLURM_JOB_ID}.out" +job_test_result_file="_bot_job${SLURM_JOB_ID}.test" + +# Check that job output file is found +[[ ${VERBOSE} -ne 0 ]] && echo ">> searching for job output file(s) matching '"${job_out}"'" +if [[ -f ${job_out} ]]; then + SLURM_OUTPUT_FOUND=1 + [[ ${VERBOSE} -ne 0 ]] && echo " found slurm output file '"${job_out}"'" +else + SLURM_OUTPUT_FOUND=0 + [[ ${VERBOSE} -ne 0 ]] && echo " Slurm output file '"${job_out}"' NOT found" +fi + +# ReFrame prints e.g. +#[----------] start processing checks +#[ RUN ] GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:rome+default +#[ RUN ] GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:genoa+default +#[ RUN ] GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=1_cpn_2_nodes %module_name=GROMACS/2021.3-foss-2021a /f4194106 @snellius:genoa+default +#[ FAIL ] (1/3) GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:genoa+default +#==> test failed during 'sanity': test staged in '/scratch-shared/casparl/reframe_output/staging/snellius/genoa/default/GROMACS_EESSI_d597cff4' +#[ OK ] (2/3) GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:rome+default +#P: perf: 8.441 ns/day (r:0, l:None, u:None) +#[ FAIL ] (3/3) GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=1_cpn_2_nodes %module_name=GROMACS/2021.3-foss-2021a /f4194106 @snellius:genoa+default +#==> test failed during 'sanity': test staged in '/scratch-shared/casparl/reframe_output/staging/snellius/genoa/default/GROMACS_EESSI_f4194106' +#[----------] all spawned checks have finished +#[ FAILED ] Ran 3/3 test case(s) from 2 check(s) (2 failure(s), 0 skipped, 0 aborted) + +# We will grep for the last and final line, since this reflects the overall result +# Specifically, we grep for FAILED, since this is also what we print if a step in the test script itself fails +FAILED=-1 +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then + GP_failed='\[\s*FAILED\s*\].*Ran .* test case' + grep_reframe_failed=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_failed}") + [[ $? -eq 0 ]] && FAILED=1 || FAILED=0 + # have to be careful to not add searched for pattern into slurm out file + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_failed}"'" + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_reframe_failed}" +fi + +# Here, we grep for 'ERROR:', which is printed if a fatal_error is encountered when executing the test step +# I.e. this is an error in execution of the run_tests.sh itself, NOT in running the actual tests +ERROR=-1 +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then + GP_error='ERROR: ' + grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_error}") + [[ $? -eq 0 ]] && ERROR=1 || ERROR=0 + # have to be careful to not add searched for pattern into slurm out file + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_error}"'" + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_out}" +fi + +SUCCESS=-1 +# Grep for the success pattern, so we can report the amount of tests run +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then + GP_success='\[\s*PASSED\s*\].*Ran .* test case' + grep_reframe_success=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_success}") + [[ $? -eq 0 ]] && SUCCESS=1 || SUCCESS=0 + # have to be careful to not add searched for pattern into slurm out file + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_success}"'" + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_reframe_success}" +fi + +if [[ ! -z ${grep_reframe_failed} ]]; then + grep_reframe_result=${grep_reframe_failed} +else + # Grep the entire output of ReFrame, so that we can report it in the foldable section of the test report + GP_success_full='(?s)\[----------\] start processing checks.*?\[==========\] Finished on [a-zA-Z0-9 ]*' + # Grab the full ReFrame report, than cut the irrelevant parts + # Note that the character limit for messages in github is around 65k, so cutting is important + grep_reframe_success_full=$( \ + grep -v "^>> searching for " ${job_dir}/${job_out} | \ + # Use -z + grep -Pzo "${GP_success_full}" | \ + # Replace null character with newline, to undo the -z option + sed 's/\x00/\n/g' | \ + # Remove the [ RUN ] lines from reframe, they are not very informative + grep -v -P '\[\s*RUN\s*]' | \ + # Remove the line '[----------] all spawned checks have finished' + grep -v '\[-*\]' | \ + # Remove the line '[==========] Finished on Mon Oct 7 21' + grep -v '\[=*\]' | \ + # Remove blank line(s) from the report + grep -v '^$' | \ + # Remove warnings about the local spawner not supporting memory requests + grep -v 'WARNING\: hooks\.req_memory_per_node does not support the scheduler you configured .local.*$' | \ + # Strip color coding characters + sed 's/\x1B\[[0-9;]*m//g' | \ + # Replace all newline characters with
+ sed ':a;N;$!ba;s/\n//g' | \ + # Replace % with %%. Use \%\% to interpret both %% as (non-special) characters + sed 's/\%/\%\%/g' \ + ) + # TODO (optional): we could impose a character limit here, and truncate if too long + # (though we should do that before inserting the
statements). + # If we do, we should probably re-append the final summary, e.g. + # [ PASSED ] Ran 10/10 test case(s) from 10 check(s) (0 failure(s), 0 skipped, 0 aborted) + # so that that is always displayed + # However, that's not implemented yet - let's see if this ever even becomes an issue + grep_reframe_result=${grep_reframe_success_full} +fi +echo "grep_reframe_result: ${grep_reframe_result}" + +echo "[TEST]" > ${job_test_result_file} +if [[ ${SLURM_OUTPUT_FOUND} -eq 0 ]]; then + summary=":cry: FAILURE" + reason="Job output file not found, cannot check test results." + status="FAILURE" +# Should come before general errors: if SUCCESS==1, it indicates the test suite ran succesfully +# regardless of other things that might have gone wrong +elif [[ ${SUCCESS} -eq 1 ]]; then + summary=":grin: SUCCESS" + reason="" + status="SUCCESS" +# Should come before general errors: if FAILED==1, it indicates the test suite ran +# otherwise the pattern wouldn't have been there +elif [[ ${FAILED} -eq 1 ]]; then + summary=":cry: FAILURE" + reason="EESSI test suite produced failures." + status="FAILURE" +elif [[ ${ERROR} -eq 1 ]]; then + summary=":cry: FAILURE" + reason="EESSI test suite was not run, test step itself failed to execute." + status="FAILURE" +else + summary=":cry: FAILURE" + reason="Failed for unknown reason" + status="FAILURE" +fi + + +echo "[TEST]" > ${job_test_result_file} +echo -n "comment_description = " >> ${job_test_result_file} + +# Use template for writing PR comment with details +# construct and write complete PR comment details: implements third alternative +comment_template="
__SUMMARY_FMT__
__REASON_FMT____REFRAME_FMT____DETAILS_FMT__
" +comment_success_item_fmt=":white_check_mark: __ITEM__" +comment_failure_item_fmt=":x: __ITEM__" + +# Initialize comment_description +comment_description=${comment_template} + +# Now, start replacing template items one by one +comment_summary_fmt="__SUMMARY__ _(click triangle for details)_" +comment_summary="${comment_summary_fmt/__SUMMARY__/${summary}}" +comment_description=${comment_description/__SUMMARY_FMT__/${comment_summary}} + + +# Only add if there is a reason (e.g. no reason for successful runs) +if [[ ! -z ${reason} ]]; then + comment_reason_fmt="
_Reason_
__REASONS__
" + reason_details="${comment_reason_fmt/__REASONS__/${reason}}" + comment_description=${comment_description/__REASON_FMT__/${reason_details}} +else + comment_description=${comment_description/__REASON_FMT__/""} +fi + +# Only add if there is a reframe summary (e.g. no reframe summary if reframe wasn't launched succesfully) +echo "ReFrame result:" +echo "${grep_reframe_result}" +if [[ ! -z ${grep_reframe_result} ]]; then + comment_reframe_fmt="
_ReFrame Summary_
__REFRAME_SUMMARY__
" + reframe_summary=${comment_reframe_fmt/__REFRAME_SUMMARY__/${grep_reframe_result}} + comment_description=${comment_description/__REFRAME_FMT__/${reframe_summary}} +else + comment_description=${comment_description/__REFRAME_FMT__/""} +fi + +# Declare functions +function print_br_item() { + format="${1}" + item="${2}" + echo -n "${format//__ITEM__/${item}}
" +} + +function success() { + format="${comment_success_item_fmt}" + item="$1" + print_br_item "${format}" "${item}" +} + +function failure() { + format="${comment_failure_item_fmt}" + item="$1" + print_br_item "${format}" "${item}" +} + +function add_detail() { + actual=${1} + expected=${2} + success_msg="${3}" + failure_msg="${4}" + if [[ ${actual} -eq ${expected} ]]; then + success "${success_msg}" + else + failure "${failure_msg}" + fi +} + +# first construct comment_details_list, abbreviated comment_details_list +# then use it to set comment_details +comment_details_list="" + +success_msg="job output file ${job_out}" +failure_msg="no job output file ${job_out}" +comment_details_list=${comment_details_list}$(add_detail ${SLURM_OUTPUT_FOUND} 1 "${success_msg}" "${failure_msg}") + +success_msg="no message matching ${GP_error}" +failure_msg="found message matching ${GP_error}" +comment_details_list=${comment_details_list}$(add_detail ${ERROR} 0 "${success_msg}" "${failure_msg}") + +# Add an escape character to every *, for it to be printed correctly in the comment on GitHub +GP_failed="${GP_failed//\*/\\*}" +success_msg="no message matching ""${GP_failed}""" +failure_msg="found message matching ""${GP_failed}""" +comment_details_list=${comment_details_list}$(add_detail ${FAILED} 0 "${success_msg}" "${failure_msg}") + +comment_details_fmt="
_Details_
__DETAILS_LIST__
" +comment_details="${comment_details_fmt/__DETAILS_LIST__/${comment_details_list}}" +comment_description=${comment_description/__DETAILS_FMT__/${comment_details}} + +# Actually writing the comment description to the result file +echo "${comment_description}" >> ${job_test_result_file} +echo "status = ${status}" >> ${job_test_result_file} + +exit 0 diff --git a/bot/inspect.sh b/bot/inspect.sh new file mode 100755 index 0000000000..533968bffc --- /dev/null +++ b/bot/inspect.sh @@ -0,0 +1,448 @@ +#!/usr/bin/env bash +# +# Script to inspect result of a build job for the EESSI software layer. +# Intended use is that it is called with a path to a job directory. +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Thomas Roeblitz (@trz42) +# +# license: GPLv2 +# + +# ASSUMPTIONs: +# - Script is executed on the same architecture the job was running on. +# - Initially, we also assume that is run on the same resource with the +# same (compute) node setup (local disk space, HTTP proxies, etc.) +# - The job directory being supplied has been prepared by the bot with a +# checkout of a pull request (OR by some other means) +# - The job directory contains a directory 'cfg' where the main config +# file 'job.cfg' has been deposited. +# - The 'cfg' directory may contain any additional files referenced in +# 'job.cfg' (repos.cfg, etc.). +# - The job produced some tarballs for its state (tmp disk for overlayfs, +# CVMFS cache, etc.) under 'previous_tmp/{build,tarball}_step'. + +# stop as soon as something fails +set -e + +# script_dir is the directory that contains THIS (inspect.sh) script, usually +# stored in the directory '.../bot' +script_dir=$(dirname $(realpath $BASH_SOURCE)) + +display_help() { + echo "usage: $0 [OPTIONS]" + echo " -h | --help - display this usage information" + echo " -r | --resume TGZ - inspect job saved in tarball path TGZ; note, we assume the path" + echo " to be something like JOB_DIR/previous_tmp/{build,tarball}_step/TARBALL.tgz" + echo " and thus determine JOB_DIR from the given path" + echo " [default: none]" + echo " -c | --command COMMAND - command to execute inside the container, in the prefix environment" + echo " -x | --http-proxy URL - provides URL for the environment variable http_proxy" + echo " -y | --https-proxy URL - provides URL for the environment variable https_proxy" +} + +resume_tgz= +http_proxy= +https_proxy= + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case ${1} in + -h|--help) + display_help + exit 0 + ;; + -r|--resume) + export resume_tgz="${2}" + shift 2 + ;; + -x|--http-proxy) + export http_proxy="${2}" + shift 2 + ;; + -y|--https-proxy) + export https_proxy="${2}" + shift 2 + ;; + -c|--command) + export run_in_prefix="${2}" + shift 2 + ;; + -*|--*) + echo "Error: Unknown option: ${1}" >&2 + exit 1 + ;; + *) # No more options + POSITIONAL_ARGS+=("${1}") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +# source utils.sh and cfg_files.sh +source ${script_dir}/../scripts/utils.sh +source ${script_dir}/../scripts/cfg_files.sh + +if [[ -z ${resume_tgz} ]]; then + echo_red "path to tarball for resuming build job is missing" + display_help + exit 1 +fi + +job_dir=$(dirname $(dirname $(dirname ${resume_tgz}))) + +if [[ -z ${job_dir} ]]; then + # job directory could be determined + echo_red "job directory could not be determined from '${resume_tgz}'" + display_help + exit 2 +fi + +# defaults +export JOB_CFG_FILE="${job_dir}/cfg/job.cfg" +HOST_ARCH=$(uname -m) + +# check if ${JOB_CFG_FILE} 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 "bot/inspect.sh: showing ${JOB_CFG_FILE} from software-layer side" +cat ${JOB_CFG_FILE} + +echo "bot/inspect.sh: obtaining configuration settings from '${JOB_CFG_FILE}'" +cfg_load ${JOB_CFG_FILE} + +# if http_proxy is defined in ${JOB_CFG_FILE} use it, if not use env var $http_proxy +HTTP_PROXY=$(cfg_get_value "site_config" "http_proxy") +HTTP_PROXY=${HTTP_PROXY:-${http_proxy}} +echo "bot/inspect.sh: HTTP_PROXY='${HTTP_PROXY}'" + +# if https_proxy is defined in ${JOB_CFG_FILE} use it, if not use env var $https_proxy +HTTPS_PROXY=$(cfg_get_value "site_config" "https_proxy") +HTTPS_PROXY=${HTTPS_PROXY:-${https_proxy}} +echo "bot/inspect.sh: HTTPS_PROXY='${HTTPS_PROXY}'" + +LOCAL_TMP=$(cfg_get_value "site_config" "local_tmp") +echo "bot/inspect.sh: LOCAL_TMP='${LOCAL_TMP}'" +# TODO should local_tmp be mandatory? --> then we check here and exit if it is not provided + +# check if path to copy build logs to is specified, so we can copy build logs for failing builds there +BUILD_LOGS_DIR=$(cfg_get_value "site_config" "build_logs_dir") +echo "bot/inspect.sh: BUILD_LOGS_DIR='${BUILD_LOGS_DIR}'" +# if $BUILD_LOGS_DIR is set, add it to $SINGULARITY_BIND so the path is available in the build container +if [[ ! -z ${BUILD_LOGS_DIR} ]]; then + mkdir -p ${BUILD_LOGS_DIR} + if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${BUILD_LOGS_DIR}" + else + export SINGULARITY_BIND="${SINGULARITY_BIND},${BUILD_LOGS_DIR}" + fi +fi + +SINGULARITY_CACHEDIR=$(cfg_get_value "site_config" "container_cachedir") +echo "bot/inspect.sh: SINGULARITY_CACHEDIR='${SINGULARITY_CACHEDIR}'" +if [[ ! -z ${SINGULARITY_CACHEDIR} ]]; then + # make sure that separate directories are used for different CPU families + SINGULARITY_CACHEDIR=${SINGULARITY_CACHEDIR}/${HOST_ARCH} + export SINGULARITY_CACHEDIR +fi + +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}'" + +# make sure ${STORAGE} exists +mkdir -p ${STORAGE} + +# make sure the base tmp storage is unique +JOB_STORAGE=$(mktemp --directory --tmpdir=${STORAGE} bot_job_tmp_XXX) +echo "bot/inspect.sh: created unique base tmp storage directory at ${JOB_STORAGE}" + +# obtain list of modules to be loaded +LOAD_MODULES=$(cfg_get_value "site_config" "load_modules") +echo "bot/inspect.sh: LOAD_MODULES='${LOAD_MODULES}'" + +# singularity/apptainer settings: CONTAINER, HOME, TMPDIR, BIND +CONTAINER=$(cfg_get_value "repository" "container") +echo "bot/inspect.sh: CONTAINER='${CONTAINER}'" +# instead of using ${PWD} as HOME in the container, we use the job directory +# to have access to output files of the job +export SINGULARITY_HOME="${job_dir}:/eessi_bot_job" +echo "bot/inspect.sh: SINGULARITY_HOME='${SINGULARITY_HOME}'" +export SINGULARITY_TMPDIR="${PWD}/singularity_tmpdir" +echo "bot/inspect.sh: SINGULARITY_TMPDIR='${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/inspect.sh: loading module '${mod}'" + module load ${mod} + done +else + echo "bot/inspect.sh: no modules to be loaded" +fi + +# determine repository to be used from entry .repository in ${JOB_CFG_FILE} +REPOSITORY=$(cfg_get_value "repository" "repo_id") +echo "bot/inspect.sh: REPOSITORY='${REPOSITORY}'" +# TODO better to read this from tarball??? +EESSI_REPOS_CFG_DIR_OVERRIDE=$(cfg_get_value "repository" "repos_cfg_dir") +export EESSI_REPOS_CFG_DIR_OVERRIDE=${EESSI_REPOS_CFG_DIR_OVERRIDE:-${PWD}/cfg} +echo "bot/inspect.sh: EESSI_REPOS_CFG_DIR_OVERRIDE='${EESSI_REPOS_CFG_DIR_OVERRIDE}'" + +# determine EESSI version to be used from .repository.repo_version in ${JOB_CFG_FILE} +# here, just set & export EESSI_VERSION_OVERRIDE +# next script (eessi_container.sh) makes use of it via sourcing init scripts +# (e.g., init/eessi_defaults or init/minimal_eessi_env) +export EESSI_VERSION_OVERRIDE=$(cfg_get_value "repository" "repo_version") +echo "bot/inspect.sh: EESSI_VERSION_OVERRIDE='${EESSI_VERSION_OVERRIDE}'" + +# determine CVMFS repo to be used from .repository.repo_name in ${JOB_CFG_FILE} +# here, just set EESSI_CVMFS_REPO_OVERRIDE, a bit further down +# "source init/eessi_defaults" via sourcing init/minimal_eessi_env +export EESSI_CVMFS_REPO_OVERRIDE="/cvmfs/$(cfg_get_value 'repository' 'repo_name')" +echo "bot/inspect.sh: EESSI_CVMFS_REPO_OVERRIDE='${EESSI_CVMFS_REPO_OVERRIDE}'" + +# determine architecture to be used from entry .architecture in ${JOB_CFG_FILE} +# fallbacks: +# - ${CPU_TARGET} handed over from bot +# - left empty to let downstream script(s) determine subdir to be used +EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(cfg_get_value "architecture" "software_subdir") +EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE:-${CPU_TARGET}} +export EESSI_SOFTWARE_SUBDIR_OVERRIDE +echo "bot/inspect.sh: EESSI_SOFTWARE_SUBDIR_OVERRIDE='${EESSI_SOFTWARE_SUBDIR_OVERRIDE}'" + +# get EESSI_OS_TYPE from .architecture.os_type in ${JOB_CFG_FILE} (default: linux) +EESSI_OS_TYPE=$(cfg_get_value "architecture" "os_type") +export EESSI_OS_TYPE=${EESSI_OS_TYPE:-linux} +echo "bot/inspect.sh: EESSI_OS_TYPE='${EESSI_OS_TYPE}'" + +# prepare arguments to eessi_container.sh common to build and tarball steps +declare -a CMDLINE_ARGS=() +CMDLINE_ARGS+=("--verbose") +CMDLINE_ARGS+=("--access" "rw") +CMDLINE_ARGS+=("--mode" "run") +[[ ! -z ${CONTAINER} ]] && CMDLINE_ARGS+=("--container" "${CONTAINER}") +[[ ! -z ${HTTP_PROXY} ]] && CMDLINE_ARGS+=("--http-proxy" "${HTTP_PROXY}") +[[ ! -z ${HTTPS_PROXY} ]] && CMDLINE_ARGS+=("--https-proxy" "${HTTPS_PROXY}") +[[ ! -z ${REPOSITORY} ]] && CMDLINE_ARGS+=("--repository" "${REPOSITORY}") + +[[ ! -z ${resume_tgz} ]] && CMDLINE_ARGS+=("--resume" "${resume_tgz}") + +# create a directory for creating temporary data and scripts for the inspection +INSPECT_DIR=$(mktemp --directory --tmpdir=${PWD} inspect.XXX) +if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${INSPECT_DIR}:/inspect_eessi_build_job" +else + export SINGULARITY_BIND="${SINGULARITY_BIND},${INSPECT_DIR}:/inspect_eessi_build_job" +fi + +# add arguments for temporary storage and storing a tarball of tmp +CMDLINE_ARGS+=("--save" "${INSPECT_DIR}") +CMDLINE_ARGS+=("--storage" "${JOB_STORAGE}") + +# # prepare arguments to install_software_layer.sh (specific to build step) +# declare -a INSTALL_SCRIPT_ARGS=() +# if [[ ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} =~ .*/generic$ ]]; then +# INSTALL_SCRIPT_ARGS+=("--generic") +# fi +# [[ ! -z ${BUILD_LOGS_DIR} ]] && INSTALL_SCRIPT_ARGS+=("--build-logs-dir" "${BUILD_LOGS_DIR}") + +# make sure some environment settings are available inside the shell started via +# startprefix +# TODO better use script from tarball??? +source ${script_dir}/../init/eessi_defaults + +if [ -z $EESSI_VERSION ]; then + echo "ERROR: \$EESSI_VERSION must be set!" >&2 + exit 1 +fi +EESSI_COMPAT_LAYER_DIR="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)" + +# NOTE The below requires access to the CVMFS repository. We could make a first +# test run with a container. For now we skip the test. +# if [ ! -d ${EESSI_COMPAT_LAYER_DIR} ]; then +# echo "ERROR: ${EESSI_COMPAT_LAYER_DIR} does not exist!" >&2 +# exit 1 +# fi + +# When we want to run a script with arguments, the next line is ensures to retain +# these arguments. +# INPUT=$(echo "$@") +mkdir -p ${INSPECT_DIR}/scripts +RESUME_SCRIPT=${INSPECT_DIR}/scripts/resume_env.sh +echo "bot/inspect.sh: creating script '${RESUME_SCRIPT}' to resume environment settings" + +cat << EOF > ${RESUME_SCRIPT} +#!${EESSI_COMPAT_LAYER_DIR}/bin/bash +echo "Sourcing '\$BASH_SOURCE' to init bot environment of build job" +EOF +if [ ! -z ${SLURM_JOB_ID} ]; then + # TODO do we need the value at all? if so which one: current or of the job to + # inspect? + echo "export CURRENT_SLURM_JOB_ID=${SLURM_JOB_ID}" >> ${RESUME_SCRIPT} +fi +if [ ! -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then + echo "export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" >> ${RESUME_SCRIPT} +fi +if [ ! -z ${EESSI_CVMFS_REPO_OVERRIDE} ]; then + echo "export EESSI_CVMFS_REPO_OVERRIDE=${EESSI_CVMFS_REPO_OVERRIDE}" >> ${RESUME_SCRIPT} +fi +if [ ! -z ${EESSI_VERSION_OVERRIDE} ]; then + echo "export EESSI_VERSION_OVERRIDE=${EESSI_VERSION_OVERRIDE}" >> ${RESUME_SCRIPT} +fi +if [ ! -z ${http_proxy} ]; then + echo "export http_proxy=${http_proxy}" >> ${RESUME_SCRIPT} +fi +if [ ! -z ${https_proxy} ]; then + echo "export https_proxy=${https_proxy}" >> ${RESUME_SCRIPT} +fi +cat << 'EOF' >> ${RESUME_SCRIPT} +TOPDIR=$(dirname $(realpath $BASH_SOURCE)) + +source ${TOPDIR}/scripts/utils.sh + +# honor $TMPDIR if it is already defined, use /tmp otherwise +if [ -z $TMPDIR ]; then + export WORKDIR=/tmp/$USER +else + export WORKDIR=$TMPDIR/$USER +fi + +TMPDIR=$(mktemp -d) + +echo ">> Setting up environment..." + +source $TOPDIR/init/minimal_eessi_env + +if [ -d $EESSI_CVMFS_REPO ]; then + echo_green "$EESSI_CVMFS_REPO available, OK!" +else + fatal_error "$EESSI_CVMFS_REPO is not available!" +fi + +# make sure we're in Prefix environment by checking $SHELL +if [[ ${SHELL} = ${EPREFIX}/bin/bash ]]; then + echo_green ">> It looks like we're in a Gentoo Prefix environment, good!" +else + fatal_error "Not running in Gentoo Prefix environment, run '${EPREFIX}/startprefix' first!" +fi + +# avoid that pyc files for EasyBuild are stored in EasyBuild installation directory +export PYTHONPYCACHEPREFIX=$TMPDIR/pycache + +DETECTION_PARAMETERS='' +GENERIC=0 +EB='eb' +if [[ "$EASYBUILD_OPTARCH" == "GENERIC" || "$EESSI_SOFTWARE_SUBDIR_OVERRIDE" == *"/generic" ]]; then + echo_yellow ">> GENERIC build requested, taking appropriate measures!" + DETECTION_PARAMETERS="$DETECTION_PARAMETERS --generic" + GENERIC=1 + export EASYBUILD_OPTARCH=GENERIC + EB='eb --optarch=GENERIC' +fi + +echo ">> Determining software subdirectory to use for current build host..." +if [ -z $EESSI_SOFTWARE_SUBDIR_OVERRIDE ]; then + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(python3 $TOPDIR/eessi_software_subdir.py $DETECTION_PARAMETERS) + echo ">> Determined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE via 'eessi_software_subdir.py $DETECTION_PARAMETERS' script" +else + echo ">> Picking up pre-defined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE: ${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" +fi + +# Set all the EESSI environment variables (respecting $EESSI_SOFTWARE_SUBDIR_OVERRIDE) +# $EESSI_SILENT - don't print any messages +# $EESSI_BASIC_ENV - give a basic set of environment variables +EESSI_SILENT=1 EESSI_BASIC_ENV=1 source $TOPDIR/init/eessi_environment_variables + +if [[ -z ${EESSI_SOFTWARE_SUBDIR} ]]; then + fatal_error "Failed to determine software subdirectory?!" +elif [[ "${EESSI_SOFTWARE_SUBDIR}" != "${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" ]]; then + fatal_error "Values for EESSI_SOFTWARE_SUBDIR_OVERRIDE (${EESSI_SOFTWARE_SUBDIR_OVERRIDE}) and EESSI_SOFTWARE_SUBDIR (${EESSI_SOFTWARE_SUBDIR}) differ!" +else + echo_green ">> Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory!" +fi + +echo ">> Initializing Lmod..." +source $EPREFIX/usr/share/Lmod/init/bash +ml_version_out=$TMPDIR/ml.out +ml --version &> $ml_version_out +if [[ $? -eq 0 ]]; then + echo_green ">> Found Lmod ${LMOD_VERSION}" +else + fatal_error "Failed to initialize Lmod?! (see output in ${ml_version_out}" +fi + +echo ">> Configuring EasyBuild..." +source $TOPDIR/configure_easybuild + +echo ">> Setting up \$MODULEPATH..." +# make sure no modules are loaded +module --force purge +# ignore current $MODULEPATH entirely +module unuse $MODULEPATH +module use $EASYBUILD_INSTALLPATH/modules/all +if [[ -z ${MODULEPATH} ]]; then + fatal_error "Failed to set up \$MODULEPATH?!" +else + echo_green ">> MODULEPATH set up: ${MODULEPATH}" +fi + +echo +echo_green "Build environment set up with install path ${EASYBUILD_INSTALLPATH}." +echo +echo "The build job can be inspected with the following resources:" +echo " - job directory is $HOME (\$HOME), check for slurm-*.out file" +echo " - temporary data of the job is available at /tmp" +echo " - note, the prefix $EESSI_PREFIX is writable" +echo +echo "You may want to load an EasyBuild module. The inspect.sh script does not load" +echo "that automatically, because multiple versions might have been used by the job." +echo "Choose an EasyBuild version (see installed versions with 'module avail EasyBuild')" +echo "and simply run" +echo +echo "module load EasyBuild/_VERSION_" +echo +echo "Replace _VERSION_ with the version you want to use." +echo + +EOF +chmod u+x ${RESUME_SCRIPT} + +# try to map it into the container's $HOME/.profile instead +# TODO check if script already exists, if so change its name and source it at the beginning of the RESUME_SCRIPT +if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${RESUME_SCRIPT}:/eessi_bot_job/.profile" +else + export SINGULARITY_BIND="${SINGULARITY_BIND},${RESUME_SCRIPT}:/eessi_bot_job/.profile" +fi + +echo "Executing command to start interactive session to inspect build job:" +# TODO possibly add information on how to init session after the prefix is +# entered, initialization consists of +# - environment variable settings (see 'run_in_compat_layer_env.sh') +# - setup steps run in 'EESSI-install-software.sh' +# These initializations are combined into a single script that is executed when +# the shell in startprefix is started. We set the env variable BASH_ENV here. +if [[ -z ${run_in_prefix} ]]; then + echo "${script_dir}/../eessi_container.sh ${CMDLINE_ARGS[@]}" + echo " -- ${EESSI_COMPAT_LAYER_DIR}/startprefix" + ${script_dir}/../eessi_container.sh "${CMDLINE_ARGS[@]}" \ + -- ${EESSI_COMPAT_LAYER_DIR}/startprefix +else + echo "${script_dir}/../eessi_container.sh ${CMDLINE_ARGS[@]}" + echo " -- ${EESSI_COMPAT_LAYER_DIR}/startprefix <<< ${run_in_prefix}" + ${script_dir}/../eessi_container.sh "${CMDLINE_ARGS[@]}" \ + -- ${EESSI_COMPAT_LAYER_DIR}/startprefix <<< ${run_in_prefix} +fi + +exit 0 diff --git a/bot/test.sh b/bot/test.sh new file mode 100755 index 0000000000..464c4817a9 --- /dev/null +++ b/bot/test.sh @@ -0,0 +1,241 @@ +#!/usr/bin/env bash +# +# script to run tests or the test suite for the whole EESSI software layer or +# just what has been built in a job. Intended use is that it is called +# at the end of 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) +# author: Caspar van Leeuwen (@casparvl) +# +# license: GPLv2 +# + +# ASSUMPTIONs: +# + assumption for the build step (as run through bot/build.sh which is provided +# in this repository too) +# - 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 referenced in job.cfg +# + assumptions for the test step +# - temporary storage is still available +# example +# Using /localscratch/9640860/NESSI/eessi.x765Dd8mFh as tmp directory (to resume session add '--resume /localscratch/9640860/NESSI/eessi.x765Dd8mFh'). +# - run test-suite.sh inside build container using tmp storage from build step +# plus possibly additional settings (repo, etc.) +# - needed setup steps may be similar to bot/inspect.sh (PR#317) + +# stop as soon as something fails +set -e + +# source utils.sh and cfg_files.sh +source scripts/utils.sh +source scripts/cfg_files.sh + +# defaults +export JOB_CFG_FILE="${JOB_CFG_FILE_OVERRIDE:=./cfg/job.cfg}" +HOST_ARCH=$(uname -m) + +# check if ${JOB_CFG_FILE} 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 "bot/test.sh: showing ${JOB_CFG_FILE} from software-layer side" +cat ${JOB_CFG_FILE} + +echo "bot/test.sh: obtaining configuration settings from '${JOB_CFG_FILE}'" +cfg_load ${JOB_CFG_FILE} + +# if http_proxy is defined in ${JOB_CFG_FILE} use it, if not use env var $http_proxy +HTTP_PROXY=$(cfg_get_value "site_config" "http_proxy") +HTTP_PROXY=${HTTP_PROXY:-${http_proxy}} +echo "bot/test.sh: HTTP_PROXY='${HTTP_PROXY}'" + +# if https_proxy is defined in ${JOB_CFG_FILE} use it, if not use env var $https_proxy +HTTPS_PROXY=$(cfg_get_value "site_config" "https_proxy") +HTTPS_PROXY=${HTTPS_PROXY:-${https_proxy}} +echo "bot/test.sh: HTTPS_PROXY='${HTTPS_PROXY}'" + +LOCAL_TMP=$(cfg_get_value "site_config" "local_tmp") +echo "bot/test.sh: LOCAL_TMP='${LOCAL_TMP}'" +# TODO should local_tmp be mandatory? --> then we check here and exit if it is not provided + +# check if path to copy build logs to is specified, so we can copy build logs for failing builds there +BUILD_LOGS_DIR=$(cfg_get_value "site_config" "build_logs_dir") +echo "bot/test.sh: BUILD_LOGS_DIR='${BUILD_LOGS_DIR}'" +# if $BUILD_LOGS_DIR is set, add it to $SINGULARITY_BIND so the path is available in the build container +if [[ ! -z ${BUILD_LOGS_DIR} ]]; then + mkdir -p ${BUILD_LOGS_DIR} + if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${BUILD_LOGS_DIR}" + else + export SINGULARITY_BIND="${SINGULARITY_BIND},${BUILD_LOGS_DIR}" + fi +fi + +# check if path to directory on shared filesystem is specified, +# and use it as location for source tarballs used by EasyBuild if so +SHARED_FS_PATH=$(cfg_get_value "site_config" "shared_fs_path") +echo "bot/test.sh: SHARED_FS_PATH='${SHARED_FS_PATH}'" +# if $SHARED_FS_PATH is set, add it to $SINGULARITY_BIND so the path is available in the build container +if [[ ! -z ${SHARED_FS_PATH} ]]; then + mkdir -p ${SHARED_FS_PATH} + if [[ -z ${SINGULARITY_BIND} ]]; then + export SINGULARITY_BIND="${SHARED_FS_PATH}" + else + export SINGULARITY_BIND="${SINGULARITY_BIND},${SHARED_FS_PATH}" + fi +fi + +SINGULARITY_CACHEDIR=$(cfg_get_value "site_config" "container_cachedir") +echo "bot/test.sh: SINGULARITY_CACHEDIR='${SINGULARITY_CACHEDIR}'" +if [[ ! -z ${SINGULARITY_CACHEDIR} ]]; then + # make sure that separate directories are used for different CPU families + SINGULARITY_CACHEDIR=${SINGULARITY_CACHEDIR}/${HOST_ARCH} + export SINGULARITY_CACHEDIR +fi + +# try to determine tmp directory from build job +RESUME_DIR=$(grep 'Using .* as tmp directory' slurm-${SLURM_JOBID}.out | head -1 | awk '{print $2}') + +if [[ -z ${RESUME_DIR} ]]; then + RESUME_TGZ=${PWD}/previous_tmp/build_step/$(ls previous_tmp/build_step) + if [[ -z ${RESUME_TGZ} ]]; then + echo "bot/test.sh: no information about tmp directory and tarball of build step; --> giving up" + exit 2 + fi +fi + +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}'" + +# make sure ${STORAGE} exists +mkdir -p ${STORAGE} + +# make sure the base tmp storage is unique +JOB_STORAGE=$(mktemp --directory --tmpdir=${STORAGE} bot_job_tmp_XXX) +echo "bot/test.sh: created unique base tmp storage directory at ${JOB_STORAGE}" + +# obtain list of modules to be loaded +LOAD_MODULES=$(cfg_get_value "site_config" "load_modules") +echo "bot/test.sh: LOAD_MODULES='${LOAD_MODULES}'" + +# singularity/apptainer settings: CONTAINER, HOME, TMPDIR, BIND +CONTAINER=$(cfg_get_value "repository" "container") +export SINGULARITY_HOME="${PWD}:/eessi_bot_job" +export SINGULARITY_TMPDIR="${JOB_STORAGE:-${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/test.sh: loading module '${mod}'" + module load ${mod} + done +else + echo "bot/test.sh: no modules to be loaded" +fi + +# determine repository to be used from entry .repository in ${JOB_CFG_FILE} +REPOSITORY=$(cfg_get_value "repository" "repo_id") +EESSI_REPOS_CFG_DIR_OVERRIDE=$(cfg_get_value "repository" "repos_cfg_dir") +export EESSI_REPOS_CFG_DIR_OVERRIDE=${EESSI_REPOS_CFG_DIR_OVERRIDE:-${PWD}/cfg} +echo "bot/test.sh: EESSI_REPOS_CFG_DIR_OVERRIDE='${EESSI_REPOS_CFG_DIR_OVERRIDE}'" + +# determine pilot version to be used from .repository.repo_version in ${JOB_CFG_FILE} +# here, just set & export EESSI_PILOT_VERSION_OVERRIDE +# next script (eessi_container.sh) makes use of it via sourcing init scripts +# (e.g., init/eessi_defaults or init/minimal_eessi_env) +export EESSI_PILOT_VERSION_OVERRIDE=$(cfg_get_value "repository" "repo_version") +echo "bot/test.sh: EESSI_PILOT_VERSION_OVERRIDE='${EESSI_PILOT_VERSION_OVERRIDE}'" + +# determine CVMFS repo to be used from .repository.repo_name in ${JOB_CFG_FILE} +# here, just set EESSI_CVMFS_REPO_OVERRIDE, a bit further down +# "source init/eessi_defaults" via sourcing init/minimal_eessi_env +export EESSI_CVMFS_REPO_OVERRIDE=/cvmfs/$(cfg_get_value "repository" "repo_name") +echo "bot/test.sh: EESSI_CVMFS_REPO_OVERRIDE='${EESSI_CVMFS_REPO_OVERRIDE}'" + +# determine architecture to be used from entry .architecture in ${JOB_CFG_FILE} +# fallbacks: +# - ${CPU_TARGET} handed over from bot +# - left empty to let downstream script(s) determine subdir to be used +EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(cfg_get_value "architecture" "software_subdir") +EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE:-${CPU_TARGET}} +export EESSI_SOFTWARE_SUBDIR_OVERRIDE +echo "bot/test.sh: EESSI_SOFTWARE_SUBDIR_OVERRIDE='${EESSI_SOFTWARE_SUBDIR_OVERRIDE}'" + +# determine accelerator target (if any) from .architecture in ${JOB_CFG_FILE} +export EESSI_ACCELERATOR_TARGET=$(cfg_get_value "architecture" "accelerator") +echo "bot/test.sh: EESSI_ACCELERATOR_TARGET='${EESSI_ACCELERATOR_TARGET}'" + +# get EESSI_OS_TYPE from .architecture.os_type in ${JOB_CFG_FILE} (default: linux) +EESSI_OS_TYPE=$(cfg_get_value "architecture" "os_type") +export EESSI_OS_TYPE=${EESSI_OS_TYPE:-linux} +echo "bot/test.sh: EESSI_OS_TYPE='${EESSI_OS_TYPE}'" + +# prepare arguments to eessi_container.sh common to build and tarball steps +declare -a COMMON_ARGS=() +COMMON_ARGS+=("--verbose") +COMMON_ARGS+=("--access" "ro") +COMMON_ARGS+=("--mode" "run") +[[ ! -z ${CONTAINER} ]] && COMMON_ARGS+=("--container" "${CONTAINER}") +[[ ! -z ${HTTP_PROXY} ]] && COMMON_ARGS+=("--http-proxy" "${HTTP_PROXY}") +[[ ! -z ${HTTPS_PROXY} ]] && COMMON_ARGS+=("--https-proxy" "${HTTPS_PROXY}") +[[ ! -z ${REPOSITORY} ]] && COMMON_ARGS+=("--repository" "${REPOSITORY}") + +# make sure to use the same parent dir for storing tarballs of tmp +PREVIOUS_TMP_DIR=${PWD}/previous_tmp + +# prepare directory to store tarball of tmp for test step +TARBALL_TMP_TEST_STEP_DIR=${PREVIOUS_TMP_DIR}/test_step +mkdir -p ${TARBALL_TMP_TEST_STEP_DIR} + +# prepare arguments to eessi_container.sh specific to test step +declare -a TEST_STEP_ARGS=() +TEST_STEP_ARGS+=("--save" "${TARBALL_TMP_TEST_STEP_DIR}") + +if [[ -z ${RESUME_DIR} ]]; then + TEST_STEP_ARGS+=("--storage" "${STORAGE}") + TEST_STEP_ARGS+=("--resume" "${RESUME_TGZ}") +else + TEST_STEP_ARGS+=("--resume" "${RESUME_DIR}") +fi +# Bind mount /sys/fs/cgroup so that we can determine the amount of memory available in our cgroup for +# Reframe configuration +TEST_STEP_ARGS+=("--extra-bind-paths" "/sys/fs/cgroup:/hostsys/fs/cgroup:ro") + +# add options required to handle NVIDIA support +if command_exists "nvidia-smi"; then + echo "Command 'nvidia-smi' found, using available GPU" + TEST_STEP_ARGS+=("--nvidia" "run") +fi + +# prepare arguments to test_suite.sh (specific to test step) +declare -a TEST_SUITE_ARGS=() +if [[ ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} =~ .*/generic$ ]]; then + TEST_SUITE_ARGS+=("--generic") +fi +if [[ ${SHARED_FS_PATH} ]]; then + TEST_SUITE_ARGS+=("--shared-fs-path" "${SHARED_FS_PATH}") +fi +# [[ ! -z ${BUILD_LOGS_DIR} ]] && TEST_SUITE_ARGS+=("--build-logs-dir" "${BUILD_LOGS_DIR}") +# [[ ! -z ${SHARED_FS_PATH} ]] && TEST_SUITE_ARGS+=("--shared-fs-path" "${SHARED_FS_PATH}") + +# create tmp file for output of build step +test_outerr=$(mktemp test.outerr.XXXX) + +echo "Executing command to test software:" +echo "./eessi_container.sh ${COMMON_ARGS[@]} ${TEST_STEP_ARGS[@]}" +echo " -- ./run_tests.sh \"${TEST_SUITE_ARGS[@]}\" \"$@\" 2>&1 | tee -a ${test_outerr}" +./eessi_container.sh "${COMMON_ARGS[@]}" "${TEST_STEP_ARGS[@]}" \ + -- ./run_tests.sh "${TEST_SUITE_ARGS[@]}" "$@" 2>&1 | tee -a ${test_outerr} + +exit 0 diff --git a/build_container.sh b/build_container.sh deleted file mode 100755 index 23a9e665c9..0000000000 --- a/build_container.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -base_dir=$(dirname $(realpath $0)) - -BUILD_CONTAINER="docker://ghcr.io/eessi/build-node:debian11" - -if [ $# -lt 2 ]; then - echo "Usage: $0 " >&2 - exit 1 -fi -SHELL_OR_RUN=$1 -EESSI_TMPDIR=$2 -shift 2 - -if [ "$SHELL_OR_RUN" == "run" ] && [ $# -eq 0 ]; then - echo "ERROR: No command specified to run?!" >&2 - exit 1 -fi - -# make sure specified temporary directory exists -mkdir -p $EESSI_TMPDIR - -echo "Using $EESSI_TMPDIR as parent for temporary directories..." - -# create temporary directories -mkdir -p $EESSI_TMPDIR/{home,overlay-upper,overlay-work} -mkdir -p $EESSI_TMPDIR/{var-lib-cvmfs,var-run-cvmfs} -# configure Singularity -export SINGULARITY_CACHEDIR=$EESSI_TMPDIR/singularity_cache - -# take into account that $SINGULARITY_BIND may be defined already, to bind additional paths into the build container -BIND_PATHS="$EESSI_TMPDIR/var-run-cvmfs:/var/run/cvmfs,$EESSI_TMPDIR/var-lib-cvmfs:/var/lib/cvmfs,$EESSI_TMPDIR" -if [ -z $SINGULARITY_BIND ]; then - export SINGULARITY_BIND="$BIND_PATHS" -else - export SINGULARITY_BIND="$SINGULARITY_BIND,$BIND_PATHS" -fi - -# allow that SINGULARITY_HOME is defined before script is run -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 ${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 - 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 - -if [ "$SHELL_OR_RUN" == "shell" ]; then - # start shell in Singularity container, with EESSI repository mounted with writable overlay - echo "Starting Singularity build container..." - singularity shell --fusemount "$EESSI_PILOT_READONLY" --fusemount "$EESSI_PILOT_WRITABLE_OVERLAY" $BUILD_CONTAINER -elif [ "$SHELL_OR_RUN" == "run" ]; then - echo "Running '$@' in Singularity build container..." - singularity exec --fusemount "$EESSI_PILOT_READONLY" --fusemount "$EESSI_PILOT_WRITABLE_OVERLAY" $BUILD_CONTAINER "$@" -else - echo "ERROR: Unknown action specified: $SHELL_OR_RUN (should be either 'shell' or 'run')" >&2 - exit 1 -fi diff --git a/check_missing_installations.sh b/check_missing_installations.sh index 4a5316c09f..79f6acc733 100755 --- a/check_missing_installations.sh +++ b/check_missing_installations.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Script to check for missing installations in EESSI pilot software stack (version 2021.12) +# Script to check for missing installations in EESSI software stack # # author: Kenneth Hoste (@boegel) # author: Thomas Roeblitz (@trz42) @@ -10,10 +10,18 @@ TOPDIR=$(dirname $(realpath $0)) -if [ -z ${EESSI_PILOT_VERSION} ]; then - echo "ERROR: \${EESSI_PILOT_VERSION} must be set to run $0!" >&2 +if [ "$#" -eq 1 ]; then + true +elif [ "$#" -eq 2 ]; then + echo "Using $2 to give create exceptions for PR filtering of easystack" + # Find lines that are added and use from-pr, make them unique, grab the + # PR numbers and use them to construct something we can use within awk + pr_exceptions=$(grep ^+ $2 | grep from-pr | uniq | awk '{print $3}' | xargs -i echo " || /'{}'/") +else + echo "ERROR: Usage: $0 ()" >&2 exit 1 fi +easystack=$1 LOCAL_TMPDIR=$(mktemp -d) @@ -21,15 +29,17 @@ source $TOPDIR/scripts/utils.sh source $TOPDIR/configure_easybuild +echo ">> Active EasyBuild configuration when checking for missing installations:" +${EB:-eb} --show-config + echo ">> Checking for missing installations in ${EASYBUILD_INSTALLPATH}..." eb_missing_out=$LOCAL_TMPDIR/eb_missing.out -# we need to use --from-pr to pull in some easyconfigs that are not available in EasyBuild version being used -# PR #16531: Nextflow-22.10.1.eb -${EB:-eb} --from-pr 16531 --easystack eessi-${EESSI_PILOT_VERSION}.yml --experimental --missing 2>&1 | tee ${eb_missing_out} +${EB:-eb} --easystack ${easystack} --missing 2>&1 | tee ${eb_missing_out} exit_code=${PIPESTATUS[0]} ok_msg="Command 'eb --missing ...' succeeded, analysing output..." fail_msg="Command 'eb --missing ...' failed, check log '${eb_missing_out}'" + check_exit_code ${exit_code} "${ok_msg}" "${fail_msg}" # the above assesses the installed software for each easyconfig provided in diff --git a/configure_easybuild b/configure_easybuild index 245553f342..3b6d40cd96 100644 --- a/configure_easybuild +++ b/configure_easybuild @@ -1,7 +1,26 @@ +# if $WORKDIR is not defined, use a local temporary directory +if [ -z ${WORKDIR} ]; then + WORKDIR=$(mktemp -d) +fi + export EASYBUILD_PREFIX=${WORKDIR}/easybuild export EASYBUILD_INSTALLPATH=${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_SOFTWARE_SUBDIR} export EASYBUILD_SOURCEPATH=${WORKDIR}/easybuild/sources:${EESSI_SOURCEPATH} +# take into account accelerator target (if specified via $EESSI_ACCELERATOR_TARGET) +if [ ! -z ${EESSI_ACCELERATOR_TARGET} ]; then + if [[ "${EESSI_ACCELERATOR_TARGET}" =~ ^nvidia/cc[0-9][0-9]$ ]]; then + # tweak path to installation directories used by EasyBuild + export EASYBUILD_INSTALLPATH=${EASYBUILD_INSTALLPATH}/accel/${EESSI_ACCELERATOR_TARGET} + # nvidia/cc80 should result in setting $EASYBUILD_CUDA_COMPUTE_CAPABILITIES to '8.0' + export EASYBUILD_CUDA_COMPUTE_CAPABILITIES=$(echo ${EESSI_ACCELERATOR_TARGET} | cut -f2 -d/ | sed 's/^cc\([0-9]\)\([0-9]\)/\1.\2/g') + else + fatal_error "Incorrect value for \$EESSI_ACCELERATOR_TARGET: ${EESSI_ACCELERATOR_TARGET}" + fi +else + echo_yellow "(configure_easybuild) \$EESSI_ACCELERATOR_TARGET not defined" +fi + # just ignore OS dependencies for now, see https://github.com/easybuilders/easybuild-framework/issues/3430 export EASYBUILD_IGNORE_OSDEPS=1 @@ -25,14 +44,22 @@ fi # note: filtering Bison may break some installations, like Qt5 (see https://github.com/EESSI/software-layer/issues/49) # filtering pkg-config breaks R-bundle-Bioconductor installation (see also https://github.com/easybuilders/easybuild-easyconfigs/pull/11104) -# problems occur when filtering pkg-config with gnuplot too (picks up Lua 5.1 from $EPREFIX rather than from Lua 5.3 dependency) -DEPS_TO_FILTER=Autoconf,Automake,Autotools,binutils,bzip2,cURL,DBus,flex,gettext,gperf,help2man,intltool,libreadline,libtool,Lua,M4,makeinfo,ncurses,util-linux,XZ,zlib +DEPS_TO_FILTER=Autoconf,Automake,Autotools,binutils,bzip2,DBus,flex,gettext,gperf,help2man,intltool,libreadline,libtool,M4,makeinfo,ncurses,util-linux,XZ,zlib # For aarch64 we need to also filter out Yasm. # See https://github.com/easybuilders/easybuild-easyconfigs/issues/11190 if [[ "$EESSI_CPU_FAMILY" == "aarch64" ]]; then DEPS_TO_FILTER="${DEPS_TO_FILTER},Yasm" fi +# Version 23.06 of EESSI ships PSM2 in the compat layer, so we can filter this out while retaining support for OFA fabric +# (longer term this is probably not the right move as PSM2 should be configured with accelerator support, hence the restricted version) +if [[ "$EESSI_VERSION" == "2023.06" ]]; then + DEPS_TO_FILTER="${DEPS_TO_FILTER},PSM2" +fi + export EASYBUILD_FILTER_DEPS=$DEPS_TO_FILTER export EASYBUILD_MODULE_EXTENSIONS=1 + +# need to enable use of experimental features, since we're using easystack files +export EASYBUILD_EXPERIMENTAL=1 diff --git a/create_directory_tarballs.sh b/create_directory_tarballs.sh index 70e666f871..0270719a73 100755 --- a/create_directory_tarballs.sh +++ b/create_directory_tarballs.sh @@ -1,7 +1,5 @@ #!/bin/bash -SOFTWARE_LAYER_TARBALL_URL=https://github.com/EESSI/software-layer/tarball/main - set -eo pipefail if [ $# -ne 1 ]; then @@ -11,6 +9,8 @@ fi version=$1 +SOFTWARE_LAYER_TARBALL_URL="https://github.com/EESSI/software-layer/tarball/${version}-software.eessi.io" + TOPDIR=$(dirname $(realpath $0)) source $TOPDIR/scripts/utils.sh @@ -28,9 +28,9 @@ mkdir "${tartmp}/${version}" tarname="eessi-${version}-init-$(date +%s).tar.gz" curl -Ls ${SOFTWARE_LAYER_TARBALL_URL} | tar xzf - -C "${tartmp}/${version}" --strip-components=1 --no-wildcards-match-slash --wildcards '*/init/' source "${tartmp}/${version}/init/minimal_eessi_env" -if [ "${EESSI_PILOT_VERSION}" != "${version}" ] +if [ "${EESSI_VERSION}" != "${version}" ] then - fatal_error "Specified version ${version} does not match version ${EESSI_PILOT_VERSION} in the init files!" + fatal_error "Specified version ${version} does not match version ${EESSI_VERSION} in the init files!" fi tar czf "${tarname}" -C "${tartmp}" "${version}" rm -rf "${tartmp}" diff --git a/create_lmodrc.py b/create_lmodrc.py index ae65153a20..1720b762f0 100755 --- a/create_lmodrc.py +++ b/create_lmodrc.py @@ -7,6 +7,7 @@ DOT_LMOD = '.lmod' +# LMOD_RC file is the place to define properties, see https://lmod.readthedocs.io/en/latest/145_properties.html TEMPLATE_LMOD_RC = """propT = { } scDescriptT = { @@ -32,6 +33,12 @@ def error(msg): error("Prefix directory %s does not exist!" % prefix) lmodrc_path = os.path.join(prefix, DOT_LMOD, 'lmodrc.lua') +# Lmod itself doesn't care about the accelerator subdir so remove this duplication from +# the target path (if it exists) +accel_subdir = os.getenv("EESSI_ACCELERATOR_TARGET") +if accel_subdir: + lmodrc_path = lmodrc_path.replace("/accel/%s" % accel_subdir, '') + lmodrc_txt = TEMPLATE_LMOD_RC % { 'dot_lmod': DOT_LMOD, 'prefix': prefix, diff --git a/create_lmodsitepackage.py b/create_lmodsitepackage.py new file mode 100755 index 0000000000..4f3d6771ff --- /dev/null +++ b/create_lmodsitepackage.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +# +# Create SitePackage.lua configuration file for Lmod. +# +import os +import sys +from stat import S_IREAD, S_IWRITE, S_IRGRP, S_IWGRP, S_IROTH + +DOT_LMOD = '.lmod' + +hook_prologue = """require("strict") +local hook = require("Hook") +local open = io.open + +""" + +hook_txt = """ +local function read_file(path) + local file = open(path, "rb") -- r read mode and b binary mode + if not file then return nil end + local content = file:read "*a" -- *a or *all reads the whole file + file:close() + return content +end + +local function from_eessi_prefix(t) + -- eessi_prefix is the prefix with official EESSI modules + -- e.g. /cvmfs/software.eessi.io/versions/2023.06 + local eessi_prefix = os.getenv("EESSI_PREFIX") + + -- If EESSI_PREFIX wasn't defined, we cannot check if this module was from the EESSI environment + -- In that case, we assume it isn't, otherwise EESSI_PREFIX would (probably) have been set + if eessi_prefix == nil then + return false + else + -- NOTE: exact paths for site so may need to be updated later. + -- See https://github.com/EESSI/software-layer/pull/371 + + -- eessi_prefix_host_injections is the prefix with site-extensions (i.e. additional modules) + -- to the official EESSI modules, e.g. /cvmfs/software.eessi.io/host_injections/2023.06 + local eessi_prefix_host_injections = string.gsub(eessi_prefix, 'versions', 'host_injections') + + -- Check if the full modulepath starts with the eessi_prefix_* + return string.find(t.fn, "^" .. eessi_prefix) ~= nil or string.find(t.fn, "^" .. eessi_prefix_host_injections) ~= nil + end +end + +local function load_site_specific_hooks() + -- This function will be run after the EESSI hooks are registered + -- It will load a local SitePackage.lua that is architecture independent (if it exists) from e.g. + -- /cvmfs/software.eessi.io/host_injections/2023.06/.lmod/SitePackage.lua + -- That can define a new hook + -- + -- function site_specific_load_hook(t) + -- + -- end + -- + -- And the either append to the existing hook: + -- + -- local function final_load_hook(t) + -- eessi_load_hook(t) + -- site_specific_load_hook(t) + -- end + -- + -- Over overwrite the EESSI hook entirely: + -- + -- hook.register("load", final_load_hook) + -- + -- Note that the appending procedure can be simplified once we have an lmod >= 8.7.36 + -- See https://github.com/TACC/Lmod/pull/696#issuecomment-1998765722 + -- + -- Subsequently, this function will look for an architecture-specific SitePackage.lua, e.g. from + -- /cvmfs/software.eessi.io/host_injections/2023.06/software/linux/x86_64/amd/zen2/.lmod/SitePackage.lua + -- This can then register an additional hook, e.g. + -- + -- function arch_specific_load_hook(t) + -- + -- end + -- + -- local function final_load_hook(t) + -- eessi_load_hook(t) + -- site_specific_load_hook(t) + -- arch_specific_load_hook(t) + -- end + -- + -- hook.register("load", final_load_hook) + -- + -- Again, the host site could also decide to overwrite by simply doing + -- + -- hook.register("load", arch_specific_load_hook) + + -- get path to to architecture independent SitePackage.lua + local prefixHostInjections = string.gsub(os.getenv('EESSI_PREFIX') or "", 'versions', 'host_injections') + local hostSitePackage = prefixHostInjections .. "/.lmod/SitePackage.lua" + + -- If the file exists, run it + if isFile(hostSitePackage) then + dofile(hostSitePackage) + end + + -- build the full architecture specific path in host_injections + local archHostInjections = string.gsub(os.getenv('EESSI_SOFTWARE_PATH') or "", 'versions', 'host_injections') + local archSitePackage = archHostInjections .. "/.lmod/SitePackage.lua" + + -- If the file exists, run it + if isFile(archSitePackage) then + dofile(archSitePackage) + end + +end + + +local function eessi_cuda_enabled_load_hook(t) + local frameStk = require("FrameStk"):singleton() + local mt = frameStk:mt() + local simpleName = string.match(t.modFullName, "(.-)/") + -- If we try to load CUDA itself, check if the full CUDA SDK was installed on the host in host_injections. + -- This is required for end users to build additional CUDA software. If the full SDK isn't present, refuse + -- to load the CUDA module and print an informative message on how to set up GPU support for EESSI + local refer_to_docs = "For more information on how to do this, see https://www.eessi.io/docs/site_specific_config/gpu/.\\n" + if simpleName == 'CUDA' then + -- get the full host_injections path + local hostInjections = string.gsub(os.getenv('EESSI_SOFTWARE_PATH') or "", 'versions', 'host_injections') + -- build final path where the CUDA software should be installed + local cudaEasyBuildDir = hostInjections .. "/software/" .. t.modFullName .. "/easybuild" + local cudaDirExists = isDir(cudaEasyBuildDir) + if not cudaDirExists then + local advice = "but while the module file exists, the actual software is not entirely shipped with EESSI " + advice = advice .. "due to licencing. You will need to install a full copy of the CUDA SDK where EESSI " + advice = advice .. "can find it.\\n" + advice = advice .. refer_to_docs + LmodError("\\nYou requested to load ", simpleName, " ", advice) + end + end + -- when loading CUDA enabled modules check if the necessary driver libraries are accessible to the EESSI linker, + -- otherwise, refuse to load the requested module and print error message + local checkGpu = mt:haveProperty(simpleName,"arch","gpu") + local overrideGpuCheck = os.getenv("EESSI_OVERRIDE_GPU_CHECK") + if checkGpu and (overrideGpuCheck == nil) then + local arch = os.getenv("EESSI_CPU_FAMILY") or "" + local cudaVersionFile = "/cvmfs/software.eessi.io/host_injections/nvidia/" .. arch .. "/latest/cuda_version.txt" + local cudaDriverFile = "/cvmfs/software.eessi.io/host_injections/nvidia/" .. arch .. "/latest/libcuda.so" + local cudaDriverExists = isFile(cudaDriverFile) + local singularityCudaExists = isFile("/.singularity.d/libs/libcuda.so") + if not (cudaDriverExists or singularityCudaExists) then + local advice = "which relies on the CUDA runtime environment and driver libraries. " + advice = advice .. "In order to be able to use the module, you will need " + advice = advice .. "to make sure EESSI can find the GPU driver libraries on your host system. You can " + advice = advice .. "override this check by setting the environment variable EESSI_OVERRIDE_GPU_CHECK but " + advice = advice .. "the loaded application will not be able to execute on your system.\\n" + advice = advice .. refer_to_docs + LmodError("\\nYou requested to load ", simpleName, " ", advice) + else + -- CUDA driver exists, now we check its version to see if an update is needed + if cudaDriverExists then + local cudaVersion = read_file(cudaVersionFile) + local cudaVersion_req = os.getenv("EESSICUDAVERSION") + -- driver CUDA versions don't give a patch version for CUDA + local major, minor = string.match(cudaVersion, "(%d+)%.(%d+)") + local major_req, minor_req, patch_req = string.match(cudaVersion_req, "(%d+)%.(%d+)%.(%d+)") + local driver_libs_need_update = false + if major < major_req then + driver_libs_need_update = true + elseif major == major_req then + if minor < minor_req then + driver_libs_need_update = true + end + end + if driver_libs_need_update == true then + local advice = "but the module you want to load requires CUDA " .. cudaVersion_req .. ". " + advice = advice .. "Please update your CUDA driver libraries and then " + advice = advice .. "let EESSI know about the update.\\n" + advice = advice .. refer_to_docs + LmodError("\\nYour driver CUDA version is ", cudaVersion, " ", advice) + end + end + end + end +end + +local function eessi_espresso_deprecated_message(t) + local frameStk = require("FrameStk"):singleton() + local mt = frameStk:mt() + local simpleName = string.match(t.modFullName, "(.-)/") + local version = string.match(t.modFullName, "%d.%d.%d") + if simpleName == 'ESPResSo' and version == '4.2.1' then + -- Print a message on loading ESPreSso v <= 4.2.1 recommending using v 4.2.2 and above. + -- A message and not a warning as the exit code would break CI runs otherwise. + local advice = 'Prefer versions >= 4.2.2 which include important bugfixes.\\n' + advice = advice .. 'For details see https://github.com/espressomd/espresso/releases/tag/4.2.2\\n' + advice = advice .. 'Use version 4.2.1 at your own risk!\\n' + LmodMessage("\\nESPResSo v4.2.1 has known issues and has been deprecated. ", advice) + end +end + +-- Combine both functions into a single one, as we can only register one function as load hook in lmod +-- Also: make it non-local, so it can be imported and extended by other lmodrc files if needed +function eessi_load_hook(t) + eessi_espresso_deprecated_message(t) + -- Only apply CUDA hooks if the loaded module is in the EESSI prefix + -- This avoids getting an Lmod Error when trying to load a CUDA module from a local software stack + if from_eessi_prefix(t) then + eessi_cuda_enabled_load_hook(t) + end +end + +hook.register("load", eessi_load_hook) + +""" + +hook_epilogue = """ +-- Note that this needs to happen at the end, so that any EESSI specific hooks can be overwritten by the site +load_site_specific_hooks() +""" + + +# This hook is only for zen4. +hook_txt_zen4 = """ +local function hide_2022b_modules(modT) + -- modT is a table with: fullName, sn, fn and isVisible + -- The latter is a boolean to determine if a module is visible or not + + local tcver = modT.fullName:match("gfbf%-(20[0-9][0-9][ab])") or + modT.fullName:match("gompi%-(20[0-9][0-9][ab])") or + modT.fullName:match("foss%-(20[0-9][0-9][ab])") or + modT.fullName:match("GCC%-([0-9]*.[0-9]*.[0-9]*)") or + modT.fullName:match("GCCcore%-([0-9]*.[0-9]*.[0-9]*)") + + -- if nothing matches, return + if tcver == nil then return end + + -- if we have matches, check if the toolchain version is either 2022b or 12.2.0 + if parseVersion(tcver) == parseVersion("2022b") or parseVersion(tcver) == parseVersion("12.2.0") then + modT.isVisible = false + end +end + +hook.register("isVisibleHook", hide_2022b_modules) +""" + +# Append conditionally for zen4 +eessi_software_subdir_override = os.getenv("EESSI_SOFTWARE_SUBDIR_OVERRIDE") +if eessi_software_subdir_override == "x86_64/amd/zen4": + hook_txt = hook_txt + hook_txt_zen4 + +# Concatenate hook prologue, body and epilogue +# Note that this has to happen after any conditional items have been added to the hook_txt +hook_txt = hook_prologue + hook_txt + hook_epilogue + +def error(msg): + sys.stderr.write("ERROR: %s\n" % msg) + sys.exit(1) + + +if len(sys.argv) != 2: + error("Usage: %s " % sys.argv[0]) + +prefix = sys.argv[1] + +if not os.path.exists(prefix): + error("Prefix directory %s does not exist!" % prefix) + +sitepackage_path = os.path.join(prefix, DOT_LMOD, 'SitePackage.lua') + +# Lmod itself doesn't care about compute capability so remove this duplication from +# the install path (if it exists) +accel_subdir = os.getenv("EESSI_ACCELERATOR_TARGET") +if accel_subdir: + sitepackage_path = sitepackage_path.replace("/accel/%s" % accel_subdir, '') +try: + os.makedirs(os.path.dirname(sitepackage_path), exist_ok=True) + with open(sitepackage_path, 'w') as fp: + fp.write(hook_txt) + # Make sure that the created Lmod file has "read/write" for the user/group and "read" permissions for others + os.chmod(sitepackage_path, S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH) + +except (IOError, OSError) as err: + error("Failed to create %s: %s" % (sitepackage_path, err)) + +print(sitepackage_path) diff --git a/create_tarball.sh b/create_tarball.sh index b6c72b341d..86160cb751 100755 --- a/create_tarball.sh +++ b/create_tarball.sh @@ -4,15 +4,20 @@ set -e base_dir=$(dirname $(realpath $0)) -if [ $# -ne 4 ]; then - echo "ERROR: Usage: $0 " >&2 +if [ $# -ne 5 ]; then + echo "ERROR: Usage: $0 " >&2 exit 1 fi eessi_tmpdir=$1 -pilot_version=$2 +eessi_version=$2 cpu_arch_subdir=$3 -target_tgz=$4 +accel_subdir=$4 +target_tgz=$5 +echo "create_tarball.sh: TMPDIR='${TMPDIR}'" +if [[ ! -z ${TMPDIR} ]]; then + ls -l ${TMPDIR} +fi tmpdir=`mktemp -d` echo ">> tmpdir: $tmpdir" @@ -20,60 +25,85 @@ os="linux" source ${base_dir}/init/eessi_defaults cvmfs_repo=${EESSI_CVMFS_REPO} -software_dir="${cvmfs_repo}/versions/${pilot_version}/software/${os}/${cpu_arch_subdir}" +software_dir="${cvmfs_repo}/versions/${eessi_version}/software/${os}/${cpu_arch_subdir}" if [ ! -d ${software_dir} ]; then echo "Software directory ${software_dir} does not exist?!" >&2 exit 2 fi -overlay_upper_dir="${eessi_tmpdir}/overlay-upper" +cvmfs_repo_name=${cvmfs_repo#/cvmfs/} +overlay_upper_dir="${eessi_tmpdir}/${cvmfs_repo_name}/overlay-upper" -software_dir_overlay="${overlay_upper_dir}/versions/${pilot_version}/software/${os}/${cpu_arch_subdir}" +software_dir_overlay="${overlay_upper_dir}/versions/${eessi_version}" if [ ! -d ${software_dir_overlay} ]; then echo "Software directory overlay ${software_dir_overlay} does not exist?!" >&2 exit 3 fi +current_workdir=${PWD} cd ${overlay_upper_dir}/versions/ echo ">> Collecting list of files/directories to include in tarball via ${PWD}..." files_list=${tmpdir}/files.list.txt module_files_list=${tmpdir}/module_files.list.txt -if [ -d ${pilot_version}/software/${os}/${cpu_arch_subdir}/.lmod ]; then +if [ -d ${eessi_version}/software/${os}/${cpu_arch_subdir}/.lmod ]; then # include Lmod cache and configuration file (lmodrc.lua), # skip whiteout files and backup copies of Lmod cache (spiderT.old.*) - find ${pilot_version}/software/${os}/${cpu_arch_subdir}/.lmod -type f | egrep -v '/\.wh\.|spiderT.old' > ${files_list} + find ${eessi_version}/software/${os}/${cpu_arch_subdir}/.lmod -type f | egrep -v '/\.wh\.|spiderT.old' >> ${files_list} fi -if [ -d ${pilot_version}/software/${os}/${cpu_arch_subdir}/modules ]; then - # module files - find ${pilot_version}/software/${os}/${cpu_arch_subdir}/modules -type f | grep -v '/\.wh\.' >> ${files_list} - # module symlinks - find ${pilot_version}/software/${os}/${cpu_arch_subdir}/modules -type l | grep -v '/\.wh\.' >> ${files_list} - # module files and symlinks - find ${pilot_version}/software/${os}/${cpu_arch_subdir}/modules/all -type f -o -type l \ - | grep -v '/\.wh\.' | sed -e 's/.lua$//' | sed -e 's@.*/modules/all/@@g' | sort -u \ - >> ${module_files_list} + +# include scripts that were copied by install_scripts.sh, which we want to ship in EESSI repository +if [ -d ${eessi_version}/scripts ]; then + find ${eessi_version}/scripts -type f | grep -v '/\.wh\.' >> ${files_list} fi -if [ -d ${pilot_version}/software/${os}/${cpu_arch_subdir}/software -a -r ${module_files_list} ]; then - # installation directories but only those for which module files were created - # Note, we assume that module names (as defined by 'PACKAGE_NAME/VERSION.lua' - # using EasyBuild's standard module naming scheme) match the name of the - # software installation directory (expected to be 'PACKAGE_NAME/VERSION/'). - # If either side changes (module naming scheme or naming of software - # installation directories), the procedure will likely not work. - for package_version in $(cat ${module_files_list}); do - echo "handling ${package_version}" - ls -d ${pilot_version}/software/${os}/${cpu_arch_subdir}/software/${package_version} \ - | grep -v '/\.wh\.' >> ${files_list} - done + +# also include init, which is also copied by install_scripts.sh +if [ -d ${eessi_version}/init ]; then + find ${eessi_version}/init -type f | grep -v '/\.wh\.' >> ${files_list} fi +# consider both CPU-only and accelerator subdirectories +for subdir in ${cpu_arch_subdir} ${cpu_arch_subdir}/accel/${accel_subdir}; do + + if [ -d ${eessi_version}/software/${os}/${subdir}/modules ]; then + # module files + find ${eessi_version}/software/${os}/${subdir}/modules -type f | grep -v '/\.wh\.' >> ${files_list} || true # Make sure we don't exit because of set -e if grep doesn't return a match + # module symlinks + find ${eessi_version}/software/${os}/${subdir}/modules -type l | grep -v '/\.wh\.' >> ${files_list} || true # Make sure we don't exit because of set -e if grep doesn't return a match + # module files and symlinks + find ${eessi_version}/software/${os}/${subdir}/modules/all -type f -o -type l \ + | grep -v '/\.wh\.' | grep -v '/\.modulerc\.lua' | sed -e 's/.lua$//' | sed -e 's@.*/modules/all/@@g' | sort -u \ + >> ${module_files_list} + fi + + if [ -d ${eessi_version}/software/${os}/${subdir}/software -a -r ${module_files_list} ]; then + # installation directories but only those for which module files were created + # Note, we assume that module names (as defined by 'PACKAGE_NAME/VERSION.lua' + # using EasyBuild's standard module naming scheme) match the name of the + # software installation directory (expected to be 'PACKAGE_NAME/VERSION/'). + # If either side changes (module naming scheme or naming of software + # installation directories), the procedure will likely not work. + for package_version in $(cat ${module_files_list}); do + echo "handling ${package_version}" + ls -d ${eessi_version}/software/${os}/${subdir}/software/${package_version} \ + | grep -v '/\.wh\.' >> ${files_list} || true # Make sure we don't exit because of set -e if grep doesn't return a match + done + fi +done + # add a bit debug output -echo "wrote file list to ${files_list}" -[ -r ${files_list} ] && cat ${files_list} -echo "wrote module file list to ${module_files_list}" -[ -r ${module_files_list} ] && cat ${module_files_list} +if [ -r ${files_list} ]; then + echo "wrote file list to ${files_list}" + cat ${files_list} +fi +if [ -r ${module_files_list} ]; then + echo "wrote module file list to ${module_files_list}" + cat ${module_files_list} + + # Copy the module files list to current workindg dir for later use in the test step + cp ${module_files_list} ${current_workdir}/module_files.list.txt +fi topdir=${cvmfs_repo}/versions/ diff --git a/easystacks/software.eessi.io/2023.06/GH/eessi-2023.06-eb-4.9.4-001-system.yml b/easystacks/software.eessi.io/2023.06/GH/eessi-2023.06-eb-4.9.4-001-system.yml new file mode 100644 index 0000000000..c5efeaa48a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/GH/eessi-2023.06-eb-4.9.4-001-system.yml @@ -0,0 +1,7 @@ +easyconfigs: + - EasyBuild-4.9.2.eb + - EasyBuild-4.9.3.eb + - EasyBuild-4.9.4.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21465 + from-commit: 39cdebd7bd2cb4a9c170ee22439401316b2e7a25 diff --git a/easystacks/software.eessi.io/2023.06/README.md b/easystacks/software.eessi.io/2023.06/README.md new file mode 100644 index 0000000000..733ebf9475 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/README.md @@ -0,0 +1,7 @@ +File naming matters, since it determines the order in which easystack files are processed. + +Software installed with system toolchain should be installed first, +this includes EasyBuild itself, see `eessi-2023.06-eb-4.8.2-001-system.yml` . + +CUDA installations must be done before CUDA is required as dependency for something +built with a non-system toolchain, see `eessi-2023.06-eb-4.8.2-010-CUDA.yml` . diff --git a/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.2-2023a.yml b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.2-2023a.yml new file mode 100644 index 0000000000..6474d658ce --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.2-2023a.yml @@ -0,0 +1,26 @@ +easyconfigs: + - OpenMPI-4.1.5-GCC-12.3.0.eb + - foss-2023a.eb + - SciPy-bundle-2023.07-gfbf-2023a.eb + - ESPResSo-4.2.2-foss-2023a.eb + - ParaView-5.11.2-foss-2023a.eb + - OpenFOAM-10-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - OpenFOAM-11-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - OpenFOAM-v2312-foss-2023a.eb: + options: + # https://github.com/easybuilders/easybuild-easyblocks/pull/3388 + include-easyblocks-from-commit: c8256a36e7062bc09f5ce30552a9de9827054c9e + # https://github.com/easybuilders/easybuild-easyconfigs/pull/20841 + from-commit: f0e91e6e430ebf902f7788ebb47f0203dee60649 + - R-4.3.2-gfbf-2023a.eb + - Highway-1.0.4-GCCcore-12.3.0.eb + - Brunsli-0.1-GCCcore-12.3.0.eb: + options: + # https://github.com/easybuilders/easybuild-easyconfigs/pull/21366 + from-commit: 1736a123b1685836452587a5c51793257570bb2d diff --git a/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.2-2023b.yml b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.2-2023b.yml new file mode 100644 index 0000000000..c7411ada0a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.2-2023b.yml @@ -0,0 +1,6 @@ +easyconfigs: + - OpenBLAS-0.3.24-GCC-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20820 + from-commit: 1fc885b35dacdeb2feef4af207a2daa2502bae08 + - foss-2023b.eb diff --git a/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.3-2023a.yml b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.3-2023a.yml new file mode 100644 index 0000000000..df3d0dedaa --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.3-2023a.yml @@ -0,0 +1,2 @@ +easyconfigs: + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos.eb diff --git a/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.4-2023a.yml b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.4-2023a.yml new file mode 100644 index 0000000000..170a639064 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.4-2023a.yml @@ -0,0 +1,11 @@ +easyconfigs: + - ROOT-6.30.06-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21526 + from-commit: 6cbfbd7d7a55dc7243f46d0beea510278f4718df + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3467 + include-easyblocks-from-commit: c3aebe1f133d064a228c5d6c282e898b83d74601 + - waLBerla-6.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21600 + from-commit: 9b12318bcff1749781d9eb71c23e21bc3a79ed01 diff --git a/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.4-2023b.yml b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.4-2023b.yml new file mode 100644 index 0000000000..a60f9bec6a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/a64fx/eessi-2023.06-eb-4.9.4-2023b.yml @@ -0,0 +1,4 @@ +easyconfigs: + - SciPy-bundle-2023.11-gfbf-2023b.eb + - ESPResSo-4.2.2-foss-2023b.eb + - pyMBE-0.8.0-foss-2023b.eb diff --git a/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.3-2023a-CUDA.yml b/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.3-2023a-CUDA.yml new file mode 100644 index 0000000000..8935a3f3c3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.3-2023a-CUDA.yml @@ -0,0 +1,6 @@ +easyconfigs: + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos-CUDA-12.1.1.eb + - ESPResSo-4.2.2-foss-2023a-CUDA-12.1.1.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21440 + from-commit: 5525968921d7b5eae54f7d16391201e17ffae13c diff --git a/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.4-2023a-CUDA.yml b/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.4-2023a-CUDA.yml new file mode 100644 index 0000000000..7ac4ba6cca --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.4-2023a-CUDA.yml @@ -0,0 +1,7 @@ +easyconfigs: + - CUDA-12.1.1.eb + - cuDNN-8.9.2.26-CUDA-12.1.1.eb + - LightGBM-4.5.0-foss-2023a-CUDA-12.1.1.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21699 + from-commit: e3407bd127d248c08960f6b09c973da0fdecc2c3 diff --git a/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.4-2023b-CUDA.yml b/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.4-2023b-CUDA.yml new file mode 100644 index 0000000000..e6562e68a3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/accel/nvidia/eessi-2023.06-eb-4.9.4-2023b-CUDA.yml @@ -0,0 +1,19 @@ +easyconfigs: + - CUDA-12.4.0.eb: + options: + accept-eula-for: CUDA + - UCX-CUDA-1.15.0-GCCcore-13.2.0-CUDA-12.4.0.eb + - UCC-CUDA-1.2.0-GCCcore-13.2.0-CUDA-12.4.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21565 + from-commit: 46141a3f40e699433fac03af2d3ed81bd5a62da7 + - OSU-Micro-Benchmarks-7.5-gompi-2023b-CUDA-12.4.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21926 + from-commit: de79ec74eb076e1aceda5e21235a73c05ed6764c + - GROMACS-2024.4-foss-2023b-CUDA-12.4.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21549 + from-commit: 12b53341343967ce5a402fe8190a3c85bce7d49b + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3523 + include-easyblocks-from-commit: 90495ed23d26b3d5fd8162bf5d7b4c073a0682fe diff --git a/easystacks/software.eessi.io/2023.06/accel/nvidia/rebuilds/20240925-eb-4.9.4-NCCL-2.18.3-in-accel-prefix.yml b/easystacks/software.eessi.io/2023.06/accel/nvidia/rebuilds/20240925-eb-4.9.4-NCCL-2.18.3-in-accel-prefix.yml new file mode 100644 index 0000000000..d6667af9a1 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/accel/nvidia/rebuilds/20240925-eb-4.9.4-NCCL-2.18.3-in-accel-prefix.yml @@ -0,0 +1,5 @@ +# 2024.09.25 +# We need to reinstall NCCL in the accelerator prefixes +# See https://github.com/EESSI/software-layer/pull/487 +easyconfigs: + - NCCL-2.18.3-GCCcore-12.3.0-CUDA-12.1.1.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-001-system.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-001-system.yml new file mode 100644 index 0000000000..f02b9f2802 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-001-system.yml @@ -0,0 +1,7 @@ +easyconfigs: + - EasyBuild-4.8.2.eb: + options: + from-pr: 19105 + - Nextflow-23.10.0.eb: + options: + from-pr: 19172 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-010-CUDA.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-010-CUDA.yml new file mode 100644 index 0000000000..dda274b8db --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-010-CUDA.yml @@ -0,0 +1,5 @@ +easyconfigs: + - CUDA-12.1.1.eb: + options: + include-easyblocks-from-pr: 3045 + accept-eula-for: CUDA diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2022b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2022b.yml new file mode 100644 index 0000000000..fd88fafb0c --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2022b.yml @@ -0,0 +1,7 @@ +easyconfigs: + - foss-2022b.eb + - HarfBuzz-5.3.1-GCCcore-12.2.0.eb: + options: + from-pr: 19339 + - Qt5-5.15.7-GCCcore-12.2.0.eb + - QuantumESPRESSO-7.2-foss-2022b.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2023a-CUDA.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2023a-CUDA.yml new file mode 100644 index 0000000000..f8bde420de --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2023a-CUDA.yml @@ -0,0 +1,9 @@ +easyconfigs: + - CUDA-Samples-12.1-GCC-12.3.0-CUDA-12.1.1.eb: + # use easyconfig that only install subset of CUDA samples, + # to circumvent problem with nvcc linking to glibc of host OS, + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19189; + # and where additional samples are excluded because they fail to build on aarch64, + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19451; + options: + from-pr: 19451 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2023a.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2023a.yml new file mode 100644 index 0000000000..43b081b122 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.8.2-2023a.yml @@ -0,0 +1,46 @@ +easyconfigs: + - GCC-12.3.0.eb + - Rust-1.70.0-GCCcore-12.3.0.eb: + # fix build of Rust 1.70.0 by disabling download of pre-built LLVM; + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3038 + options: + include-easyblocks-from-pr: 3038 + - foss-2023a.eb + - pybind11-2.11.1-GCCcore-12.3.0.eb: + # avoid indirect dependency on old CMake version built with GCCcore/10.2.0 via Catch2 build dependency; + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19270 + options: + from-pr: 19270 + - SciPy-bundle-2023.07-gfbf-2023a.eb + - TensorFlow-2.13.0-foss-2023a.eb: + # patch setup.py for grpcio extension in TensorFlow 2.13.0 easyconfigs to take into account alternate sysroot; + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19268 + options: + from-pr: 19268 + - X11-20230603-GCCcore-12.3.0.eb + - HarfBuzz-5.3.1-GCCcore-12.3.0.eb: + options: + from-pr: 19339 + - Qt5-5.15.10-GCCcore-12.3.0.eb + - OSU-Micro-Benchmarks-7.1-1-gompi-2023a.eb + - LHAPDF-6.5.4-GCC-12.3.0.eb: + options: + from-pr: 19363 + - LoopTools-2.15-GCC-12.3.0.eb: + options: + from-pr: 19397 + - R-4.3.2-gfbf-2023a.eb: + options: + from-pr: 19185 + - Boost-1.82.0-GCC-12.3.0.eb + - netCDF-4.9.2-gompi-2023a.eb + - FFmpeg-6.0-GCCcore-12.3.0.eb + - ALL-0.9.2-foss-2023a.eb: + options: + from-pr: 19455 + - CDO-2.2.2-gompi-2023a.eb: + options: + from-pr: 19735 + - BWA-0.7.17-20220923-GCCcore-12.3.0.eb: + options: + from-pr: 19820 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-001-system.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-001-system.yml new file mode 100644 index 0000000000..25c13e49c9 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-001-system.yml @@ -0,0 +1,5 @@ +easyconfigs: + - EasyBuild-4.9.0.eb: + options: + from-pr: 19464 + - ReFrame-4.3.3.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2022b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2022b.yml new file mode 100644 index 0000000000..3962f63bda --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2022b.yml @@ -0,0 +1,13 @@ +easyconfigs: + - SciPy-bundle-2023.02-gfbf-2022b.eb + - GDAL-3.6.2-foss-2022b.eb + - waLBerla-6.1-foss-2022b.eb: + options: + from-pr: 19324 + - WRF-4.4.1-foss-2022b-dmpar.eb + - ImageMagick-7.1.0-53-GCCcore-12.2.0.eb: + options: + from-pr: 20086 + - R-4.2.2-foss-2022b.eb: + options: + from-pr: 20238 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a-CUDA.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a-CUDA.yml new file mode 100644 index 0000000000..cccbfa6808 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a-CUDA.yml @@ -0,0 +1,2 @@ +easyconfigs: + - OSU-Micro-Benchmarks-7.2-gompi-2023a-CUDA-12.1.1.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a.yml new file mode 100644 index 0000000000..3f6590c3cd --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a.yml @@ -0,0 +1,75 @@ +easyconfigs: + - OpenFOAM-11-foss-2023a.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19545 + options: + from-pr: 19545 + - at-spi2-core-2.49.91-GCCcore-12.3.0.eb + - ESPResSo-4.2.1-foss-2023a.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19592 + options: + from-pr: 19592 + - Rivet-3.1.9-gompi-2023a-HepMC3-3.2.6.eb: + options: + from-pr: 19679 + - PyTorch-2.1.2-foss-2023a.eb: + options: + from-pr: 19573 + - scikit-learn-1.3.1-gfbf-2023a.eb + - snakemake-8.4.2-foss-2023a.eb: + options: + from-pr: 19646 + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19471 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3036 + options: + from-pr: 19471 + include-easyblocks-from-pr: 3036 + - matplotlib-3.7.2-gfbf-2023a.eb + - PyQt5-5.15.10-GCCcore-12.3.0.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19554 + options: + from-pr: 19554 + - Pillow-SIMD-9.5.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19996 + from-pr: 19996 + - dask-2023.9.2-foss-2023a.eb + - JupyterNotebook-7.0.2-GCCcore-12.3.0.eb + - ImageMagick-7.1.1-15-GCCcore-12.3.0.eb: + options: + from-pr: 20086 + - Z3-4.12.2-GCCcore-12.3.0.eb: + options: + # The Z3 dependency of PyTorch had it's versionsuffix removed + # and we need to workaround the problem this creates, + # see https://github.com/EESSI/software-layer/pull/501 for details + from-pr: 20050 + - PyOpenGL-3.1.7-GCCcore-12.3.0.eb: + options: + from-pr: 20007 + # removed by https://github.com/easybuilders/easybuild-easyconfigs/pull/20586 + # adding ipympl-0.9.3-gfbf-2023a.eb as a replacement in + # easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023a.yml + # comment the below out here or CI will fail + # - ipympl-0.9.3-foss-2023a.eb: + # options: + # from-pr: 20126 + - OpenJPEG-2.5.0-GCCcore-12.3.0.eb + - OpenFOAM-10-foss-2023a.eb + - Highway-1.0.4-GCCcore-12.3.0.eb + - ELPA-2023.05.001-foss-2023a.eb + - libxc-6.2.2-GCC-12.3.0.eb + - SuperLU_DIST-8.1.2-foss-2023a.eb: + options: + from-pr: 20162 + - PETSc-3.20.3-foss-2023a.eb: + options: + include-easyblocks-from-pr: 3086 + from-pr: 19686 + - MODFLOW-6.4.4-foss-2023a.eb: + options: + from-pr: 20142 + - R-bundle-CRAN-2023.12-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20238 + from-pr: 20238 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023b.yml new file mode 100644 index 0000000000..15c02951d7 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023b.yml @@ -0,0 +1,60 @@ +easyconfigs: + - GCC-13.2.0.eb + - foss-2023b.eb + - SciPy-bundle-2023.11-gfbf-2023b.eb + - netCDF-4.9.2-gompi-2023b.eb: + options: + from-pr: 19534 + - matplotlib-3.8.2-gfbf-2023b.eb: + options: + from-pr: 19552 + - AOFlagger-3.4.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - arpack-ng-3.9.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - Armadillo-12.8.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - casacore-3.5.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - IDG-1.2.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - EveryBeam-0.5.2-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - DP3-6.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - WSClean-3.4-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - CDO-2.2.2-gompi-2023b.eb: + options: + from-pr: 19792 + - python-casacore-3.5.2-foss-2023b.eb: + options: + from-pr: 20089 + - libspatialindex-1.9.3-GCCcore-13.2.0.eb: + options: + from-pr: 19922 + - LittleCMS-2.15-GCCcore-13.2.0.eb + - giflib-5.2.1-GCCcore-13.2.0.eb + - OpenJPEG-2.5.0-GCCcore-13.2.0.eb + - libwebp-1.3.2-GCCcore-13.2.0.eb + - Wayland-1.22.0-GCCcore-13.2.0.eb + - Qt5-5.15.13-GCCcore-13.2.0.eb: + options: + from-pr: 20201 + - OSU-Micro-Benchmarks-7.2-gompi-2023b.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-001-system.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-001-system.yml new file mode 100644 index 0000000000..748ecc8a02 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-001-system.yml @@ -0,0 +1,8 @@ +easyconfigs: + - EasyBuild-4.9.1.eb: + options: + from-pr: 20299 + - EESSI-extend-easybuild.eb + - EasyBuild-4.9.2.eb: + options: + from-pr: 20818 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2022b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2022b.yml new file mode 100644 index 0000000000..1805c581c3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2022b.yml @@ -0,0 +1,8 @@ +easyconfigs: + - R-bundle-Bioconductor-3.16-foss-2022b-R-4.2.2.eb: + options: + from-pr: 20379 + - ParaView-5.11.1-foss-2022b.eb + - ASE-3.22.1-gfbf-2022b.eb + - SEPP-4.5.1-foss-2022b.eb + - Valgrind-3.21.0-gompi-2022b.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023a.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023a.yml new file mode 100644 index 0000000000..27c18a487e --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023a.yml @@ -0,0 +1,24 @@ +easyconfigs: + - ncdu-1.18-GCC-12.3.0.eb + - SAMtools-1.18-GCC-12.3.0.eb + - R-bundle-Bioconductor-3.18-foss-2023a-R-4.3.2.eb: + options: + from-pr: 20379 + # replacement for ipympl-0.9.3-foss-2023a.eb which has been built via + # easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.0-2023a.yml and was + # later removed in https://github.com/easybuilders/easybuild-easyconfigs/pull/20586 + # below we use the replacement ec file which is provided by + # https://github.com/easybuilders/easybuild-easyconfigs/pull/18852 + - ipympl-0.9.3-gfbf-2023a.eb: + options: + from-pr: 18852 + - ESPResSo-4.2.2-foss-2023a.eb: + options: + from-pr: 20595 + - GATK-4.5.0.0-GCCcore-12.3.0-Java-17.eb + - WhatsHap-2.2-foss-2023a.eb + - BLAST+-2.14.1-gompi-2023a.eb: + options: + from-pr: 20784 + - Valgrind-3.21.0-gompi-2023a.eb + - OrthoFinder-2.5.5-foss-2023a.eb diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023b.yml new file mode 100644 index 0000000000..888bddace3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.1-2023b.yml @@ -0,0 +1,8 @@ +easyconfigs: + - GROMACS-2024.1-foss-2023b.eb: + options: + from-pr: 20439 + - NLTK-3.8.1-foss-2023b.eb + - Valgrind-3.23.0-gompi-2023b.eb: + options: + from-pr: 20792 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-001-system.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-001-system.yml new file mode 100644 index 0000000000..1b2343ec1f --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-001-system.yml @@ -0,0 +1,11 @@ +easyconfigs: + - EasyBuild-4.9.3.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21412 + from-commit: 1cdd81524c974a29825e37bcf8ef3ccc291f5227 + - ReFrame-4.6.2.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21307 + from-commit: 0c4bd5c5a80f571a8932fbc38880d72455406816 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3431 + include-easyblocks-from-commit: efddeb02abe1a679324ac01ef19601dedbe79cc0 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2022b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2022b.yml new file mode 100644 index 0000000000..969b0d469b --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2022b.yml @@ -0,0 +1,52 @@ +easyconfigs: + - BLAST+-2.14.0-gompi-2022b.eb + - BioPerl-1.7.8-GCCcore-12.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21136 + from-commit: d8076ebaf8cb915762adebf88d385cc672b350dc + - gnuplot-5.4.6-GCCcore-12.2.0.eb + - h5py-3.8.0-foss-2022b.eb + - MDAnalysis-2.4.2-foss-2022b.eb + - ncbi-vdb-3.0.5-gompi-2022b.eb + - Bio-DB-HTS-3.01-GCC-12.2.0.eb + - MAFFT-7.505-GCC-12.2.0-with-extensions.eb + - MetaEuk-6-GCC-12.2.0.eb + - BamTools-2.5.2-GCC-12.2.0.eb + - Bio-SearchIO-hmmer-1.7.3-GCC-12.2.0.eb + - Mash-2.3-GCC-12.2.0.eb + - CapnProto-0.10.3-GCCcore-12.2.0.eb + - WhatsHap-2.1-foss-2022b.eb + - SAMtools-1.17-GCC-12.2.0.eb + - Bowtie2-2.5.1-GCC-12.2.0.eb + - CD-HIT-4.8.1-GCC-12.2.0.eb + - VCFtools-0.1.16-GCC-12.2.0.eb + - GenomeTools-1.6.2-GCC-12.2.0.eb + - Bio-SearchIO-hmmer-1.7.3-GCC-12.2.0.eb + - parallel-20230722-GCCcore-12.2.0.eb + - BCFtools-1.17-GCC-12.2.0.eb + - lpsolve-5.5.2.11-GCC-12.2.0.eb + - fastp-0.23.4-GCC-12.2.0.eb + - KronaTools-2.8.1-GCCcore-12.2.0.eb + - MultiQC-1.14-foss-2022b.eb + - CGAL-5.5.2-GCCcore-12.2.0.eb + - KaHIP-3.14-gompi-2022b.eb + - MPC-1.3.1-GCCcore-12.2.0.eb + - MUMPS-5.6.1-foss-2022b-metis.eb + - GL2PS-1.4.2-GCCcore-12.2.0.eb + - GST-plugins-base-1.22.1-GCC-12.2.0.eb + - wxWidgets-3.2.2.1-GCC-12.2.0.eb + - Archive-Zip-1.68-GCCcore-12.2.0.eb + - jemalloc-5.3.0-GCCcore-12.2.0.eb + - Judy-1.0.5-GCCcore-12.2.0.eb + - libaio-0.3.113-GCCcore-12.2.0.eb + - Z3-4.12.2-GCCcore-12.2.0.eb + - tbb-2021.10.0-GCCcore-12.2.0.eb + - dask-2023.7.1-foss-2022b.eb + - netcdf4-python-1.6.3-foss-2022b.eb + - Ruby-3.2.2-GCCcore-12.2.0.eb + - ROOT-6.26.10-foss-2022b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21526 + from-commit: 6cbfbd7d7a55dc7243f46d0beea510278f4718df + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3467 + include-easyblocks-from-commit: c3aebe1f133d064a228c5d6c282e898b83d74601 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2023a.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2023a.yml new file mode 100644 index 0000000000..e9011a0664 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2023a.yml @@ -0,0 +1,73 @@ +easyconfigs: + - BCFtools-1.18-GCC-12.3.0.eb + - BWA-0.7.18-GCCcore-12.3.0.eb + - CapnProto-1.0.1-GCCcore-12.3.0.eb + - DendroPy-4.6.1-GCCcore-12.3.0.eb + - DIAMOND-2.1.8-GCC-12.3.0.eb + - FastME-2.1.6.3-GCC-12.3.0.eb + - fastp-0.23.4-GCC-12.3.0.eb + - HMMER-3.4-gompi-2023a.eb + - IQ-TREE-2.3.5-gompi-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20955 + from-commit: 185f88b9a03d65a7fb74edc7acb4221e87e90784 + - KronaTools-2.8.1-GCCcore-12.3.0.eb + - LSD2-2.4.1-GCCcore-12.3.0.eb + - MAFFT-7.520-GCC-12.3.0-with-extensions.eb + - ncbi-vdb-3.0.10-gompi-2023a.eb + - MetalWalls-21.06.1-foss-2023a.eb + - QuantumESPRESSO-7.3.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20138 + from-commit: dbdaacc0739fdee91baa9123864ea4428cf21273 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3338 + include-easyblocks-from-commit: 32e45bd1f2d916732ca5852d55d17fa4d99e388b + - CP2K-2023.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20951 + from-commit: a92667fe32396bbd4106243658625f7ff2adcd68 + - amdahl-0.3.1-gompi-2023a.eb + - librosa-0.10.1-foss-2023a.eb + - xarray-2023.9.0-gfbf-2023a.eb + - SciTools-Iris-3.9.0-foss-2023a.eb + - OpenFOAM-v2312-foss-2023a.eb: + options: + # https://github.com/easybuilders/easybuild-easyblocks/pull/3388 + include-easyblocks-from-commit: c8256a36e7062bc09f5ce30552a9de9827054c9e + # https://github.com/easybuilders/easybuild-easyconfigs/pull/20841 + from-commit: f0e91e6e430ebf902f7788ebb47f0203dee60649 + - BioPerl-1.7.8-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21136 + from-commit: d8076ebaf8cb915762adebf88d385cc672b350dc + - grpcio-1.57.0-GCCcore-12.3.0.eb + - orjson-3.9.15-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20880 + from-commit: bc6e08f89759b8b70166de5bfcb5056b9db8ec90 + - wradlib-2.0.3-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21094 + from-commit: 3a2e0b8e6ee45277d01fb7e2eb93027a28c9461a + - MBX-1.1.0-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21155 + from-commit: 6929a67401f2a2ec58f91fb306332a77497d73ff + - Transrate-1.0.3-GCC-12.3.0.eb: + options: + # https://github.com/easybuilders/easybuild-easyblocks/pull/3381 + include-easyblocks-from-commit: bb86f05d4917b29e022023f152efdf0ca5c14ded + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20964 + from-commit: 7d539a9e599d8bc5ac2bda6ee9587ef62351ee03 + - Critic2-1.2-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20833 + from-commit: 78426c2383fc7e4b9b9e77d7a77f336e1bee3843 + - LRBinner-0.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21310 + from-commit: 799d9101df2cf81aabe252f00cc82a7246363f53 + - Redland-1.0.17-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21227 + from-commit: 4c5e3455dec31e68e8383c7fd86d1f80c434676d diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2023b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2023b.yml new file mode 100644 index 0000000000..6398f014dc --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.2-2023b.yml @@ -0,0 +1,30 @@ +easyconfigs: + - IPython-8.17.2-GCCcore-13.2.0.eb + - dlb-3.4-gompi-2023b.eb + - pystencils-1.3.4-gfbf-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20889 + from-commit: c66c4788a17f7e4f55aa23f9fdb782aad97c9ce7 + - Extrae-4.2.0-gompi-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21017 + from-commit: 120f4d56efebd2bc61382db4c84a664a339c66cf + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3393 + include-easyblocks-from-commit: c4951c78d62fa5cf8e9f6fe0ead212d2a4d7cb9c + - pyMBE-0.8.0-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21034 + from-commit: 76e7fc6657bab64bfbec826540a3a8f0040258f2 + - STAR-2.7.11b-GCC-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21200 + from-commit: 765ba900daf5953e306c4dad896febe52fdd6c00 + - HPL-2.3-foss-2023b.eb + - Brunsli-0.1-GCCcore-13.2.0.eb: + options: + # https://github.com/easybuilders/easybuild-easyconfigs/pull/21366 + from-commit: 1736a123b1685836452587a5c51793257570bb2d + - R-bundle-CRAN-2024.06-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21285 + from-commit: 41a2cd83f9fb017b76f0693f6a264d8acb548317 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-001-system.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-001-system.yml new file mode 100644 index 0000000000..d9c6075561 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-001-system.yml @@ -0,0 +1,5 @@ +easyconfigs: + - EasyBuild-4.9.4.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21465 + from-commit: 39cdebd7bd2cb4a9c170ee22439401316b2e7a25 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-2023a.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-2023a.yml new file mode 100644 index 0000000000..0c863f0025 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-2023a.yml @@ -0,0 +1,8 @@ +easyconfigs: + - ccache-4.9-GCCcore-12.3.0.eb + - GDB-13.2-GCCcore-12.3.0.eb + - tmux-3.3a-GCCcore-12.3.0.eb + - Vim-9.1.0004-GCCcore-12.3.0.eb + - gmsh-4.12.2-foss-2023a.eb + - basemap-1.3.9-foss-2023a.eb + - geopandas-0.14.2-foss-2023a.eb \ No newline at end of file diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-2023b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-2023b.yml new file mode 100644 index 0000000000..5325f2e553 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.3-2023b.yml @@ -0,0 +1,9 @@ +easyconfigs: + - LAMMPS-29Aug2024-foss-2023b-kokkos.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21436 + options: + from-commit: 9dc24e57880a8adb06ae10557c5315e66671a533 + - GROMACS-2024.3-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21430 + from-commit: 8b509882d03402e2998ff9b22c154a6957e36d6b diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.4-2023a.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.4-2023a.yml new file mode 100644 index 0000000000..c6c735f2b9 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.4-2023a.yml @@ -0,0 +1,51 @@ +easyconfigs: + - ROOT-6.30.06-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21526 + from-commit: 6cbfbd7d7a55dc7243f46d0beea510278f4718df + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3467 + include-easyblocks-from-commit: c3aebe1f133d064a228c5d6c282e898b83d74601 + - waLBerla-6.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21600 + from-commit: 9b12318bcff1749781d9eb71c23e21bc3a79ed01 + - mpl-ascii-0.10.0-gfbf-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21679 + from-commit: 7106f63160b1418d605882dd02ba151d099300bd + - jedi-0.19.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21650 + from-commit: 109998f6adcda7efb4174b1e5f73b41ee82d1f13 + - Solids4foam-2.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21606 + from-commit: 63562c58acf1be64407192b6862c3bd80253d2e0 + - Cassiopeia-2.0.0-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21657 + from-commit: 7f1f0e60487e7e1fcb5c4e6bc4fbc4f89994e3fd + - LightGBM-4.5.0-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21699 + from-commit: e3407bd127d248c08960f6b09c973da0fdecc2c3 + - OpenFOAM-v2406-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3519 + include-easyblocks-from-commit: e4a3ff1932350d575dffc7597435609fad6dd691 + - Paraver-4.11.4-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20230 + from-commit: 91c8df6b4c0810061e9f325427c9c79e961bc4b0 + - Tombo-1.5.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21925 + from-commit: 522ca010ab11949ab9594037f72b975cf1cd0d33 + - elfx86exts-0.6.2-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/22145 + from-commit: 31478e5c9869de3add74d0a02dd5df01ea65b21e + - archspec-0.2.5-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/22235 + from-commit: 01dd97ea62fe4d7d0df040ede3af03eb2f1b8641 diff --git a/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.4-2023b.yml b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.4-2023b.yml new file mode 100644 index 0000000000..0ff41ec4fa --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/eessi-2023.06-eb-4.9.4-2023b.yml @@ -0,0 +1,39 @@ +easyconfigs: + - SIONlib-1.7.7-GCCcore-13.2.0-tools.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21752 + from-commit: 6b8b53493a1188a5baa56a133574daac239730e7 + - Score-P-8.4-gompi-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3496 + include-easyblocks-from-commit: 60633b0acfd41a0732992d9e16800dae71a056eb + - Cython-3.0.10-GCCcore-13.2.0.eb + - Mustache-1.3.3-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21783 + from-commit: 5fa3db9eb36f91cba3fbf351549f8ba2849abc33 + - GDRCopy-2.4-GCCcore-13.2.0.eb + - GROMACS-2024.4-foss-2023b.eb: + options: + # https://github.com/easybuilders/easybuild-easyconfigs/pull/21851 + from-commit: f0fa64b440deaf5fb0a6d26ff1bb3e9f36626c8a + - SlurmViewer-1.0.1-GCCcore-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21899 + from-commit: 0bdeb23c9ea5a3caefd353ecd936919424c1bba4 + - wxWidgets-3.2.6-GCC-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21915 + from-commit: 58f16c0caf8c5494c68e9eda8cbf19e9145d3cfa + - DP3-6.2-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21765 + from-commit: c7e4bfe1a57cf9781ce346ba8ae9081644408c23 + - WSClean-3.5-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21765 + from-commit: c7e4bfe1a57cf9781ce346ba8ae9081644408c23 + - EveryBeam-0.6.1-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21765 + from-commit: c7e4bfe1a57cf9781ce346ba8ae9081644408c23 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240301-eb-4.9.0-OpenMPI-4.1.x-fix-smcuda.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240301-eb-4.9.0-OpenMPI-4.1.x-fix-smcuda.yml new file mode 100644 index 0000000000..042d0a214c --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240301-eb-4.9.0-OpenMPI-4.1.x-fix-smcuda.yml @@ -0,0 +1,15 @@ +# 2024-03-01 +# Rebuild all OpenMPI 4.1.x versions due to an issue with smcuda: +# https://github.com/open-mpi/ompi/issues/12270 +# https://github.com/open-mpi/ompi/pull/12344 +# https://github.com/easybuilders/easybuild-easyconfigs/pull/19940 +easyconfigs: + - OpenMPI-4.1.4-GCC-12.2.0.eb: + options: + from-pr: 19940 + - OpenMPI-4.1.5-GCC-12.3.0: + options: + from-pr: 19940 + - OpenMPI-4.1.6-GCC-13.2.0: + options: + from-pr: 19940 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240328-eb-4.9.0-GCCcore-fix-aarch64-vectorization.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240328-eb-4.9.0-GCCcore-fix-aarch64-vectorization.yml new file mode 100644 index 0000000000..f63aa421f5 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240328-eb-4.9.0-GCCcore-fix-aarch64-vectorization.yml @@ -0,0 +1,15 @@ +# 2024-03-28 +# Rebuild GCCcore to fix a compiler bug in the tree-vectorizer +# We encountered it in https://github.com/EESSI/software-layer/pull/479#issuecomment-1957091774 +# and https://github.com/EESSI/software-layer/pull/507#issuecomment-2011724613 +# Upstream issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111478 +# Upstream fix: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=e5f1956498251a4973d52c8aad3faf34d0443169 +# Fix in EasyBuild https://github.com/easybuilders/easybuild-easyconfigs/pull/19974 +# https://github.com/easybuilders/easybuild-easyconfigs/pull/20218 +easyconfigs: + - GCCcore-12.3.0.eb: + options: + from-pr: 20218 + - GCCcore-13.2.0.eb: + options: + from-pr: 19974 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240419-eb-4.9.1-move-setuptools_scm-from-hatchling-to-Python.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240419-eb-4.9.1-move-setuptools_scm-from-hatchling-to-Python.yml new file mode 100644 index 0000000000..56ea7a46a1 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240419-eb-4.9.1-move-setuptools_scm-from-hatchling-to-Python.yml @@ -0,0 +1,13 @@ +# 2024-04-19 +# Move setuptools_scm extension from hatchling to Python by rebuilding +# all affected modules with EasyBuild 4.9.1. +# This solves an issue with pyarrow, which is part of the Arrow installation. +# https://github.com/easybuilders/easybuild-easyconfigs/pull/19777 +# https://github.com/easybuilders/easybuild-easyconfigs/issues/19849 +easyconfigs: + - hatchling-1.18.0-GCCcore-12.3.0.eb + - hatchling-1.18.0-GCCcore-13.2.0.eb + - Python-bundle-PyPI-2023.06-GCCcore-12.3.0.eb + - Python-bundle-PyPI-2023.10-GCCcore-13.2.0.eb + - Python-3.11.3-GCCcore-12.3.0.eb + - Python-3.11.5-GCCcore-13.2.0.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240506-eb-4.9.1-CUDA-12.1.1-ship-full-runtime.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240506-eb-4.9.1-CUDA-12.1.1-ship-full-runtime.yml new file mode 100644 index 0000000000..058ab75e80 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240506-eb-4.9.1-CUDA-12.1.1-ship-full-runtime.yml @@ -0,0 +1,9 @@ +# 2024.05.06 +# Original matching of files we could ship was not done correctly. We were +# matching the basename for files (e.g., libcudart.so from libcudart.so.12) +# rather than the name stub (libcudart) +# See https://github.com/EESSI/software-layer/pull/559 +easyconfigs: + - CUDA-12.1.1.eb: + options: + accept-eula-for: CUDA diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240506-eb-4.9.1-EESSI-extend-allow-loaded.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240506-eb-4.9.1-EESSI-extend-allow-loaded.yml new file mode 100644 index 0000000000..2e0030b05a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240506-eb-4.9.1-EESSI-extend-allow-loaded.yml @@ -0,0 +1,5 @@ +# 2024.05.15 +# The module is an EasyBuild created module and therefore needs to be an allowed +# module when running EasyBuild +easyconfigs: + - EESSI-extend-easybuild.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240515-eb-4.9.1-GROMACS-correct-gmxapi-version.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240515-eb-4.9.1-GROMACS-correct-gmxapi-version.yml new file mode 100644 index 0000000000..eacfad7079 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240515-eb-4.9.1-GROMACS-correct-gmxapi-version.yml @@ -0,0 +1,18 @@ +# 2024.05.15 +# Originally shipped version forgot to bump the gmxapi version and source +# tarball, it was still using an older version from the 2023.3 tarball. Looking +# at https://gitlab.com/gromacs/gromacs/-/blob/v2024.1/python_packaging/gmxapi/src/gmxapi/version.py?ref_type=tags#L68, +# the 2024.1 release includes gmxapi 0.5.0. +# +# This also introduced a new build dependency on scikit-build-core for GROMACS +# +# See https://github.com/easybuilders/easybuild-easyconfigs/pull/20522 +easyconfigs: + - scikit-build-core-0.9.3-GCCcore-13.2.0.eb: + options: + # from-commit: 61d07bff09afe63cfe1ae35dc58a0c8be01eed62 + from-pr: 20526 + - GROMACS-2024.1-foss-2023b.eb: + options: + # from-commit: a0a467a88506c765a93a96b20d7a8fcb01d46b24 + from-pr: 20522 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240706-eb-4.9.2-OpenFOAM-no-ftree-vectorize.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240706-eb-4.9.2-OpenFOAM-no-ftree-vectorize.yml new file mode 100644 index 0000000000..c12d244790 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240706-eb-4.9.2-OpenFOAM-no-ftree-vectorize.yml @@ -0,0 +1,12 @@ +# 2024.07.06 +# OpenFOAM 10 and 11 built with GCC 11.3.0 or 12.3.0 and -ftree-vectorize yields incorrect results, +# see https://github.com/easybuilders/easybuild-easyconfigs/issues/20927 +easyconfigs: + - OpenFOAM-10-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - OpenFOAM-11-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240719-eb-4.9.2-GObject-Introspection-filter-envvars-zen4.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240719-eb-4.9.2-GObject-Introspection-filter-envvars-zen4.yml new file mode 100644 index 0000000000..2c9b411736 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240719-eb-4.9.2-GObject-Introspection-filter-envvars-zen4.yml @@ -0,0 +1,11 @@ +# 2024.07.19 +# GObject-Introspection sets $LD_LIBRARY_PATH (to many different paths, including $EPREFIX/lib) +# when calling gcc, and this causes a lot of issues for, especially, scripts using /bin/bash. +# +# This rebuild ensures (by using a new EasyBuild hook) that GObject-Introspection will not set +# environment variables that are configured to be filtered by EasyBuild. +# +# See https://github.com/EESSI/software-layer/issues/196 +easyconfigs: + - GObject-Introspection-1.76.1-GCCcore-12.3.0.eb + - GObject-Introspection-1.78.1-GCCcore-13.2.0.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240719-eb-4.9.2-GObject-Introspection-filter-envvars.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240719-eb-4.9.2-GObject-Introspection-filter-envvars.yml new file mode 100644 index 0000000000..a61cd9705b --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240719-eb-4.9.2-GObject-Introspection-filter-envvars.yml @@ -0,0 +1,14 @@ +# 2024.07.19 +# GObject-Introspection sets $LD_LIBRARY_PATH (to many different paths, including $EPREFIX/lib) +# when calling gcc, and this causes a lot of issues for, especially, scripts using /bin/bash. +# +# This rebuild ensures (by using a new EasyBuild hook) that GObject-Introspection will not set +# environment variables that are configured to be filtered by EasyBuild. +# +# See https://github.com/EESSI/software-layer/issues/196 +easyconfigs: + - GObject-Introspection-1.74.0-GCCcore-12.2.0.eb + - GObject-Introspection-1.76.1-GCCcore-12.3.0.eb + - GObject-Introspection-1.78.1-GCCcore-13.2.0.eb + - at-spi2-core-2.46.0-GCCcore-12.2.0.eb + - at-spi2-core-2.49.91-GCCcore-12.3.0.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240729-eb-4.9.2-Python-ctypes.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240729-eb-4.9.2-Python-ctypes.yml new file mode 100644 index 0000000000..7554289c3b --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240729-eb-4.9.2-Python-ctypes.yml @@ -0,0 +1,24 @@ +# 2024.07.29 +# Python ctypes relies on LD_LIBRARY_PATH and doesn't respect rpath linking. There is a workaround +# for the EasyBuild context in https://github.com/easybuilders/easybuild-easyblocks/pull/3352. +# +# This rebuild ensures this fix is available for all Python versions shipped with EESSI. +# +# See https://gitlab.com/eessi/support/-/issues/77 +easyconfigs: + - Python-3.10.8-GCCcore-12.2.0-bare: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.10.8-GCCcore-12.2.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.11.3-GCCcore-12.3.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.11.5-GCCcore-13.2.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240801-eb-4.9.2-Python-ctypes-zen4.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240801-eb-4.9.2-Python-ctypes-zen4.yml new file mode 100644 index 0000000000..2104b4d836 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240801-eb-4.9.2-Python-ctypes-zen4.yml @@ -0,0 +1,17 @@ +# 2024.08.01 +# Python ctypes relies on LD_LIBRARY_PATH and doesn't respect rpath linking. There is a workaround +# for the EasyBuild context in https://github.com/easybuilders/easybuild-easyblocks/pull/3352. +# +# This rebuild ensures this fix is available for all Python versions shipped for +# zen4 with EESSI. +# +# See https://gitlab.com/eessi/support/-/issues/77 +easyconfigs: + - Python-3.11.3-GCCcore-12.3.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.11.5-GCCcore-13.2.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240814-eb-4.9.2-hatchling-1.18.0-updated-easyconfig.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240814-eb-4.9.2-hatchling-1.18.0-updated-easyconfig.yml new file mode 100644 index 0000000000..7ab02420ca --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240814-eb-4.9.2-hatchling-1.18.0-updated-easyconfig.yml @@ -0,0 +1,9 @@ +# 2024.08.14 +# hatchling-1.18.0 rebuild to account for easyconfig changed upstream +# see https://gitlab.com/eessi/support/-/issues/85 and +# https://github.com/easybuilders/easybuild-easyconfigs/pull/20389 +easyconfigs: + - hatchling-1.18.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20389 + from-commit: 9580c0d67d6dd97b160b768a839bfcba6d5b21b9 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240823-eb-4.9.2-GObject-Introspection-filter-envvars-a64fx.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240823-eb-4.9.2-GObject-Introspection-filter-envvars-a64fx.yml new file mode 100644 index 0000000000..782db66e78 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240823-eb-4.9.2-GObject-Introspection-filter-envvars-a64fx.yml @@ -0,0 +1,13 @@ +# 2024.08.23 +# GObject-Introspection sets $LD_LIBRARY_PATH (to many different paths, including $EPREFIX/lib) +# when calling gcc, and this causes a lot of issues for, especially, scripts using /bin/bash. +# +# This rebuild ensures (by using a new EasyBuild hook) that GObject-Introspection will not set +# environment variables that are configured to be filtered by EasyBuild. +# This rebuild was not done initially for A64FX. This file is meant to do the same as the +# previous rebuild of GObject-Introspection-1.76.1-GCCcore-12.3.0 in other architectures, +# but for A64FX. +# +# See https://github.com/EESSI/software-layer/issues/196 +easyconfigs: + - GObject-Introspection-1.76.1-GCCcore-12.3.0.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240918-eb-4.9.3-CUDA-12.1.1-in-accel-prefix.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240918-eb-4.9.3-CUDA-12.1.1-in-accel-prefix.yml new file mode 100644 index 0000000000..755bea096e --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240918-eb-4.9.3-CUDA-12.1.1-in-accel-prefix.yml @@ -0,0 +1,7 @@ +# 2024.09.18 +# We need to reinstall CUDA in the accelerator prefixes +# See https://github.com/EESSI/software-layer/pull/720 +easyconfigs: + - CUDA-12.1.1.eb: + options: + accept-eula-for: CUDA diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-Cuda-Samples-in-accel-prefix.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-Cuda-Samples-in-accel-prefix.yml new file mode 100644 index 0000000000..da2c06ae1e --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-Cuda-Samples-in-accel-prefix.yml @@ -0,0 +1,5 @@ +# 2024.09.19 +# We need to reinstall CUDA-Samples in the accelerator prefixes +# See https://github.com/EESSI/software-layer/pull/715 +easyconfigs: + - CUDA-Samples-12.1-GCC-12.3.0-CUDA-12.1.1.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-osu-microbenchmarks-in-accel-prefix.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-osu-microbenchmarks-in-accel-prefix.yml new file mode 100644 index 0000000000..23801e0250 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-osu-microbenchmarks-in-accel-prefix.yml @@ -0,0 +1,5 @@ +# 2024.09.19 +# We need to reinstall OSU-Micro-Benchmarks in the accelerator prefixes +# See https://github.com/EESSI/software-layer/pull/716 +easyconfigs: + - OSU-Micro-Benchmarks-7.2-gompi-2023a-CUDA-12.1.1.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-uxc-cuda-in-accel-prefix.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-uxc-cuda-in-accel-prefix.yml new file mode 100644 index 0000000000..d347af335a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240919-eb-4.9.3-uxc-cuda-in-accel-prefix.yml @@ -0,0 +1,5 @@ +# 2024.09.19 +# We need to reinstall UCX-CUDA in the accelerator prefixes +# See https://github.com/EESSI/software-layer/pull/719 +easyconfigs: + - UCX-CUDA-1.14.1-GCCcore-12.3.0-CUDA-12.1.1.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240925-eb-4.9.3-ucc-cuda-in-accel-prefix.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240925-eb-4.9.3-ucc-cuda-in-accel-prefix.yml new file mode 100644 index 0000000000..a418086c44 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240925-eb-4.9.3-ucc-cuda-in-accel-prefix.yml @@ -0,0 +1,4 @@ +# 2024.09.19 +# We need to reinstall UCC-CUDA in the accelerator prefixes +easyconfigs: + - UCC-CUDA-1.2.0-GCCcore-12.3.0-CUDA-12.1.1.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20240925-eb-4.9.4-EESSI-extend.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20240925-eb-4.9.4-EESSI-extend.yml new file mode 100644 index 0000000000..5c1eb292e4 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20240925-eb-4.9.4-EESSI-extend.yml @@ -0,0 +1,6 @@ +# 2024.09.25 +# EESSI-extend did not support LMOD_EXACT_MATCH +# (see https://github.com/EESSI/software-layer/pull/747) +easyconfigs: + - EESSI-extend-easybuild.eb + diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20241008-eb-4.9.4-EESSI-extend.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20241008-eb-4.9.4-EESSI-extend.yml new file mode 100644 index 0000000000..b1f69e3297 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20241008-eb-4.9.4-EESSI-extend.yml @@ -0,0 +1,5 @@ +# 2024.10.08 +# EESSI-extend should use EESSI_SITE_INSTALLPATH, instead of recalculating this +easyconfigs: + - EESSI-extend-easybuild.eb + diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20241015-eb-4.9.4-LAMMPS-generic-builds.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20241015-eb-4.9.4-LAMMPS-generic-builds.yml new file mode 100644 index 0000000000..5b90d44a89 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20241015-eb-4.9.4-LAMMPS-generic-builds.yml @@ -0,0 +1,16 @@ +# 2024.10.15 +# Generic build of LAMMPS have optimizations for the build host CPU, +# this is fixed in https://github.com/easybuilders/easybuild-easyblocks/pull/3484 +easyconfigs: + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos.eb: + options: + # see: https://github.com/easybuilders/easybuild-easyblocks/pull/3484 + include-easyblocks-from-commit: 3671c5b7c238c7dc8aadd2c510329770ef1bdcdf + - LAMMPS-29Aug2024-foss-2023b-kokkos.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21436 + from-commit: 9dc24e57880a8adb06ae10557c5315e66671a533 + # see: https://github.com/easybuilders/easybuild-easyblocks/pull/3484 + include-easyblocks-from-commit: 3671c5b7c238c7dc8aadd2c510329770ef1bdcdf + + diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20241017-eb-4.9.4-OpenBLAS-aarch64-generic.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20241017-eb-4.9.4-OpenBLAS-aarch64-generic.yml new file mode 100644 index 0000000000..d6d8f70143 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20241017-eb-4.9.4-OpenBLAS-aarch64-generic.yml @@ -0,0 +1,18 @@ +# 2024.10.17 +# TARGET=ARMV8 must be used when building OpenBLAS for aarch64/generic, +# since otherwise "Illegal instruction" errors may happen in the driver part of OpenBLAS +# on systems that only support a minimal instruction set like Arm v8 (like Raspberry Pi SBCs); +# see also https://github.com/OpenMathLib/OpenBLAS/issues/4945 +easyconfigs: + - OpenBLAS-0.3.21-GCC-12.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3492 + include-easyblocks-from-commit: d06d9617d9bfb63d338b6879eab9da81c8a312d8 + - OpenBLAS-0.3.23-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3492 + include-easyblocks-from-commit: d06d9617d9bfb63d338b6879eab9da81c8a312d8 + - OpenBLAS-0.3.24-GCC-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3492 + include-easyblocks-from-commit: d06d9617d9bfb63d338b6879eab9da81c8a312d8 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20241112-eb-4.9.4-EESSI-extend.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20241112-eb-4.9.4-EESSI-extend.yml new file mode 100644 index 0000000000..9b2910a83a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20241112-eb-4.9.4-EESSI-extend.yml @@ -0,0 +1,6 @@ +# 2024.11.12 +# for installations under /cvmfs, if EESSI_ACCELERATOR_TARGET is set, +# EESSI-extend should adjust EASYBUILD_INSTALLPATH and set +# EASYBUILD_CUDA_COMPUTE_CAPABILITIES +easyconfigs: + - EESSI-extend-easybuild.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20241206-eb-4.9.4-EESSI-extend.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20241206-eb-4.9.4-EESSI-extend.yml new file mode 100644 index 0000000000..04a60f595c --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20241206-eb-4.9.4-EESSI-extend.yml @@ -0,0 +1,6 @@ +# 2024.12.06 +# - Use $EESSI_VERSION to determine version of EESSI-extend module +# - Fix the filtered dependencies for aarch64: Yasm instead of yasm +# - Also add filtered dependencies for RISC-V +easyconfigs: + - EESSI-extend-easybuild.eb diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20250119-eb-4.9.2-Python-ctypes-sapphire_rapids.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20250119-eb-4.9.2-Python-ctypes-sapphire_rapids.yml new file mode 100644 index 0000000000..1d9acf0988 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20250119-eb-4.9.2-Python-ctypes-sapphire_rapids.yml @@ -0,0 +1,24 @@ +# 2025.01.19 +# Python ctypes relies on LD_LIBRARY_PATH and doesn't respect rpath linking. There is a workaround +# for the EasyBuild context in https://github.com/easybuilders/easybuild-easyblocks/pull/3352. +# +# This rebuild ensures this fix is available for all Python versions shipped with EESSI. +# +# See https://gitlab.com/eessi/support/-/issues/77 +easyconfigs: + - Python-3.10.8-GCCcore-12.2.0-bare: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.10.8-GCCcore-12.2.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.11.3-GCCcore-12.3.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + - Python-3.11.5-GCCcore-13.2.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20250120-eb-4.9.2-hatchling-1.18.0-updated-easyconfig-sapphire_rapids.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20250120-eb-4.9.2-hatchling-1.18.0-updated-easyconfig-sapphire_rapids.yml new file mode 100644 index 0000000000..a86eb166bd --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20250120-eb-4.9.2-hatchling-1.18.0-updated-easyconfig-sapphire_rapids.yml @@ -0,0 +1,9 @@ +# 2025.01.20 +# hatchling-1.18.0 rebuild to account for easyconfig changed upstream +# see https://gitlab.com/eessi/support/-/issues/85 and +# https://github.com/easybuilders/easybuild-easyconfigs/pull/20389 +easyconfigs: + - hatchling-1.18.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20389 + from-commit: 9580c0d67d6dd97b160b768a839bfcba6d5b21b9 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20250121-eb-4.9.4-SciPy-bundle-2023.07-bug-fixes.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20250121-eb-4.9.4-SciPy-bundle-2023.07-bug-fixes.yml new file mode 100644 index 0000000000..f7db7a994c --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20250121-eb-4.9.4-SciPy-bundle-2023.07-bug-fixes.yml @@ -0,0 +1,14 @@ +# 2025.01.21 +# While adding support for Intel Sapphire Rapids, additional patches applied to the +# original easyconfig were required to successfully build SciPy-bundle 2023.07. +# In order to keep the stack consistent across the different CPUs, +# a rebuild is done for all CPU targets with this updated easyconfig. +# See: +# - https://github.com/easybuilders/easybuild-easyconfigs/pull/19419 +# - https://github.com/easybuilders/easybuild-easyconfigs/pull/20817 +# - https://github.com/easybuilders/easybuild-easyconfigs/pull/21693 +easyconfigs: + - SciPy-bundle-2023.07-gfbf-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21693 + from-commit: 7c5144d2c1a061cd9f08b5901970b7f6ec5eb5c0 diff --git a/easystacks/software.eessi.io/2023.06/rebuilds/20250203-eb-4.9.4-LAMMPS-2Aug2023-add-support-for-sapphire_rapids.yml b/easystacks/software.eessi.io/2023.06/rebuilds/20250203-eb-4.9.4-LAMMPS-2Aug2023-add-support-for-sapphire_rapids.yml new file mode 100644 index 0000000000..fb612ed513 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/rebuilds/20250203-eb-4.9.4-LAMMPS-2Aug2023-add-support-for-sapphire_rapids.yml @@ -0,0 +1,12 @@ +# 2025.02.03 +# Rebuild LAMMPS 2Aug2023_update2 for Sapphire Rapids, +# as the existing version used an old version of archspec that detected the CPU as Icelake. +# See https://github.com/easybuilders/easybuild-easyconfigs/pull/22235 +# and https://github.com/easybuilders/easybuild-easyblocks/pull/3569. +easyconfigs: + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/22235 + from-commit: 01dd97ea62fe4d7d0df040ede3af03eb2f1b8641 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3569 + include-easyblocks-from-commit: b0ce5ec66c8f797220b2c2a773acfc4aeae7a0c7 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-001-system.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-001-system.yml new file mode 100644 index 0000000000..a033316c1e --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-001-system.yml @@ -0,0 +1,4 @@ +easyconfigs: + - Nextflow-23.10.0.eb: + options: + from-pr: 19172 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-2022b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-2022b.yml new file mode 100644 index 0000000000..f261e467b1 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-2022b.yml @@ -0,0 +1,14 @@ +easyconfigs: + - GCC-12.2.0.eb + - Python-3.10.8-GCCcore-12.2.0-bare.eb + - make-4.3-GCCcore-12.2.0.eb + - cairo-1.17.4-GCCcore-12.2.0.eb + - UCC-1.1.0-GCCcore-12.2.0.eb + - PMIx-4.2.2-GCCcore-12.2.0.eb + - libfabric-1.16.1-GCCcore-12.2.0.eb + - foss-2022b.eb + - HarfBuzz-5.3.1-GCCcore-12.2.0.eb: + options: + from-pr: 19339 + - Qt5-5.15.7-GCCcore-12.2.0.eb + - QuantumESPRESSO-7.2-foss-2022b.eb diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-2023a.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-2023a.yml new file mode 100644 index 0000000000..bd34313a10 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.8.2-2023a.yml @@ -0,0 +1,59 @@ +easyconfigs: + - XZ-5.4.2-GCCcore-12.3.0.eb + - libffi-3.4.4-GCCcore-12.3.0.eb + - SQLite-3.42.0-GCCcore-12.3.0.eb + - bzip2-1.0.8-GCCcore-12.3.0.eb + - UnZip-6.0-GCCcore-12.3.0.eb + - cairo-1.17.8-GCCcore-12.3.0.eb + - Rust-1.70.0-GCCcore-12.3.0.eb: + options: + include-easyblocks-from-pr: 3038 + - poetry-1.5.1-GCCcore-12.3.0.eb + - git-2.41.0-GCCcore-12.3.0-nodocs.eb + - flit-3.9.0-GCCcore-12.3.0.eb + - OpenBLAS-0.3.23-GCC-12.3.0.eb: + options: + # required for Intel Sapphire Rapids support + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19159 + from-pr: 19159 + - foss-2023a.eb + - pybind11-2.11.1-GCCcore-12.3.0.eb: + # avoid indirect dependency on old CMake version built with GCCcore/10.2.0 via Catch2 build dependency; + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19270 + options: + from-pr: 19270 + - SciPy-bundle-2023.07-gfbf-2023a.eb: + options: + from-pr: 21693 + - TensorFlow-2.13.0-foss-2023a.eb: + # patch setup.py for grpcio extension in TensorFlow 2.13.0 easyconfigs to take into account alternate sysroot; + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19268 + options: + from-pr: 19268 + - X11-20230603-GCCcore-12.3.0.eb + - HarfBuzz-5.3.1-GCCcore-12.3.0.eb: + options: + from-pr: 19339 + - Qt5-5.15.10-GCCcore-12.3.0.eb + - OSU-Micro-Benchmarks-7.1-1-gompi-2023a.eb + - LHAPDF-6.5.4-GCC-12.3.0.eb: + options: + from-pr: 19363 + - LoopTools-2.15-GCC-12.3.0.eb: + options: + from-pr: 19397 + - R-4.3.2-gfbf-2023a.eb: + options: + from-pr: 19185 + - Boost-1.82.0-GCC-12.3.0.eb + - netCDF-4.9.2-gompi-2023a.eb + - FFmpeg-6.0-GCCcore-12.3.0.eb + - ALL-0.9.2-foss-2023a.eb: + options: + from-pr: 19455 + - CDO-2.2.2-gompi-2023a.eb: + options: + from-pr: 19735 + - BWA-0.7.17-20220923-GCCcore-12.3.0.eb: + options: + from-pr: 19820 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-001-system.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-001-system.yml new file mode 100644 index 0000000000..1e6233a041 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-001-system.yml @@ -0,0 +1,4 @@ +easyconfigs: + - ReFrame-4.3.3.eb: + options: + from-pr: 22183 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2022b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2022b.yml new file mode 100644 index 0000000000..a8dc0693a3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2022b.yml @@ -0,0 +1,17 @@ +easyconfigs: + - OpenMPI-4.1.4-GCC-12.2.0.eb + - Highway-1.0.3-GCCcore-12.2.0.eb: + options: + from-pr: 20298 + - SciPy-bundle-2023.02-gfbf-2022b.eb + - GDAL-3.6.2-foss-2022b.eb + - waLBerla-6.1-foss-2022b.eb: + options: + from-pr: 19324 + - WRF-4.4.1-foss-2022b-dmpar.eb + - ImageMagick-7.1.0-53-GCCcore-12.2.0.eb: + options: + from-pr: 20086 + - R-4.2.2-foss-2022b.eb: + options: + from-pr: 20238 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2023a.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2023a.yml new file mode 100644 index 0000000000..a6c6dd5aa5 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2023a.yml @@ -0,0 +1,88 @@ +easyconfigs: + - GCCcore-12.3.0.eb: + options: + from-pr: 20218 + - OpenMPI-4.1.5-GCC-12.3.0: + options: + from-pr: 19940 + - METIS-5.1.0-GCCcore-12.3.0.eb + - SCOTCH-7.0.3-gompi-2023a.eb + - CGAL-5.6-GCCcore-12.3.0.eb + - ParaView-5.11.2-foss-2023a.eb + - gnuplot-5.4.8-GCCcore-12.3.0.eb + - ESPResSo-4.2.1-foss-2023a.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19592 + options: + from-pr: 19592 + - Rivet-3.1.9-gompi-2023a-HepMC3-3.2.6.eb: + options: + from-pr: 19679 + - Pillow-10.0.0-GCCcore-12.3.0.eb + - sympy-1.12-gfbf-2023a.eb + - networkx-3.1-gfbf-2023a.eb + - expecttest-0.1.5-GCCcore-12.3.0.eb + - PyYAML-6.0-GCCcore-12.3.0.eb + - pytest-flakefinder-1.1.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19480 + from-pr: 19480 + - pytest-rerunfailures-12.0-GCCcore-12.3.0.eb + - pytest-shard-0.1.2-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19480 + from-pr: 19480 + - scikit-learn-1.3.1-gfbf-2023a.eb + - snakemake-8.4.2-foss-2023a.eb: + options: + from-pr: 19646 + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19471 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3036 + options: + from-pr: 19471 + include-easyblocks-from-pr: 3036 + - PyTorch-2.1.2-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19573 + from-pr: 19573 + - matplotlib-3.7.2-gfbf-2023a.eb + - PyQt5-5.15.10-GCCcore-12.3.0.eb: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19554 + options: + from-pr: 19554 + - Pillow-SIMD-9.5.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/19996 + from-pr: 19996 + - dask-2023.9.2-foss-2023a.eb + - JupyterNotebook-7.0.2-GCCcore-12.3.0.eb + - ImageMagick-7.1.1-15-GCCcore-12.3.0.eb: + options: + from-pr: 20086 + - Z3-4.12.2-GCCcore-12.3.0.eb: + options: + # The Z3 dependency of PyTorch had it's versionsuffix removed + # and we need to workaround the problem this creates, + # see https://github.com/EESSI/software-layer/pull/501 for details + from-pr: 20050 + - PyOpenGL-3.1.7-GCCcore-12.3.0.eb: + options: + from-pr: 20007 + - OpenJPEG-2.5.0-GCCcore-12.3.0.eb + - Highway-1.0.4-GCCcore-12.3.0.eb + - ELPA-2023.05.001-foss-2023a.eb + - libxc-6.2.2-GCC-12.3.0.eb + - SuperLU_DIST-8.1.2-foss-2023a.eb: + options: + from-pr: 20162 + - PETSc-3.20.3-foss-2023a.eb: + options: + include-easyblocks-from-pr: 3086 + from-pr: 19686 + - MODFLOW-6.4.4-foss-2023a.eb: + options: + from-pr: 20142 + - R-bundle-CRAN-2023.12-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20238 + from-pr: 20238 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2023b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2023b.yml new file mode 100644 index 0000000000..23fc934645 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.0-2023b.yml @@ -0,0 +1,74 @@ +easyconfigs: + - GCCcore-13.2.0.eb: + options: + from-pr: 19974 + - OpenMPI-4.1.6-GCC-13.2.0: + options: + from-pr: 19940 + - XZ-5.4.4-GCCcore-13.2.0.eb + - SQLite-3.43.1-GCCcore-13.2.0.eb + - UnZip-6.0-GCCcore-13.2.0.eb + - libffi-3.4.4-GCCcore-13.2.0.eb + - cairo-1.18.0-GCCcore-13.2.0.eb + - poetry-1.6.1-GCCcore-13.2.0.eb + - git-2.42.0-GCCcore-13.2.0.eb + - flit-3.9.0-GCCcore-13.2.0.eb + - expat-2.5.0-GCCcore-13.2.0.eb + - foss-2023b.eb + - SciPy-bundle-2023.11-gfbf-2023b.eb + - netCDF-4.9.2-gompi-2023b.eb: + options: + from-pr: 19534 + - matplotlib-3.8.2-gfbf-2023b.eb: + options: + from-pr: 19552 + - AOFlagger-3.4.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - arpack-ng-3.9.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - Armadillo-12.8.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - casacore-3.5.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - IDG-1.2.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - EveryBeam-0.5.2-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - DP3-6.0-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - WSClean-3.4-foss-2023b.eb: + options: + from-pr: 19840 + include-easyblocks-from-pr: 3088 + - CDO-2.2.2-gompi-2023b.eb: + options: + from-pr: 19792 + - python-casacore-3.5.2-foss-2023b.eb: + options: + from-pr: 20089 + - libspatialindex-1.9.3-GCCcore-13.2.0.eb: + options: + from-pr: 19922 + - LittleCMS-2.15-GCCcore-13.2.0.eb + - giflib-5.2.1-GCCcore-13.2.0.eb + - OpenJPEG-2.5.0-GCCcore-13.2.0.eb + - libwebp-1.3.2-GCCcore-13.2.0.eb + - Wayland-1.22.0-GCCcore-13.2.0.eb + - Qt5-5.15.13-GCCcore-13.2.0.eb: + options: + from-pr: 20201 + - OSU-Micro-Benchmarks-7.2-gompi-2023b.eb diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2022b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2022b.yml new file mode 100644 index 0000000000..1805c581c3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2022b.yml @@ -0,0 +1,8 @@ +easyconfigs: + - R-bundle-Bioconductor-3.16-foss-2022b-R-4.2.2.eb: + options: + from-pr: 20379 + - ParaView-5.11.1-foss-2022b.eb + - ASE-3.22.1-gfbf-2022b.eb + - SEPP-4.5.1-foss-2022b.eb + - Valgrind-3.21.0-gompi-2022b.eb diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2023a.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2023a.yml new file mode 100644 index 0000000000..d35be0c6c2 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2023a.yml @@ -0,0 +1,22 @@ +easyconfigs: + - Python-3.11.3-GCCcore-12.3.0.eb + - hatchling-1.18.0-GCCcore-12.3.0.eb + - Python-bundle-PyPI-2023.06-GCCcore-12.3.0.eb + - ncdu-1.18-GCC-12.3.0.eb + - SAMtools-1.18-GCC-12.3.0.eb + - R-bundle-Bioconductor-3.18-foss-2023a-R-4.3.2.eb: + options: + from-pr: 20379 + - ipympl-0.9.3-gfbf-2023a.eb: + options: + from-pr: 18852 + - ESPResSo-4.2.2-foss-2023a.eb: + options: + from-pr: 20595 + - GATK-4.5.0.0-GCCcore-12.3.0-Java-17.eb + - WhatsHap-2.2-foss-2023a.eb + - BLAST+-2.14.1-gompi-2023a.eb: + options: + from-pr: 20784 + - Valgrind-3.21.0-gompi-2023a.eb + - OrthoFinder-2.5.5-foss-2023a.eb diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2023b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2023b.yml new file mode 100644 index 0000000000..987d8c2625 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.1-2023b.yml @@ -0,0 +1,16 @@ +easyconfigs: + - Python-3.11.5-GCCcore-13.2.0.eb + - hatchling-1.18.0-GCCcore-13.2.0.eb + - Python-bundle-PyPI-2023.10-GCCcore-13.2.0.eb + - scikit-build-core-0.9.3-GCCcore-13.2.0.eb: + options: + # from-commit: 61d07bff09afe63cfe1ae35dc58a0c8be01eed62 + from-pr: 20526 + - GROMACS-2024.1-foss-2023b.eb: + options: + # from-commit: a0a467a88506c765a93a96b20d7a8fcb01d46b24 + from-pr: 20522 + - NLTK-3.8.1-foss-2023b.eb + - Valgrind-3.23.0-gompi-2023b.eb: + options: + from-pr: 20792 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-001-system.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-001-system.yml new file mode 100644 index 0000000000..18e5f0a3e9 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-001-system.yml @@ -0,0 +1,7 @@ +easyconfigs: + - ReFrame-4.6.2.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21307 + from-commit: 0c4bd5c5a80f571a8932fbc38880d72455406816 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3431 + include-easyblocks-from-commit: efddeb02abe1a679324ac01ef19601dedbe79cc0 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2022b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2022b.yml new file mode 100644 index 0000000000..e5464dc4e2 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2022b.yml @@ -0,0 +1,53 @@ +easyconfigs: + - GObject-Introspection-1.74.0-GCCcore-12.2.0.eb + - BLAST+-2.14.0-gompi-2022b.eb + - BioPerl-1.7.8-GCCcore-12.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21136 + from-commit: d8076ebaf8cb915762adebf88d385cc672b350dc + - gnuplot-5.4.6-GCCcore-12.2.0.eb + - h5py-3.8.0-foss-2022b.eb + - MDAnalysis-2.4.2-foss-2022b.eb + - ncbi-vdb-3.0.5-gompi-2022b.eb + - Bio-DB-HTS-3.01-GCC-12.2.0.eb + - MAFFT-7.505-GCC-12.2.0-with-extensions.eb + - MetaEuk-6-GCC-12.2.0.eb + - BamTools-2.5.2-GCC-12.2.0.eb + - Bio-SearchIO-hmmer-1.7.3-GCC-12.2.0.eb + - Mash-2.3-GCC-12.2.0.eb + - CapnProto-0.10.3-GCCcore-12.2.0.eb + - WhatsHap-2.1-foss-2022b.eb + - SAMtools-1.17-GCC-12.2.0.eb + - Bowtie2-2.5.1-GCC-12.2.0.eb + - CD-HIT-4.8.1-GCC-12.2.0.eb + - VCFtools-0.1.16-GCC-12.2.0.eb + - GenomeTools-1.6.2-GCC-12.2.0.eb + - Bio-SearchIO-hmmer-1.7.3-GCC-12.2.0.eb + - parallel-20230722-GCCcore-12.2.0.eb + - BCFtools-1.17-GCC-12.2.0.eb + - lpsolve-5.5.2.11-GCC-12.2.0.eb + - fastp-0.23.4-GCC-12.2.0.eb + - KronaTools-2.8.1-GCCcore-12.2.0.eb + - MultiQC-1.14-foss-2022b.eb + - CGAL-5.5.2-GCCcore-12.2.0.eb + - KaHIP-3.14-gompi-2022b.eb + - MPC-1.3.1-GCCcore-12.2.0.eb + - MUMPS-5.6.1-foss-2022b-metis.eb + - GL2PS-1.4.2-GCCcore-12.2.0.eb + - GST-plugins-base-1.22.1-GCC-12.2.0.eb + - wxWidgets-3.2.2.1-GCC-12.2.0.eb + - Archive-Zip-1.68-GCCcore-12.2.0.eb + - jemalloc-5.3.0-GCCcore-12.2.0.eb + - Judy-1.0.5-GCCcore-12.2.0.eb + - libaio-0.3.113-GCCcore-12.2.0.eb + - Z3-4.12.2-GCCcore-12.2.0.eb + - tbb-2021.10.0-GCCcore-12.2.0.eb + - dask-2023.7.1-foss-2022b.eb + - netcdf4-python-1.6.3-foss-2022b.eb + - Ruby-3.2.2-GCCcore-12.2.0.eb + - ROOT-6.26.10-foss-2022b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21526 + from-commit: 6cbfbd7d7a55dc7243f46d0beea510278f4718df + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3467 + include-easyblocks-from-commit: c3aebe1f133d064a228c5d6c282e898b83d74601 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2023a.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2023a.yml new file mode 100644 index 0000000000..3caa1edf62 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2023a.yml @@ -0,0 +1,82 @@ +easyconfigs: + - GObject-Introspection-1.76.1-GCCcore-12.3.0.eb + - at-spi2-core-2.49.91-GCCcore-12.3.0.eb + - OpenFOAM-10-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - OpenFOAM-11-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - BCFtools-1.18-GCC-12.3.0.eb + - BWA-0.7.18-GCCcore-12.3.0.eb + - CapnProto-1.0.1-GCCcore-12.3.0.eb + - DendroPy-4.6.1-GCCcore-12.3.0.eb + - DIAMOND-2.1.8-GCC-12.3.0.eb + - FastME-2.1.6.3-GCC-12.3.0.eb + - fastp-0.23.4-GCC-12.3.0.eb + - HMMER-3.4-gompi-2023a.eb + - IQ-TREE-2.3.5-gompi-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20955 + from-commit: 185f88b9a03d65a7fb74edc7acb4221e87e90784 + - KronaTools-2.8.1-GCCcore-12.3.0.eb + - LSD2-2.4.1-GCCcore-12.3.0.eb + - MAFFT-7.520-GCC-12.3.0-with-extensions.eb + - ncbi-vdb-3.0.10-gompi-2023a.eb + - MetalWalls-21.06.1-foss-2023a.eb + - QuantumESPRESSO-7.3.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20138 + from-commit: dbdaacc0739fdee91baa9123864ea4428cf21273 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3338 + include-easyblocks-from-commit: 32e45bd1f2d916732ca5852d55d17fa4d99e388b + - CP2K-2023.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20951 + from-commit: a92667fe32396bbd4106243658625f7ff2adcd68 + - amdahl-0.3.1-gompi-2023a.eb + - xarray-2023.9.0-gfbf-2023a.eb + - SciTools-Iris-3.9.0-foss-2023a.eb + - OpenFOAM-v2312-foss-2023a.eb: + options: + # https://github.com/easybuilders/easybuild-easyblocks/pull/3388 + include-easyblocks-from-commit: c8256a36e7062bc09f5ce30552a9de9827054c9e + # https://github.com/easybuilders/easybuild-easyconfigs/pull/20841 + from-commit: f0e91e6e430ebf902f7788ebb47f0203dee60649 + - BioPerl-1.7.8-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21136 + from-commit: d8076ebaf8cb915762adebf88d385cc672b350dc + - grpcio-1.57.0-GCCcore-12.3.0.eb + - orjson-3.9.15-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20880 + from-commit: bc6e08f89759b8b70166de5bfcb5056b9db8ec90 + - wradlib-2.0.3-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21094 + from-commit: 3a2e0b8e6ee45277d01fb7e2eb93027a28c9461a + - MBX-1.1.0-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21155 + from-commit: 6929a67401f2a2ec58f91fb306332a77497d73ff + - Transrate-1.0.3-GCC-12.3.0.eb: + options: + # https://github.com/easybuilders/easybuild-easyblocks/pull/3381 + include-easyblocks-from-commit: bb86f05d4917b29e022023f152efdf0ca5c14ded + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20964 + from-commit: 7d539a9e599d8bc5ac2bda6ee9587ef62351ee03 + - Critic2-1.2-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20833 + from-commit: 78426c2383fc7e4b9b9e77d7a77f336e1bee3843 + - LRBinner-0.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21310 + from-commit: 799d9101df2cf81aabe252f00cc82a7246363f53 + - Redland-1.0.17-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21227 + from-commit: 4c5e3455dec31e68e8383c7fd86d1f80c434676d diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2023b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2023b.yml new file mode 100644 index 0000000000..02bd5f6f43 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.2-2023b.yml @@ -0,0 +1,29 @@ +easyconfigs: + - GObject-Introspection-1.78.1-GCCcore-13.2.0.eb + - at-spi2-core-2.50.0-GCCcore-13.2.0.eb + - IPython-8.17.2-GCCcore-13.2.0.eb + - dlb-3.4-gompi-2023b.eb + - pystencils-1.3.4-gfbf-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20889 + from-commit: c66c4788a17f7e4f55aa23f9fdb782aad97c9ce7 + - Extrae-4.2.0-gompi-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21017 + from-commit: 120f4d56efebd2bc61382db4c84a664a339c66cf + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3393 + include-easyblocks-from-commit: c4951c78d62fa5cf8e9f6fe0ead212d2a4d7cb9c + - pyMBE-0.8.0-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21034 + from-commit: 76e7fc6657bab64bfbec826540a3a8f0040258f2 + - STAR-2.7.11b-GCC-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21200 + from-commit: 765ba900daf5953e306c4dad896febe52fdd6c00 + - HPL-2.3-foss-2023b.eb + - R-bundle-CRAN-2024.06-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21366 + # we use a commit from the Brunsli PR here to get rid of the Highway dependency + from-commit: 1736a123b1685836452587a5c51793257570bb2d diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.3-2023a.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.3-2023a.yml new file mode 100644 index 0000000000..0c863f0025 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.3-2023a.yml @@ -0,0 +1,8 @@ +easyconfigs: + - ccache-4.9-GCCcore-12.3.0.eb + - GDB-13.2-GCCcore-12.3.0.eb + - tmux-3.3a-GCCcore-12.3.0.eb + - Vim-9.1.0004-GCCcore-12.3.0.eb + - gmsh-4.12.2-foss-2023a.eb + - basemap-1.3.9-foss-2023a.eb + - geopandas-0.14.2-foss-2023a.eb \ No newline at end of file diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.3-2023b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.3-2023b.yml new file mode 100644 index 0000000000..2cf72ca098 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.3-2023b.yml @@ -0,0 +1,11 @@ +easyconfigs: + - GROMACS-2024.3-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21430 + from-commit: 8b509882d03402e2998ff9b22c154a6957e36d6b + - LAMMPS-29Aug2024-foss-2023b-kokkos.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21436 + from-commit: 9dc24e57880a8adb06ae10557c5315e66671a533 + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3569 + include-easyblocks-from-commit: 362b4679193612e04abe336fa041e2a34d183991 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-001-system.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-001-system.yml new file mode 100644 index 0000000000..c92d62717b --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-001-system.yml @@ -0,0 +1,10 @@ +easyconfigs: + - EasyBuild-4.8.2.eb + - EasyBuild-4.9.0.eb + - EasyBuild-4.9.1.eb + - EasyBuild-4.9.2.eb + - EasyBuild-4.9.3.eb + - EasyBuild-4.9.4.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21465 + from-commit: 39cdebd7bd2cb4a9c170ee22439401316b2e7a25 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2022b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2022b.yml new file mode 100644 index 0000000000..ac5139290c --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2022b.yml @@ -0,0 +1,5 @@ +easyconfigs: + - OpenBLAS-0.3.21-GCC-12.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3492 + include-easyblocks-from-commit: d06d9617d9bfb63d338b6879eab9da81c8a312d8 diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2023a.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2023a.yml new file mode 100644 index 0000000000..c50f0ddf88 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2023a.yml @@ -0,0 +1,48 @@ +easyconfigs: + - librosa-0.10.1-foss-2023a.eb + - ROOT-6.30.06-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21526 + from-commit: 6cbfbd7d7a55dc7243f46d0beea510278f4718df + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3467 + include-easyblocks-from-commit: c3aebe1f133d064a228c5d6c282e898b83d74601 + - waLBerla-6.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21600 + from-commit: 9b12318bcff1749781d9eb71c23e21bc3a79ed01 + - mpl-ascii-0.10.0-gfbf-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21679 + from-commit: 7106f63160b1418d605882dd02ba151d099300bd + - jedi-0.19.0-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21650 + from-commit: 109998f6adcda7efb4174b1e5f73b41ee82d1f13 + - Solids4foam-2.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21606 + from-commit: 63562c58acf1be64407192b6862c3bd80253d2e0 + - Cassiopeia-2.0.0-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21657 + from-commit: 7f1f0e60487e7e1fcb5c4e6bc4fbc4f89994e3fd + - LightGBM-4.5.0-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21699 + from-commit: e3407bd127d248c08960f6b09c973da0fdecc2c3 + - OpenFOAM-v2406-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3519 + include-easyblocks-from-commit: e4a3ff1932350d575dffc7597435609fad6dd691 + - Paraver-4.11.4-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20230 + from-commit: 91c8df6b4c0810061e9f325427c9c79e961bc4b0 + - Tombo-1.5.1-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21925 + from-commit: 522ca010ab11949ab9594037f72b975cf1cd0d33 + - elfx86exts-0.6.2-GCC-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/22145 + from-commit: 31478e5c9869de3add74d0a02dd5df01ea65b21e diff --git a/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2023b.yml b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2023b.yml new file mode 100644 index 0000000000..ee161b8b9c --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/sapphire_rapids/eessi-2023.06-eb-4.9.4-2023b.yml @@ -0,0 +1,27 @@ +easyconfigs: + - SIONlib-1.7.7-GCCcore-13.2.0-tools.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21752 + from-commit: 6b8b53493a1188a5baa56a133574daac239730e7 + - Score-P-8.4-gompi-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3496 + include-easyblocks-from-commit: 60633b0acfd41a0732992d9e16800dae71a056eb + - Cython-3.0.10-GCCcore-13.2.0.eb + - Mustache-1.3.3-foss-2023b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21783 + from-commit: 5fa3db9eb36f91cba3fbf351549f8ba2849abc33 + - GDRCopy-2.4-GCCcore-13.2.0.eb + - GROMACS-2024.4-foss-2023b.eb: + options: + # https://github.com/easybuilders/easybuild-easyconfigs/pull/21851 + from-commit: f0fa64b440deaf5fb0a6d26ff1bb3e9f36626c8a + - SlurmViewer-1.0.1-GCCcore-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21899 + from-commit: 0bdeb23c9ea5a3caefd353ecd936919424c1bba4 + - wxWidgets-3.2.6-GCC-13.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21915 + from-commit: 58f16c0caf8c5494c68e9eda8cbf19e9145d3cfa diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.8.2-2022b.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.8.2-2022b.yml new file mode 100644 index 0000000000..ddc783d11a --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.8.2-2022b.yml @@ -0,0 +1,11 @@ +easyconfigs: + # Adding OpenMPI explicitely, as defined in 20240301-eb-4.9.0-OpenMPI-4.1.x-fix-smcuda.yml + - OpenMPI-4.1.4-GCC-12.2.0.eb: + options: + from-pr: 19940 + - foss-2022b.eb + - HarfBuzz-5.3.1-GCCcore-12.2.0.eb: + options: + from-pr: 19339 + - Qt5-5.15.7-GCCcore-12.2.0.eb + - QuantumESPRESSO-7.2-foss-2022b.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.0-2022b.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.0-2022b.yml new file mode 100644 index 0000000000..763fcb20a8 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.0-2022b.yml @@ -0,0 +1,28 @@ +easyconfigs: + # Adding Python explicitely, as defined in 20240729-eb-4.9.2-Python-ctypes.yml + - Python-3.10.8-GCCcore-12.2.0-bare: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + # Can't use include-easyblocks-from-commit here, as was done for rebuilds for the other archs + # because the eb version from this easystack isn't new enough to know it + # include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + include-easyblocks-from-pr: 3352 + - Python-3.10.8-GCCcore-12.2.0: + options: + # See https://github.com/easybuilders/easybuild-easyblocks/pull/3352 + # Can't use include-easyblocks-from-commit here, as was done for rebuilds for the other archs + # because the eb version from this easystack isn't new enough to know it + # include-easyblocks-from-commit: 1ee17c0f7726c69e97442f53c65c5f041d65c94f + include-easyblocks-from-pr: 3352 + - SciPy-bundle-2023.02-gfbf-2022b.eb + - GDAL-3.6.2-foss-2022b.eb + - waLBerla-6.1-foss-2022b.eb: + options: + from-pr: 19324 + - WRF-4.4.1-foss-2022b-dmpar.eb + - ImageMagick-7.1.0-53-GCCcore-12.2.0.eb: + options: + from-pr: 20086 + - R-4.2.2-foss-2022b.eb: + options: + from-pr: 20238 diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-001-system.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-001-system.yml new file mode 100644 index 0000000000..c5a08b5209 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-001-system.yml @@ -0,0 +1,4 @@ +easyconfigs: + - EasyBuild-4.9.1.eb: + options: + from-pr: 20299 diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2022b.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2022b.yml new file mode 100644 index 0000000000..1805c581c3 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2022b.yml @@ -0,0 +1,8 @@ +easyconfigs: + - R-bundle-Bioconductor-3.16-foss-2022b-R-4.2.2.eb: + options: + from-pr: 20379 + - ParaView-5.11.1-foss-2022b.eb + - ASE-3.22.1-gfbf-2022b.eb + - SEPP-4.5.1-foss-2022b.eb + - Valgrind-3.21.0-gompi-2022b.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2023a.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2023a.yml new file mode 100644 index 0000000000..a529746676 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2023a.yml @@ -0,0 +1,4 @@ +easyconfigs: + - foss-2023a.eb + - SciPy-bundle-2023.07-gfbf-2023a.eb + - ESPResSo-4.2.1-foss-2023a.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2023b.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2023b.yml new file mode 100644 index 0000000000..bc736c4056 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.1-2023b.yml @@ -0,0 +1,3 @@ +easyconfigs: + - foss-2023b.eb + - SciPy-bundle-2023.11-gfbf-2023b.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-001-system.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-001-system.yml new file mode 100644 index 0000000000..f1fde247d0 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-001-system.yml @@ -0,0 +1,2 @@ +easyconfigs: + - ReFrame-4.3.3.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2022b.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2022b.yml new file mode 100644 index 0000000000..969b0d469b --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2022b.yml @@ -0,0 +1,52 @@ +easyconfigs: + - BLAST+-2.14.0-gompi-2022b.eb + - BioPerl-1.7.8-GCCcore-12.2.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21136 + from-commit: d8076ebaf8cb915762adebf88d385cc672b350dc + - gnuplot-5.4.6-GCCcore-12.2.0.eb + - h5py-3.8.0-foss-2022b.eb + - MDAnalysis-2.4.2-foss-2022b.eb + - ncbi-vdb-3.0.5-gompi-2022b.eb + - Bio-DB-HTS-3.01-GCC-12.2.0.eb + - MAFFT-7.505-GCC-12.2.0-with-extensions.eb + - MetaEuk-6-GCC-12.2.0.eb + - BamTools-2.5.2-GCC-12.2.0.eb + - Bio-SearchIO-hmmer-1.7.3-GCC-12.2.0.eb + - Mash-2.3-GCC-12.2.0.eb + - CapnProto-0.10.3-GCCcore-12.2.0.eb + - WhatsHap-2.1-foss-2022b.eb + - SAMtools-1.17-GCC-12.2.0.eb + - Bowtie2-2.5.1-GCC-12.2.0.eb + - CD-HIT-4.8.1-GCC-12.2.0.eb + - VCFtools-0.1.16-GCC-12.2.0.eb + - GenomeTools-1.6.2-GCC-12.2.0.eb + - Bio-SearchIO-hmmer-1.7.3-GCC-12.2.0.eb + - parallel-20230722-GCCcore-12.2.0.eb + - BCFtools-1.17-GCC-12.2.0.eb + - lpsolve-5.5.2.11-GCC-12.2.0.eb + - fastp-0.23.4-GCC-12.2.0.eb + - KronaTools-2.8.1-GCCcore-12.2.0.eb + - MultiQC-1.14-foss-2022b.eb + - CGAL-5.5.2-GCCcore-12.2.0.eb + - KaHIP-3.14-gompi-2022b.eb + - MPC-1.3.1-GCCcore-12.2.0.eb + - MUMPS-5.6.1-foss-2022b-metis.eb + - GL2PS-1.4.2-GCCcore-12.2.0.eb + - GST-plugins-base-1.22.1-GCC-12.2.0.eb + - wxWidgets-3.2.2.1-GCC-12.2.0.eb + - Archive-Zip-1.68-GCCcore-12.2.0.eb + - jemalloc-5.3.0-GCCcore-12.2.0.eb + - Judy-1.0.5-GCCcore-12.2.0.eb + - libaio-0.3.113-GCCcore-12.2.0.eb + - Z3-4.12.2-GCCcore-12.2.0.eb + - tbb-2021.10.0-GCCcore-12.2.0.eb + - dask-2023.7.1-foss-2022b.eb + - netcdf4-python-1.6.3-foss-2022b.eb + - Ruby-3.2.2-GCCcore-12.2.0.eb + - ROOT-6.26.10-foss-2022b.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21526 + from-commit: 6cbfbd7d7a55dc7243f46d0beea510278f4718df + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3467 + include-easyblocks-from-commit: c3aebe1f133d064a228c5d6c282e898b83d74601 diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2023a.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2023a.yml new file mode 100644 index 0000000000..316754a6d1 --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2023a.yml @@ -0,0 +1,25 @@ +easyconfigs: + - ESPResSo-4.2.2-foss-2023a.eb + - TensorFlow-2.13.0-foss-2023a.eb + - R-4.3.2-gfbf-2023a.eb + - ParaView-5.11.2-foss-2023a.eb + - OpenFOAM-10-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - OpenFOAM-11-foss-2023a.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20958 + from-commit: dbadb2074464d816740ee0e95595c2cb31b6338f + - Highway-1.0.4-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/20942 + from-commit: 524da37b903585cea5a9eeb4156d1c8d57636bd8 + - librosa-0.10.1-foss-2023a.eb + - R-bundle-Bioconductor-3.18-foss-2023a-R-4.3.2.eb + - BioPerl-1.7.8-GCCcore-12.3.0.eb: + options: + # see https://github.com/easybuilders/easybuild-easyconfigs/pull/21136 + from-commit: d8076ebaf8cb915762adebf88d385cc672b350dc + - MODFLOW-6.4.4-foss-2023a.eb + - ALL-0.9.2-foss-2023a.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2023b.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2023b.yml new file mode 100644 index 0000000000..30a6745ccc --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.2-2023b.yml @@ -0,0 +1,18 @@ +easyconfigs: + - GROMACS-2024.1-foss-2023b.eb + - netCDF-4.9.2-gompi-2023b.eb + - matplotlib-3.8.2-gfbf-2023b.eb + - DP3-6.0-foss-2023b.eb + - WSClean-3.4-foss-2023b.eb + - CDO-2.2.2-gompi-2023b.eb + - python-casacore-3.5.2-foss-2023b.eb + - libspatialindex-1.9.3-GCCcore-13.2.0.eb + - LittleCMS-2.15-GCCcore-13.2.0.eb + - giflib-5.2.1-GCCcore-13.2.0.eb + - OpenJPEG-2.5.0-GCCcore-13.2.0.eb + - libwebp-1.3.2-GCCcore-13.2.0.eb + - Wayland-1.22.0-GCCcore-13.2.0.eb + - Qt5-5.15.13-GCCcore-13.2.0.eb + - OSU-Micro-Benchmarks-7.2-gompi-2023b.eb + - NLTK-3.8.1-foss-2023b.eb + - Valgrind-3.23.0-gompi-2023b.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.3-001-system.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.3-001-system.yml new file mode 100644 index 0000000000..25337649ce --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.3-001-system.yml @@ -0,0 +1,4 @@ +easyconfigs: + - Nextflow-23.10.0.eb + - EasyBuild-4.8.2.eb + - EasyBuild-4.9.0.eb diff --git a/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.3-2023a.yml b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.3-2023a.yml new file mode 100644 index 0000000000..519d7701dc --- /dev/null +++ b/easystacks/software.eessi.io/2023.06/zen4/eessi-2023.06-eb-4.9.3-2023a.yml @@ -0,0 +1,19 @@ +easyconfigs: + - LAMMPS-2Aug2023_update2-foss-2023a-kokkos.eb + - JupyterNotebook-7.0.2-GCCcore-12.3.0.eb + - PyQt5-5.15.10-GCCcore-12.3.0.eb + - OrthoFinder-2.5.5-foss-2023a.eb + - snakemake-8.4.2-foss-2023a.eb + - Rivet-3.1.9-gompi-2023a-HepMC3-3.2.6.eb + - GATK-4.5.0.0-GCCcore-12.3.0-Java-17.eb + - ipympl-0.9.3-gfbf-2023a.eb + - LHAPDF-6.5.4-GCC-12.3.0.eb + - LoopTools-2.15-GCC-12.3.0.eb + - ncdu-1.18-GCC-12.3.0.eb + - WhatsHap-2.2-foss-2023a.eb + - PyOpenGL-3.1.7-GCCcore-12.3.0.eb + - SAMtools-1.18-GCC-12.3.0.eb + - CDO-2.2.2-gompi-2023a.eb + - OSU-Micro-Benchmarks-7.1-1-gompi-2023a.eb + - BWA-0.7.17-20220923-GCCcore-12.3.0.eb + - Valgrind-3.21.0-gompi-2023a.eb diff --git a/eb_hooks.py b/eb_hooks.py index 2fba925b01..9f3793a0db 100644 --- a/eb_hooks.py +++ b/eb_hooks.py @@ -1,17 +1,71 @@ # Hooks to customize how EasyBuild installs software in EESSI # see https://docs.easybuild.io/en/latest/Hooks.html +import glob import os import re +import easybuild.tools.environment as env from easybuild.easyblocks.generic.configuremake import obtain_config_guess +from easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS from easybuild.tools.build_log import EasyBuildError, print_msg from easybuild.tools.config import build_option, update_build_option -from easybuild.tools.filetools import apply_regex_substitutions, copy_file, which +from easybuild.tools.filetools import apply_regex_substitutions, copy_file, remove_file, symlink, which from easybuild.tools.run import run_cmd from easybuild.tools.systemtools import AARCH64, POWER, X86_64, get_cpu_architecture, get_cpu_features from easybuild.tools.toolchain.compiler import OPTARCH_GENERIC +# prefer importing LooseVersion from easybuild.tools, but fall back to distuils in case EasyBuild <= 4.7.0 is used +try: + from easybuild.tools import LooseVersion +except ImportError: + from distutils.version import LooseVersion + + +CPU_TARGET_NEOVERSE_N1 = 'aarch64/neoverse_n1' +CPU_TARGET_NEOVERSE_V1 = 'aarch64/neoverse_v1' +CPU_TARGET_AARCH64_GENERIC = 'aarch64/generic' +CPU_TARGET_A64FX = 'aarch64/a64fx' + +CPU_TARGET_SAPPHIRE_RAPIDS = 'x86_64/intel/sapphire_rapids' +CPU_TARGET_ZEN4 = 'x86_64/amd/zen4' + EESSI_RPATH_OVERRIDE_ATTR = 'orig_rpath_override_dirs' +EESSI_MODULE_ONLY_ATTR = 'orig_module_only' +EESSI_FORCE_ATTR = 'orig_force' + +SYSTEM = EASYCONFIG_CONSTANTS['SYSTEM'][0] + +EESSI_INSTALLATION_REGEX = r"^/cvmfs/[^/]*.eessi.io/versions/" +HOST_INJECTIONS_LOCATION = "/cvmfs/software.eessi.io/host_injections/" + +# Make sure a single environment variable name is used for this throughout the hooks +EESSI_IGNORE_ZEN4_GCC1220_ENVVAR="EESSI_IGNORE_LMOD_ERROR_ZEN4_GCC1220" + +def is_gcccore_1220_based(**kwargs): +# ecname, ecversion, tcname, tcversion): + """ + Checks if this easyconfig either _is_ or _uses_ a GCCcore-12.2.0 based toolchain. + This function is, for example, used to generate errors in GCCcore-12.2.0 based modules for the zen4 architecture + since zen4 is not fully supported with that toolchain. + + :param str ecname: Name of the software specified in the EasyConfig + :param str ecversion: Version of the software specified in the EasyConfig + :param str tcname: Toolchain name specified in the EasyConfig + :param str tcversion: Toolchain version specified in the EasyConfig + """ + ecname = kwargs.get('ecname', None) + ecversion = kwargs.get('ecversion', None) + tcname = kwargs.get('tcname', None) + tcversion = kwargs.get('tcversion', None) + + gcccore_based_names = ['GCCcore', 'GCC'] + foss_based_names = ['gfbf', 'gompi', 'foss'] + return ( + (tcname in foss_based_names and tcversion == '2022b') or + (tcname in gcccore_based_names and LooseVersion(tcversion) == LooseVersion('12.2.0')) or + (ecname in foss_based_names and ecversion == '2022b') or + (ecname in gcccore_based_names and LooseVersion(ecversion) == LooseVersion('12.2.0')) + ) def get_eessi_envvar(eessi_envvar): @@ -55,12 +109,32 @@ def parse_hook(ec, *args, **kwargs): if ec.name in PARSE_HOOKS: PARSE_HOOKS[ec.name](ec, eprefix) + # Always trigger this one, regardless of ec.name + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if cpu_target == CPU_TARGET_ZEN4: + parse_hook_zen4_module_only(ec, eprefix) -def pre_configure_hook(self, *args, **kwargs): - """Main pre-configure hook: trigger custom functions based on software name.""" + # inject the GPU property (if required) + ec = inject_gpu_property(ec) - if self.name in PRE_CONFIGURE_HOOKS: - PRE_CONFIGURE_HOOKS[self.name](self, *args, **kwargs) + +def post_ready_hook(self, *args, **kwargs): + """ + Post-ready hook: limit parallellism for selected builds, because they require a lot of memory per used core. + """ + # 'parallel' easyconfig parameter is set via EasyBlock.set_parallel in ready step based on available cores. + # here we reduce parallellism to only use half of that for selected software, + # to avoid failing builds/tests due to out-of-memory problems; + memory_hungry_build = self.name in ['libxc', 'MBX', 'TensorFlow'] + # on A64FX systems, (HBM) memory is typically scarce, so we need to use fewer cores for some builds + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + memory_hungry_build_a64fx = cpu_target == CPU_TARGET_A64FX and self.name in ['Qt5', 'ROOT'] + if memory_hungry_build or memory_hungry_build_a64fx: + parallel = self.cfg['parallel'] + if parallel > 1: + self.cfg['parallel'] = parallel // 2 + msg = "limiting parallelism to %s (was %s) for %s to avoid out-of-memory failures during building/testing" + print_msg(msg % (self.cfg['parallel'], parallel, self.name), log=self.log) def pre_prepare_hook(self, *args, **kwargs): @@ -90,11 +164,20 @@ def pre_prepare_hook(self, *args, **kwargs): print_msg("Updated rpath_override_dirs (to allow overriding MPI family %s): %s", mpi_family, rpath_override_dirs) + if self.name in PRE_PREPARE_HOOKS: + PRE_PREPARE_HOOKS[self.name](self, *args, **kwargs) + + # Always trigger this one, regardless of ec.name + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if cpu_target == CPU_TARGET_ZEN4: + pre_prepare_hook_ignore_zen4_gcccore1220_error(self, *args, **kwargs) -def gcc_postprepare(self, *args, **kwargs): + +def post_prepare_hook_gcc_prefixed_ld_rpath_wrapper(self, *args, **kwargs): """ Post-configure hook for GCCcore: - - copy RPATH wrapper script for linker commands to also have a wrapper in place with system type prefix like 'x86_64-pc-linux-gnu' + - copy RPATH wrapper script for linker commands to also have a wrapper in + place with system type prefix like 'x86_64-pc-linux-gnu' """ if self.name == 'GCCcore': config_guess = obtain_config_guess() @@ -121,6 +204,7 @@ def gcc_postprepare(self, *args, **kwargs): else: raise EasyBuildError("GCCcore-specific hook triggered for non-GCCcore easyconfig?!") + def post_prepare_hook(self, *args, **kwargs): """Main post-prepare hook: trigger custom functions.""" @@ -133,8 +217,41 @@ def post_prepare_hook(self, *args, **kwargs): if self.name in POST_PREPARE_HOOKS: POST_PREPARE_HOOKS[self.name](self, *args, **kwargs) + # Always trigger this one, regardless of ec.name + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if cpu_target == CPU_TARGET_ZEN4: + post_prepare_hook_ignore_zen4_gcccore1220_error(self, *args, **kwargs) + + +def parse_hook_casacore_disable_vectorize(ec, eprefix): + """ + Disable 'vectorize' toolchain option for casacore 3.5.0 on aarch64/neoverse_v1 + Compiling casacore 3.5.0 with GCC 13.2.0 (foss-2023b) gives an error when building for aarch64/neoverse_v1. + See also, https://github.com/EESSI/software-layer/pull/479 + """ + if ec.name == 'casacore': + tcname, tcversion = ec['toolchain']['name'], ec['toolchain']['version'] + if ( + LooseVersion(ec.version) == LooseVersion('3.5.0') and + tcname == 'foss' and tcversion == '2023b' + ): + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if cpu_target == CPU_TARGET_NEOVERSE_V1: + # Make sure the toolchainopts key exists, and the value is a dict, + # before we add the option to disable vectorization + if 'toolchainopts' not in ec or ec['toolchainopts'] is None: + ec['toolchainopts'] = {} + ec['toolchainopts']['vectorize'] = False + print_msg("Changed toochainopts for %s: %s", ec.name, ec['toolchainopts']) + else: + print_msg("Not changing option vectorize for %s on non-neoverse_v1", ec.name) + else: + print_msg("Not changing option vectorize for %s %s %s", ec.name, ec.version, ec.toolchain) + else: + raise EasyBuildError("casacore-specific hook triggered for non-casacore easyconfig?!") + -def cgal_toolchainopts_precise(ec, eprefix): +def parse_hook_cgal_toolchainopts_precise(ec, eprefix): """Enable 'precise' rather than 'strict' toolchain option for CGAL on POWER.""" if ec.name == 'CGAL': if get_cpu_architecture() == POWER: @@ -147,7 +264,7 @@ def cgal_toolchainopts_precise(ec, eprefix): raise EasyBuildError("CGAL-specific hook triggered for non-CGAL easyconfig?!") -def fontconfig_add_fonts(ec, eprefix): +def parse_hook_fontconfig_add_fonts(ec, eprefix): """Inject --with-add-fonts configure option for fontconfig.""" if ec.name == 'fontconfig': # make fontconfig aware of fonts included with compat layer @@ -158,7 +275,72 @@ def fontconfig_add_fonts(ec, eprefix): raise EasyBuildError("fontconfig-specific hook triggered for non-fontconfig easyconfig?!") -def ucx_eprefix(ec, eprefix): +def parse_hook_grpcio_zlib(ec, ecprefix): + """Adjust preinstallopts to use ZLIB from compat layer.""" + if ec.name == 'grpcio' and ec.version in ['1.57.0']: + exts_list = ec['exts_list'] + original_preinstallopts = (exts_list[0][2])['preinstallopts'] + original_option = "GRPC_PYTHON_BUILD_SYSTEM_ZLIB=True" + new_option = "GRPC_PYTHON_BUILD_SYSTEM_ZLIB=False" + (exts_list[0][2])['preinstallopts'] = original_preinstallopts.replace(original_option, new_option, 1) + print_msg("Modified the easyconfig to use compat ZLIB with GRPC_PYTHON_BUILD_SYSTEM_ZLIB=False") + else: + raise EasyBuildError("grpcio-specific hook triggered for a non-grpcio easyconfig?!") + + +def parse_hook_openblas_relax_lapack_tests_num_errors(ec, eprefix): + """Relax number of failing numerical LAPACK tests for aarch64/neoverse_v1 CPU target for OpenBLAS < 0.3.23""" + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if ec.name == 'OpenBLAS': + if LooseVersion(ec.version) < LooseVersion('0.3.23'): + # relax maximum number of failed numerical LAPACK tests for aarch64/neoverse_v1 CPU target + # since the default setting of 150 that works well on other aarch64 targets and x86_64 is a bit too strict + # See https://github.com/EESSI/software-layer/issues/314 + cfg_option = 'max_failing_lapack_tests_num_errors' + if cpu_target == CPU_TARGET_NEOVERSE_V1: + orig_value = ec[cfg_option] + ec[cfg_option] = 400 + print_msg("Maximum number of failing LAPACK tests with numerical errors for %s relaxed to %s (was %s)", + ec.name, ec[cfg_option], orig_value) + else: + print_msg("Not changing option %s for %s on non-AARCH64", cfg_option, ec.name) + else: + raise EasyBuildError("OpenBLAS-specific hook triggered for non-OpenBLAS easyconfig?!") + + +def parse_hook_pybind11_replace_catch2(ec, eprefix): + """ + Replace Catch2 build dependency in pybind11 easyconfigs with one that doesn't use system toolchain. + cfr. https://github.com/easybuilders/easybuild-easyconfigs/pull/19270 + """ + # this is mainly necessary to avoid that --missing keeps reporting Catch2/2.13.9 is missing, + # and to avoid that we need to use "--from-pr 19270" for every easyconfigs that (indirectly) depends on pybind11 + if ec.name == 'pybind11' and ec.version in ['2.10.3', '2.11.1']: + build_deps = ec['builddependencies'] + catch2_build_dep = None + catch2_name, catch2_version = ('Catch2', '2.13.9') + for idx, build_dep in enumerate(build_deps): + if build_dep[0] == catch2_name and build_dep[1] == catch2_version: + catch2_build_dep = build_dep + break + if catch2_build_dep and len(catch2_build_dep) == 4 and catch2_build_dep[3] == SYSTEM: + build_deps[idx] = (catch2_name, catch2_version) + + +def parse_hook_qt5_check_qtwebengine_disable(ec, eprefix): + """ + Disable check for QtWebEngine in Qt5 as workaround for problem with determining glibc version. + """ + if ec.name == 'Qt5': + # workaround for glibc version being reported as "UNKNOWN" in Gentoo Prefix environment by EasyBuild v4.7.2, + # see also https://github.com/easybuilders/easybuild-framework/pull/4290 + ec['check_qtwebengine'] = False + print_msg("Checking for QtWebEgine in Qt5 installation has been disabled") + else: + raise EasyBuildError("Qt5-specific hook triggered for non-Qt5 easyconfig?!") + + +def parse_hook_ucx_eprefix(ec, eprefix): """Make UCX aware of compatibility layer via additional configuration options.""" if ec.name == 'UCX': ec.update('configopts', '--with-sysroot=%s' % eprefix) @@ -168,13 +350,331 @@ def ucx_eprefix(ec, eprefix): raise EasyBuildError("UCX-specific hook triggered for non-UCX easyconfig?!") +def parse_hook_freeimage_aarch64(ec, *args, **kwargs): + """ + Make sure to build with -fPIC on ARM to avoid + https://github.com/EESSI/software-layer/pull/736#issuecomment-2373261889 + """ + if ec.name == 'FreeImage' and ec.version in ('3.18.0',): + if os.getenv('EESSI_CPU_FAMILY') == 'aarch64': + # Make sure the toolchainopts key exists, and the value is a dict, + # before we add the option to enable PIC and disable PNG_ARM_NEON_OPT + if 'toolchainopts' not in ec or ec['toolchainopts'] is None: + ec['toolchainopts'] = {} + ec['toolchainopts']['pic'] = True + ec['toolchainopts']['extra_cflags'] = '-DPNG_ARM_NEON_OPT=0' + print_msg("Changed toolchainopts for %s: %s", ec.name, ec['toolchainopts']) + + +def parse_hook_lammps_remove_deps_for_aarch64(ec, *args, **kwargs): + """ + Remove x86_64 specific dependencies for the CI and missing installations to pass on aarch64 + """ + if ec.name == 'LAMMPS': + if ec.version in ('2Aug2023_update2', '29Aug2024'): + if os.getenv('EESSI_CPU_FAMILY') == 'aarch64': + # ScaFaCoS and tbb are not compatible with aarch64/* CPU targets, + # so remove them as dependencies for LAMMPS (they're optional); + # see also https://github.com/easybuilders/easybuild-easyconfigs/pull/19164 + + # https://github.com/easybuilders/easybuild-easyconfigs/pull/19000; + # we need this hook because we check for missing installations for all CPU targets + # on an x86_64 VM in GitHub Actions (so condition based on ARCH in LAMMPS easyconfig is always true) + ec['dependencies'] = [dep for dep in ec['dependencies'] if dep[0] not in ('ScaFaCoS', 'tbb',)] + else: + raise EasyBuildError("LAMMPS-specific hook triggered for non-LAMMPS easyconfig?!") + + +def parse_hook_CP2K_remove_deps_for_aarch64(ec, *args, **kwargs): + """ + Remove x86_64 specific dependencies for the CI and missing installations to pass on aarch64 + """ + if ec.name == 'CP2K' and ec.version in ('2023.1',): + if os.getenv('EESSI_CPU_FAMILY') == 'aarch64': + # LIBXSMM is not supported on ARM with GCC 12.2.0 and 12.3.0 + # See https://www.cp2k.org/dev:compiler_support + # See https://github.com/easybuilders/easybuild-easyconfigs/pull/20951 + # we need this hook because we check for missing installations for all CPU targets + # on an x86_64 VM in GitHub Actions (so condition based on ARCH in LAMMPS easyconfig is always true) + ec['dependencies'] = [dep for dep in ec['dependencies'] if dep[0] not in ('libxsmm',)] + else: + raise EasyBuildError("CP2K-specific hook triggered for non-CP2K easyconfig?!") + + +def parse_hook_zen4_module_only(ec, eprefix): + """ + Use --force --module-only if building a foss-2022b-based EasyConfig for Zen4. + This toolchain will not be supported on Zen4, so we will generate a modulefile + and have it print an LmodError. + """ + if is_gcccore_1220_based(ecname=ec['name'], ecversion=ec['version'], tcname=ec['toolchain']['name'], + tcversion=ec['toolchain']['version']): + env_varname = EESSI_IGNORE_ZEN4_GCC1220_ENVVAR + # TODO: create a docs page to which we can refer for more info here + # TODO: then update the link to the known issues page to the _specific_ issue + # Need to escape newline character so that the newline character actually ends up in the module file + # (otherwise, it splits the string, and a 2-line string ends up in the modulefile, resulting in syntax error) + errmsg = "EasyConfigs using toolchains based on GCCcore-12.2.0 are not supported for the Zen4 architecture.\\n" + errmsg += "See https://www.eessi.io/docs/known_issues/eessi-2023.06/#gcc-1220-and-foss-2022b-based-modules-cannot-be-loaded-on-zen4-architecture" + ec['modluafooter'] = 'if (not os.getenv("%s")) then LmodError("%s") end' % (env_varname, errmsg) + + +def pre_fetch_hook(self, *args, **kwargs): + """Main pre fetch hook: trigger custom functions based on software name.""" + if self.name in PRE_FETCH_HOOKS: + PRE_FETCH_HOOKS[ec.name](self, *args, **kwargs) + + # Always trigger this one, regardless of self.name + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if cpu_target == CPU_TARGET_ZEN4: + pre_fetch_hook_zen4_gcccore1220(self, *args, **kwargs) + + +def pre_fetch_hook_zen4_gcccore1220(self, *args, **kwargs): + """Use --force --module-only if building a foss-2022b-based EasyConfig for Zen4. + This toolchain will not be supported on Zen4, so we will generate a modulefile + and have it print an LmodError. + """ + if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name, + tcversion=self.toolchain.version): + if hasattr(self, EESSI_MODULE_ONLY_ATTR): + raise EasyBuildError("'self' already has attribute %s! Can't use pre_fetch hook.", + EESSI_MODULE_ONLY_ATTR) + setattr(self, EESSI_MODULE_ONLY_ATTR, build_option('module_only')) + update_build_option('module_only', 'True') + print_msg("Updated build option 'module-only' to 'True'") + + if hasattr(self, EESSI_FORCE_ATTR): + raise EasyBuildError("'self' already has attribute %s! Can't use pre_fetch hook.", + EESSI_FORCE_ATTR) + setattr(self, EESSI_FORCE_ATTR, build_option('force')) + update_build_option('force', 'True') + print_msg("Updated build option 'force' to 'True'") + + +def post_module_hook_zen4_gcccore1220(self, *args, **kwargs): + """Revert changes from pre_fetch_hook_zen4_gcccore1220""" + if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name, + tcversion=self.toolchain.version): + if hasattr(self, EESSI_MODULE_ONLY_ATTR): + update_build_option('module_only', getattr(self, EESSI_MODULE_ONLY_ATTR)) + print_msg("Restored original build option 'module_only' to %s" % getattr(self, EESSI_MODULE_ONLY_ATTR)) + else: + raise EasyBuildError("Cannot restore module_only to it's original value: 'self' is missing attribute %s.", + EESSI_MODULE_ONLY_ATTR) + + if hasattr(self, EESSI_FORCE_ATTR): + update_build_option('force', getattr(self, EESSI_FORCE_ATTR)) + print_msg("Restored original build option 'force' to %s" % getattr(self, EESSI_FORCE_ATTR)) + else: + raise EasyBuildError("Cannot restore force to it's original value: 'self' is misisng attribute %s.", + EESSI_FORCE_ATTR) + + +# Modules for dependencies are loaded in the prepare step. Thus, that's where we need this variable to be set +# so that the modules can be succesfully loaded without printing the error (so that we can create a module +# _with_ the warning for the current software being installed) +def pre_prepare_hook_ignore_zen4_gcccore1220_error(self, *args, **kwargs): + """Set environment variable to ignore the LmodError from parse_hook_zen4_module_only during build phase""" + if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name, + tcversion=self.toolchain.version): + os.environ[EESSI_IGNORE_ZEN4_GCC1220_ENVVAR] = "1" + + +def post_prepare_hook_ignore_zen4_gcccore1220_error(self, *args, **kwargs): + """Unset environment variable to ignore the LmodError from parse_hook_zen4_module_only during build phase""" + if is_gcccore_1220_based(ecname=self.name, ecversion=self.version, tcname=self.toolchain.name, + tcversion=self.toolchain.version): + del os.environ[EESSI_IGNORE_ZEN4_GCC1220_ENVVAR] + + +def pre_prepare_hook_highway_handle_test_compilation_issues(self, *args, **kwargs): + """ + Solve issues with compiling or running the tests on both + neoverse_n1 and neoverse_v1 with Highway 1.0.4 and GCC 12.3.0: + - for neoverse_n1 we set optarch to GENERIC + - for neoverse_v1 and a64fx we completely disable the tests + cfr. https://github.com/EESSI/software-layer/issues/469 + """ + if self.name == 'Highway': + tcname, tcversion = self.toolchain.name, self.toolchain.version + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + # note: keep condition in sync with the one used in + # post_prepare_hook_highway_handle_test_compilation_issues + if self.version in ['1.0.4'] and tcname == 'GCCcore' and tcversion == '12.3.0': + if cpu_target in [CPU_TARGET_A64FX, CPU_TARGET_NEOVERSE_V1]: + self.cfg.update('configopts', '-DHWY_ENABLE_TESTS=OFF') + if cpu_target == CPU_TARGET_NEOVERSE_N1: + self.orig_optarch = build_option('optarch') + update_build_option('optarch', OPTARCH_GENERIC) + else: + raise EasyBuildError("Highway-specific hook triggered for non-Highway easyconfig?!") + + +def post_prepare_hook_highway_handle_test_compilation_issues(self, *args, **kwargs): + """ + Post-prepare hook for Highway to reset optarch build option. + """ + if self.name == 'Highway': + tcname, tcversion = self.toolchain.name, self.toolchain.version + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + # note: keep condition in sync with the one used in + # pre_prepare_hook_highway_handle_test_compilation_issues + if self.version in ['1.0.4'] and tcname == 'GCCcore' and tcversion == '12.3.0': + if cpu_target == CPU_TARGET_NEOVERSE_N1: + update_build_option('optarch', self.orig_optarch) + + def pre_configure_hook(self, *args, **kwargs): """Main pre-configure hook: trigger custom functions based on software name.""" if self.name in PRE_CONFIGURE_HOOKS: PRE_CONFIGURE_HOOKS[self.name](self, *args, **kwargs) -def libfabric_disable_psm3_x86_64_generic(self, *args, **kwargs): +def pre_configure_hook_BLIS_a64fx(self, *args, **kwargs): + """ + Pre-configure hook for BLIS when building for A64FX: + - add -DCACHE_SECTOR_SIZE_READONLY to $CFLAGS for BLIS 0.9.0, cfr. https://github.com/flame/blis/issues/800 + """ + if self.name == 'BLIS': + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if self.version == '0.9.0' and cpu_target == CPU_TARGET_A64FX: + # last argument of BLIS' configure command is configuration target (usually 'auto' for auto-detect), + # specifying of variables should be done before that + config_opts = self.cfg['configopts'].split(' ') + cflags_var = 'CFLAGS="$CFLAGS -DCACHE_SECTOR_SIZE_READONLY"' + config_target = config_opts[-1] + self.cfg['configopts'] = ' '.join(config_opts[:-1] + [cflags_var, config_target]) + else: + raise EasyBuildError("BLIS-specific hook triggered for non-BLIS easyconfig?!") + + +def pre_configure_hook_score_p(self, *args, **kwargs): + """ + Pre-configure hook for Score-p + - specify correct path to binutils (in compat layer) + """ + if self.name == 'Score-P': + + # determine path to Prefix installation in compat layer via $EPREFIX + eprefix = get_eessi_envvar('EPREFIX') + + binutils_lib_path_glob_pattern = os.path.join(eprefix, 'usr', 'lib*', 'binutils', '*-linux-gnu', '2.*') + binutils_lib_path = glob.glob(binutils_lib_path_glob_pattern) + if len(binutils_lib_path) == 1: + self.cfg.update('configopts', '--with-libbfd-lib=' + binutils_lib_path[0]) + self.cfg.update('configopts', '--with-libbfd-include=' + os.path.join(binutils_lib_path[0], 'include')) + else: + raise EasyBuildError("Failed to isolate path for binutils libraries using %s, got %s", + binutils_lib_path_glob_pattern, binutils_lib_path) + + else: + raise EasyBuildError("Score-P-specific hook triggered for non-Score-P easyconfig?!") + + +def pre_configure_hook_extrae(self, *args, **kwargs): + """ + Pre-configure hook for Extrae + - avoid use of 'which' in configure script + - specify correct path to binutils/zlib (in compat layer) + """ + if self.name == 'Extrae': + + # determine path to Prefix installation in compat layer via $EPREFIX + eprefix = get_eessi_envvar('EPREFIX') + + binutils_lib_path_glob_pattern = os.path.join(eprefix, 'usr', 'lib*', 'binutils', '*-linux-gnu', '2.*') + binutils_lib_path = glob.glob(binutils_lib_path_glob_pattern) + if len(binutils_lib_path) == 1: + self.cfg.update('configopts', '--with-binutils=' + binutils_lib_path[0]) + else: + raise EasyBuildError("Failed to isolate path for binutils libraries using %s, got %s", + binutils_lib_path_glob_pattern, binutils_lib_path) + + # zlib is a filtered dependency, so we need to manually specify it's location to avoid the host version + self.cfg.update('configopts', '--with-libz=' + eprefix) + + # replace use of 'which' with 'command -v', since 'which' is broken in EESSI build container; + # this must be done *after* running configure script, because initial configuration re-writes configure script, + # and problem due to use of which only pops up when running make ?! + self.cfg.update( + 'prebuildopts', + "cp config/mpi-macros.m4 config/mpi-macros.m4.orig && " + "sed -i 's/`which /`command -v /g' config/mpi-macros.m4 && " + ) + else: + raise EasyBuildError("Extrae-specific hook triggered for non-Extrae easyconfig?!") + + +def pre_configure_hook_gobject_introspection(self, *args, **kwargs): + """ + pre-configure hook for GObject-Introspection: + - prevent GObject-Introspection from setting $LD_LIBRARY_PATH if EasyBuild is configured to filter it, see: + https://github.com/EESSI/software-layer/issues/196 + """ + if self.name == 'GObject-Introspection': + # inject a line that removes all items from runtime_path_envvar that are in $EASYBUILD_FILTER_ENVVARS + sed_cmd = r'sed -i "s@\(^\s*runtime_path_envvar = \)\(.*\)@' + sed_cmd += r'\1\2\n\1 [x for x in runtime_path_envvar if not x in os.environ.get(\'EASYBUILD_FILTER_ENV_VARS\', \'\').split(\',\')]@g"' + sed_cmd += ' %(start_dir)s/giscanner/ccompiler.py && ' + self.cfg.update('preconfigopts', sed_cmd) + else: + raise EasyBuildError("GObject-Introspection-specific hook triggered for non-GObject-Introspection easyconfig?!") + + +def pre_configure_hook_gromacs(self, *args, **kwargs): + """ + Pre-configure hook for GROMACS: + - avoid building with SVE instructions on Neoverse V1 as workaround for failing tests, + see https://gitlab.com/gromacs/gromacs/-/issues/5057 + https://gitlab.com/eessi/support/-/issues/47 + """ + if self.name == 'GROMACS': + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if LooseVersion(self.version) <= LooseVersion('2024.1') and cpu_target == CPU_TARGET_NEOVERSE_V1: + self.cfg.update('configopts', '-DGMX_SIMD=ARM_NEON_ASIMD') + print_msg( + "Avoiding use of SVE instructions for GROMACS %s by using ARM_NEON_ASIMD as GMX_SIMD value", + self.version + ) + else: + raise EasyBuildError("GROMACS-specific hook triggered for non-GROMACS easyconfig?!") + + +def pre_configure_hook_openblas_optarch_generic(self, *args, **kwargs): + """ + Pre-configure hook for OpenBLAS: add DYNAMIC_ARCH=1 to build/test/install options when using --optarch=GENERIC + """ + # note: OpenBLAS easyblock was updated in https://github.com/easybuilders/easybuild-easyblocks/pull/3492 + # to take care of this already, so at some point this hook can be removed... + if self.name == 'OpenBLAS': + if build_option('optarch') == OPTARCH_GENERIC: + dynamic_arch = 'DYNAMIC_ARCH=1' + for step in ('build', 'test', 'install'): + if dynamic_arch not in self.cfg[f'{step}opts']: + self.cfg.update(f'{step}opts', dynamic_arch) + + if get_cpu_architecture() == AARCH64: + # when building for aarch64/generic, we also need to set TARGET=ARMV8 to make sure + # that the driver parts of OpenBLAS are compiled generically; + # see also https://github.com/OpenMathLib/OpenBLAS/issues/4945 + target_armv8 = 'TARGET=ARMV8' + for step in ('build', 'test', 'install'): + if target_armv8 not in self.cfg[f'{step}opts']: + self.cfg.update(f'{step}opts', target_armv8) + + # use -mtune=generic rather than -mcpu=generic in $CFLAGS for aarch64/generic, + # because -mcpu=generic implies a particular -march=armv* which clashes with those used by OpenBLAS + # when building with DYNAMIC_ARCH=1 + mcpu_generic = '-mcpu=generic' + cflags = os.getenv('CFLAGS') + if mcpu_generic in cflags: + cflags = cflags.replace(mcpu_generic, '-mtune=generic') + self.log.info("Replaced -mcpu=generic with -mtune=generic in $CFLAGS") + env.setvar('CFLAGS', cflags) + else: + raise EasyBuildError("OpenBLAS-specific hook triggered for non-OpenBLAS easyconfig?!") + + +def pre_configure_hook_libfabric_disable_psm3_x86_64_generic(self, *args, **kwargs): """Add --disable-psm3 to libfabric configure options when building with --optarch=GENERIC on x86_64.""" if self.name == 'libfabric': if get_cpu_architecture() == X86_64: @@ -187,7 +687,7 @@ def libfabric_disable_psm3_x86_64_generic(self, *args, **kwargs): raise EasyBuildError("libfabric-specific hook triggered for non-libfabric easyconfig?!") -def metabat_preconfigure(self, *args, **kwargs): +def pre_configure_hook_metabat_filtered_zlib_dep(self, *args, **kwargs): """ Pre-configure hook for MetaBAT: - take into account that zlib is a filtered dependency, @@ -201,7 +701,7 @@ def metabat_preconfigure(self, *args, **kwargs): raise EasyBuildError("MetaBAT-specific hook triggered for non-MetaBAT easyconfig?!") -def wrf_preconfigure(self, *args, **kwargs): +def pre_configure_hook_wrf_aarch64(self, *args, **kwargs): """ Pre-configure hook for WRF: - patch arch/configure_new.defaults so building WRF with foss toolchain works on aarch64 @@ -210,24 +710,473 @@ def wrf_preconfigure(self, *args, **kwargs): if get_cpu_architecture() == AARCH64: pattern = "Linux x86_64 ppc64le, gfortran" repl = "Linux x86_64 aarch64 ppc64le, gfortran" - self.cfg.update('preconfigopts', "sed -i 's/%s/%s/g' arch/configure_new.defaults && " % (pattern, repl)) - print_msg("Using custom preconfigopts for %s: %s", self.name, self.cfg['preconfigopts']) + if LooseVersion(self.version) <= LooseVersion('3.9.0'): + self.cfg.update('preconfigopts', "sed -i 's/%s/%s/g' arch/configure_new.defaults && " % (pattern, repl)) + print_msg("Using custom preconfigopts for %s: %s", self.name, self.cfg['preconfigopts']) + + if LooseVersion('4.0.0') <= LooseVersion(self.version) <= LooseVersion('4.2.1'): + self.cfg.update('preconfigopts', "sed -i 's/%s/%s/g' arch/configure.defaults && " % (pattern, repl)) + print_msg("Using custom preconfigopts for %s: %s", self.name, self.cfg['preconfigopts']) else: raise EasyBuildError("WRF-specific hook triggered for non-WRF easyconfig?!") +def pre_configure_hook_LAMMPS_zen4(self, *args, **kwargs): + """ + pre-configure hook for LAMMPS: + - set kokkos_arch on x86_64/amd/zen4 + """ + + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if self.name == 'LAMMPS': + if self.version in ('2Aug2023_update2', '2Aug2023_update4', '29Aug2024'): + if get_cpu_architecture() == X86_64: + if cpu_target == CPU_TARGET_ZEN4: + # There is no support for ZEN4 in LAMMPS yet so falling back to ZEN3 + self.cfg['kokkos_arch'] = 'ZEN3' + else: + raise EasyBuildError("LAMMPS-specific hook triggered for non-LAMMPS easyconfig?!") + + +def pre_test_hook(self, *args, **kwargs): + """Main pre-test hook: trigger custom functions based on software name.""" + if self.name in PRE_TEST_HOOKS: + PRE_TEST_HOOKS[self.name](self, *args, **kwargs) + + +def pre_test_hook_exclude_failing_test_Highway(self, *args, **kwargs): + """ + Pre-test hook for Highway: exclude failing TestAllShiftRightLanes/SVE_256 test on neoverse_v1 + cfr. https://github.com/EESSI/software-layer/issues/469 + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if self.name == 'Highway' and self.version in ['1.0.3'] and cpu_target == CPU_TARGET_NEOVERSE_V1: + self.cfg['runtest'] += ' ARGS="-E TestAllShiftRightLanes/SVE_256"' + + +def pre_test_hook_ignore_failing_tests_ESPResSo(self, *args, **kwargs): + """ + Pre-test hook for ESPResSo: skip failing tests, tests frequently timeout due to known bugs in ESPResSo v4.2.1 + cfr. https://github.com/EESSI/software-layer/issues/363 + """ + if self.name == 'ESPResSo' and self.version == '4.2.1': + self.cfg['testopts'] = "|| echo 'ignoring failing tests (probably due to timeouts)'" + + +def pre_test_hook_ignore_failing_tests_FFTWMPI(self, *args, **kwargs): + """ + Pre-test hook for FFTW.MPI: skip failing tests for FFTW.MPI 3.3.10 on neoverse_v1 + cfr. https://github.com/EESSI/software-layer/issues/325 + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if self.name == 'FFTW.MPI' and self.version == '3.3.10' and cpu_target == CPU_TARGET_NEOVERSE_V1: + self.cfg['testopts'] = "|| echo ignoring failing tests" + + +def pre_test_hook_ignore_failing_tests_SciPybundle(self, *args, **kwargs): + """ + Pre-test hook for SciPy-bundle: skip failing tests for selected SciPy-bundle versions + In version 2021.10 on neoverse_v1, 2 failing tests in scipy 1.6.3: + FAILED optimize/tests/test_linprog.py::TestLinprogIPSparse::test_bug_6139 - A... + FAILED optimize/tests/test_linprog.py::TestLinprogIPSparsePresolve::test_bug_6139 + = 2 failed, 30554 passed, 2064 skipped, 10992 deselected, 76 xfailed, 7 xpassed, 40 warnings in 380.27s (0:06:20) = + In versions 2023.02 + 2023.07 + 2023.11 on neoverse_v1, 2 failing tests in scipy (versions 1.10.1, 1.11.1, 1.11.4): + FAILED scipy/spatial/tests/test_distance.py::TestPdist::test_pdist_correlation_iris + FAILED scipy/spatial/tests/test_distance.py::TestPdist::test_pdist_correlation_iris_float32 + = 2 failed, 54409 passed, 3016 skipped, 223 xfailed, 13 xpassed, 10917 warnings in 892.04s (0:14:52) = + In version 2023.07 on a64fx, 4 failing tests in scipy 1.11.1: + FAILED scipy/optimize/tests/test_linprog.py::TestLinprogIPSparse::test_bug_6139 + FAILED scipy/optimize/tests/test_linprog.py::TestLinprogIPSparsePresolve::test_bug_6139 + FAILED scipy/spatial/tests/test_distance.py::TestPdist::test_pdist_correlation_iris + FAILED scipy/spatial/tests/test_distance.py::TestPdist::test_pdist_correlation_iris_float32 + = 4 failed, 54407 passed, 3016 skipped, 223 xfailed, 13 xpassed, 10917 warnings in 6068.43s (1:41:08) = + (in previous versions we were not as strict yet on the numpy/SciPy tests) + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + scipy_bundle_versions_nv1 = ('2021.10', '2023.02', '2023.07', '2023.11') + scipy_bundle_versions_a64fx = ('2023.07', '2023.11') + if self.name == 'SciPy-bundle': + if cpu_target == CPU_TARGET_NEOVERSE_V1 and self.version in scipy_bundle_versions_nv1: + self.cfg['testopts'] = "|| echo ignoring failing tests" + elif cpu_target == CPU_TARGET_A64FX and self.version in scipy_bundle_versions_a64fx: + self.cfg['testopts'] = "|| echo ignoring failing tests" + + +def pre_test_hook_ignore_failing_tests_netCDF(self, *args, **kwargs): + """ + Pre-test hook for netCDF: skip failing tests for selected netCDF versions on neoverse_v1 + cfr. https://github.com/EESSI/software-layer/issues/425 + The following tests are problematic: + 163 - nc_test4_run_par_test (Timeout) + 190 - h5_test_run_par_tests (Timeout) + A few other tests are skipped in the easyconfig and patches for similar issues, see above issue for details. + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if self.name == 'netCDF' and self.version == '4.9.2' and cpu_target == CPU_TARGET_NEOVERSE_V1: + self.cfg['testopts'] = "|| echo ignoring failing tests" + + +def pre_test_hook_increase_max_failed_tests_arm_PyTorch(self, *args, **kwargs): + """ + Pre-test hook for PyTorch: increase max failing tests for ARM and Intel Sapphire Rapids for PyTorch 2.1.2 + See https://github.com/EESSI/software-layer/pull/444#issuecomment-1890416171 and + https://github.com/EESSI/software-layer/pull/875#issuecomment-2606854400 + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if self.name == 'PyTorch' and self.version == '2.1.2': + if get_cpu_architecture() == AARCH64: + self.cfg['max_failed_tests'] = 10 + if cpu_target == CPU_TARGET_SAPPHIRE_RAPIDS: + self.cfg['max_failed_tests'] = 4 + + +def pre_single_extension_hook(ext, *args, **kwargs): + """Main pre-extension: trigger custom functions based on software name.""" + if ext.name in PRE_SINGLE_EXTENSION_HOOKS: + PRE_SINGLE_EXTENSION_HOOKS[ext.name](ext, *args, **kwargs) + + +def post_single_extension_hook(ext, *args, **kwargs): + """Main post-extension hook: trigger custom functions based on software name.""" + if ext.name in POST_SINGLE_EXTENSION_HOOKS: + POST_SINGLE_EXTENSION_HOOKS[ext.name](ext, *args, **kwargs) + + +def pre_single_extension_isoband(ext, *args, **kwargs): + """ + Pre-extension hook for isoband R package, to fix build on top of recent glibc. + """ + if ext.name == 'isoband' and LooseVersion(ext.version) < LooseVersion('0.2.5'): + # use constant value instead of SIGSTKSZ for stack size in vendored testthat included in isoband sources, + # cfr. https://github.com/r-lib/isoband/commit/6984e6ce8d977f06e0b5ff73f5d88e5c9a44c027 + ext.cfg['preinstallopts'] = "sed -i 's/SIGSTKSZ/32768/g' src/testthat/vendor/catch.h && " + + +def pre_single_extension_numpy(ext, *args, **kwargs): + """ + Pre-extension hook for numpy, to change -march=native to -march=armv8.4-a for numpy 1.24.2 + when building for aarch64/neoverse_v1 CPU target. + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if ext.name == 'numpy' and ext.version == '1.24.2' and cpu_target == CPU_TARGET_NEOVERSE_V1: + # note: this hook is called before build environment is set up (by calling toolchain.prepare()), + # so environment variables like $CFLAGS are not defined yet + # unsure which of these actually matter for numpy, so changing all of them + ext.orig_optarch = build_option('optarch') + update_build_option('optarch', 'march=armv8.4-a') + + +def post_single_extension_numpy(ext, *args, **kwargs): + """ + Post-extension hook for numpy, to reset 'optarch' build option. + """ + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if ext.name == 'numpy' and ext.version == '1.24.2' and cpu_target == CPU_TARGET_NEOVERSE_V1: + update_build_option('optarch', ext.orig_optarch) + + +def pre_single_extension_testthat(ext, *args, **kwargs): + """ + Pre-extension hook for testthat R package, to fix build on top of recent glibc. + """ + if ext.name == 'testthat' and LooseVersion(ext.version) < LooseVersion('3.1.0'): + # use constant value instead of SIGSTKSZ for stack size, + # cfr. https://github.com/r-lib/testthat/issues/1373 + https://github.com/r-lib/testthat/pull/1403 + ext.cfg['preinstallopts'] = "sed -i 's/SIGSTKSZ/32768/g' inst/include/testthat/vendor/catch.h && " + + +def post_postproc_hook(self, *args, **kwargs): + """Main post-postprocessing hook: trigger custom functions based on software name.""" + if self.name in POST_POSTPROC_HOOKS: + POST_POSTPROC_HOOKS[self.name](self, *args, **kwargs) + + +def post_postproc_cuda(self, *args, **kwargs): + """ + Remove files from CUDA installation that we are not allowed to ship, + and replace them with a symlink to a corresponding installation under host_injections. + """ + + # We need to check if we are doing an EESSI-distributed installation + eessi_installation = bool(re.search(EESSI_INSTALLATION_REGEX, self.installdir)) + + if self.name == 'CUDA' and eessi_installation: + print_msg("Replacing files in CUDA installation that we can not ship with symlinks to host_injections...") + + # read CUDA EULA, construct allowlist based on section 2.6 that specifies list of files that can be shipped + eula_path = os.path.join(self.installdir, 'EULA.txt') + relevant_eula_lines = [] + with open(eula_path) as infile: + copy = False + for line in infile: + if line.strip() == "2.6. Attachment A": + copy = True + continue + elif line.strip() == "2.7. Attachment B": + copy = False + continue + elif copy: + relevant_eula_lines.append(line) + + # create list without file extensions, they're not really needed and they only complicate things + allowlist = ['EULA', 'README'] + file_extensions = ['.so', '.a', '.h', '.bc'] + for line in relevant_eula_lines: + for word in line.split(): + if any(ext in word for ext in file_extensions): + allowlist.append(os.path.splitext(word)[0]) + # The EULA of CUDA 12.4 introduced a typo (confirmed by NVIDIA): + # libnvrtx-builtins_static.so should be libnvrtc-builtins_static.so + if 'libnvrtx-builtins_static' in allowlist: + allowlist.remove('libnvrtx-builtins_static') + allowlist.append('libnvrtc-builtins_static') + allowlist = sorted(set(allowlist)) + self.log.info("Allowlist for files in CUDA installation that can be redistributed: " + ', '.join(allowlist)) + + # Do some quick sanity checks for things we should or shouldn't have in the list + if 'nvcc' in allowlist: + raise EasyBuildError("Found 'nvcc' in allowlist: %s" % allowlist) + if 'libcudart' not in allowlist: + raise EasyBuildError("Did not find 'libcudart' in allowlist: %s" % allowlist) + + # replace files that are not distributable with symlinks into + # host_injections + replace_non_distributable_files_with_symlinks(self.log, self.installdir, self.name, allowlist) + else: + raise EasyBuildError("CUDA-specific hook triggered for non-CUDA easyconfig?!") + + +def post_postproc_cudnn(self, *args, **kwargs): + """ + Remove files from cuDNN installation that we are not allowed to ship, + and replace them with a symlink to a corresponding installation under host_injections. + """ + + # We need to check if we are doing an EESSI-distributed installation + eessi_installation = bool(re.search(EESSI_INSTALLATION_REGEX, self.installdir)) + + if self.name == 'cuDNN' and eessi_installation: + print_msg("Replacing files in cuDNN installation that we can not ship with symlinks to host_injections...") + + allowlist = ['LICENSE'] + + # read cuDNN LICENSE, construct allowlist based on section "2. Distribution" that specifies list of files that can be shipped + license_path = os.path.join(self.installdir, 'LICENSE') + search_string = "2. Distribution. The following portions of the SDK are distributable under the Agreement:" + found_search_string = False + with open(license_path) as infile: + for line in infile: + if line.strip().startswith(search_string): + found_search_string = True + # remove search string, split into words, remove trailing + # dots '.' and only retain words starting with a dot '.' + distributable = line[len(search_string):] + # distributable looks like ' the runtime files .so and .dll.' + # note the '.' after '.dll' + for word in distributable.split(): + if word[0] == '.': + # rstrip is used to remove the '.' after '.dll' + allowlist.append(word.rstrip('.')) + if not found_search_string: + # search string wasn't found in LICENSE file + raise EasyBuildError("search string '%s' was not found in license file '%s';" + "hence installation may be replaced by symlinks only", + search_string, license_path) + + allowlist = sorted(set(allowlist)) + self.log.info("Allowlist for files in cuDNN installation that can be redistributed: " + ', '.join(allowlist)) + + # replace files that are not distributable with symlinks into + # host_injections + replace_non_distributable_files_with_symlinks(self.log, self.installdir, self.name, allowlist) + else: + raise EasyBuildError("cuDNN-specific hook triggered for non-cuDNN easyconfig?!") + + +def replace_non_distributable_files_with_symlinks(log, install_dir, pkg_name, allowlist): + """ + Replace files that cannot be distributed with symlinks into host_injections + """ + # Different packages use different ways to specify which files or file + # 'types' may be redistributed. For CUDA, the 'EULA.txt' lists full file + # names. For cuDNN, the 'LICENSE' lists file endings/suffixes (e.g., '.so') + # that can be redistributed. + # The map 'extension_based' defines which of these two ways are employed. If + # full file names are used it maps a package name (key) to False (value). If + # endings/suffixes are used, it maps a package name to True. Later we can + # easily use this data structure to employ the correct method for + # postprocessing an installation. + extension_based = { + "CUDA": False, + "cuDNN": True, + } + if not pkg_name in extension_based: + raise EasyBuildError("Don't know how to strip non-distributable files from package %s.", pkg_name) + + # iterate over all files in the package installation directory + for dir_path, _, files in os.walk(install_dir): + for filename in files: + full_path = os.path.join(dir_path, filename) + # we only really care about real files, i.e. not symlinks + if not os.path.islink(full_path): + check_by_extension = extension_based[pkg_name] and '.' in filename + if check_by_extension: + # if the allowlist only contains extensions, we have to + # determine that from filename. we assume the extension is + # the second element when splitting the filename at dots + # (e.g., for 'libcudnn_adv_infer.so.8.9.2' the extension + # would be '.so') + extension = '.' + filename.split('.')[1] + # check if the current file name stub or its extension is part of the allowlist + basename = filename.split('.')[0] + if basename in allowlist: + log.debug("%s is found in allowlist, so keeping it: %s", basename, full_path) + elif check_by_extension and extension in allowlist: + log.debug("%s is found in allowlist, so keeping it: %s", extension, full_path) + else: + print_name = filename if extension_based[pkg_name] else basename + log.debug("%s is not found in allowlist, so replacing it with symlink: %s", + print_name, full_path) + # the host_injections path is under a fixed repo/location for CUDA or cuDNN + host_inj_path = re.sub(EESSI_INSTALLATION_REGEX, HOST_INJECTIONS_LOCATION, full_path) + # CUDA and cu* libraries themselves don't care about compute capability so remove this + # duplication from under host_injections (symlink to a single CUDA or cu* library + # installation for all compute capabilities) + accel_subdir = os.getenv("EESSI_ACCELERATOR_TARGET") + if accel_subdir: + host_inj_path = host_inj_path.replace("/accel/%s" % accel_subdir, '') + # make sure source and target of symlink are not the same + if full_path == host_inj_path: + raise EasyBuildError("Source (%s) and target (%s) are the same location, are you sure you " + "are using this hook for an EESSI installation?", + full_path, host_inj_path) + remove_file(full_path) + symlink(host_inj_path, full_path) + + +def inject_gpu_property(ec): + """ + Add 'gpu' property and EESSIVERSION envvars via modluafooter + easyconfig parameter, and drop dependencies to build dependencies + """ + ec_dict = ec.asdict() + # Check if CUDA, cuDNN, you-name-it is in the dependencies, if so + # - drop dependency to build dependency + # - add 'gpu' Lmod property + # - add envvar with package version + pkg_names = ( "CUDA", "cuDNN" ) + pkg_versions = { } + add_gpu_property = '' + + for pkg_name in pkg_names: + # Check if pkg_name is in the dependencies, if so drop dependency to build + # dependency and set variable for later adding the 'gpu' Lmod property + # to '.remove' dependencies from ec_dict['dependencies'] we make a copy, + # iterate over the copy and can then savely use '.remove' on the original + # ec_dict['dependencies']. + deps = ec_dict['dependencies'][:] + if (pkg_name in [dep[0] for dep in deps]): + add_gpu_property = 'add_property("arch","gpu")' + for dep in deps: + if pkg_name == dep[0]: + # make pkg_name a build dependency only (rpathing saves us from link errors) + ec.log.info("Dropping dependency on %s to build dependency" % pkg_name) + ec_dict['dependencies'].remove(dep) + if dep not in ec_dict['builddependencies']: + ec_dict['builddependencies'].append(dep) + # take note of version for creating the modluafooter + pkg_versions[pkg_name] = dep[1] + if add_gpu_property: + ec.log.info("Injecting gpu as Lmod arch property and envvars for dependencies with their version") + modluafooter = 'modluafooter' + extra_mod_footer_lines = [add_gpu_property] + for pkg_name, version in pkg_versions.items(): + envvar = "EESSI%sVERSION" % pkg_name.upper() + extra_mod_footer_lines.append('setenv("%s","%s")' % (envvar, version)) + # take into account that modluafooter may already be set + if modluafooter in ec_dict: + value = ec_dict[modluafooter] + for line in extra_mod_footer_lines: + if not line in value: + value = '\n'.join([value, line]) + ec[modluafooter] = value + else: + ec[modluafooter] = '\n'.join(extra_mod_footer_lines) + + return ec + + +def post_module_hook(self, *args, **kwargs): + """Main post module hook: trigger custom functions based on software name.""" + if self.name in POST_MODULE_HOOKS: + POST_MODULE_HOOKS[ec.name](self, *args, **kwargs) + + # Always trigger this one, regardless of self.name + cpu_target = get_eessi_envvar('EESSI_SOFTWARE_SUBDIR') + if cpu_target == CPU_TARGET_ZEN4: + post_module_hook_zen4_gcccore1220(self, *args, **kwargs) + + PARSE_HOOKS = { - 'CGAL': cgal_toolchainopts_precise, - 'fontconfig': fontconfig_add_fonts, - 'UCX': ucx_eprefix, + 'casacore': parse_hook_casacore_disable_vectorize, + 'CGAL': parse_hook_cgal_toolchainopts_precise, + 'fontconfig': parse_hook_fontconfig_add_fonts, + 'FreeImage': parse_hook_freeimage_aarch64, + 'grpcio': parse_hook_grpcio_zlib, + 'LAMMPS': parse_hook_lammps_remove_deps_for_aarch64, + 'CP2K': parse_hook_CP2K_remove_deps_for_aarch64, + 'OpenBLAS': parse_hook_openblas_relax_lapack_tests_num_errors, + 'pybind11': parse_hook_pybind11_replace_catch2, + 'Qt5': parse_hook_qt5_check_qtwebengine_disable, + 'UCX': parse_hook_ucx_eprefix, +} + +PRE_FETCH_HOOKS = {} + +PRE_PREPARE_HOOKS = { + 'Highway': pre_prepare_hook_highway_handle_test_compilation_issues, } POST_PREPARE_HOOKS = { - 'GCCcore': gcc_postprepare, + 'GCCcore': post_prepare_hook_gcc_prefixed_ld_rpath_wrapper, + 'Highway': post_prepare_hook_highway_handle_test_compilation_issues, } PRE_CONFIGURE_HOOKS = { - 'libfabric': libfabric_disable_psm3_x86_64_generic, - 'MetaBAT': metabat_preconfigure, - 'WRF': wrf_preconfigure, + 'BLIS': pre_configure_hook_BLIS_a64fx, + 'GObject-Introspection': pre_configure_hook_gobject_introspection, + 'Extrae': pre_configure_hook_extrae, + 'GROMACS': pre_configure_hook_gromacs, + 'libfabric': pre_configure_hook_libfabric_disable_psm3_x86_64_generic, + 'MetaBAT': pre_configure_hook_metabat_filtered_zlib_dep, + 'OpenBLAS': pre_configure_hook_openblas_optarch_generic, + 'WRF': pre_configure_hook_wrf_aarch64, + 'LAMMPS': pre_configure_hook_LAMMPS_zen4, + 'Score-P': pre_configure_hook_score_p, +} + +PRE_TEST_HOOKS = { + 'ESPResSo': pre_test_hook_ignore_failing_tests_ESPResSo, + 'FFTW.MPI': pre_test_hook_ignore_failing_tests_FFTWMPI, + 'Highway': pre_test_hook_exclude_failing_test_Highway, + 'SciPy-bundle': pre_test_hook_ignore_failing_tests_SciPybundle, + 'netCDF': pre_test_hook_ignore_failing_tests_netCDF, + 'PyTorch': pre_test_hook_increase_max_failed_tests_arm_PyTorch, } + +PRE_SINGLE_EXTENSION_HOOKS = { + 'isoband': pre_single_extension_isoband, + 'numpy': pre_single_extension_numpy, + 'testthat': pre_single_extension_testthat, +} + +POST_SINGLE_EXTENSION_HOOKS = { + 'numpy': post_single_extension_numpy, +} + +POST_POSTPROC_HOOKS = { + 'CUDA': post_postproc_cuda, + 'cuDNN': post_postproc_cudnn, +} + +POST_MODULE_HOOKS = {} diff --git a/eessi-2021.06.yml b/eessi-2021.06.yml deleted file mode 100644 index 3587827746..0000000000 --- a/eessi-2021.06.yml +++ /dev/null @@ -1,53 +0,0 @@ -software: - R-bundle-Bioconductor: - toolchains: - foss-2020a: - versions: - '3.11': - versionsuffix: -R-4.0.0 - GROMACS: - toolchains: - foss-2020a: - versions: - '2020.1': - versionsuffix: -Python-3.8.2 - '2020.4': - versionsuffix: -Python-3.8.2 - Horovod: - toolchains: - foss-2020a: - versions: - '0.21.3': - versionsuffix: -TensorFlow-2.3.1-Python-3.8.2 - OpenFOAM: - toolchains: - foss-2020a: - versions: ['8', 'v2006'] - OSU-Micro-Benchmarks: - toolchains: - gompi-2020a: - versions: ['5.6.3'] - QuantumESPRESSO: - toolchains: - foss-2020a: - versions: ['6.6'] - TensorFlow: - toolchains: - foss-2020a: - versions: - '2.3.1': - versionsuffix: -Python-3.8.2 - RStudio-Server: - toolchains: - foss-2020a: - versions: - '1.3.1093': - versionsuffix: -Java-11-R-4.0.0 - ReFrame: - toolchains: - SYSTEM: - versions: '3.6.2' - code-server: - toolchains: - SYSTEM: - versions: '3.7.3' diff --git a/eessi-2021.12.yml b/eessi-2021.12.yml deleted file mode 100644 index 210bbb2845..0000000000 --- a/eessi-2021.12.yml +++ /dev/null @@ -1,69 +0,0 @@ -software: - code-server: - toolchains: - SYSTEM: - versions: '3.7.3' - GROMACS: - toolchains: - foss-2020a: - versions: - '2020.1': - versionsuffix: -Python-3.8.2 - '2020.4': - versionsuffix: -Python-3.8.2 - Horovod: - toolchains: - foss-2020a: - versions: - '0.21.3': - versionsuffix: -TensorFlow-2.3.1-Python-3.8.2 - Nextflow: - toolchains: - SYSTEM: - versions: '22.10.1' - OpenFOAM: - toolchains: - foss-2020a: - versions: ['8', 'v2006'] - OSU-Micro-Benchmarks: - toolchains: - gompi-2020a: - versions: ['5.6.3'] - gompi-2021a: - versions: ['5.7.1'] - QuantumESPRESSO: - toolchains: - foss-2020a: - versions: ['6.6'] - R: - toolchains: - foss-2021a: - versions: '4.1.0' - R-bundle-Bioconductor: - toolchains: - foss-2020a: - versions: - '3.11': - versionsuffix: -R-4.0.0 - RStudio-Server: - toolchains: - foss-2020a: - versions: - '1.3.1093': - versionsuffix: -Java-11-R-4.0.0 - SciPy-bundle: - toolchains: - foss-2021a: - versions: ['2021.05'] - TensorFlow: - toolchains: - foss-2020a: - versions: - '2.3.1': - versionsuffix: -Python-3.8.2 - WRF: - toolchains: - foss-2020a: - versions: - '3.9.1.1': - versionsuffix: -dmpar diff --git a/eessi-2023.06-known-issues.yml b/eessi-2023.06-known-issues.yml new file mode 100644 index 0000000000..bdef076dcd --- /dev/null +++ b/eessi-2023.06-known-issues.yml @@ -0,0 +1,62 @@ +- aarch64/a64x: + - SciPy-bundle-2023.07-gfbf-2023a: + - issue: https://github.com/EESSI/software-layer/issues/318 + - info: "4 failing tests (vs 54407 passed) in scipy test suite" + - SciPy-bundle-2023.11-gfbf-2023b: + - issue: https://github.com/EESSI/software-layer/issues/318 + - info: "3 failing tests (vs 54875 passed) in scipy test suite" +- aarch64/generic: + - PyTorch-2.1.2-foss-2023a: + - issue: https://github.com/EESSI/software-layer/issues/461 + - info: "8 failing tests (out of 209539) on aarch64/*" +- aarch64/neoverse_n1: + - Highway-1.0.4-GCCcore-12.3.0.eb: + - issue: https://github.com/EESSI/software-layer/issues/469 + - info: "failing to build the tests" + - PyTorch-2.1.2-foss-2023a: + - issue: https://github.com/EESSI/software-layer/issues/461 + - info: "8 failing tests (out of 209539) on aarch64/*" +- aarch64/neoverse_v1: + - ESPResSo-4.2.1-foss-2023a: + - issue: https://github.com/EESSI/software-layer/issues/363 + - info: "ESPResSo tests failing due to timeouts" + - FFTW.MPI-3.3.10-gompi-2023a: + - issue: https://github.com/EESSI/software-layer/issues/325 + - info: "Flaky FFTW tests, random failures" + - FFTW.MPI-3.3.10-gompi-2023b: + - issue: https://github.com/EESSI/software-layer/issues/325 + - info: "Flaky FFTW tests, random failures" + - GROMACS-2024.1-foss-2023b: + - issue: https://github.com/EESSI/software-layer/issues/557 + - info: "SVE disabled due to known bug which causes test failures" + - Highway-1.0.3-GCCcore-12.2.0.eb: + - issue: https://github.com/EESSI/software-layer/issues/469 + - info: "failing SVE test due to wrong expected value" + - Highway-1.0.4-GCCcore-12.3.0.eb: + - issue: https://github.com/EESSI/software-layer/issues/469 + - info: "failing to build the tests" + - netCDF-4.9.2-gompi-2023a.eb: + - issue: https://github.com/EESSI/software-layer/issues/425 + - info: "netCDF intermittent test failures" + - netCDF-4.9.2-gompi-2023b.eb: + - issue: https://github.com/EESSI/software-layer/issues/425 + - info: "netCDF intermittent test failures" + - OpenBLAS-0.3.21-GCC-12.2.0: + - issue: https://github.com/EESSI/software-layer/issues/314 + - info: "Increased number of numerical errors in OpenBLAS test suite (344 vs max. 150 on x86_64/*)" + - PyTorch-2.1.2-foss-2023a: + - issue: https://github.com/EESSI/software-layer/issues/461 + - info: "8 failing tests (out of 209539) on aarch64/*" + - SciPy-bundle-2023.02-gfbf-2022b: + - issue: https://github.com/EESSI/software-layer/issues/318 + - info: "numpy built with -march=armv8.4-a instead of -mcpu=native (no SVE) + 2 failing tests (vs 50005 passed) in scipy test suite" + - SciPy-bundle-2023.07-gfbf-2023a: + - issue: https://github.com/EESSI/software-layer/issues/318 + - info: "2 failing tests (vs 54409 passed) in scipy test suite" + - SciPy-bundle-2023.11-gfbf-2023b: + - issue: https://github.com/EESSI/software-layer/issues/318 + - info: "2 failing tests (vs 54876 passed) in scipy test suite" +- x86_64/intel/sapphire_rapids: + - PyTorch-2.1.2-foss-2023a: + - issue: https://github.com/EESSI/software-layer/issues/461 + - info: "4 failing tests (out of 209567) on x86_64/intel/sapphire_rapids" diff --git a/eessi_container.sh b/eessi_container.sh index 48c4653ba9..7259fb69a8 100755 --- a/eessi_container.sh +++ b/eessi_container.sh @@ -30,8 +30,8 @@ # -. initial settings & exit codes TOPDIR=$(dirname $(realpath $0)) -source ${TOPDIR}/scripts/utils.sh -source ${TOPDIR}/scripts/cfg_files.sh +source "${TOPDIR}"/scripts/utils.sh +source "${TOPDIR}"/scripts/cfg_files.sh # exit codes: bitwise shift codes to allow for combination of exit codes # ANY_ERROR_EXITCODE is sourced from ${TOPDIR}/scripts/utils.sh @@ -46,6 +46,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)) +NVIDIA_MODE_UNKNOWN_EXITCODE=$((${ANY_ERROR_EXITCODE} << 12)) # CernVM-FS settings CVMFS_VAR_LIB="var-lib-cvmfs" @@ -69,34 +70,47 @@ export EESSI_REPOS_CFG_FILE="${EESSI_REPOS_CFG_DIR}/repos.cfg" display_help() { echo "usage: $0 [OPTIONS] [[--] SCRIPT or COMMAND]" 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 " -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 or command) [default: shell]" - echo " -r | --repository CFG - configuration file or identifier defining the" - echo " repository to use [default: EESSI-pilot via" - echo " default container, see --container]" - 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 " -v | --verbose - display more information [default: false]" - 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 " -a | --access {ro,rw} - sets access globally for all CVMFS repositories:" + echo " ro (read-only), rw (read & write) [default: ro]" + echo " -b | --extra-bind-paths - specify extra paths to be bound into the container." + echo " To specify multiple bind paths, separate by comma." + echo " Example: '/src:/dest:ro,/src2:/dest2:rw'" + echo " -c | --container IMG - image file or URL defining the container to use" + echo " [default: docker://ghcr.io/eessi/build-node:debian11]" + echo " -f | --fakeroot - run the container with --fakeroot [default: false]" + echo " -g | --storage DIR - directory space on host machine (used for" + echo " temporary data) [default: 1. TMPDIR, 2. /tmp]" + echo " -h | --help - display this usage information [default: false]" + echo " -i | --host-injections - directory to link to for host_injections " + echo " [default: /..storage../opt-eessi]" + 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 or command) [default: shell]" + echo " -n | --nvidia MODE - configure the container to work with NVIDIA GPUs," + echo " MODE==install for a CUDA installation, MODE==run to" + echo " attach a GPU, MODE==all for both [default: false]" + 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 " [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," + 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 " -v | --verbose - display more information [default: false]" + 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/COMMAND provided is executed. If" echo " arguments to the script/command start with '-' or '--', use the flag terminator" @@ -107,11 +121,13 @@ display_help() { ACCESS="ro" CONTAINER="docker://ghcr.io/eessi/build-node:debian11" #DRY_RUN=0 +FAKEROOT=0 VERBOSE=0 STORAGE= LIST_REPOS=0 MODE="shell" -REPOSITORY="EESSI-pilot" +SETUP_NVIDIA=0 +REPOSITORIES=() RESUME= SAVE= HTTP_PROXY=${http_proxy:-} @@ -125,6 +141,10 @@ while [[ $# -gt 0 ]]; do ACCESS="$2" shift 2 ;; + -b|--extra-bind-paths) + EXTRA_BIND_PATHS="$2" + shift 2 + ;; -c|--container) CONTAINER="$2" shift 2 @@ -133,6 +153,10 @@ while [[ $# -gt 0 ]]; do # DRY_RUN=1 # shift 1 # ;; + -f|--fakeroot) + FAKEROOT=1 + shift 1 + ;; -g|--storage) STORAGE="$2" shift 2 @@ -141,6 +165,10 @@ while [[ $# -gt 0 ]]; do display_help exit 0 ;; + -i|--host-injections) + USER_HOST_INJECTIONS="$2" + shift 2 + ;; -l|--list-repos) LIST_REPOS=1 shift 1 @@ -149,8 +177,13 @@ while [[ $# -gt 0 ]]; do MODE="$2" shift 2 ;; + -n|--nvidia) + SETUP_NVIDIA=1 + NVIDIA_MODE="$2" + shift 2 + ;; -r|--repository) - REPOSITORY="$2" + REPOSITORIES+=("$2") shift 2 ;; -s|--save) @@ -192,22 +225,53 @@ done set -- "${POSITIONAL_ARGS[@]}" +# define a list of CVMFS repositories that are accessible via the +# CVMFS config repository which is always mounted +# TODO instead of hard-coding the 'extra' and 'default' repositories here one +# could have another script in the GitHub and/or CVMFS repository which +# provides this "configuration" +declare -A eessi_cvmfs_repos=(["dev.eessi.io"]="extra", ["riscv.eessi.io"]="extra", ["software.eessi.io"]="default") +eessi_default_cvmfs_repo="software.eessi.io,access=${ACCESS}" + +# define a list of CVMFS repositories that are accessible via the +# configuration file provided via $EESSI_REPOS_CFG_FILE +declare -A cfg_cvmfs_repos=() +if [[ -r ${EESSI_REPOS_CFG_FILE} ]]; then + cfg_load ${EESSI_REPOS_CFG_FILE} + sections=$(cfg_sections) + while IFS= read -r repo_id + do + cfg_cvmfs_repos[${repo_id}]=${EESSI_REPOS_CFG_FILE} + done <<< "${sections}" +fi + if [[ ${LIST_REPOS} -eq 1 ]]; then - echo "Listing available repositories with format 'name [source]':" - echo " EESSI-pilot [default]" - if [[ -r ${EESSI_REPOS_CFG_FILE} ]]; then - cfg_load ${EESSI_REPOS_CFG_FILE} - sections=$(cfg_sections) - while IFS= read -r repo_id - do - echo " ${repo_id} [${EESSI_REPOS_CFG_FILE}]" - done <<< "${sections}" - fi + echo "Listing available repositories with format 'name [source[, 'default']]'." + echo "Note, without argument '--repository' the one labeled 'default' will be mounted." + for cvmfs_repo in "${!eessi_cvmfs_repos[@]}" + do + if [[ ${eessi_cvmfs_repos[${cvmfs_repo}]} == "default" ]] ; then + default_label=", default" + else + default_label="" + fi + echo " ${cvmfs_repo} [CVMFS config repo${default_label}]" + done + for cfg_repo in "${!cfg_cvmfs_repos[@]}" + do + echo " ${cfg_repo} [${cfg_cvmfs_repos[$cfg_repo]}]" + done exit 0 fi +# if REPOSITORIES is empty add default repository given above +if [[ ${#REPOSITORIES[@]} -eq 0 ]]; then + REPOSITORIES+=(${eessi_default_cvmfs_repo}) +fi + # 1. check if argument values are valid # (arg -a|--access) check if ACCESS is supported +# use the value as global setting, suffix to --repository can specify an access mode per repository if [[ "${ACCESS}" != "ro" && "${ACCESS}" != "rw" ]]; then fatal_error "unknown access method '${ACCESS}'" "${ACCESS_UNKNOWN_EXITCODE}" fi @@ -224,12 +288,55 @@ 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}" +# Also validate the NVIDIA GPU mode (if present) +if [[ ${SETUP_NVIDIA} -eq 1 ]]; then + if [[ "${NVIDIA_MODE}" != "run" && "${NVIDIA_MODE}" != "install" && "${NVIDIA_MODE}" != "all" ]]; then + fatal_error "unknown NVIDIA mode '${NVIDIA_MODE}'" "${NVIDIA_MODE_UNKNOWN_EXITCODE}" + fi fi +# TODO (arg -r|--repository) check if all explicitly listed repositories are known +# REPOSITORY_ERROR_EXITCODE +# iterate over entries in REPOSITORIES and check if they are known +for cvmfs_repo in "${REPOSITORIES[@]}" +do + # 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 + else + cvmfs_repo_name="${cvmfs_repo}" + fi + if [[ ! -n "${eessi_cvmfs_repos[${cvmfs_repo_name}]}" && ! -n ${cfg_cvmfs_repos[${cvmfs_repo_name}]} ]]; then + fatal_error "The repository '${cvmfs_repo_name}' is not an EESSI CVMFS repository or it is not known how to mount it (could be due to a typo or missing configuration). Run '$0 -l' to obtain a list of available repositories." "${REPOSITORY_ERROR_EXITCODE}" + fi +done + +# make sure each repository is only listed once +declare -A listed_repos=() +for cvmfs_repo in "${REPOSITORIES[@]}" +do + cvmfs_repo_name=${cvmfs_repo/,access=*/} # remove access mode + [[ ${VERBOSE} -eq 1 ]] && echo "checking for duplicates: '${cvmfs_repo}' and '${cvmfs_repo_name}'" + # if cvmfs_repo_name is not in eessi_cvmfs_repos, assume it's in cfg_cvmfs_repos + # and obtain actual repo_name from config + cfg_repo_id='' + if [[ ! -n "${eessi_cvmfs_repos[${cvmfs_repo_name}]}" ]] ; then + [[ ${VERBOSE} -eq 1 ]] && echo "repo '${cvmfs_repo_name}' is not an EESSI CVMFS repository..." + # cvmfs_repo_name is actually a repository ID, use that to obtain + # the actual name from the EESSI_REPOS_CFG_FILE + cfg_repo_id=${cvmfs_repo_name} + cvmfs_repo_name=$(cfg_get_value ${cfg_repo_id} "repo_name") + fi + if [[ -n "${listed_repos[${cvmfs_repo_name}]}" ]] ; then + via_cfg="" + if [[ -n "${cfg_repo_id}" ]] ; then + via_cfg=" (via repository ID '${cfg_repo_id}')" + fi + fatal_error "CVMFS repository '${cvmfs_repo_name}'${via_cfg} listed multiple times" + fi + listed_repos+=([${cvmfs_repo_name}]=true) +done + # TODO (arg -u|--resume) check if it exists, if user has read permission, # if it contains data from a previous run # RESUME_ERROR_EXITCODE @@ -275,6 +382,7 @@ else # note, (b) & (c) are automatically ensured by using 'mktemp -d --tmpdir' to # create a temporary directory if [[ ! -z ${STORAGE} ]]; then + [[ ${VERBOSE} -eq 1 ]] && echo "export TMPDIR=${STORAGE}" export TMPDIR=${STORAGE} # mktemp fails if TMPDIR does not exist, so let's create it mkdir -p ${TMPDIR} @@ -304,18 +412,42 @@ fi # directory structure should be: # ${EESSI_HOST_STORAGE} # |-singularity_cache -# |-${CVMFS_VAR_LIB} -# |-${CVMFS_VAR_RUN} -# |-overlay-upper -# |-overlay-work # |-home # |-repos_cfg +# |-${CVMFS_VAR_LIB} +# |-${CVMFS_VAR_RUN} +# |-CVMFS_REPO_1 +# | |-repo_settings.sh (name, id, access, host_injections) +# | |-overlay-upper +# | |-overlay-work +# | |-opt-eessi (unless otherwise specificed for host_injections) +# |-CVMFS_REPO_n +# |-repo_settings.sh (name, id, access, host_injections) +# |-overlay-upper +# |-overlay-work +# |-opt-eessi (unless otherwise specificed for host_injections) # tmp dir for EESSI EESSI_TMPDIR=${EESSI_HOST_STORAGE} mkdir -p ${EESSI_TMPDIR} [[ ${VERBOSE} -eq 1 ]] && echo "EESSI_TMPDIR=${EESSI_TMPDIR}" +# TODO make this specific to repository? +# TODO move this code to when we already know which repositories we want to access +# actually we should know this already here, but we should rather move this to +# where repository args are being processed +# Set host_injections directory and ensure it is a writable directory (if user provided) +if [ -z ${USER_HOST_INJECTIONS+x} ]; then + # Not set, so use our default + HOST_INJECTIONS=${EESSI_TMPDIR}/opt-eessi + mkdir -p $HOST_INJECTIONS +else + # Make sure the host_injections directory specified exists and is a folder + mkdir -p ${USER_HOST_INJECTIONS} || fatal_error "host_injections directory ${USER_HOST_INJECTIONS} is either not a directory or cannot be created" + HOST_INJECTIONS=${USER_HOST_INJECTIONS} +fi +[[ ${VERBOSE} -eq 1 ]] && echo "HOST_INJECTIONS=${HOST_INJECTIONS}" + # configure Singularity: if SINGULARITY_CACHEDIR is already defined, use that # a global SINGULARITY_CACHEDIR would ensure that we don't consume # storage space again and again for the container & also speed-up @@ -394,100 +526,166 @@ fi [[ ${VERBOSE} -eq 1 ]] && echo "SINGULARITY_HOME=${SINGULARITY_HOME}" # 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" +BIND_PATHS="${EESSI_CVMFS_VAR_LIB}:/var/lib/cvmfs,${EESSI_CVMFS_VAR_RUN}:/var/run/cvmfs,${HOST_INJECTIONS}:/opt/eessi" + # provide a '/tmp' inside the container BIND_PATHS="${BIND_PATHS},${EESSI_TMPDIR}:${TMP_IN_CONTAINER}" -[[ ${VERBOSE} -eq 1 ]] && echo "BIND_PATHS=${BIND_PATHS}" +# if TMPDIR is not empty and if TMP_IN_CONTAINER is not a prefix of TMPDIR, we need to add a bind mount for TMPDIR +if [[ ! -z ${TMPDIR} && ${TMP_IN_CONTAINER} != ${TMPDIR}* ]]; then + echo "TMPDIR is not empty (${TMPDIR}) and TMP_IN_CONTAINER (${TMP_IN_CONTAINER}) is not a prefix of TMPDIR: adding bind mount for TMPDIR" + BIND_PATHS="${BIND_PATHS},${TMPDIR}" +fi -# set up repository config (always create directory repos_cfg and populate it with info when -# arg -r|--repository is used) -mkdir -p ${EESSI_TMPDIR}/repos_cfg -if [[ "${REPOSITORY}" == "EESSI-pilot" ]]; then - # need to source defaults as late as possible (see other sourcing below) - source ${TOPDIR}/init/eessi_defaults +# add bind mount for extra bind paths +if [[ ! -z ${EXTRA_BIND_PATHS} ]]; then + BIND_PATHS="${BIND_PATHS},${EXTRA_BIND_PATHS}" +fi - # 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} - - # copy repos.cfg to job directory --> makes it easier to inspect the job - cp -a ${EESSI_REPOS_CFG_FILE} ${EESSI_TMPDIR}/repos_cfg/. - - # 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}" - [[ ${VERBOSE} -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 +[[ ${VERBOSE} -eq 1 ]] && echo "BIND_PATHS=${BIND_PATHS}" - if [[ ! -r ${config_bundle_path} ]]; then - fatal_error "config bundle '${config_bundle_path}' is not readable" ${REPOSITORY_ERROR_EXITCODE} - fi +declare -a ADDITIONAL_CONTAINER_OPTIONS=() - # 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 +# Configure anything we need for NVIDIA GPUs and CUDA installation +if [[ ${SETUP_NVIDIA} -eq 1 ]]; then + if [[ "${NVIDIA_MODE}" == "run" || "${NVIDIA_MODE}" == "all" ]]; then + # Give singularity the appropriate flag + ADDITIONAL_CONTAINER_OPTIONS+=("--nv") + [[ ${VERBOSE} -eq 1 ]] && echo "ADDITIONAL_CONTAINER_OPTIONS=${ADDITIONAL_CONTAINER_OPTIONS[@]}" + fi + if [[ "${NVIDIA_MODE}" == "install" || "${NVIDIA_MODE}" == "all" ]]; then + # Add additional bind mounts to allow CUDA to install within a container + # (Experience tells us that these are necessary, but we don't know _why_ + # as the CUDA installer is a black box. The suspicion is that the CUDA + # installer gets confused by the permissions on these directories when + # inside a container) + EESSI_VAR_LOG=${EESSI_TMPDIR}/var-log + EESSI_USR_LOCAL_CUDA=${EESSI_TMPDIR}/usr-local-cuda + mkdir -p ${EESSI_VAR_LOG} + mkdir -p ${EESSI_USR_LOCAL_CUDA} + BIND_PATHS="${BIND_PATHS},${EESSI_VAR_LOG}:/var/log,${EESSI_USR_LOCAL_CUDA}:/usr/local/cuda" + [[ ${VERBOSE} -eq 1 ]] && echo "BIND_PATHS=${BIND_PATHS}" + if [[ "${NVIDIA_MODE}" == "install" ]] ; then + # No GPU so we need to "trick" Lmod to allow us to load CUDA modules even without a CUDA driver + # (this variable means EESSI_OVERRIDE_GPU_CHECK=1 will be set inside the container) + export SINGULARITYENV_EESSI_OVERRIDE_GPU_CHECK=1 + fi + fi +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 ${TOPDIR}/init/eessi_defaults +# Configure the fakeroot setting for the container +if [[ ${FAKEROOT} -eq 1 ]]; then + ADDITIONAL_CONTAINER_OPTIONS+=("--fakeroot") fi +# set up repository config (always create directory repos_cfg and populate it with info when +# arg -r|--repository is used) +mkdir -p ${EESSI_TMPDIR}/repos_cfg +[[ ${VERBOSE} -eq 1 ]] && echo +[[ ${VERBOSE} -eq 1 ]] && echo -e "BIND_PATHS before processing REPOSITORIES\n BIND_PATHS=${BIND_PATHS}" +[[ ${VERBOSE} -eq 1 ]] && echo +# iterate over repositories in array REPOSITORIES +for cvmfs_repo in "${REPOSITORIES[@]}" +do + [[ ${VERBOSE} -eq 1 ]] && echo "process CVMFS repo spec '${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 + fi + # if cvmfs_repo_name is in cfg_cvmfs_repos, it is a "repository ID" and was + # derived from information in EESSI_REPOS_CFG_FILE, namely the section + # names in that .ini-type file + # in the if-block below, we'll use cfg_repo_id to refer to that ID + # we need to process/provide the config from EESSI_REPOS_CFG_FILE, such + # that the necessary information for accessing a CVMFS repository is made + # available inside the container + if [[ -n "${cfg_cvmfs_repos[${cvmfs_repo_name}]}" ]] ; then + cfg_repo_id=${cvmfs_repo_name} + + # obtain CVMFS repository name from section for the given ID + cfg_repo_name=$(cfg_get_value ${cfg_repo_id} "repo_name") + # derive domain part from (cfg_)repo_name (everything after first '.') + repo_name_domain=${repo_name#*.} + + # cfg_cvmfs_repos is populated through reading the file pointed to by + # EESSI_REPOS_CFG_FILE. We need to copy that file and data it needs + # into the job's working directory. + + # copy repos.cfg to job directory --> makes it easier to inspect the job + cp -a ${EESSI_REPOS_CFG_FILE} ${EESSI_TMPDIR}/repos_cfg/. + + # cfg file should include sections (one per CVMFS repository to be mounted) + # with each section containing the settings: + # - repo_name, + # - repo_version, + # - config_bundle, and + # - a map { filepath_in_bundle -> container_filepath } + # + # The config_bundle includes the files which are mapped ('->') to a 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}/${cfg_repo_name}.pub + # (-> /etc/cvmfs/keys/${repo_name_domain}/${cfg_repo_name}.pub + # the public key to access the repository, key itself is BIND mounted + # via directory ${repo_name_domain} + cfg_repo_version=$(cfg_get_value ${cfg_repo_id} "repo_version") + cfg_config_bundle=$(cfg_get_value ${cfg_repo_id} "config_bundle") + cfg_config_map=$(cfg_get_value ${cfg_repo_id} "config_map") + + # convert cfg_config_map into associative array cfg_file_map + cfg_init_file_map "${cfg_config_map}" + [[ ${VERBOSE} -eq 1 ]] && cfg_print_map + + # use information to set up dir ${EESSI_TMPDIR}/repos_cfg and define + # BIND mounts + # check if config_bundle exists, if so, unpack it into + # ${EESSI_TMPDIR}/repos_cfg; if it doesn't, exit with an error + # if config_bundle is relative path (no '/' at start) prepend it with + # EESSI_REPOS_CFG_DIR + config_bundle_path= + if [[ ! "${cfg_config_bundle}" =~ ^/ ]]; then + config_bundle_path=${EESSI_REPOS_CFG_DIR}/${cfg_config_bundle} + else + config_bundle_path=${cfg_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 cfg_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}]} + # if target is alreay BIND mounted, exit with an error + if [[ ${BIND_PATHS} =~ "${target}" ]]; then + fatal_error "target '${target}' is already listed in paths to bind mount into the container ('${BIND_PATHS}')" ${REPOSITORY_ERROR_EXITCODE} + fi + BIND_PATHS="${BIND_PATHS},${EESSI_TMPDIR}/repos_cfg/${src}:${target}" + done + fi + [[ ${VERBOSE} -eq 1 ]] && echo -e "BIND_PATHS after processing '${cvmfs_repo}'\n BIND_PATHS=${BIND_PATHS}" + [[ ${VERBOSE} -eq 1 ]] && echo +done + # 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 +# ${EESSI_TMPDIR}/repos_cfg/default.local on the 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 @@ -505,41 +703,128 @@ if [[ ! -z ${http_proxy} ]]; then [[ ${VERBOSE} -eq 1 ]] && 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" + src=${EESSI_TMPDIR}/repos_cfg/default.local + target=/etc/cvmfs/default.local + if [[ ${BIND_PATHS} =~ "${target}" ]]; then + fatal_error "BIND target in '${src}:${target}' is already in paths to be bind mounted into the container ('${BIND_PATHS}')" ${REPOSITORY_ERROR_EXITCODE} fi + BIND_PATHS="${BIND_PATHS},${src}:${target}" 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 +# always mount cvmfs-config repo (to get access to EESSI repositories such as software.eessi.io) +EESSI_FUSE_MOUNTS+=("--fusemount" "container:cvmfs2 cvmfs-config.cern.ch /cvmfs/cvmfs-config.cern.ch") + +# iterate over REPOSITORIES and either use repository-specific access mode or global setting (possibly a global default) +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 + 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..." + # cvmfs_repo_name is actually a repository ID, use that to obtain + # the actual name from the EESSI_REPOS_CFG_FILE + cfg_repo_id=${cvmfs_repo_name} + cvmfs_repo_name=$(cfg_get_value ${cfg_repo_id} "repo_name") + fi + # always create a directory for the repository (e.g., to store settings, ...) + mkdir -p ${EESSI_TMPDIR}/${cvmfs_repo_name} + + # add fusemount options depending on requested access mode ('ro' - read-only; 'rw' - read & write) + if [[ ${cvmfs_repo_access} == "ro" ]] ; then + # need to distinguish between basic "ro" access and "ro" after a "rw" session + if [[ -d ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper ]]; then + # the overlay-upper directory is only created in a read-write-session, thus + # we are resuming from such a session here (otherwise there shouldn't be such + # directory yet as it is only created for read-write-sessions a bit further + # below); the overlay-upper directory can only exist because it is part of + # the ${RESUME} directory or tarball + # to be able to see the contents of the read-write session we have to mount + # the fuse-overlayfs (in read-only mode) on top of the CernVM-FS repository + + echo "While processing '${cvmfs_repo_name}' to be mounted 'read-only' we detected an overlay-upper" + echo " directory (${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper) likely from a previous" + 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}") + + # now, put the overlay-upper read-only on top of the repo and make it available under the usual prefix /cvmfs + EESSI_READONLY_OVERLAY="container:fuse-overlayfs" + # The contents of the previous session are available under + # ${EESSI_TMPDIR} which is bind mounted to ${TMP_IN_CONTAINER}. + # Hence, we have to use ${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper + # the left-most directory given for the lowerdir argument is put on top, + # and with no upperdir=... the whole overlayfs is made available read-only + EESSI_READONLY_OVERLAY+=" -o lowerdir=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper:/cvmfs_ro/${cvmfs_repo_name}" + EESSI_READONLY_OVERLAY+=" /cvmfs/${cvmfs_repo_name}" + export EESSI_READONLY_OVERLAY + + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY_OVERLAY}") + export EESSI_FUSE_MOUNTS + else + # 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}" + + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}") + export EESSI_FUSE_MOUNTS + fi + elif [[ ${cvmfs_repo_access} == "rw" ]] ; then + # use repo-specific overlay directories + mkdir -p ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper + mkdir -p ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-work + [[ ${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}") + + EESSI_WRITABLE_OVERLAY="container:fuse-overlayfs" + EESSI_WRITABLE_OVERLAY+=" -o lowerdir=/cvmfs_ro/${cvmfs_repo_name}" + EESSI_WRITABLE_OVERLAY+=" -o upperdir=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper" + EESSI_WRITABLE_OVERLAY+=" -o workdir=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-work" + EESSI_WRITABLE_OVERLAY+=" /cvmfs/${cvmfs_repo_name}" + export EESSI_WRITABLE_OVERLAY + + EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_WRITABLE_OVERLAY}") + export EESSI_FUSE_MOUNTS + else + echo -e "ERROR: access mode '${cvmfs_repo_access}' for CVMFS repository\n '${cvmfs_repo_name}' is not known" + exit ${REPOSITORY_ERROR_EXITCODE} + fi + # create repo_settings.sh file in ${EESSI_TMPDIR}/${cvmfs_repo_name} to store + # (intention is that the file could be just sourced to obtain the settings) + # repo_name = ${cvmfs_repo_name} + # repo_id = ${cfg_repo_id} # empty if not an EESSI repo + # repo_access = ${cvmfs_repo_access} + # repo_host_injections = [ {"src_path":"target_path"}... ] # TODO + settings= + #[[ -n ${cfg_repo_id} ]] && settings="[${cvmfs_repo_name}]\n" || settings="[${cfg_repo_id}]\n" + settings="${settings}repo_name = ${cvmfs_repo_name}\n" + settings="${settings}repo_id = ${cfg_repo_id}\n" + settings="${settings}repo_access = ${cvmfs_repo_access}\n" + # TODO iterate over host_injections (first need means to define them (globally and/or per repository) + # settings="${settings}repo_host_injections = ${host_injections}\n" + echo -e "${settings}" > ${EESSI_TMPDIR}/${cvmfs_repo_name}/repo_settings.sh +done # 5. run container # final settings @@ -558,8 +843,8 @@ if [ ! -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then fi echo "Launching container with command (next line):" -echo "singularity ${RUN_QUIET} ${MODE} ${EESSI_FUSE_MOUNTS[@]} ${CONTAINER} $@" -singularity ${RUN_QUIET} ${MODE} "${EESSI_FUSE_MOUNTS[@]}" ${CONTAINER} "$@" +echo "singularity ${RUN_QUIET} ${MODE} ${ADDITIONAL_CONTAINER_OPTIONS[@]} ${EESSI_FUSE_MOUNTS[@]} ${CONTAINER} $@" +singularity ${RUN_QUIET} ${MODE} "${ADDITIONAL_CONTAINER_OPTIONS[@]}" "${EESSI_FUSE_MOUNTS[@]}" ${CONTAINER} "$@" exit_code=$? # 6. save tmp if requested (arg -s|--save) @@ -570,14 +855,14 @@ if [[ ! -z ${SAVE} ]]; then # 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 + # name format: tmp_storage-{TIMESTAMP}.tgz ts=$(date +%s) - TGZ=${SAVE}/${REPOSITORY}-${ts}.tgz + TGZ=${SAVE}/tmp_storage-${ts}.tgz else # assume SAVE is the full path to a tarball's name TGZ=${SAVE} fi - tar cf ${TGZ} -C ${EESSI_TMPDIR} . + tar czf ${TGZ} -C ${EESSI_TMPDIR} . echo "Saved contents of tmp directory '${EESSI_TMPDIR}' to tarball '${TGZ}' (to resume session add '--resume ${TGZ}')" fi diff --git a/init/Magic_Castle/bash b/init/Magic_Castle/bash index 85e4d54241..bf625e7e7b 100644 --- a/init/Magic_Castle/bash +++ b/init/Magic_Castle/bash @@ -6,11 +6,11 @@ EESSI_SILENT=1 source $(dirname "$BASH_SOURCE")/../eessi_environment_variables # Don't change the default prompt -# export PS1="[EESSI pilot $EESSI_PILOT_VERSION] $ " +# export PS1="[EESSI $EESSI_VERSION] $ " # Provide a clean MODULEPATH export MODULEPATH_ROOT=$EESSI_MODULEPATH -export MODULEPATH=$EESSI_MODULEPATH +export MODULEPATH=$EESSI_SITE_MODULEPATH:$EESSI_MODULEPATH # Extensions are too many, let's not print them by default (requires Lmod 8.4.12) export LMOD_AVAIL_EXTENSIONS=no @@ -36,4 +36,4 @@ else module reload fi -echo "Environment set up to use EESSI pilot software stack (${EESSI_PILOT_VERSION}), have fun!" +echo "Environment set up to use EESSI (${EESSI_VERSION}), have fun!" diff --git a/init/Magic_Castle/eessi_pilot_python3 b/init/Magic_Castle/eessi_python3 similarity index 73% rename from init/Magic_Castle/eessi_pilot_python3 rename to init/Magic_Castle/eessi_python3 index a762ac7b84..b2f7fd4d66 100755 --- a/init/Magic_Castle/eessi_pilot_python3 +++ b/init/Magic_Castle/eessi_python3 @@ -12,10 +12,10 @@ export EESSI_SILENT=1 # for MacOS due to the use of `readlink`) source $(dirname "$(readlink -f "$BASH_SOURCE")")/../eessi_environment_variables -eessi_pilot_python=$(ls ${EESSI_SOFTWARE_PATH}/software/Python/3*GCCcore*/bin/python | sed 1q) -if [ -f "$eessi_pilot_python" ]; then - $eessi_pilot_python "$@" +eessi_python=$(ls ${EESSI_SOFTWARE_PATH}/software/Python/3*GCCcore*/bin/python | sed 1q) +if [ -f "$eessi_python" ]; then + $eessi_python "$@" else - echo "ERROR: No EESSI pilot python 3 available." + echo "ERROR: No EESSI Python 3 available." false fi diff --git a/init/arch_specs/eessi_arch_arm.spec b/init/arch_specs/eessi_arch_arm.spec index b5c9275043..c0d74bd4ad 100755 --- a/init/arch_specs/eessi_arch_arm.spec +++ b/init/arch_specs/eessi_arch_arm.spec @@ -1,6 +1,9 @@ -# ARM CPU architecture specifications -# Software path in EESSI | Vendor ID | List of defining CPU features -"aarch64/neoverse_n1" "ARM" "asimd" # Ampere Altra -"aarch64/neoverse_n1" "" "asimd" # AWS Graviton2 -"aarch64/neoverse_v1" "ARM" "asimd svei8mm" -"aarch64/neoverse_v1" "" "asimd svei8mm" # AWS Graviton3 +# ARM CPU architecture specifications (see https://gpages.juszkiewicz.com.pl/arm-socs-table/arm-socs.html for guidance) +# CPU implementers: 0x41 (ARM), 0x46 (Fujitsu) - also see https://github.com/hrw/arm-socs-table/blob/main/data/socs.yml + +# Software path in EESSI | 'Vendor ID' or 'CPU implementer' | List of defining CPU features +"aarch64/a64fx" "0x46" "asimdhp sve" # Fujitsu A64FX +"aarch64/neoverse_n1" "ARM" "asimddp" # Ampere Altra +"aarch64/neoverse_n1" "0x41" "asimddp" # AWS Graviton2 +"aarch64/neoverse_v1" "ARM" "asimddp svei8mm" +"aarch64/neoverse_v1" "0x41" "asimddp svei8mm" # AWS Graviton3 diff --git a/init/arch_specs/eessi_arch_riscv.spec b/init/arch_specs/eessi_arch_riscv.spec new file mode 100644 index 0000000000..430dd2e72d --- /dev/null +++ b/init/arch_specs/eessi_arch_riscv.spec @@ -0,0 +1 @@ +# Software path in EESSI | Vendor ID | List of defining CPU features diff --git a/init/arch_specs/eessi_arch_x86.spec b/init/arch_specs/eessi_arch_x86.spec index 8d01cb0c03..bfbc5b4be1 100755 --- a/init/arch_specs/eessi_arch_x86.spec +++ b/init/arch_specs/eessi_arch_x86.spec @@ -1,6 +1,7 @@ # x86_64 CPU architecture specifications # Software path in EESSI | Vendor ID | List of defining CPU features -"x86_64/intel/haswell" "GenuineIntel" "avx2 fma" # Intel Haswell, Broadwell +"x86_64/intel/haswell" "GenuineIntel" "avx2 fma" # Intel Haswell, Broadwell "x86_64/intel/skylake_avx512" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl" # Intel Skylake, Cascade Lake -"x86_64/amd/zen2" "AuthenticAMD" "avx2 fma" # AMD Rome -"x86_64/amd/zen3" "AuthenticAMD" "avx2 fma vaes" # AMD Milan, Milan-X +"x86_64/amd/zen2" "AuthenticAMD" "avx2 fma" # AMD Rome +"x86_64/amd/zen3" "AuthenticAMD" "avx2 fma vaes" # AMD Milan, Milan-X +"x86_64/amd/zen4" "AuthenticAMD" "avx2 fma vaes avx512f avx512ifma" # AMD Genoa, Genoa-X diff --git a/init/bash b/init/bash index ea605db0b5..928ac6efdf 100644 --- a/init/bash +++ b/init/bash @@ -1,10 +1,10 @@ -# Allow for a silent mode -if [[ -v EESSI_SILENT ]]; then - # EESSI_SILENT set - output=/dev/null -else - output=/dev/stdout -fi +function show_msg { + # only echo msg if EESSI_SILENT is unset + msg=$1 + if [[ -z ${EESSI_SILENT+x} ]]; then + echo "$msg" + fi +} # The following method should be safe, but might break if file is a symlink # (could switch to $(dirname "$(readlink -f "$BASH_SOURCE")") in that case) @@ -13,27 +13,34 @@ source $(dirname "$BASH_SOURCE")/eessi_environment_variables # only continue if setting EESSI environment variables worked fine if [ $? -eq 0 ]; then - export PS1="[EESSI pilot $EESSI_PILOT_VERSION] $ " + export PS1="{EESSI $EESSI_VERSION} $PS1" # add location of commands provided by compat layer to $PATH; # see https://github.com/EESSI/software-layer/issues/52 export PATH=$EPREFIX/usr/bin:$EPREFIX/bin:$PATH # init Lmod - echo "Initializing Lmod..." >> $output + show_msg "Initializing Lmod..." source $EESSI_EPREFIX/usr/share/Lmod/init/bash # prepend location of modules for EESSI software stack to $MODULEPATH - echo "Prepending $EESSI_MODULEPATH to \$MODULEPATH..." >> $output + show_msg "Prepending $EESSI_MODULEPATH to \$MODULEPATH..." module use $EESSI_MODULEPATH - - #echo >> $output - #echo "*** Known problems in the ${EESSI_PILOT_VERSION} pilot software stack ***" >> $output - #echo >> $output - #echo "1) ..." >> $output - #echo >> $output - #echo >> $output - - echo "Environment set up to use EESSI pilot software stack, have fun!" >> $output + show_msg "Prepending site path $EESSI_SITE_MODULEPATH to \$MODULEPATH..." + module use $EESSI_SITE_MODULEPATH + + if [ ! -z ${EESSI_MODULEPATH_ACCEL} ]; then + show_msg "Prepending $EESSI_MODULEPATH_ACCEL to \$MODULEPATH..." + module use $EESSI_MODULEPATH_ACCEL + fi + + #show_msg "" + #show_msg "*** Known problems in the ${EESSI_VERSION} software stack ***" + #show_msg "" + #show_msg "1) ..." + #show_msg "" + #show_msg "" + + echo "Environment set up to use EESSI (${EESSI_VERSION}), have fun!" fi diff --git a/init/eessi_archdetect.sh b/init/eessi_archdetect.sh index 58dd99eb6b..4fd979cea5 100755 --- a/init/eessi_archdetect.sh +++ b/init/eessi_archdetect.sh @@ -1,8 +1,26 @@ #!/usr/bin/env bash -VERSION="1.1.0" -# Logging -LOG_LEVEL="INFO" +# Confirm the current shell is Bash >= 4 +# (works for sh, bash, dash, zsh, ksh, but not fish, tcsh, elvish) +if [ -n "$BASH_VERSION" ]; then + # Extract the major version numbers + bash_version=$(echo "$BASH_VERSION" | grep -oP '^\d+\.\d+') + major_version=$(echo "$bash_version" | cut -d. -f1) + + # Check if the major version is 4 or higher + if [ "$major_version" -lt 4 ]; then + echo "Error: This script must be run with Bash >= 4, you have $BASH_VERSION." >&2 + exit 1 + fi +else + echo "Error: This script must be run with Bash." >&2 + exit 1 +fi + +VERSION="1.2.0" + +# default log level: only emit warnings or errors +LOG_LEVEL="WARN" # Default result type is a best match CPUPATH_RESULT="best" @@ -69,8 +87,8 @@ check_allinfirst(){ cpupath(){ # If EESSI_SOFTWARE_SUBDIR_OVERRIDE is set, use it - log "DEBUG" "cpupath: Override variable set as '$EESI_SOFTWARE_SUBDIR_OVERRIDE' " - [ $EESI_SOFTWARE_SUBDIR_OVERRIDE ] && echo ${EESI_SOFTWARE_SUBDIR_OVERRIDE} && exit + log "DEBUG" "cpupath: Override variable set as '$EESSI_SOFTWARE_SUBDIR_OVERRIDE' " + [ $EESSI_SOFTWARE_SUBDIR_OVERRIDE ] && echo ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} && exit # Identify the best matching CPU architecture from a list of supported specifications for the host CPU # Return the path to the installation files in EESSI of the best matching architecture @@ -85,23 +103,35 @@ cpupath(){ "x86_64") local spec_file="eessi_arch_x86.spec";; "aarch64") local spec_file="eessi_arch_arm.spec";; "ppc64le") local spec_file="eessi_arch_ppc.spec";; + "riscv64") local spec_file="eessi_arch_riscv.spec";; *) log "ERROR" "cpupath: Unsupported CPU architecture $machine_type" esac # spec files are located in a subfolder with this script - local base_dir=$(dirname $(realpath $0)) + local base_dir=$(dirname $(readlink -f $0)) update_arch_specs "$base_dir/arch_specs/${spec_file}" # Identify the host CPU vendor - local cpu_vendor_tag="vendor[ _]id" - local cpu_vendor=$(get_cpuinfo "$cpu_vendor_tag") + local cpu_vendor=$(get_cpuinfo "vendor[ _]id") + if [ "${cpu_vendor}" == "" ]; then + cpu_vendor=$(get_cpuinfo "cpu[ _]implementer") + fi log "DEBUG" "cpupath: CPU vendor of host system: '$cpu_vendor'" # Identify the host CPU flags or features - local cpu_flag_tag='flags' # cpuinfo systems print different line identifiers, eg features, instead of flags - [ "${cpu_vendor}" == "ARM" ] && cpu_flag_tag='flags' - [ "${machine_type}" == "aarch64" ] && [ "${cpu_vendor}x" == "x" ] && cpu_flag_tag='features' - [ "${machine_type}" == "ppc64le" ] && cpu_flag_tag='cpu' + local cpu_flag_tag; + if [ "${cpu_vendor}" == "ARM" ]; then + # if CPU vendor field is ARM, then we should be able to determine CPU microarchitecture based on 'flags' field + cpu_flag_tag='flags' + # if 64-bit Arm CPU without "ARM" as vendor ID, we need to take into account 'features' field + elif [ "${machine_type}" == "aarch64" ]; then + cpu_flag_tag='features' + # on 64-bit POWER, we need to look at 'cpu' field + elif [ "${machine_type}" == "ppc64le" ]; then + cpu_flag_tag='cpu' + else + cpu_flag_tag='flags' + fi local cpu_flags=$(get_cpuinfo "$cpu_flag_tag") log "DEBUG" "cpupath: CPU flags of host system: '$cpu_flags'" @@ -131,8 +161,45 @@ cpupath(){ fi } +accelpath() { + # If EESSI_ACCELERATOR_TARGET_OVERRIDE is set, use it + log "DEBUG" "accelpath: Override variable set as '$EESSI_ACCELERATOR_TARGET_OVERRIDE' " + if [ ! -z $EESSI_ACCELERATOR_TARGET_OVERRIDE ]; then + if [[ "$EESSI_ACCELERATOR_TARGET_OVERRIDE" =~ ^accel/nvidia/cc[0-9][0-9]$ ]]; then + echo ${EESSI_ACCELERATOR_TARGET_OVERRIDE} + return 0 + else + log "ERROR" "Value of \$EESSI_ACCELERATOR_TARGET_OVERRIDE should match 'accel/nvidia/cc[0-9[0-9]', but it does not: '$EESSI_ACCELERATOR_TARGET_OVERRIDE'" + fi + return 0 + fi + + # check for NVIDIA GPUs via nvidia-smi command + nvidia_smi=$(command -v nvidia-smi) + if [[ $? -eq 0 ]]; then + log "DEBUG" "accelpath: nvidia-smi command found @ ${nvidia_smi}" + nvidia_smi_out=$(mktemp -p /tmp nvidia_smi_out.XXXXX) + nvidia-smi --query-gpu=gpu_name,count,driver_version,compute_cap --format=csv,noheader 2>&1 > $nvidia_smi_out + if [[ $? -eq 0 ]]; then + nvidia_smi_info=$(head -1 $nvidia_smi_out) + cuda_cc=$(echo $nvidia_smi_info | sed 's/, /,/g' | cut -f4 -d, | sed 's/\.//g') + log "DEBUG" "accelpath: CUDA compute capability '${cuda_cc}' derived from nvidia-smi output '${nvidia_smi_info}'" + res="accel/nvidia/cc${cuda_cc}" + log "DEBUG" "accelpath: result: ${res}" + echo $res + rm -f $nvidia_smi_out + else + log "DEBUG" "accelpath: nvidia-smi command failed, see output in $nvidia_smi_out" + exit 3 + fi + else + log "DEBUG" "accelpath: nvidia-smi command not found" + exit 2 + fi +} + # Parse command line arguments -USAGE="Usage: eessi_archdetect.sh [-h][-d][-a] " +USAGE="Usage: eessi_archdetect.sh [-h][-d][-a] " while getopts 'hdva' OPTION; do case "$OPTION" in @@ -149,5 +216,6 @@ ARGUMENT=${1:-none} case "$ARGUMENT" in "cpupath") cpupath; exit;; - *) echo "$USAGE"; log "ERROR" "Missing argument (possible actions: 'cpupath')";; + "accelpath") accelpath; exit;; + *) echo "$USAGE"; log "ERROR" "Missing argument (possible actions: 'cpupath', 'accelpath')";; esac diff --git a/init/eessi_defaults b/init/eessi_defaults index f482cbc269..654a829425 100644 --- a/init/eessi_defaults +++ b/init/eessi_defaults @@ -8,5 +8,20 @@ # 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}" +# use different defaults for RISC-V, as we want to redirect to the riscv.eessi.io repo +if [[ $(uname -m) == "riscv64" ]]; then + export EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO_OVERRIDE:=/cvmfs/riscv.eessi.io}" + export EESSI_VERSION="${EESSI_VERSION_OVERRIDE:=20240402}" + if [[ -z ${EESSI_SILENT+x} ]]; then + echo "RISC-V architecture detected, but there is no RISC-V support yet in the production repository." + echo "Automatically switching to version ${EESSI_VERSION} of the RISC-V development repository ${EESSI_CVMFS_REPO}." + echo "For more details about this repository, see https://www.eessi.io/docs/repositories/riscv.eessi.io/." + echo "" + fi +else + export EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO_OVERRIDE:=/cvmfs/software.eessi.io}" + export EESSI_VERSION="${EESSI_VERSION_OVERRIDE:=2023.06}" +fi +# use archdetect by default, unless otherwise specified +export EESSI_USE_ARCHDETECT="${EESSI_USE_ARCHDETECT:=1}" +export EESSI_USE_ARCHSPEC="${EESSI_USE_ARCHSPEC:=0}" diff --git a/init/eessi_environment_variables b/init/eessi_environment_variables index 10ac1926f4..0f13b1493a 100644 --- a/init/eessi_environment_variables +++ b/init/eessi_environment_variables @@ -1,25 +1,25 @@ # 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)) - -# Allow for a silent mode -if [[ -v EESSI_SILENT ]]; then - # EESSI_SILENT set - output=/dev/null -else - output=/dev/stdout -fi +EESSI_INIT_DIR_PATH=$(dirname $(readlink -f $BASH_SOURCE)) function error() { echo -e "\e[31mERROR: $1\e[0m" >&2 false } -# set up minimal environment: $EESSI_PREFIX, $EESSI_PILOT_VERSION, $EESSI_OS_TYPE, $EESSI_CPU_FAMILY, $EPREFIX +function show_msg { + # only echo msg if EESSI_SILENT is unset + msg=$1 + if [[ -z ${EESSI_SILENT+x} ]]; then + echo "$msg" + fi +} + +# set up minimal environment: $EESSI_PREFIX, $EESSI_VERSION, $EESSI_OS_TYPE, $EESSI_CPU_FAMILY, $EPREFIX source $EESSI_INIT_DIR_PATH/minimal_eessi_env if [ -d $EESSI_PREFIX ]; then - echo "Found EESSI pilot repo @ $EESSI_PREFIX!" >> $output + show_msg "Found EESSI repo @ $EESSI_PREFIX!" export EESSI_EPREFIX=$EPREFIX if [ -d $EESSI_EPREFIX ]; then @@ -27,49 +27,129 @@ if [ -d $EESSI_PREFIX ]; then # determine subdirectory in software layer if [ "$EESSI_USE_ARCHDETECT" == "1" ]; then # if archdetect is enabled, use internal code - export EESSI_SOFTWARE_SUBDIR=$(${EESSI_INIT_DIR_PATH}/eessi_archdetect.sh cpupath) - echo "archdetect says ${EESSI_SOFTWARE_SUBDIR}" >> $output - else + all_cpupaths=$(${EESSI_INIT_DIR_PATH}/eessi_archdetect.sh -a cpupath) + # iterate over colon-separated list verifying if the architecture is present + # under $EESSI_PREFIX/software/$EESSI_OS_TYPE; if so use the architecture as best match + IFS=: read -r -a archs <<< "${all_cpupaths}" + for arch in "${archs[@]}"; do + if [ -d ${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${arch} ]; then + export EESSI_SOFTWARE_SUBDIR=${arch} + show_msg "archdetect says ${EESSI_SOFTWARE_SUBDIR}" + break + fi + done + + # we need to make sure that errexit shell option (set -e) is not enabled, + # since archdetect will produce non-zero exit code if no accelerator was found + if [[ "$-" =~ e ]]; then + errexit_shell_option_set='yes' + set +e + else + errexit_shell_option_set='no' + fi + + # to be able to grab exit code of archdetect trying to detect accelerators, + # we can not run it via $(...), so we have to redirect the output to a temporary file + tmpout=$(mktemp) + ${EESSI_INIT_DIR_PATH}/eessi_archdetect.sh accelpath 2>&1 > $tmpout + accelpath_exit_code=$? + + if [[ "$errexit_shell_option_set" == "yes" ]]; then + set -e + fi + + if [[ $accelpath_exit_code -eq 0 ]]; then + export EESSI_ACCEL_SUBDIR=$(tail -1 $tmpout && rm -f $tmpout) + if [ -z ${EESSI_ACCEL_SUBDIR} ]; then + error "accelerator detection with archdetect worked, but no result was returned?!" + else + # allow specifying different parent directory for accel/* subdirectory via $EESSI_ACCEL_SOFTWARE_SUBDIR_OVERRIDE + EESSI_ACCEL_SOFTWARE_SUBDIR=${EESSI_ACCEL_SOFTWARE_SUBDIR_OVERRIDE:-$EESSI_SOFTWARE_SUBDIR} + # path to where accel/* subdirectory is located + EESSI_ACCEL_SOFTWARE_PATH=${EESSI_PREFIX}/software/${EESSI_OS_TYPE}/${EESSI_ACCEL_SOFTWARE_SUBDIR} + if [ -d $EESSI_ACCEL_SOFTWARE_PATH/${EESSI_ACCEL_SUBDIR} ]; then + show_msg "archdetect found supported accelerator for CPU target ${EESSI_ACCEL_SOFTWARE_SUBDIR}: ${EESSI_ACCEL_SUBDIR}" + else + show_msg "No matching path found in ${EESSI_ACCEL_SOFTWARE_SUBDIR} for accelerator detected by archdetect (${EESSI_ACCEL_SUBDIR})" + fi + fi + else + show_msg "archdetect could not detect any accelerators" + rm -f $tmpout + fi + elif [ "$EESSI_USE_ARCHSPEC" == "1" ]; then # note: eessi_software_subdir_for_host.py will pick up value from $EESSI_SOFTWARE_SUBDIR_OVERRIDE if it's defined! export EESSI_EPREFIX_PYTHON=$EESSI_EPREFIX/usr/bin/python3 export EESSI_SOFTWARE_SUBDIR=$($EESSI_EPREFIX_PYTHON ${EESSI_INIT_DIR_PATH}/eessi_software_subdir_for_host.py $EESSI_PREFIX) - echo "archspec says ${EESSI_SOFTWARE_SUBDIR}" >> $output + show_msg "archspec says ${EESSI_SOFTWARE_SUBDIR}" + else + error "Don't know how to detect host CPU, giving up!" fi if [ ! -z $EESSI_SOFTWARE_SUBDIR ]; then - echo "Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory." >> $output + show_msg "Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory." export EESSI_SOFTWARE_PATH=$EESSI_PREFIX/software/$EESSI_OS_TYPE/$EESSI_SOFTWARE_SUBDIR + + # Configure our LMOD + export LMOD_CONFIG_DIR="$EESSI_SOFTWARE_PATH/.lmod" + lmod_rc_file="$LMOD_CONFIG_DIR/lmodrc.lua" + if [ -f $lmod_rc_file ]; then + show_msg "Found Lmod configuration file at $lmod_rc_file" + else + error "Lmod configuration file not found at $lmod_rc_file" + fi + + export LMOD_PACKAGE_PATH="$EESSI_SOFTWARE_PATH/.lmod" + lmod_sitepackage_file="$LMOD_PACKAGE_PATH/SitePackage.lua" + if [ -f $lmod_sitepackage_file ]; then + show_msg "Found Lmod SitePackage.lua file at $lmod_sitepackage_file" + else + error "Lmod SitePackage.lua file not found at $lmod_sitepackage_file" + fi + if [ ! -z $EESSI_BASIC_ENV ]; then - echo "Only setting up basic environment, so we're done" >> $output + show_msg "Only setting up basic environment, so we're done" elif [ -d $EESSI_SOFTWARE_PATH ]; then + export EESSI_SITE_SOFTWARE_PATH=${EESSI_SOFTWARE_PATH/versions/host_injections} + show_msg "Using ${EESSI_SITE_SOFTWARE_PATH} as the site extension directory for installations." + # Allow for use of alternative module tree shipped with EESSI + if [ -z ${EESSI_MODULE_SUBDIR+x} ]; then + # EESSI_MODULE_SUBDIR not set + EESSI_MODULE_SUBDIR="modules/all" + fi # Allow for the use of a custom MNS if [ -z ${EESSI_CUSTOM_MODULEPATH+x} ]; then # EESSI_CUSTOM_MODULEPATH not set so we use our defaults - # Allow for use of alternative module tree shipped with EESSI - if [ -z ${EESSI_MODULE_SUBDIR+x} ]; then - # EESSI_MODULE_SUBDIR not set - EESSI_MODULE_SUBDIR="modules/all" - fi EESSI_MODULEPATH=$EESSI_SOFTWARE_PATH/$EESSI_MODULE_SUBDIR else - echo "Using defined environment variable \$EESSI_CUSTOM_MODULEPATH to set EESSI_MODULEPATH." >> $output + show_msg "Using defined environment variable \$EESSI_CUSTOM_MODULEPATH to set EESSI_MODULEPATH." EESSI_MODULEPATH=$EESSI_CUSTOM_MODULEPATH fi if [ -d $EESSI_MODULEPATH ]; then export EESSI_MODULEPATH=$EESSI_MODULEPATH - echo "Using ${EESSI_MODULEPATH} as the directory to be added to MODULEPATH." >> $output + show_msg "Using ${EESSI_MODULEPATH} as the directory to be added to MODULEPATH." + export EESSI_SITE_MODULEPATH=$EESSI_SITE_SOFTWARE_PATH/$EESSI_MODULE_SUBDIR + show_msg "Using ${EESSI_SITE_MODULEPATH} as the site extension directory to be added to MODULEPATH." else error "EESSI module path at $EESSI_MODULEPATH not found!" false fi - export LMOD_RC="$EESSI_SOFTWARE_PATH/.lmod/lmodrc.lua" - if [ -f $LMOD_RC ]; then - echo "Found Lmod configuration file at $LMOD_RC" >> $output - else - error "Lmod configuration file not found at $LMOD_RC" + if [ -d ${EESSI_ACCEL_SOFTWARE_PATH}/${EESSI_ACCEL_SUBDIR}/${EESSI_MODULE_SUBDIR} ]; then + export EESSI_MODULEPATH_ACCEL=${EESSI_ACCEL_SOFTWARE_PATH}/${EESSI_ACCEL_SUBDIR}/${EESSI_MODULE_SUBDIR} + show_msg "Using ${EESSI_MODULEPATH_ACCEL} as additional directory (for accelerators) to be added to MODULEPATH." + fi + + # Fix wrong path for RHEL >=8 libcurl + # This is required here because we ship curl in our compat layer. If we only provided + # curl as a module file we could instead do this via a `modluafooter` in an EasyBuild + # hook (or via an Lmod hook) + rhel_libcurl_file="/etc/pki/tls/certs/ca-bundle.crt" + if [ -f $rhel_libcurl_file ]; then + show_msg "Found libcurl CAs file at RHEL location, setting CURL_CA_BUNDLE" + export CURL_CA_BUNDLE=$rhel_libcurl_file fi else @@ -82,5 +162,5 @@ if [ -d $EESSI_PREFIX ]; then error "Compatibility layer directory $EESSI_EPREFIX not found!" fi else - error "EESSI pilot repository at $EESSI_PREFIX not found!" + error "EESSI repository at $EESSI_PREFIX not found!" fi diff --git a/init/lmod/bash b/init/lmod/bash new file mode 100644 index 0000000000..b2db9a8802 --- /dev/null +++ b/init/lmod/bash @@ -0,0 +1,18 @@ +# Choose an EESSI CVMFS repository +EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO:-/cvmfs/software.eessi.io}" +# Choose an EESSI version +EESSI_VERSION="${EESSI_VERSION:-2023.06}" +# Path to top-level module tree +export MODULEPATH="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" +. "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash" + +if [ -z "$__Init_Default_Modules" ]; then + export __Init_Default_Modules=1; + + ## ability to predefine elsewhere the default list + LMOD_SYSTEM_DEFAULT_MODULES=${LMOD_SYSTEM_DEFAULT_MODULES:-"EESSI/$EESSI_VERSION"} + export LMOD_SYSTEM_DEFAULT_MODULES + module --initial_load --no_redirect restore +else + module refresh +fi diff --git a/init/lmod/csh b/init/lmod/csh new file mode 100644 index 0000000000..f2e9100255 --- /dev/null +++ b/init/lmod/csh @@ -0,0 +1,18 @@ +# Choose an EESSI CVMFS repository +if (! $?EESSI_CVMFS_REPO) then; set EESSI_CVMFS_REPO = "/cvmfs/software.eessi.io"; endif +# Choose an EESSI version +if (! $?EESSI_VERSION) then; set EESSI_VERSION = "2023.06"; endif +# Path to top-level module tree +setenv MODULEPATH "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" +source "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/csh" + +if (! $?__Init_Default_Modules ) then + setenv __Init_Default_Modules 1; + + ## ability to predefine elsewhere the default list + if (! $?LMOD_SYSTEM_DEFAULT_MODULES) then; setenv LMOD_SYSTEM_DEFAULT_MODULES "EESSI/$EESSI_VERSION"; endif + module --initial_load --no_redirect restore +else + module refresh +endif + diff --git a/init/lmod/fish b/init/lmod/fish new file mode 100644 index 0000000000..46cd7cacf4 --- /dev/null +++ b/init/lmod/fish @@ -0,0 +1,17 @@ +# Choose an EESSI CVMFS repository +set EESSI_CVMFS_REPO (set -q EESSI_CVMFS_REPO; and echo "$EESSI_CVMFS_REPO"; or echo "/cvmfs/software.eessi.io") +# Choose an EESSI version +set EESSI_VERSION (set -q EESSI_VERSION; and echo "$EESSI_VERSION"; or echo "2023.06") +# Path to top-level module tree +set -x MODULEPATH "$EESSI_CVMFS_REPO"/versions/"$EESSI_VERSION"/init/modules +. "$EESSI_CVMFS_REPO"/versions/"$EESSI_VERSION"/compat/linux/(uname -m)/usr/share/Lmod/init/fish + +if test -z "$__Init_Default_Modules" + export __Init_Default_Modules=1; + + ## ability to predefine elsewhere the default list + set -x LMOD_SYSTEM_DEFAULT_MODULES (set -q LMOD_SYSTEM_DEFAULT_MODULE; and echo "$LMOD_SYSTEM_DEFAULT_MODULE"; or echo "EESSI/$EESSI_VERSION") + module --initial_load --no_redirect restore +else + module refresh +end diff --git a/init/lmod/ksh b/init/lmod/ksh new file mode 100644 index 0000000000..7d9a05d688 --- /dev/null +++ b/init/lmod/ksh @@ -0,0 +1,18 @@ +# Choose an EESSI CVMFS repository +EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO:-/cvmfs/software.eessi.io}" +# Choose an EESSI version +EESSI_VERSION="${EESSI_VERSION:-2023.06}" +# Path to top-level module tree +export MODULEPATH="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" +. "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/ksh" + +if [ -z "$__Init_Default_Modules" ]; then + export __Init_Default_Modules=1; + + ## ability to predefine elsewhere the default list + LMOD_SYSTEM_DEFAULT_MODULES=${LMOD_SYSTEM_DEFAULT_MODULES:-"EESSI/$EESSI_VERSION"} + export LMOD_SYSTEM_DEFAULT_MODULES + module --initial_load --no_redirect restore +else + module refresh +fi diff --git a/init/lmod/zsh b/init/lmod/zsh new file mode 100644 index 0000000000..bc6e8e4deb --- /dev/null +++ b/init/lmod/zsh @@ -0,0 +1,18 @@ +# Choose an EESSI CVMFS repository +EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO:-/cvmfs/software.eessi.io}" +# Choose an EESSI version +EESSI_VERSION="${EESSI_VERSION:-2023.06}" +# Path to top-level module tree +export MODULEPATH="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" +. "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/zsh" + +if [ -z "$__Init_Default_Modules" ]; then + export __Init_Default_Modules=1; + + ## ability to predefine elsewhere the default list + LMOD_SYSTEM_DEFAULT_MODULES=${LMOD_SYSTEM_DEFAULT_MODULES:-"EESSI/$EESSI_VERSION"} + export LMOD_SYSTEM_DEFAULT_MODULES + module --initial_load --no_redirect restore +else + module refresh +fi diff --git a/init/lmod_eessi_archdetect_wrapper.sh b/init/lmod_eessi_archdetect_wrapper.sh new file mode 100644 index 0000000000..c12452c71d --- /dev/null +++ b/init/lmod_eessi_archdetect_wrapper.sh @@ -0,0 +1,2 @@ +# This can be leveraged by the source_sh() feature of Lmod +export EESSI_ARCHDETECT_OPTIONS=$($(dirname $(readlink -f $BASH_SOURCE))/eessi_archdetect.sh -a cpupath) diff --git a/init/lmod_eessi_archdetect_wrapper_accel.sh b/init/lmod_eessi_archdetect_wrapper_accel.sh new file mode 100644 index 0000000000..d4a0038cb5 --- /dev/null +++ b/init/lmod_eessi_archdetect_wrapper_accel.sh @@ -0,0 +1,2 @@ +# This can be leveraged by the source_sh() feature of Lmod +export EESSI_ACCEL_SUBDIR=$($(dirname $(readlink -f $BASH_SOURCE))/eessi_archdetect.sh accelpath) diff --git a/init/minimal_eessi_env b/init/minimal_eessi_env index b7cb7c5e9e..5e513c3c9f 100644 --- a/init/minimal_eessi_env +++ b/init/minimal_eessi_env @@ -2,13 +2,13 @@ # # 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)) +EESSI_INIT_DIR_PATH=$(dirname $(readlink -f $BASH_SOURCE)) -# set up defaults: EESSI_CVMFS_REPO, EESSI_PILOT_VERSION +# set up defaults: EESSI_CVMFS_REPO, EESSI_VERSION # script takes *_OVERRIDEs into account source ${EESSI_INIT_DIR_PATH}/eessi_defaults -export EESSI_PREFIX=$EESSI_CVMFS_REPO/versions/$EESSI_PILOT_VERSION +export EESSI_PREFIX=$EESSI_CVMFS_REPO/versions/$EESSI_VERSION if [[ $(uname -s) == 'Linux' ]]; then export EESSI_OS_TYPE='linux' @@ -16,8 +16,13 @@ else export EESSI_OS_TYPE='macos' fi -# aarch64 (Arm 64-bit), ppc64le (POWER 64-bit), x86_64 (x86 64-bit) +# aarch64 (Arm 64-bit), riscv64 (RISC-V 64-bit), x86_64 (x86 64-bit) export EESSI_CPU_FAMILY=$(uname -m) # set $EPREFIX since that is basically a standard in Gentoo Prefix -export EPREFIX=$EESSI_PREFIX/compat/$EESSI_OS_TYPE/$EESSI_CPU_FAMILY +# if $EESSI_COMPAT_LAYER_DIR is defined (for example by run_in_compat_layer_env.sh script), we use that value +if [ ! -z ${EESSI_COMPAT_LAYER_DIR} ]; then + export EPREFIX=$EESSI_COMPAT_LAYER_DIR +else + export EPREFIX=$EESSI_PREFIX/compat/$EESSI_OS_TYPE/$EESSI_CPU_FAMILY +fi diff --git a/init/modules/EESSI/2023.06.lua b/init/modules/EESSI/2023.06.lua new file mode 100644 index 0000000000..d5105e89fc --- /dev/null +++ b/init/modules/EESSI/2023.06.lua @@ -0,0 +1,155 @@ +help([[ +Description +=========== +The European Environment for Scientific Software Installations (EESSI, pronounced as easy) is a collaboration between different European partners in HPC community.The goal of this project is to build a common stack of scientific software installations for HPC systems and beyond, including laptops, personal workstations and cloud infrastructure. + +More information +================ + - URL: https://www.eessi.io/docs/ +]]) +whatis("Description: The European Environment for Scientific Software Installations (EESSI, pronounced as easy) is a collaboration between different European partners in HPC community. The goal of this project is to build a common stack of scientific software installations for HPC systems and beyond, including laptops, personal workstations and cloud infrastructure.") +whatis("URL: https://www.eessi.io/docs/") +conflict("EESSI") +local eessi_version = myModuleVersion() +local eessi_repo = "/cvmfs/software.eessi.io" +if (subprocess("uname -m"):gsub("\n$","") == "riscv64") then + eessi_version = os.getenv("EESSI_VERSION_OVERRIDE") or "20240402" + eessi_repo = "/cvmfs/riscv.eessi.io" + LmodMessage("RISC-V architecture detected, but there is no RISC-V support yet in the production repository.\n" .. + "Automatically switching to version " .. eessi_version .. " of the RISC-V development repository " .. eessi_repo .. ".\n" .. + "For more details about this repository, see https://www.eessi.io/docs/repositories/riscv.eessi.io/.") +end +local eessi_prefix = pathJoin(eessi_repo, "versions", eessi_version) +local eessi_os_type = "linux" +setenv("EESSI_VERSION", eessi_version) +setenv("EESSI_CVMFS_REPO", eessi_repo) +setenv("EESSI_OS_TYPE", eessi_os_type) +function eessiDebug(text) + if (mode() == "load" and os.getenv("EESSI_DEBUG_INIT")) then + LmodMessage(text) + end +end +function archdetect_cpu() + local script = pathJoin(eessi_prefix, 'init', 'lmod_eessi_archdetect_wrapper.sh') + -- make sure that we grab the value for architecture before the module unsets the environment variable (in unload mode) + local archdetect_options = os.getenv("EESSI_ARCHDETECT_OPTIONS") or (os.getenv("EESSI_ARCHDETECT_OPTIONS_OVERRIDE") or "") + if not os.getenv("EESSI_ARCHDETECT_OPTIONS_OVERRIDE") then + if convertToCanonical(LmodVersion()) < convertToCanonical("8.6") then + LmodError("Loading this modulefile requires using Lmod version >= 8.6, but you can export EESSI_ARCHDETECT_OPTIONS_OVERRIDE to the available cpu architecture in the form of: x86_64/intel/haswell:x86_64/generic or aarch64/neoverse_v1:aarch64/generic") + end + source_sh("bash", script) + end + -- EESSI_ARCHDETECT_OPTIONS is set by the script (_if_ it was called) + archdetect_options = os.getenv("EESSI_ARCHDETECT_OPTIONS") or archdetect_options + if archdetect_options then + eessiDebug("Got archdetect CPU options: " .. archdetect_options) + -- archdetect_options is a colon-separated list of CPU architectures that are compatible with + -- the host CPU and ordered from most specific to least specific, e.g., + -- x86_64/intel/skylake_avx512:x86_64/intel/haswell:x86_64/generic + -- We loop over the list, and return the highest matching arch for which a directory exists for this EESSI version + for archdetect_filter_cpu in string.gmatch(archdetect_options, "([^" .. ":" .. "]+)") do + if isDir(pathJoin(eessi_prefix, "software", eessi_os_type, archdetect_filter_cpu, "software")) then + eessiDebug("Selected archdetect CPU: " .. archdetect_filter_cpu) + return archdetect_filter_cpu + end + end + LmodError("Software directory check for the detected architecture failed") + else + -- Still need to return something + return nil + end +end +function archdetect_accel() + local script = pathJoin(eessi_prefix, 'init', 'lmod_eessi_archdetect_wrapper_accel.sh') + -- for unload mode, we need to grab the value before it is unset + local archdetect_accel = os.getenv("EESSI_ACCEL_SUBDIR") or (os.getenv("EESSI_ACCELERATOR_TARGET_OVERRIDE") or "") + if not os.getenv("EESSI_ACCELERATOR_TARGET_OVERRIDE ") then + if convertToCanonical(LmodVersion()) < convertToCanonical("8.6") then + LmodError("Loading this modulefile requires using Lmod version >= 8.6, but you can export EESSI_ACCELERATOR_TARGET_OVERRIDE to the available accelerator architecture in the form of: accel/nvidia/cc80") + end + source_sh("bash", script) + end + archdetect_accel = os.getenv("EESSI_ACCEL_SUBDIR") or archdetect_accel + eessiDebug("Got archdetect accel option: " .. archdetect_accel) + return archdetect_accel +end +-- archdetect finds the best compatible architecture, e.g., x86_64/amd/zen3 +local archdetect = archdetect_cpu() +-- archdetect_accel() attempts to identify an accelerator, e.g., accel/nvidia/cc80 +local archdetect_accel = archdetect_accel() +-- eessi_cpu_family is derived from the archdetect match, e.g., x86_64 +local eessi_cpu_family = archdetect:match("([^/]+)") +local eessi_software_subdir = archdetect +-- eessi_eprefix is the base location of the compat layer, e.g., /cvmfs/software.eessi.io/versions/2023.06/compat/linux/x86_64 +local eessi_eprefix = pathJoin(eessi_prefix, "compat", eessi_os_type, eessi_cpu_family) +-- eessi_software_path is the location of the software installations, e.g., +-- /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen3 +local eessi_software_path = pathJoin(eessi_prefix, "software", eessi_os_type, eessi_software_subdir) +local eessi_modules_subdir = pathJoin("modules", "all") +-- eessi_module_path is the location of the _CPU_ module files, e.g., +-- /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen3/modules/all +local eessi_module_path = pathJoin(eessi_software_path, eessi_modules_subdir) +local eessi_site_software_path = string.gsub(eessi_software_path, "versions", "host_injections") +-- Site module path is the same as the EESSI one, but with `versions` changed to `host_injections`, e.g., +-- /cvmfs/software.eessi.io/host_injections/2023.06/software/linux/x86_64/amd/zen3/modules/all +local eessi_site_module_path = pathJoin(eessi_site_software_path, eessi_modules_subdir) +setenv("EPREFIX", eessi_eprefix) +eessiDebug("Setting EPREFIX to " .. eessi_eprefix) +setenv("EESSI_CPU_FAMILY", eessi_cpu_family) +eessiDebug("Setting EESSI_CPU_FAMILY to " .. eessi_cpu_family) +setenv("EESSI_SITE_SOFTWARE_PATH", eessi_site_software_path) +eessiDebug("Setting EESSI_SITE_SOFTWARE_PATH to " .. eessi_site_software_path) +setenv("EESSI_SITE_MODULEPATH", eessi_site_module_path) +eessiDebug("Setting EESSI_SITE_MODULEPATH to " .. eessi_site_module_path) +setenv("EESSI_SOFTWARE_SUBDIR", eessi_software_subdir) +eessiDebug("Setting EESSI_SOFTWARE_SUBDIR to " .. eessi_software_subdir) +setenv("EESSI_PREFIX", eessi_prefix) +eessiDebug("Setting EESSI_PREFIX to " .. eessi_prefix) +setenv("EESSI_EPREFIX", eessi_eprefix) +eessiDebug("Setting EPREFIX to " .. eessi_eprefix) +prepend_path("PATH", pathJoin(eessi_eprefix, "bin")) +eessiDebug("Adding " .. pathJoin(eessi_eprefix, "bin") .. " to PATH") +prepend_path("PATH", pathJoin(eessi_eprefix, "usr", "bin")) +eessiDebug("Adding " .. pathJoin(eessi_eprefix, "usr", "bin") .. " to PATH") +setenv("EESSI_SOFTWARE_PATH", eessi_software_path) +eessiDebug("Setting EESSI_SOFTWARE_PATH to " .. eessi_software_path) +setenv("EESSI_MODULEPATH", eessi_module_path) +eessiDebug("Setting EESSI_MODULEPATH to " .. eessi_module_path) +-- We ship our spider cache, so this location does not need to be spider-ed +if ( mode() ~= "spider" ) then + prepend_path("MODULEPATH", eessi_module_path) + eessiDebug("Adding " .. eessi_module_path .. " to MODULEPATH") +end +prepend_path("LMOD_RC", pathJoin(eessi_software_path, ".lmod", "lmodrc.lua")) +eessiDebug("Adding " .. pathJoin(eessi_software_path, ".lmod", "lmodrc.lua") .. " to LMOD_RC") +-- Use pushenv for LMOD_PACKAGE_PATH as this may be set locally by the site +pushenv("LMOD_PACKAGE_PATH", pathJoin(eessi_software_path, ".lmod")) +eessiDebug("Setting LMOD_PACKAGE_PATH to " .. pathJoin(eessi_software_path, ".lmod")) + +-- the accelerator may have an empty value and we need to give some flexibility +-- * construct the path we expect to find +-- * then check it exists +-- * then update the modulepath +if not (archdetect_accel == nil or archdetect_accel == '') then + -- The CPU subdirectory of the accelerator installations is _usually_ the same as host CPU, but this can be overridden + eessi_accel_software_subdir = os.getenv("EESSI_ACCEL_SOFTWARE_SUBDIR_OVERRIDE") or eessi_software_subdir + -- CPU location of the accelerator installations, e.g., + -- /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen3 + eessi_accel_software_path = pathJoin(eessi_prefix, "software", eessi_os_type, eessi_accel_software_subdir) + -- location of the accelerator modules, e.g., + -- /cvmfs/software.eessi.io/versions/2023.06/software/linux/x86_64/amd/zen3/accel/nvidia/cc80/modules/all + eessi_module_path_accel = pathJoin(eessi_accel_software_path, archdetect_accel, eessi_modules_subdir) + eessiDebug("Checking if " .. eessi_module_path_accel .. " exists") + if isDir(eessi_module_path_accel) then + setenv("EESSI_MODULEPATH_ACCEL", eessi_module_path_accel) + prepend_path("MODULEPATH", eessi_module_path_accel) + eessiDebug("Using acclerator modules at: " .. eessi_module_path_accel) + end +end + +-- prepend the site module path last so it has priority +prepend_path("MODULEPATH", eessi_site_module_path) +eessiDebug("Adding " .. eessi_site_module_path .. " to MODULEPATH") +if mode() == "load" then + LmodMessage("EESSI/" .. eessi_version .. " loaded successfully") +end diff --git a/init/modules/EESSI/20240402.lua b/init/modules/EESSI/20240402.lua new file mode 120000 index 0000000000..cbf80d1fcd --- /dev/null +++ b/init/modules/EESSI/20240402.lua @@ -0,0 +1 @@ +2023.06.lua \ No newline at end of file diff --git a/install_apptainer_ubuntu.sh b/install_apptainer_ubuntu.sh index c35c34cda6..192a36a483 100755 --- a/install_apptainer_ubuntu.sh +++ b/install_apptainer_ubuntu.sh @@ -5,10 +5,27 @@ set -e # see https://github.com/apptainer/singularity/issues/5390#issuecomment-899111181 sudo apt-get install alien alien --version -apptainer_rpm=$(curl --silent -L https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/a/ | grep 'apptainer-[0-9]' | sed 's/.*\(apptainer[0-9._a-z-]*.rpm\).*/\1/g') -curl -OL https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/a/${apptainer_rpm} +epel_subdir="pub/epel/8" +apptainer_rpm=$(curl --silent -L https://dl.fedoraproject.org/${epel_subdir}/Everything/x86_64/Packages/a/ | grep 'apptainer-[0-9]' | sed 's/.*\(apptainer[0-9._a-z-]*.rpm\).*/\1/g') +curl -OL https://dl.fedoraproject.org/${epel_subdir}/Everything/x86_64/Packages/a/${apptainer_rpm} sudo alien -d ${apptainer_rpm} sudo apt install ./apptainer*.deb +# No unpriviledged user name spaces in Ubuntu 23.10+ +ubuntu_version=$(lsb_release -r | awk '{print $2}') +if [[ $(echo -e "$ubuntu_version\n23.10" | sort -V | head -n 1) == "23.10" ]]; then + sudo tee /etc/apparmor.d/apptainer << 'EOF' +# Permit unprivileged user namespace creation for apptainer starter +abi , +include +profile apptainer /usr/libexec/apptainer/bin/starter{,-suid} + flags=(unconfined) { + userns, + # Site-specific additions and overrides. See local/README for details. + include if exists +} +EOF + sudo systemctl reload apparmor +fi apptainer --version # also check whether 'singularity' command is still provided by Apptainer installation singularity --version diff --git a/install_scripts.sh b/install_scripts.sh new file mode 100755 index 0000000000..c5a9a556c2 --- /dev/null +++ b/install_scripts.sh @@ -0,0 +1,144 @@ +#!/bin/bash +# +# Script to install scripts from the software-layer repo into the EESSI software stack + +display_help() { + echo "usage: $0 [OPTIONS]" + echo " -p | --prefix - prefix to copy the scripts to" + echo " -h | --help - display this usage information" +} + +compare_and_copy() { + if [ "$#" -ne 2 ]; then + echo "Usage of function: compare_and_copy " + return 1 + fi + + source_file="$1" + destination_file="$2" + + if [ ! -f "$destination_file" ] || ! diff -q "$source_file" "$destination_file" ; then + cp "$source_file" "$destination_file" + echo "File $1 copied to $2" + else + echo "Files $1 and $2 are identical. No copy needed." + fi +} + +copy_files_by_list() { +# Compares and copies listed files from a source to a target directory + if [ ! "$#" -ge 3 ]; then + echo "Usage of function: copy_files_by_list " + echo "Here, file_list is an (expanded) bash array" + echo "Example:" + echo "my_files=(file1 file2)" + echo 'copy_files_by_list /my/source /my/target "${my_files[@]}"' + return 1 + fi + source_dir="$1" + target_dir="$2" + # Need to shift all arguments to the left twice. Then, rebuild the array with the rest of the arguments + shift + shift + file_list=("$@") + + # Create target dir + mkdir -p ${target_dir} + + # Copy from source to target + echo "Copying files: ${file_list[@]}" + echo "From directory: ${source_dir}" + echo "To directory: ${target_dir}" + + for file in ${file_list[@]}; do + compare_and_copy ${source_dir}/${file} ${target_dir}/${file} + done +} + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -p|--prefix) + INSTALL_PREFIX="$2" + shift 2 + ;; + -h|--help) + display_help # Call your function + # no shifting needed here, we're done. + exit 0 + ;; + -*|--*) + echo "Error: Unknown option: $1" >&2 + exit 1 + ;; + *) # No more options + POSITIONAL_ARGS+=("$1") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +TOPDIR=$(dirname $(realpath $0)) + +# Copy for init directory +init_files=( + bash eessi_archdetect.sh eessi_defaults eessi_environment_variables eessi_software_subdir_for_host.py + minimal_eessi_env README.md test.py lmod_eessi_archdetect_wrapper.sh lmod_eessi_archdetect_wrapper_accel.sh + +) +copy_files_by_list ${TOPDIR}/init ${INSTALL_PREFIX}/init "${init_files[@]}" + +# Copy for the init/arch_specs directory +arch_specs_files=( + eessi_arch_arm.spec eessi_arch_ppc.spec eessi_arch_riscv.spec eessi_arch_x86.spec +) +copy_files_by_list ${TOPDIR}/init/arch_specs ${INSTALL_PREFIX}/init/arch_specs "${arch_specs_files[@]}" + +# Copy for init/Magic_castle directory +mc_files=( + bash eessi_python3 +) +copy_files_by_list ${TOPDIR}/init/Magic_Castle ${INSTALL_PREFIX}/init/Magic_Castle "${mc_files[@]}" + +# Copy for init/modules/EESSI directory +mc_files=( + 2023.06.lua +) +copy_files_by_list ${TOPDIR}/init/modules/EESSI ${INSTALL_PREFIX}/init/modules/EESSI "${mc_files[@]}" + +# Copy for init/lmod directory +init_script_files=( + bash zsh ksh fish csh +) +copy_files_by_list ${TOPDIR}/init/lmod ${INSTALL_PREFIX}/init/lmod "${init_script_files[@]}" + +# Copy for the scripts directory +script_files=( + utils.sh +) +copy_files_by_list ${TOPDIR}/scripts ${INSTALL_PREFIX}/scripts "${script_files[@]}" + +# Copy files for the scripts/gpu_support/nvidia directory +nvidia_files=( + install_cuda_and_libraries.sh + install_cuda_host_injections.sh + link_nvidia_host_libraries.sh +) +copy_files_by_list ${TOPDIR}/scripts/gpu_support/nvidia ${INSTALL_PREFIX}/scripts/gpu_support/nvidia "${nvidia_files[@]}" + +# Easystacks to be used to install software in host injections +host_injections_easystacks=( + eessi-2023.06-eb-4.9.4-2023a-CUDA-host-injections.yml + eessi-2023.06-eb-4.9.4-2023b-CUDA-host-injections.yml +) +copy_files_by_list ${TOPDIR}/scripts/gpu_support/nvidia/easystacks \ +${INSTALL_PREFIX}/scripts/gpu_support/nvidia/easystacks "${host_injections_easystacks[@]}" + +# Copy over EasyBuild hooks file used for installations +hook_files=( + eb_hooks.py +) +copy_files_by_list ${TOPDIR} ${INSTALL_PREFIX}/init/easybuild "${hook_files[@]}" diff --git a/install_software_layer.sh b/install_software_layer.sh index bf3006a4a0..8b88e75713 100755 --- a/install_software_layer.sh +++ b/install_software_layer.sh @@ -1,4 +1,4 @@ #!/bin/bash base_dir=$(dirname $(realpath $0)) source ${base_dir}/init/eessi_defaults -./run_in_compat_layer_env.sh ./EESSI-pilot-install-software.sh "$@" +$base_dir/run_in_compat_layer_env.sh $base_dir/EESSI-install-software.sh "$@" diff --git a/licenses/README.md b/licenses/README.md new file mode 100644 index 0000000000..36a7615b21 --- /dev/null +++ b/licenses/README.md @@ -0,0 +1,3 @@ +see https://spdx.org/licenses + +Python function to download SPDX list of licenses is available in `spdx.py` diff --git a/licenses/licenses.json b/licenses/licenses.json new file mode 100644 index 0000000000..8831ed368c --- /dev/null +++ b/licenses/licenses.json @@ -0,0 +1,10 @@ +{ + "EasyBuild": { + "spdx": "GPL-2.0-only", + "license_url": "https://easybuild.io" + }, + "GCCcore": { + "spdx": "GPL-2.0-with-GCC-exception", + "license_url": "https://github.com/gcc-mirror/gcc/blob/master/COPYING" + } +} diff --git a/licenses/spdx.py b/licenses/spdx.py new file mode 100644 index 0000000000..06c3edb4e6 --- /dev/null +++ b/licenses/spdx.py @@ -0,0 +1,100 @@ +import json +import logging +import sys +import urllib.request + +SPDX_LICENSE_LIST_URL = 'https://raw.githubusercontent.com/spdx/license-list-data/main/json/licenses.json' + +LICENSE_URL = 'license_url' +SPDX = 'spdx' + +spdx_license_list = None + +# Configure the logging module +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") + + +def get_spdx_license_list(): + """ + Download JSON file with current list of SPDX licenses, parse it, and return it as a Python dictionary. + """ + global spdx_license_list + + if spdx_license_list is None: + with urllib.request.urlopen(SPDX_LICENSE_LIST_URL) as fp: + spdx_license_list = json.load(fp) + version, release_date = spdx_license_list['licenseListVersion'], spdx_license_list['releaseDate'] + logging.info(f"Downloaded version {version} of SPDX license list (release date: {release_date})") + licenses = spdx_license_list['licenses'] + logging.info(f"Found info on {len(licenses)} licenses!") + + return spdx_license_list + + +def license_info(spdx_id): + """Find license with specified SPDX identifier.""" + + spdx_license_list = get_spdx_license_list() + + licenses = spdx_license_list['licenses'] + for lic in licenses: + if lic['licenseId'] == spdx_id: + return lic + + # if no match is found, return None as result + return None + + +def read_licenses(path): + """ + Read software project to license mapping from specified path + """ + with open(path) as fp: + licenses = json.loads(fp.read()) + + return licenses + + +def check_licenses(licenses): + """ + Check mapping of software licenses: make sure SPDX identifiers are valid. + """ + faulty_licenses = {} + + for software_name in licenses: + spdx_lic_id = licenses[software_name][SPDX] + lic_info = license_info(spdx_lic_id) + if lic_info: + lic_url = licenses[software_name][LICENSE_URL] + logging.info(f"License for software '{software_name}': {lic_info['name']} (see {lic_url})") + else: + logging.warning(f"Found faulty SPDX license ID for {software_name}: {spdx_lic_id}") + faulty_licenses[software_name] = spdx_lic_id + + if faulty_licenses: + logging.warning(f"Found {len(faulty_licenses)} faulty SPDIX license IDs (out of {len(licenses)})!") + result = False + else: + logging.info(f"License check passed for {len(licenses)} licenses!") + result = True + + return result + + +def main(args): + if len(args) == 1: + licenses_path = args[0] + else: + logging.error("Usage: python spdx.py ") + sys.exit(1) + + licenses = read_licenses(licenses_path) + if check_licenses(licenses): + logging.info("All license checks PASSED!") + else: + logging.error("One or more licence checks failed!") + sys.exit(2) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/load_easybuild_module.sh b/load_easybuild_module.sh index 4ff2a3c37c..d1bfd18bb5 100755 --- a/load_easybuild_module.sh +++ b/load_easybuild_module.sh @@ -23,14 +23,14 @@ fi EB_VERSION=${1} # make sure that environment variables that we expect to be set are indeed set -if [ -z "${TMPDIR}" ]; then +if [ -z "${TMPDIR}" ]; then echo "\$TMPDIR is not set" >&2 exit 2 fi # ${EB} is used to specify which 'eb' command should be used; # can potentially be more than just 'eb', for example when using 'eb --optarch=GENERIC' -if [ -z "${EB}" ]; then +if [ -z "${EB}" ]; then echo "\$EB is not set" >&2 exit 2 fi @@ -71,21 +71,28 @@ else check_exit_code $? "${ok_msg}" "${fail_msg}" # maybe the module obtained with --install-latest-eb-release is exactly the EasyBuild version we wanted? + IGNORE_CACHE='' module avail 2>&1 | grep -i easybuild/${EB_VERSION} &> ${ml_av_easybuild_out} if [[ $? -eq 0 ]]; then echo_green ">> Module for EasyBuild v${EB_VERSION} found!" else - eb_ec=EasyBuild-${EB_VERSION}.eb - echo_yellow ">> Still no module for EasyBuild v${EB_VERSION}, trying with easyconfig ${eb_ec}..." - ${EB} --search ${eb_ec} | grep ${eb_ec} > /dev/null + module --ignore_cache avail 2>&1 | grep -i easybuild/${EB_VERSION} &> ${ml_av_easybuild_out} if [[ $? -eq 0 ]]; then - echo "Easyconfig ${eb_ec} found for EasyBuild v${EB_VERSION}, so installing it..." - ok_msg="EasyBuild v${EB_VERSION} installed, alright!" - fail_msg="Installing EasyBuild v${EB_VERSION}, yikes! (output: ${eb_install_out})" - ${EB} EasyBuild-${EB_VERSION}.eb 2>&1 | tee -a ${eb_install_out} - check_exit_code $? "${ok_msg}" "${fail_msg}" + echo_green ">> Module for EasyBuild v${EB_VERSION} found!" + IGNORE_CACHE='--ignore_cache' else - fatal_error "No easyconfig found for EasyBuild v${EB_VERSION}" + eb_ec=EasyBuild-${EB_VERSION}.eb + echo_yellow ">> Still no module for EasyBuild v${EB_VERSION}, trying with easyconfig ${eb_ec}..." + ${EB} --search ${eb_ec} | grep ${eb_ec} > /dev/null + if [[ $? -eq 0 ]]; then + echo "Easyconfig ${eb_ec} found for EasyBuild v${EB_VERSION}, so installing it..." + ok_msg="EasyBuild v${EB_VERSION} installed, alright!" + fail_msg="Installing EasyBuild v${EB_VERSION}, yikes! (output: ${eb_install_out})" + ${EB} EasyBuild-${EB_VERSION}.eb 2>&1 | tee -a ${eb_install_out} + check_exit_code $? "${ok_msg}" "${fail_msg}" + else + fatal_error "No easyconfig found for EasyBuild v${EB_VERSION}" + fi fi fi @@ -103,7 +110,7 @@ else fi echo ">> Loading EasyBuild v${EB_VERSION} module..." -module load EasyBuild/${EB_VERSION} +module ${IGNORE_CACHE} load EasyBuild/${EB_VERSION} eb_show_system_info_out=${TMPDIR}/eb_show_system_info.out ${EB} --show-system-info > ${eb_show_system_info_out} if [[ $? -eq 0 ]]; then diff --git a/load_eessi_extend_module.sh b/load_eessi_extend_module.sh new file mode 100755 index 0000000000..b5ad47de4e --- /dev/null +++ b/load_eessi_extend_module.sh @@ -0,0 +1,123 @@ +# Script to load the environment module for EESSI-extend. +# If that module is not available yet, a specific version will be installed using the latest EasyBuild. +# +# This script must be sourced, since it makes changes in the current environment, like loading an EESSI-extend module. +# +# Assumptions (if one is not satisfied the script prints a message and exits) +# - EESSI version is given as first argument +# - TMPDIR is set +# - EB is set +# - EASYBUILD_INSTALLPATH needs to be set +# - Function check_exit_code is defined; +# scripts/utils.sh in EESSI/software-layer repository defines this function, hence +# scripts/utils.sh shall be sourced before this script is run +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Kenneth Hoste (@boegel, HPC-UGent) +# author: Alan O'Cais (@ocaisa, CECAM) +# author: Thomas Roeblitz (@trz42, University of Bergen) +# +# license: GPLv2 +# +# +set -o pipefail + +# this script is *sourced*, not executed, so can't rely on $0 to determine path to self or script name +# $BASH_SOURCE points to correct path or script name, see also http://mywiki.wooledge.org/BashFAQ/028 +if [ $# -ne 1 ]; then + echo "Usage: source ${BASH_SOURCE} " >&2 + exit 1 +fi + +EESSI_EXTEND_VERSION="${1}-easybuild" + +# make sure that environment variables that we expect to be set are indeed set +if [ -z "${TMPDIR}" ]; then + echo "\$TMPDIR is not set; exiting" >&2 + exit 2 +fi + +# ${EB} is used to specify which 'eb' command should be used; +# can potentially be more than just 'eb', for example when using 'eb --optarch=GENERIC' +if [ -z "${EB}" ]; then + echo "\$EB is not set; exiting" >&2 + exit 2 +fi + +# ${EASYBUILD_INSTALLPATH} points to the installation path and needs to be set +if [ -z "${EASYBUILD_INSTALLPATH}" ]; then + echo "\$EASYBUILD_INSTALLPATH is not set; exiting" >&2 + exit 2 +fi + +# make sure that utility functions are defined (cfr. scripts/utils.sh script in EESSI/software-layer repo) +type check_exit_code +if [ $? -ne 0 ]; then + echo "check_exit_code function is not defined; exiting" >&2 + exit 3 +fi + +echo ">> Checking for EESSI-extend module..." + +ml_av_eessi_extend_out=${TMPDIR}/ml_av_eessi_extend.out +# need to use --ignore_cache to avoid the case that the module was removed (to be +# rebuilt) but it is still in the cache +module --ignore_cache avail 2>&1 | grep -i EESSI-extend/${EESSI_EXTEND_VERSION} &> ${ml_av_eessi_extend_out} + +if [[ $? -eq 0 ]]; then + echo_green ">> Module for EESSI-extend/${EESSI_EXTEND_VERSION} found!" +else + echo_yellow ">> No module yet for EESSI-extend/${EESSI_EXTEND_VERSION}, installing it..." + + EB_TMPDIR=${TMPDIR}/ebtmp + echo ">> Using temporary installation of EasyBuild (in ${EB_TMPDIR})..." + pip_install_out=${TMPDIR}/pip_install.out + pip3 install --prefix ${EB_TMPDIR} easybuild &> ${pip_install_out} + + # keep track of original $PATH and $PYTHONPATH values, so we can restore them + ORIG_PATH=${PATH} + ORIG_PYTHONPATH=${PYTHONPATH} + + # source configure_easybuild to use correct eb settings + ( + export EASYBUILD_PREFIX=${TMPDIR}/easybuild + export EASYBUILD_READ_ONLY_INSTALLDIR=1 + + echo ">> Final installation in ${EASYBUILD_INSTALLPATH}..." + export PATH=${EB_TMPDIR}/bin:${PATH} + export PYTHONPATH=$(ls -d ${EB_TMPDIR}/lib/python*/site-packages):${PYTHONPATH} + # EESSI-extend also needs EasyBuild to be installed as a module, so install the latest release + eb_install_out=${TMPDIR}/eb_install.out + ok_msg="Latest EasyBuild installed, let's go!" + fail_msg="Installing latest EasyBuild failed, that's not good... (output: ${eb_install_out})" + ${EB} --install-latest-eb-release 2>&1 | tee ${eb_install_out} + check_exit_code $? "${ok_msg}" "${fail_msg}" + # Now install EESSI-extend + eessi_install_out=${TMPDIR}/eessi_install.out + ok_msg="EESSI-extend/${EESSI_EXTEND_VERSION} installed, let's go!" + fail_msg="Installing EESSI-extend/${EESSI_EXTEND_VERSION} failed, that's not good... (output: ${eessi_install_out})" + # while always adding --try-amend=keep... may do no harm, we could make + # an attempt to figure out if it is needed, e.g., when we are rebuilding + ${EB} "EESSI-extend-easybuild.eb" --try-amend=keeppreviousinstall=True 2>&1 | tee ${eessi_install_out} + check_exit_code $? "${ok_msg}" "${fail_msg}" + ) + + # restore origin $PATH and $PYTHONPATH values, and clean up environment variables that are no longer needed + export PATH=${ORIG_PATH} + export PYTHONPATH=${ORIG_PYTHONPATH} + unset EB_TMPDIR ORIG_PATH ORIG_PYTHONPATH + + module --ignore_cache avail EESSI-extend/${EESSI_EXTEND_VERSION} &> ${ml_av_eessi_extend_out} + if [[ $? -eq 0 ]]; then + echo_green ">> EESSI-extend/${EESSI_EXTEND_VERSION} module installed!" + else + fatal_error "EESSI-extend/${EESSI_EXTEND_VERSION} module failed to install?! (output of 'pip install' in ${pip_install_out}, output of 'eb' in ${eb_install_out}, output of 'module avail EESSI-extend' in ${ml_av_eessi_extend_out})" + fi +fi + +echo ">> Loading EESSI-extend/${EESSI_EXTEND_VERSION} module..." +module --ignore_cache load EESSI-extend/${EESSI_EXTEND_VERSION} + +unset EESSI_EXTEND_VERSION diff --git a/run_in_compat_layer_env.sh b/run_in_compat_layer_env.sh index c70077bf15..b4299c7a0d 100755 --- a/run_in_compat_layer_env.sh +++ b/run_in_compat_layer_env.sh @@ -3,25 +3,46 @@ base_dir=$(dirname $(realpath $0)) source ${base_dir}/init/eessi_defaults -if [ -z $EESSI_PILOT_VERSION ]; then - echo "ERROR: \$EESSI_PILOT_VERSION must be set!" >&2 +if [ -z $EESSI_VERSION ]; then + echo "ERROR: \$EESSI_VERSION must be set!" >&2 exit 1 fi -EESSI_COMPAT_LAYER_DIR="${EESSI_CVMFS_REPO}/versions/${EESSI_PILOT_VERSION}/compat/linux/$(uname -m)" + +echo "EESSI_COMPAT_LAYER_DIR_OVERRIDE: ${EESSI_COMPAT_LAYER_DIR_OVERRIDE}" + +if [ ! -z ${EESSI_COMPAT_LAYER_DIR_OVERRIDE} ]; then + echo "EESSI_COMPAT_LAYER_DIR_OVERRIDE found. Setting EESSI_COMPAT_LAYER_DIR to ${EESSI_COMPAT_LAYER_DIR_OVERRIDE}" + EESSI_COMPAT_LAYER_DIR=${EESSI_COMPAT_LAYER_DIR_OVERRIDE} +else + EESSI_COMPAT_LAYER_DIR="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)" +fi + if [ ! -d ${EESSI_COMPAT_LAYER_DIR} ]; then echo "ERROR: ${EESSI_COMPAT_LAYER_DIR} does not exist!" >&2 exit 1 fi INPUT=$(echo "$@") +if [ ! -z ${SLURM_JOB_ID} ]; then + INPUT="export SLURM_JOB_ID=${SLURM_JOB_ID}; ${INPUT}" +fi if [ ! -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then INPUT="export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${EESSI_SOFTWARE_SUBDIR_OVERRIDE}; ${INPUT}" fi +if [ ! -z ${EESSI_ACCELERATOR_TARGET} ]; then + INPUT="export EESSI_ACCELERATOR_TARGET=${EESSI_ACCELERATOR_TARGET}; ${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}" +if [ ! -z ${EESSI_VERSION_OVERRIDE} ]; then + INPUT="export EESSI_VERSION_OVERRIDE=${EESSI_VERSION_OVERRIDE}; ${INPUT}" +fi +if [ ! -z ${EESSI_COMPAT_LAYER_DIR} ]; then + INPUT="export EESSI_COMPAT_LAYER_DIR=${EESSI_COMPAT_LAYER_DIR}; ${INPUT}" +fi +if [ ! -z ${EESSI_OVERRIDE_GPU_CHECK} ]; then + INPUT="export EESSI_OVERRIDE_GPU_CHECK=${EESSI_OVERRIDE_GPU_CHECK}; ${INPUT}" fi if [ ! -z ${http_proxy} ]; then INPUT="export http_proxy=${http_proxy}; ${INPUT}" @@ -29,6 +50,9 @@ fi if [ ! -z ${https_proxy} ]; then INPUT="export https_proxy=${https_proxy}; ${INPUT}" fi +if [ ! -z ${EASYBUILD_ROBOT_PATHS} ]; then + INPUT="export EASYBUILD_ROBOT_PATHS=${EASYBUILD_ROBOT_PATHS}; ${INPUT}" +fi -echo "Running '${INPUT}' in EESSI (${EESSI_CVMFS_REPO}) ${EESSI_PILOT_VERSION} compatibility layer environment..." +echo "Running '${INPUT}' in EESSI (${EESSI_CVMFS_REPO}) ${EESSI_VERSION} compatibility layer environment..." ${EESSI_COMPAT_LAYER_DIR}/startprefix <<< "${INPUT}" diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 0000000000..f6264c3cc8 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# This script gets invoked by the bot/test.sh script to run within the EESSI container +# Thus, this script defines all of the steps that should run for the tests. +# Note that, unless we have good reason, we don't run test steps in the prefix environment: +# users also typically don't run in the prefix environment, and we want to check if the +# software works well in that specific setup. +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Caspar van Leeuwen (@casparvl) +# +# license: GPLv2 +# + +base_dir=$(dirname $(realpath $0)) +source ${base_dir}/init/eessi_defaults + +# Make sure we clone the latest version. This assumes versions are of the format "v1.2.3", then picks the latest +# then checks it out +TEST_CLONE="git clone https://github.com/EESSI/test-suite EESSI-test-suite && cd EESSI-test-suite" +LATEST_VERSION="VERSION=\$(git tag | grep '^v[0-9]\+\.[0-9]\+\.[0-9]\+$' | sort -t. -k 1,1n -k 2,2n -k 3,3n | tail -1)" +CHECKOUT_LATEST="git checkout \${VERSION}" + +# Git clone has to be run in compat layer, to make the git command available +./run_in_compat_layer_env.sh "${TEST_CLONE} && ${LATEST_VERSION} && ${CHECKOUT_LATEST}" + +# Run the test suite +./test_suite.sh "$@" diff --git a/scripts/gpu_support/nvidia/easystacks/eessi-2023.06-eb-4.9.4-2023a-CUDA-host-injections.yml b/scripts/gpu_support/nvidia/easystacks/eessi-2023.06-eb-4.9.4-2023a-CUDA-host-injections.yml new file mode 100644 index 0000000000..83e68077a2 --- /dev/null +++ b/scripts/gpu_support/nvidia/easystacks/eessi-2023.06-eb-4.9.4-2023a-CUDA-host-injections.yml @@ -0,0 +1,9 @@ +# This EasyStack provides a list of all the EasyConfigs that should be installed in host_injections +# for nvidia GPU support, because they cannot (fully) be shipped as part of EESSI due to license constraints +easyconfigs: + - CUDA-12.1.1.eb + - cuDNN-8.9.2.26-CUDA-12.1.1.eb: + options: + # needed to enforce acceptance of EULA in cuDNN easyblock, + # see https://github.com/easybuilders/easybuild-easyblocks/pull/3473 + include-easyblocks-from-commit: 11afb88ec55e0ca431cbe823696aa43e2a9bfca8 diff --git a/scripts/gpu_support/nvidia/easystacks/eessi-2023.06-eb-4.9.4-2023b-CUDA-host-injections.yml b/scripts/gpu_support/nvidia/easystacks/eessi-2023.06-eb-4.9.4-2023b-CUDA-host-injections.yml new file mode 100644 index 0000000000..5cfec813f6 --- /dev/null +++ b/scripts/gpu_support/nvidia/easystacks/eessi-2023.06-eb-4.9.4-2023b-CUDA-host-injections.yml @@ -0,0 +1,4 @@ +# This EasyStack provides a list of all the EasyConfigs that should be installed in host_injections +# for nvidia GPU support, because they cannot (fully) be shipped as part of EESSI due to license constraints +easyconfigs: + - CUDA-12.4.0.eb diff --git a/scripts/gpu_support/nvidia/install_cuda_and_libraries.sh b/scripts/gpu_support/nvidia/install_cuda_and_libraries.sh new file mode 100755 index 0000000000..741ead0559 --- /dev/null +++ b/scripts/gpu_support/nvidia/install_cuda_and_libraries.sh @@ -0,0 +1,265 @@ +#!/usr/bin/env bash + +# This script can be used to install CUDA and other libraries by NVIDIA under +# the `.../host_injections` directory. +# +# This provides the parts of the CUDA installation and other libriaries that +# cannot be redistributed as part of EESSI due to license limitations. While +# GPU-based software from EESSI will _run_ without these, installation of +# additional software that builds upon CUDA or other libraries requires that +# these installation are present under `host_injections`. +# +# The `host_injections` directory is a variant symlink that by default points to +# `/opt/eessi`, unless otherwise defined in the local CVMFS configuration (see +# https://cvmfs.readthedocs.io/en/stable/cpt-repo.html#variant-symlinks). For the +# installation to be successful, this directory needs to be writeable by the user +# executing this script. + +# Initialise our bash functions +TOPDIR=$(dirname $(realpath $BASH_SOURCE)) +source "$TOPDIR"/../../utils.sh + +# Function to display help message +show_help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --accept-cuda-eula You _must_ accept the CUDA EULA to install" + echo " CUDA, see the EULA at" + echo " https://docs.nvidia.com/cuda/eula/index.html" + echo " --accept-cudnn-eula You _must_ accept the cuDNN EULA to install" + echo " cuDNN, see the EULA at" + echo " https://docs.nvidia.com/deeplearning/cudnn/latest/reference/eula.html" + echo " -t, --temp-dir /path/to/tmpdir Specify a location to use for temporary" + echo " storage during the installation of CUDA" + echo " and/or other libraries (must have" + echo " several GB available; depends on the number of installations)" +} + +# Initialize variables +cuda_eula_accepted=0 +cudnn_eula_accepted=0 +EASYSTACK_FILE= +TEMP_DIR= + +# Parse command-line options +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + show_help + exit 0 + ;; + --accept-cuda-eula) + cuda_eula_accepted=1 + shift 1 + ;; + --accept-cudnn-eula) + cudnn_eula_accepted=1 + shift 1 + ;; + -t|--temp-dir) + if [ -n "$2" ]; then + TEMP_DIR="$2" + shift 2 + else + echo "Error: Argument required for $1" + show_help + exit 1 + fi + ;; + *) + show_help + fatal_error "Error: Unknown option: $1" + ;; + esac +done + +# Make sure EESSI is initialised +check_eessi_initialised + +# we need a directory we can use for temporary storage +if [[ -z "${TEMP_DIR}" ]]; then + tmpdir=$(mktemp -d) +else + mkdir -p ${TEMP_DIR} + tmpdir=$(mktemp -d --tmpdir=${TEMP_DIR} cuda_n_co.XXX) + if [[ ! -d "$tmpdir" ]] ; then + fatal_error "Could not create directory ${tmpdir}" + fi +fi +echo "Created temporary directory '${tmpdir}'" + +# Store MODULEPATH so it can be restored at the end of each loop iteration +SAVE_MODULEPATH=${MODULEPATH} + +for EASYSTACK_FILE in ${TOPDIR}/easystacks/eessi-*CUDA*.yml; do + echo -e "Processing easystack file ${easystack_file}...\n\n" + + # determine version of EasyBuild module to load based on EasyBuild version included in name of easystack file + eb_version=$(echo ${EASYSTACK_FILE} | sed 's/.*eb-\([0-9.]*\).*/\1/g') + + # Load EasyBuild version for this easystack file _before_ loading EESSI-extend + module_avail_out=${tmpdir}/ml.out + module avail 2>&1 | grep EasyBuild/${eb_version} &> ${module_avail_out} + if [[ $? -eq 0 ]]; then + echo_green ">> Found an EasyBuild/${eb_version} module" + else + echo_yellow ">> No EasyBuild/${eb_version} module found: skipping step to install easystack file ${easystack_file} (see output in ${module_avail_out})" + continue + fi + module load EasyBuild/${eb_version} + + # Make sure EESSI-extend does a site install here + # We need to reload it with the current environment variables set + unset EESSI_CVMFS_INSTALL + unset EESSI_PROJECT_INSTALL + unset EESSI_USER_INSTALL + export EESSI_SITE_INSTALL=1 + module unload EESSI-extend + ml_av_eessi_extend_out=${tmpdir}/ml_av_eessi_extend.out + # need to use --ignore_cache to avoid the case that the module was removed (to be + # rebuilt) but it is still in the cache and the rebuild failed + EESSI_EXTEND_VERSION=${EESSI_VERSION}-easybuild + module --ignore_cache avail 2>&1 | grep -i EESSI-extend/${EESSI_EXTEND_VERSION} &> ${ml_av_eessi_extend_out} + if [[ $? -eq 0 ]]; then + echo_green ">> Module for EESSI-extend/${EESSI_EXTEND_VERSION} found!" + else + error="\nNo module for EESSI-extend/${EESSI_EXTEND_VERSION} found\nwhile EESSI has been initialised to use software under ${EESSI_SOFTWARE_PATH}\n" + fatal_error "${error}" + fi + module --ignore_cache load EESSI-extend/${EESSI_EXTEND_VERSION} + unset EESSI_EXTEND_VERSION + + # Install modules in hidden .modules dir to keep track of what was installed before + # (this action is temporary, and we do not call Lmod again within the current shell context, but in EasyBuild + # subshells, so loaded modules are not automatically unloaded) + MODULEPATH=${EESSI_SITE_SOFTWARE_PATH}/.modules/all + echo "set MODULEPATH=${MODULEPATH}" + + # We don't want hooks used in this install, we need vanilla installations + touch "${tmpdir}"/none.py + export EASYBUILD_HOOKS="${tmpdir}/none.py" + + # show EasyBuild configuration + echo "Show EasyBuild configuration" + eb --show-config + + # do a 'eb --dry-run-short' with the EASYSTACK_FILE and determine list of packages + # to be installed + echo ">> Determining if packages specified in ${EASYSTACK_FILE} are missing under ${EESSI_SITE_SOFTWARE_PATH}" + eb_dry_run_short_out=${tmpdir}/eb_dry_run_short.out + eb --dry-run-short --easystack ${EASYSTACK_FILE} 2>&1 | tee ${eb_dry_run_short_out} + ret=$? + + # Check if CUDA shall be installed + cuda_install_needed=0 + cat ${eb_dry_run_short_out} | grep "^ \* \[[ ]\]" | grep "module: CUDA/" > /dev/null + ret=$? + if [ "${ret}" -eq 0 ]; then + cuda_install_needed=1 + fi + + # Make sure the CUDA EULA is accepted if it shall be installed + if [ "${cuda_install_needed}" -eq 1 ] && [ "${cuda_eula_accepted}" -ne 1 ]; then + show_help + error="\nCUDA shall be installed. However, the CUDA EULA has not been accepted\nYou _must_ accept the CUDA EULA via the appropriate command line option.\n" + fatal_error "${error}" + fi + + # Check if cdDNN shall be installed + cudnn_install_needed=0 + cat ${eb_dry_run_short_out} | grep "^ \* \[[ ]\]" | grep "module: cuDNN/" > /dev/null + ret=$? + if [ "${ret}" -eq 0 ]; then + cudnn_install_needed=1 + fi + + # Make sure the cuDNN EULA is accepted if it shall be installed + if [ "${cudnn_install_needed}" -eq 1 ] && [ "${cudnn_eula_accepted}" -ne 1 ]; then + show_help + error="\ncuDNN shall be installed. However, the cuDNN EULA has not been accepted\nYou _must_ accept the cuDNN EULA via the appropriate command line option.\n" + fatal_error "${error}" + fi + + # determine the number of packages to be installed (assume 5 GB + num_packages * + # 3GB space needed). Both CUDA and cuDNN are about this size + number_of_packages=$(cat ${eb_dry_run_short_out} | grep "^ \* \[[ ]\]" | sed -e 's/^.*module: //' | sort -u | wc -l) + echo "number of packages to be (re-)installed: '${number_of_packages}'" + base_storage_space=$((5000000 + ${number_of_packages} * 3000000)) + + required_space_in_tmpdir=${base_storage_space} + # Let's see if we have sources and build locations defined if not, we use the temporary space + if [[ -z "${EASYBUILD_BUILDPATH}" ]]; then + export EASYBUILD_BUILDPATH=${tmpdir}/build + required_space_in_tmpdir=$((required_space_in_tmpdir + ${base_storage_space})) + fi + if [[ -z "${EASYBUILD_SOURCEPATH}" ]]; then + export EASYBUILD_SOURCEPATH=${tmpdir}/sources + required_space_in_tmpdir=$((required_space_in_tmpdir + ${base_storage_space})) + fi + + # The install is pretty fat, you need lots of space for download/unpack/install + # (~3*${base_storage_space}*1000 Bytes), + # need to do a space check before we proceed + avail_space=$(df --output=avail "${EESSI_SITE_SOFTWARE_PATH}"/ | tail -n 1 | awk '{print $1}') + min_disk_storage=$((3 * ${base_storage_space})) + if (( avail_space < ${min_disk_storage} )); then + fatal_error "Need at least $(echo "${min_disk_storage} / 1000000" | bc) GB disk space to install CUDA and other libraries under ${EESSI_SITE_SOFTWARE_PATH}, exiting now..." + fi + avail_space=$(df --output=avail "${tmpdir}"/ | tail -n 1 | awk '{print $1}') + if (( avail_space < required_space_in_tmpdir )); then + error="Need at least $(echo "${required_space_in_tmpdir} / 1000000" | bc) temporary disk space under ${tmpdir}.\n" + error="${error}Set the environment variable TEMP_DIR to a location with adequate space to pass this check." + error="${error}You can alternatively set EASYBUILD_BUILDPATH and/or EASYBUILD_SOURCEPATH" + error="${error}to reduce this requirement. Exiting now..." + fatal_error "${error}" + fi + + # Brief explanation of parameters: + # - prefix: using $tmpdir as default base directory for several EB settings + # - installpath-modules: We install the module in a hidden .modules, so that next time this script + # is run, it is not reinstalled. + # - ${accept_eula_opt}: We only set the --accept-eula-for=CUDA option if CUDA will be installed and if + # this script was called with the argument --accept-cuda-eula. + # - hooks: We don't want hooks used in this install, we need vanilla + # installations of CUDA and/or other libraries + # - easystack: Path to easystack file that defines which packages shall be + # installed + accept_eula_opt= + if [[ ${cuda_eula_accepted} -eq 1 ]]; then + accept_eula_opt="CUDA" + fi + if [[ ${cudnn_eula_accepted} -eq 1 ]]; then + if [[ -z ${accept_eula_opt} ]]; then + accept_eula_opt="cuDNN" + else + accept_eula_opt="${accept_eula_opt},cuDNN" + fi + fi + touch "$tmpdir"/none.py + eb_args="--prefix=$tmpdir" + eb_args="$eb_args --installpath-modules=${EASYBUILD_INSTALLPATH}/.modules" + eb_args="$eb_args --hooks="$tmpdir"/none.py" + eb_args="$eb_args --easystack ${EASYSTACK_FILE}" + if [[ ! -z ${accept_eula_opt} ]]; then + eb_args="$eb_args --accept-eula-for=$accept_eula_opt" + fi + echo "Running eb $eb_args" + eb $eb_args + ret=$? + if [ $ret -ne 0 ]; then + eb_last_log=$(unset EB_VERBOSE; eb --last-log) + cp -a ${eb_last_log} . + fatal_error "some installation failed, please check EasyBuild logs ${PWD}/$(basename ${eb_last_log})..." + else + echo_green "all installations at ${EESSI_SITE_SOFTWARE_PATH}/software/... succeeded!" + fi + + # clean up tmpdir content + rm -rf "${tmpdir}"/* + + # Restore MODULEPATH for next loop iteration + MODULEPATH=${SAVE_MODULEPATH} +done +# Remove the temporary directory +rm -rf "${tmpdir}" diff --git a/scripts/gpu_support/nvidia/install_cuda_host_injections.sh b/scripts/gpu_support/nvidia/install_cuda_host_injections.sh new file mode 100755 index 0000000000..3842aff307 --- /dev/null +++ b/scripts/gpu_support/nvidia/install_cuda_host_injections.sh @@ -0,0 +1,211 @@ +#!/usr/bin/env bash + +# This script can be used to install CUDA under the `.../host_injections` directory. +# This provides the parts of the CUDA installation that cannot be redistributed as +# part of EESSI due to license limitations. While GPU-based software from EESSI will +# _run_ without these, installation of additional CUDA software requires the CUDA +# installation(s) under `host_injections` to be present. +# +# The `host_injections` directory is a variant symlink that by default points to +# `/opt/eessi`, unless otherwise defined in the local CVMFS configuration (see +# https://cvmfs.readthedocs.io/en/stable/cpt-repo.html#variant-symlinks). For the +# installation to be successful, this directory needs to be writeable by the user +# executing this script. + +# Initialise our bash functions +TOPDIR=$(dirname $(realpath $BASH_SOURCE)) +source "$TOPDIR"/../../utils.sh + +# Function to display help message +show_help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --accept-cuda-eula You _must_ accept the CUDA EULA to install" + echo " CUDA, see the EULA at" + echo " https://docs.nvidia.com/cuda/eula/index.html" + echo " -c, --cuda-version CUDA_VERSION Specify a version o CUDA to install (must" + echo " have a corresponding easyconfig in the" + echo " EasyBuild release)" + echo " -t, --temp-dir /path/to/tmpdir Specify a location to use for temporary" + echo " storage during the CUDA install" + echo " (must have >10GB available)" +} + +# Initialize variables +install_cuda_version="" +eula_accepted=0 + +# Parse command-line options +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + show_help + exit 0 + ;; + -c|--cuda-version) + if [ -n "$2" ]; then + install_cuda_version="$2" + shift 2 + else + echo "Error: Argument required for $1" + show_help + exit 1 + fi + ;; + --accept-cuda-eula) + eula_accepted=1 + shift 1 + ;; + -t|--temp-dir) + if [ -n "$2" ]; then + CUDA_TEMP_DIR="$2" + shift 2 + else + echo "Error: Argument required for $1" + show_help + exit 1 + fi + ;; + *) + show_help + fatal_error "Error: Unknown option: $1" + ;; + esac +done + +# Make sure EESSI is initialised +check_eessi_initialised + +# Make sure the CUDA version supplied is a semantic version +is_semantic_version() { + local version=$1 + local regex='^[0-9]+\.[0-9]+\.[0-9]+$' + + if [[ $version =~ $regex ]]; then + return 0 # Return success (0) if it's a semantic version + else + return 1 # Return failure (1) if it's not a semantic version + fi +} +if ! is_semantic_version "$install_cuda_version"; then + show_help + error="\nYou must provide a semantic version for CUDA (e.g., 12.1.1) via the appropriate\n" + error="${error}command line option. This script is intended for use with EESSI so the 'correct'\n" + error="${error}version to provide is probably one of those available under\n" + error="${error}$EESSI_SOFTWARE_PATH/software/CUDA\n" + fatal_error "${error}" +fi + +# Make sure they have accepted the CUDA EULA +if [ "$eula_accepted" -ne 1 ]; then + show_help + error="\nYou _must_ accept the CUDA EULA via the appropriate command line option.\n" + fatal_error "${error}" +fi + +# As an installation location just use $EESSI_SOFTWARE_PATH but replacing `versions` with `host_injections` +# (CUDA is a binary installation so no need to worry too much about the EasyBuild setup) +cuda_install_parent=${EESSI_SOFTWARE_PATH/versions/host_injections} + +# Only install CUDA if specified version is not found. +# (existence of easybuild subdir implies a successful install) +if [ -d "${cuda_install_parent}"/software/CUDA/"${install_cuda_version}"/easybuild ]; then + echo_green "CUDA software found! No need to install CUDA again." +else + # We need to be able write to the installation space so let's make sure we can + if ! create_directory_structure "${cuda_install_parent}"/software/CUDA ; then + fatal_error "No write permissions to directory ${cuda_install_parent}/software/CUDA" + fi + + # we need a directory we can use for temporary storage + if [[ -z "${CUDA_TEMP_DIR}" ]]; then + tmpdir=$(mktemp -d) + else + tmpdir="${CUDA_TEMP_DIR}"/temp + if ! mkdir -p "$tmpdir" ; then + fatal_error "Could not create directory ${tmpdir}" + fi + fi + + required_space_in_tmpdir=50000 + # Let's see if we have sources and build locations defined if not, we use the temporary space + if [[ -z "${EASYBUILD_BUILDPATH}" ]]; then + export EASYBUILD_BUILDPATH=${tmpdir}/build + required_space_in_tmpdir=$((required_space_in_tmpdir + 5000000)) + fi + if [[ -z "${EASYBUILD_SOURCEPATH}" ]]; then + export EASYBUILD_SOURCEPATH=${tmpdir}/sources + required_space_in_tmpdir=$((required_space_in_tmpdir + 5000000)) + fi + + # The install is pretty fat, you need lots of space for download/unpack/install (~3*5GB), + # need to do a space check before we proceed + avail_space=$(df --output=avail "${cuda_install_parent}"/ | tail -n 1 | awk '{print $1}') + if (( avail_space < 5000000 )); then + fatal_error "Need at least 5GB disk space to install CUDA under ${cuda_install_parent}, exiting now..." + fi + avail_space=$(df --output=avail "${tmpdir}"/ | tail -n 1 | awk '{print $1}') + if (( avail_space < required_space_in_tmpdir )); then + error="Need at least ${required_space_in_tmpdir} disk space under ${tmpdir}.\n" + error="${error}Set the environment variable CUDA_TEMP_DIR to a location with adequate space to pass this check." + error="${error}You can alternatively set EASYBUILD_BUILDPATH and/or EASYBUILD_SOURCEPATH " + error="${error}to reduce this requirement. Exiting now..." + fatal_error "${error}" + fi + + if ! command -v "eb" &>/dev/null; then + echo_yellow "Attempting to load an EasyBuild module to do actual install" + module load EasyBuild + # There are some scenarios where this may fail + if [ $? -ne 0 ]; then + error="'eb' command not found in your environment and\n" + error="${error} module load EasyBuild\n" + error="${error}failed for some reason.\n" + error="${error}Please re-run this script with the 'eb' command available." + fatal_error "${error}" + fi + fi + + cuda_easyconfig="CUDA-${install_cuda_version}.eb" + + # Check the easyconfig file is available in the release + # (eb search always returns 0, so we need a grep to ensure a usable exit code) + eb --search ^${cuda_easyconfig}|grep CUDA > /dev/null 2>&1 + # Check the exit code + if [ $? -ne 0 ]; then + eb_version=$(eb --version) + available_cuda_easyconfigs=$(eb --search "^CUDA-.*.eb"|grep CUDA) + + error="The easyconfig ${cuda_easyconfig} was not found in EasyBuild version:\n" + error="${error} ${eb_version}\n" + error="${error}You either need to give a different version of CUDA to install _or_ \n" + error="${error}use a different version of EasyBuild for the installation.\n" + error="${error}\nThe versions of CUDA available with the current eb command are:\n" + error="${error}${available_cuda_easyconfigs}" + fatal_error "${error}" + fi + + # We need the --rebuild option, as the CUDA module may or may not be on the + # `MODULEPATH` yet. Even if it is, we still want to redo this installation + # since it will provide the symlinked targets for the parts of the CUDA + # installation in the `.../versions/...` prefix + # We install the module in our `tmpdir` since we do not need the modulefile, + # we only care about providing the targets for the symlinks. + extra_args="--rebuild --installpath-modules=${tmpdir}" + + # We don't want hooks used in this install, we need a vanilla CUDA installation + touch "$tmpdir"/none.py + # shellcheck disable=SC2086 # Intended splitting of extra_args + eb --prefix="$tmpdir" ${extra_args} --accept-eula-for=CUDA --hooks="$tmpdir"/none.py --installpath="${cuda_install_parent}"/ "${cuda_easyconfig}" + ret=$? + if [ $ret -ne 0 ]; then + eb_last_log=$(unset EB_VERBOSE; eb --last-log) + cp -a ${eb_last_log} . + fatal_error "CUDA installation failed, please check EasyBuild logs $(basename ${eb_last_log})..." + else + echo_green "CUDA installation at ${cuda_install_parent}/software/CUDA/${install_cuda_version} succeeded!" + fi + # clean up tmpdir + rm -rf "${tmpdir}" +fi diff --git a/scripts/gpu_support/nvidia/link_nvidia_host_libraries.sh b/scripts/gpu_support/nvidia/link_nvidia_host_libraries.sh new file mode 100755 index 0000000000..2218a92116 --- /dev/null +++ b/scripts/gpu_support/nvidia/link_nvidia_host_libraries.sh @@ -0,0 +1,416 @@ +#!/bin/bash + +# This script links host libraries related to GPU drivers to a location where +# they can be found by the EESSI linker (or sets LD_PRELOAD as an +# alternative.) + +# Initialise our bash functions +TOPDIR=$(dirname "$(realpath "$BASH_SOURCE")") +source "$TOPDIR"/../../utils.sh + +# Define a function to find the host ld_config +get_host_ldconfig() { + local command_name="ldconfig" # Set command to find + local exclude_prefix="/cvmfs" # Set excluded prefix (paths to ignore) + local found_paths=() # Initialize an array to store found paths + + # Always attempt to use /sbin/ldconfig + if [ -x "/sbin/${command_name}" ]; then + found_paths+=("/sbin/${command_name}") + fi + + # Split the $PATH and iterate over each directory + IFS=':' read -ra path_dirs <<< "$PATH" + for dir in "${path_dirs[@]}"; do + if [ "$dir" = "/sbin" ]; then + continue # Skip /sbin since it's already checked + fi + + # Check if directory does not start with the exclude prefix + if [[ ! "$dir" =~ ^$exclude_prefix ]]; then + if [ -x "${dir}/${command_name}" ]; then + found_paths+=("${dir}/${command_name}") + fi + fi + done + + # Check if any paths were found + if [ ${#found_paths[@]} -gt 0 ]; then + # echo the first version we found and return success + echo "${found_paths[0]}" + return 0 + else + fatal_error "$command_name not found in PATH or only found in paths starting with $exclude_prefix." + fi +} + +get_nvlib_list() { + local nvliblist_url="https://raw.githubusercontent.com/apptainer/apptainer/main/etc/nvliblist.conf" + local default_nvlib_list=( + "libcuda.so" + "libcudadebugger.so" + "libEGL_installertest.so" + "libEGL_nvidia.so" + "libEGL.so" + "libGLdispatch.so" + "libGLESv1_CM_nvidia.so" + "libGLESv1_CM.so" + "libGLESv2_nvidia.so" + "libGLESv2.so" + "libGL.so" + "libGLX_installertest.so" + "libGLX_nvidia.so" + "libglx.so" + "libGLX.so" + "libnvcuvid.so" + "libnvidia-cbl.so" + "libnvidia-cfg.so" + "libnvidia-compiler.so" + "libnvidia-eglcore.so" + "libnvidia-egl-wayland.so" + "libnvidia-encode.so" + "libnvidia-fatbinaryloader.so" + "libnvidia-fbc.so" + "libnvidia-glcore.so" + "libnvidia-glsi.so" + "libnvidia-glvkspirv.so" + "libnvidia-gpucomp.so" + "libnvidia-gtk2.so" + "libnvidia-gtk3.so" + "libnvidia-ifr.so" + "libnvidia-ml.so" + "libnvidia-nvvm.so" + "libnvidia-opencl.so" + "libnvidia-opticalflow.so" + "libnvidia-ptxjitcompiler.so" + "libnvidia-rtcore.so" + "libnvidia-tls.so" + "libnvidia-wfb.so" + "libnvoptix.so" + "libOpenCL.so" + "libOpenGL.so" + "libvdpau_nvidia.so" + "nvidia_drv.so" + "tls_test_.so" + ) + + # Check if the function was called with the "default" argument + if [[ "$1" == "default" ]]; then + printf "%s\n" "${default_nvlib_list[@]}" + return 1 + fi + + # Try to download the nvliblist.conf file with curl + nvliblist_content=$(curl --silent "$nvliblist_url") + + # Check if curl failed (i.e., the content is empty) + if [ -z "$nvliblist_content" ]; then + # Failed to download nvliblist.conf, using default list instead + printf "%s\n" "${default_nvlib_list[@]}" + return 1 + fi + + # If curl succeeded, filter and return the libraries from the downloaded content + echo "$nvliblist_content" | grep '.so$' + + return 0 +} + +# Function to check if umask allows global read +check_global_read() { + # Get the current umask value + local current_umask=$(umask) + + # Convert umask to decimal to analyze + local umask_octal=$(printf '%03o\n' "$current_umask") + + # Check if umask allows global read + if [ "$umask_octal" -gt 022 ]; then + fatal_error "The current umask ($current_umask) does not allow global read permissions, you'll want everyone to be able to read the created directory." + fi +} + +# Make sure EESSI is initialised (doesn't matter what version) +check_eessi_initialised + +# Check for required commands +command -v nvidia-smi >/dev/null 2>&1 || { echo_yellow "nvidia-smi not found, this script won't do anything useful"; return 1; } + +# Variables +LD_PRELOAD_MODE=0 +LIBS_LIST="" + +# Parse command-line options +while [[ "$#" -gt 0 ]]; do + case "$1" in + --ld-preload) LD_PRELOAD_MODE=1 ;; # Enable LD_PRELOAD mode + --no-download) LIBS_LIST="default" ;; # Download latest list of CUDA libraries + *) fatal_error "Unknown option: $1";; + esac + shift +done + +# Gather information about NVIDIA drivers (even if we are inside a Gentoo Prefix in a container) +export LD_LIBRARY_PATH="/.singularity.d/libs:${LD_LIBRARY_PATH}" + +# Check for NVIDIA GPUs via nvidia-smi command +nvidia_smi=$(command -v nvidia-smi) +if [[ $? -eq 0 ]]; then + nvidia_smi_out=$(mktemp -p /tmp nvidia_smi_out.XXXXX) + nvidia-smi --query-gpu=gpu_name,count,driver_version,compute_cap --format=csv,noheader 2>&1 > $nvidia_smi_out + if [[ $? -eq 0 ]]; then + nvidia_smi_info=$(head -1 "${nvidia_smi_out}") + host_cuda_version=$(echo "${nvidia_smi_info}" | sed 's/, /,/g' | cut -f4 -d,) + host_driver_version=$(echo "${nvidia_smi_info}" | sed 's/, /,/g' | cut -f3 -d,) + echo_green "Found host CUDA version ${host_cuda_version}" + echo_green "Found NVIDIA GPU driver version ${host_driver_version}" + rm -f $nvidia_smi_out + else + fatal_error "nvidia-smi command failed, see output in $nvidia_smi_out" + fi +else + fatal_error "nvidia-smi command not found" + exit 2 +fi + +# Gather any CUDA related driver libraries from the host +# - First let's see what driver libraries are there +# - then extract the ones we need for CUDA + +# Find the host ldconfig +host_ldconfig=$(get_host_ldconfig) +# Gather libraries on the host (_must_ be host ldconfig) +host_libraries=$("${host_ldconfig}" -p | awk '{print $NF}') +singularity_libs=$(ls /.singularity.d/libs/* 2>/dev/null) + +# Now gather the list of possible CUDA libraries and make them into an array +cuda_candidate_libraries=($(get_nvlib_list "${LIBS_LIST}")) +# Check if the function returned an error (e.g., curl failed) +if [ $? -ne 0 ]; then + echo "Using default list of libraries" +else + echo "Using downloaded list of libraries" +fi + +# Filter the host libraries to find the CUDA libaries locations +# Initialize an array to hold the matched libraries +matched_libraries=() + +# Process each library and check for matches in libs.txt +for library in "${cuda_candidate_libraries[@]}"; do + # Search for the library in libs.txt and add it to the matched_libraries array + matched=$(echo "$host_libraries $singularity_libs" | grep "$library") + if [ -n "$matched" ]; then + matched_libraries+=( $matched ) # Add matched library to the array + fi +done + +# Output the number of matched libraries +echo "Matched ${#matched_libraries[@]} CUDA Libraries" + +# LD_PRELOAD Mode +if [ "$LD_PRELOAD_MODE" -eq 1 ]; then + echo + echo_yellow "When attempting to use LD_PRELOAD we exclude anything related to graphics" + cuda_compat_nvlib_list=( + "libcuda.so" + "libcudadebugger.so" + "libnvidia-nvvm.so" + "libnvidia-ptxjitcompiler.so" + ) + # Filter out all symlinks and libraries that have missing library dependencies under EESSI + filtered_libraries=() + compat_filtered_libraries=() + for library in "${matched_libraries[@]}"; do + # Run ldd on the given binary and filter for "not found" libraries + not_found_libs=$(ldd "${library}" 2>/dev/null | grep "not found" | awk '{print $1}') + # Check if it is missing an so dep under EESSI + if [[ -z "$not_found_libs" ]]; then + # Resolve any symlink + realpath_library=$(realpath "$library") + if [[ ! " ${filtered_libraries[@]} " =~ " $realpath_library " ]]; then + filtered_libraries+=("${realpath_library}") + # Also prepare compat only libraries for the short list + for item in "${cuda_compat_nvlib_list[@]}"; do + # Check if the current item is a substring of $library + if [[ "$realpath_library" == *"$item"* ]]; then + echo "Match found for $item for CUDA compat libraries" + if [[ ! " ${compat_filtered_libraries[@]} " =~ " $realpath_library " ]]; then + compat_filtered_libraries+=("$realpath_library") + fi + break + fi + done + fi + else + # Iterate over "not found" libraries and check if they are in the array + all_found=true + for lib in $not_found_libs; do + found=false + for listed_lib in "${matched_libraries[@]}"; do + # Matching to the .so or a symlink target is enough + realpath_lib=$(realpath "${listed_lib}") + if [[ "$lib" == "$listed_lib"* || "$realpath_lib" == *"$lib" ]]; then + found=true + break + fi + done + + if [[ "$found" == false ]]; then + echo "$lib is NOT in the provided preload list, filtering $library" + all_found=false + break + fi + done + + # If we find all the missing libs in our list include it + if [[ "$all_found" == true ]]; then + # Resolve any symlink + realpath_library=$(realpath "${library}") + if [[ ! " ${filtered_libraries[@]} " =~ " $realpath_library " ]]; then + filtered_libraries+=("${realpath_library}") + # Also prepare compat only libraries for the short list + for item in "${cuda_compat_nvlib_list[@]}"; do + # Check if the current item is a substring of $library + if [[ "$realpath_library" == *"$item"* ]]; then + echo "Match found for $item for CUDA compat libraries" + if [[ ! " ${compat_filtered_libraries[@]} " =~ " $realpath_library " ]]; then + compat_filtered_libraries+=("${realpath_library}") + fi + break + fi + done + fi + fi + fi + done + + # Set EESSI_GPU_LD_PRELOAD with the matched libraries + if [ ${#filtered_libraries[@]} -gt 0 ]; then + echo + echo_yellow "The recommended way to use LD_PRELOAD is to only use it when you need to." + echo + EESSI_GPU_COMPAT_LD_PRELOAD=$(printf "%s\n" "${compat_filtered_libraries[@]}" | tr '\n' ':') + # Remove the trailing colon from LD_PRELOAD if it exists + EESSI_GPU_COMPAT_LD_PRELOAD=${EESSI_GPU_COMPAT_LD_PRELOAD%:} + export EESSI_GPU_COMPAT_LD_PRELOAD + echo_yellow "A minimal preload which should work in most cases:" + echo_green "export EESSI_GPU_COMPAT_LD_PRELOAD=\"$EESSI_GPU_COMPAT_LD_PRELOAD\"" + echo + + EESSI_GPU_LD_PRELOAD=$(printf "%s\n" "${filtered_libraries[@]}" | tr '\n' ':') + # Remove the trailing colon from LD_PRELOAD if it exists + EESSI_GPU_LD_PRELOAD=${EESSI_GPU_LD_PRELOAD%:} + export EESSI_GPU_LD_PRELOAD + echo_yellow "A corner-case full preload (which is hard on memory) for exceptional use:" + + echo_green "export EESSI_GPU_LD_PRELOAD=\"$EESSI_GPU_LD_PRELOAD\"" + export EESSI_OVERRIDE_GPU_CHECK=1 + echo_green "export EESSI_OVERRIDE_GPU_CHECK=\"$EESSI_OVERRIDE_GPU_CHECK\"" + echo + echo_yellow "Then you can set LD_PRELOAD only when you want to run a GPU application, e.g.," + echo_yellow " LD_PRELOAD=\"\$EESSI_GPU_COMPAT_LD_PRELOAD\" device_query" + else + echo "No libraries matched, LD_PRELOAD not set." + fi + [[ "${BASH_SOURCE[0]}" != "${0}" ]] && return 1 || exit 1 +fi + +# If we haven't already exited, we may need to create the symlinks + +# First let's make sure the driver libraries are not already in place +link_drivers=1 + +# Make sure that target of host_injections variant symlink is an existing directory +host_injections_target=$(realpath -m "${EESSI_CVMFS_REPO}/host_injections") +if [ ! -d "$host_injections_target" ]; then + check_global_read + create_directory_structure "$host_injections_target" +fi + +host_injections_nvidia_dir="${EESSI_CVMFS_REPO}/host_injections/nvidia/${EESSI_CPU_FAMILY}" +host_injection_driver_dir="${host_injections_nvidia_dir}/host" +host_injection_driver_version_file="${host_injection_driver_dir}/driver_version.txt" +if [ -e "$host_injection_driver_version_file" ]; then + if grep -q "$host_driver_version" "$host_injection_driver_version_file"; then + echo_green "The host GPU driver libraries (v${host_driver_version}) have already been linked! (based on ${host_injection_driver_version_file})" + link_drivers=0 + else + # There's something there but it is out of date + echo_yellow "Cleaning out outdated symlinks" + rm "${host_injection_driver_dir}"/* || fatal_error "Unable to remove files under '${host_injection_driver_dir}'." + fi +fi + +drivers_linked=0 +if [ "$link_drivers" -eq 1 ]; then + check_global_read + if ! create_directory_structure "${host_injection_driver_dir}" ; then + fatal_error "No write permissions to directory ${host_injection_driver_dir}" + fi + cd "${host_injection_driver_dir}" || fatal_error "Failed to cd to ${host_injection_driver_dir}" + + # Make symlinks to all the interesting libraries + # Loop over each matched library + for library in "${matched_libraries[@]}"; do + # Create a symlink in the current directory + ln -s "$library" . + # Check if the symlink was created successfully + if [ $? -ne 0 ]; then + fatal_error "Error: Failed to create symlink for library $library in $PWD" + fi + done + + # Inject driver and CUDA versions into the directory + echo "$host_driver_version" > driver_version.txt + echo "$host_cuda_version" > cuda_version.txt + drivers_linked=1 +fi + +# Make latest symlink for NVIDIA drivers +cd "$host_injections_nvidia_dir" || fatal_error "Failed to cd to $host_injections_nvidia_dir" +symlink="latest" +if [ -L "$symlink" ]; then + if [ "$drivers_linked" -eq 1 ]; then + ln -sf host "$symlink" + if [ $? -eq 0 ]; then + echo "Successfully created symlink between $symlink and host in $PWD" + else + fatal_error "Failed to create symlink between $symlink and host in $PWD" + fi + fi +else + ln -s host "$symlink" + if [ $? -eq 0 ]; then + echo "Successfully created symlink between $symlink and host in $PWD" + else + fatal_error "Failed to create symlink between $symlink and host in $PWD" + fi +fi + +# Make sure the libraries can be found by the EESSI linker +host_injection_linker_dir=${EESSI_EPREFIX/versions/host_injections} +if [ -L "$host_injection_linker_dir/lib" ]; then + target_path=$(readlink -f "$host_injection_linker_dir/lib") + if [ "$target_path" != "$host_injections_nvidia_dir/latest" ]; then + cd "$host_injection_linker_dir" || fatal_error "Failed to cd to $host_injection_linker_dir" + ln -sf "$host_injections_nvidia_dir/latest" lib + if [ $? -eq 0 ]; then + echo "Successfully created symlink between $host_injections_nvidia_dir/latest and lib in $PWD" + else + fatal_error "Failed to create symlink between $host_injections_nvidia_dir/latest and lib in $PWD" + fi + fi +else + check_global_read + create_directory_structure "$host_injection_linker_dir" + cd "$host_injection_linker_dir" || fatal_error "Failed to cd to $host_injection_linker_dir" + ln -s "$host_injections_nvidia_dir/latest" lib + if [ $? -eq 0 ]; then + echo "Successfully created symlink between $host_injections_nvidia_dir/latest and lib in $PWD" + else + fatal_error "Failed to create symlink between $host_injections_nvidia_dir/latest and lib in $PWD" + fi +fi + +echo_green "Host NVIDIA GPU drivers linked successfully for EESSI" diff --git a/scripts/utils.sh b/scripts/utils.sh index d0da95e87f..962decd20e 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -14,7 +14,7 @@ ANY_ERROR_EXITCODE=1 function fatal_error() { echo_red "ERROR: $1" >&2 if [[ $# -gt 1 ]]; then - exit $2 + exit "$2" else exit "${ANY_ERROR_EXITCODE}" fi @@ -32,11 +32,62 @@ function check_exit_code { fi } +function check_eessi_initialised() { + if [[ -z "${EESSI_SOFTWARE_PATH}" ]]; then + fatal_error "EESSI has not been initialised!" + else + return 0 + fi +} + +function check_in_prefix_shell() { + # Make sure EPREFIX is defined + if [[ -z "${EPREFIX}" ]]; then + fatal_error "This script cannot be used without having first defined EPREFIX" + fi + if [[ ! ${SHELL} = ${EPREFIX}/bin/bash ]]; then + fatal_error "Not running in Gentoo Prefix environment, run '${EPREFIX}/startprefix' first!" + fi +} + +function create_directory_structure() { + # Ensure we are given a single path argument + if [ $# -ne 1 ]; then + echo_red "Function requires a single (relative or absolute) path argument" >&2 + return $ANY_ERROR_EXITCODE + fi + dir_structure="$1" + + # Attempt to create the directory structure + error_message=$(mkdir -p "$dir_structure" 2>&1) + return_code=$? + # If it fails be explicit about the error + if [ ${return_code} -ne 0 ]; then + real_dir=$(realpath -m "$dir_structure") + echo_red "Creating ${dir_structure} (real path ${real_dir}) failed with:\n ${error_message}" >&2 + else + # If we're creating it, our use case is that we want to be able to write there + # (this is a check in case the directory already existed) + if [ ! -w "${dir_structure}" ]; then + real_dir=$(realpath -m "$dir_structure") + echo_red "You do not have (required) write permissions to ${dir_structure} (real path ${real_dir})!" + return_code=$ANY_ERROR_EXITCODE + fi + fi + + return $return_code +} + +# Function to check if a command exists +function command_exists() { + command -v "$1" >/dev/null 2>&1 +} + function get_path_for_tool { tool_name=$1 tool_envvar_name=$2 - which_out=$(which ${tool_name} 2>&1) + 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 @@ -68,7 +119,7 @@ function get_host_from_url { url=$1 re="(http|https)://([^/:]+)" if [[ $url =~ $re ]]; then - echo ${BASH_REMATCH[2]} + echo "${BASH_REMATCH[2]}" return 0 else echo "" @@ -80,7 +131,7 @@ function get_port_from_url { url=$1 re="(http|https)://[^:]+:([0-9]+)" if [[ $url =~ $re ]]; then - echo ${BASH_REMATCH[2]} + echo "${BASH_REMATCH[2]}" return 0 else echo "" @@ -90,7 +141,7 @@ function get_port_from_url { function get_ipv4_address { hname=$1 - hipv4=$(grep ${hname} /etc/hosts | grep -v '^[[:space:]]*#' | cut -d ' ' -f 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}" diff --git a/test_suite.sh b/test_suite.sh new file mode 100755 index 0000000000..4121a37c2e --- /dev/null +++ b/test_suite.sh @@ -0,0 +1,241 @@ +#!/bin/bash +# +# This script creates a ReFrame config file from a template, in which CPU properties get replaced +# based on where this script is run (typically: a build node). Then, it runs the EESSI test suite. +# +# This script is part of the EESSI software layer, see +# https://github.com/EESSI/software-layer.git +# +# author: Caspar van Leeuwen (@casparvl) +# +# license: GPLv2 + +display_help() { + echo "usage: $0 [OPTIONS]" + echo " -g | --generic - instructs script to test for generic architecture target" + echo " -h | --help - display this usage information" + echo " -x | --http-proxy URL - provides URL for the environment variable http_proxy" + echo " -y | --https-proxy URL - provides URL for the environment variable https_proxy" +} + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -g|--generic) + DETECTION_PARAMETERS="--generic" + shift + ;; + -h|--help) + display_help # Call your function + # no shifting needed here, we're done. + exit 0 + ;; + -x|--http-proxy) + export http_proxy="$2" + shift 2 + ;; + -y|--https-proxy) + export https_proxy="$2" + shift 2 + ;; + --build-logs-dir) + export build_logs_dir="${2}" + shift 2 + ;; + --shared-fs-path) + export shared_fs_path="${2}" + shift 2 + ;; + -*|--*) + echo "Error: Unknown option: $1" >&2 + exit 1 + ;; + *) # No more options + POSITIONAL_ARGS+=("$1") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +TOPDIR=$(dirname $(realpath $0)) + +source $TOPDIR/scripts/utils.sh + +# honor $TMPDIR if it is already defined, use /tmp otherwise +if [ -z $TMPDIR ]; then + export WORKDIR=/tmp/$USER +else + export WORKDIR=$TMPDIR/$USER +fi + +TMPDIR=$(mktemp -d) + +echo ">> Setting up environment..." +# For this call to be succesful, it needs to be able to import archspec (which is part of EESSI) +# Thus, we execute it in a subshell where EESSI is already initialized (a bit like a bootstrap) +export EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(source $TOPDIR/init/bash > /dev/null 2>&1; python3 $TOPDIR/eessi_software_subdir.py $DETECTION_PARAMETERS) +echo "EESSI_SOFTWARE_SUBDIR_OVERRIDE: $EESSI_SOFTWARE_SUBDIR_OVERRIDE" + +source $TOPDIR/init/bash + +# We have to ignore the LMOD cache, otherwise the software that is built in the build step cannot be found/loaded +# Reason is that the LMOD cache is normally only updated on the Stratum 0, once everything is ingested +export LMOD_IGNORE_CACHE=1 + +# Load the ReFrame module +# Currently, we load the default version. Maybe we should somehow make this configurable in the future? +module load ReFrame +if [[ $? -eq 0 ]]; then + echo_green ">> Loaded ReFrame module" +else + fatal_error "Failed to load the ReFrame module" +fi + +# Check that a system python3 is available +python3_found=$(command -v python3) +if [ -z ${python3_found} ]; then + fatal_error "No system python3 found" +else + echo_green "System python3 found:" + python3 -V +fi + +# Check ReFrame came with the hpctestlib and we can import it +reframe_import="hpctestlib.sciapps.gromacs" +python3 -c "import ${reframe_import}" +if [[ $? -eq 0 ]]; then + echo_green "Succesfully found and imported ${reframe_import}" +else + fatal_error "Failed to import ${reframe_import}" +fi + +# Cloning should already be done in run_tests.sh before test_suite.sh is invoked +# Check if that succeeded +export TESTSUITEPREFIX=$PWD/EESSI-test-suite +if [ -d $TESTSUITEPREFIX ]; then + echo_green "Clone of the test suite $TESTSUITEPREFIX available, OK!" +else + fatal_error "Clone of the test suite $TESTSUITEPREFIX is not available!" +fi +export PYTHONPATH=$TESTSUITEPREFIX:$PYTHONPATH + +# Check that we can import from the testsuite +testsuite_import="eessi.testsuite" +python3 -c "import ${testsuite_import}" +if [[ $? -eq 0 ]]; then + echo_green "Succesfully found and imported ${testsuite_import}" +else + fatal_error "Failed to import ${testsuite_import}" +fi + +# Configure ReFrame, see https://www.eessi.io/docs/test-suite/installation-configuration +# RFM_CONFIG_FILES _has_ to be set by the site hosting the bot, so that it knows where to find the ReFrame +# config file that matches the bot config. See https://gitlab.com/eessi/support/-/issues/114#note_2293660921 +if [ -z "$RFM_CONFIG_FILES" ]; then + if [ -z "${shared_fs_path}" ]; then + fatal_error "Environment variable 'shared_fs_path' was expected, but was not set" + fi + # Try to find a config file at $shared_fs_path/reframe_config.py + export RFM_CONFIG_FILES="${shared_fs_path}/reframe_config.py" + if [ ! -f "${RFM_CONFIG_FILES}" ]; then + # If we haven't found the ReFrame config, print an informative error + err_msg="Please put a ReFrame configuration file in ${shared_fs_path}/reframe_config.py" + err_msg="${err_msg} or set RFM_CONFIG_FILES in the environment of this bot instance to point to a valid" + err_msg="${err_msg} ReFrame configuration file that matches the bot config." + err_msg="${err_msg} For more information, see https://gitlab.com/eessi/support/-/issues/114#note_2293660921" + fatal_error "${err_msg}" + fi +fi +export RFM_CHECK_SEARCH_PATH=$TESTSUITEPREFIX/eessi/testsuite/tests +export RFM_CHECK_SEARCH_RECURSIVE=1 +export RFM_PREFIX=$PWD/reframe_runs + +# Get the correct partition name +REFRAME_PARTITION_NAME=${EESSI_SOFTWARE_SUBDIR//\//_} +if [ ! -z "$EESSI_ACCELERATOR_TARGET" ]; then + REFRAME_PARTITION_NAME=${REFRAME_PARTITION_NAME}_${EESSI_ACCELERATOR_TARGET//\//_} +fi +echo "Constructed partition name based on EESSI_SOFTWARE_SUBDIR and EESSI_ACCELERATOR_TARGET: ${REFRAME_PARTITION_NAME}" + +# Set the reframe system name, including partition +export RFM_SYSTEM="BotBuildTests:${REFRAME_PARTITION_NAME}" + +echo "Configured reframe with the following environment variables:" +env | grep "RFM_" + +# Make debugging easier by printing the final config file: +echo "ReFrame config file used:" +cat "${RFM_CONFIG_FILES}" + +# Workaround for https://github.com/EESSI/software-layer/pull/467#issuecomment-1973341966 +export PSM3_DEVICES='self,shm' # this is enough, since we only run single node for now + +# Check we can run reframe +reframe --version +if [[ $? -eq 0 ]]; then + echo_green "Succesfully ran 'reframe --version'" +else + fatal_error "Failed to run 'reframe --version'" +fi + +# Get the subset of test names based on the test mapping and tags (e.g. CI, 1_node) +module_list="module_files.list.txt" +mapping_config="tests/eessi_test_mapping/software_to_tests.yml" +if [[ ! -f "$module_list" ]]; then + echo_green "File ${module_list} not found, so only running the default set of tests from ${mapping_config}" + # Run with --debug for easier debugging in case there are issues: + python3 tests/eessi_test_mapping/map_software_to_test.py --mapping-file "${mapping_config}" --debug --defaults-only + REFRAME_NAME_ARGS=$(python3 tests/eessi_test_mapping/map_software_to_test.py --mapping-file "${mapping_config}" --defaults-only) + test_selection_exit_code=$? +else + # Run with --debug for easier debugging in case there are issues: + python3 tests/eessi_test_mapping/map_software_to_test.py --module-list "${module_list}" --mapping-file "${mapping_config}" --debug + REFRAME_NAME_ARGS=$(python3 tests/eessi_test_mapping/map_software_to_test.py --module-list "${module_list}" --mapping-file "${mapping_config}") + test_selection_exit_code=$? +fi +# Check exit status +if [[ ${test_selection_exit_code} -eq 0 ]]; then + echo_green "Succesfully extracted names of tests to run: ${REFRAME_NAME_ARGS}" +else + fatal_error "Failed to extract names of tests to run: ${REFRAME_NAME_ARGS}" + exit ${test_selection_exit_code} +fi +# Allow people deploying the bot to overrwide this +if [ -z "$REFRAME_SCALE_TAG" ]; then + REFRAME_SCALE_TAG="--tag 1_node" +fi +if [ -z "$REFRAME_CI_TAG" ]; then + REFRAME_CI_TAG="--tag CI" +fi +# Allow bot-deployers to add additional args through the environment +if [ -z "$REFRAME_ADDITIONAL_ARGS" ]; then + REFRAME_ADDITIONAL_ARGS="" +fi +export REFRAME_ARGS="${REFRAME_CI_TAG} ${REFRAME_SCALE_TAG} ${REFRAME_ADDITIONAL_ARGS} --nocolor ${REFRAME_NAME_ARGS}" + +# List the tests we want to run +echo "Listing tests: reframe ${REFRAME_ARGS} --list" +reframe ${REFRAME_ARGS} --list +if [[ $? -eq 0 ]]; then + echo_green "Succesfully listed ReFrame tests with command: reframe ${REFRAME_ARGS} --list" +else + fatal_error "Failed to list ReFrame tests with command: reframe ${REFRAME_ARGS} --list" +fi + +# Run all tests +echo "Running tests: reframe ${REFRAME_ARGS} --run" +reframe ${REFRAME_ARGS} --run +reframe_exit_code=$? +if [[ ${reframe_exit_code} -eq 0 ]]; then + echo_green "ReFrame runtime ran succesfully with command: reframe ${REFRAME_ARGS} --run." +else + fatal_error "ReFrame runtime failed to run with command: reframe ${REFRAME_ARGS} --run." +fi + +echo ">> Cleaning up ${TMPDIR}..." +rm -r ${TMPDIR} + +exit ${reframe_exit_code} diff --git a/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.all.output b/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.all.output new file mode 100644 index 0000000000..f6f97c2aaa --- /dev/null +++ b/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.all.output @@ -0,0 +1 @@ +aarch64/a64fx:aarch64/generic diff --git a/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.cpuinfo b/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.cpuinfo new file mode 100644 index 0000000000..2484dbe3e7 --- /dev/null +++ b/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.cpuinfo @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 200.00 +Features : fp asimd evtstrm sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm fcma dcpop sve +CPU implementer : 0x46 +CPU architecture: 8 +CPU variant : 0x1 +CPU part : 0x001 +CPU revision : 0 diff --git a/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.output b/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.output new file mode 100644 index 0000000000..13b6c575c1 --- /dev/null +++ b/tests/archdetect/aarch64/a64fx/Deucalion-Rocky85.output @@ -0,0 +1 @@ +aarch64/a64fx diff --git a/tests/archdetect/nvidia-smi/1xa100.output b/tests/archdetect/nvidia-smi/1xa100.output new file mode 100644 index 0000000000..5eb3aaff18 --- /dev/null +++ b/tests/archdetect/nvidia-smi/1xa100.output @@ -0,0 +1 @@ +accel/nvidia/cc80 diff --git a/tests/archdetect/nvidia-smi/1xa100.sh b/tests/archdetect/nvidia-smi/1xa100.sh new file mode 100755 index 0000000000..ead191418b --- /dev/null +++ b/tests/archdetect/nvidia-smi/1xa100.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# output from NVIDIA A100 system, +# produced by: nvidia-smi --query-gpu=gpu_name,count,driver_version,compute_cap --format=csv,noheader +echo "NVIDIA A100-SXM4-80GB, 1, 545.23.08, 8.0" +exit 0 diff --git a/tests/archdetect/nvidia-smi/2xa100.output b/tests/archdetect/nvidia-smi/2xa100.output new file mode 100644 index 0000000000..5eb3aaff18 --- /dev/null +++ b/tests/archdetect/nvidia-smi/2xa100.output @@ -0,0 +1 @@ +accel/nvidia/cc80 diff --git a/tests/archdetect/nvidia-smi/2xa100.sh b/tests/archdetect/nvidia-smi/2xa100.sh new file mode 100755 index 0000000000..5539607fbe --- /dev/null +++ b/tests/archdetect/nvidia-smi/2xa100.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# output from NVIDIA A100 system, +# produced by: nvidia-smi --query-gpu=gpu_name,count,driver_version,compute_cap --format=csv,noheader +echo "NVIDIA A100-SXM4-80GB, 2, 545.23.08, 8.0" +echo "NVIDIA A100-SXM4-80GB, 2, 545.23.08, 8.0" +exit 0 diff --git a/tests/archdetect/nvidia-smi/4xa100.output b/tests/archdetect/nvidia-smi/4xa100.output new file mode 100644 index 0000000000..5eb3aaff18 --- /dev/null +++ b/tests/archdetect/nvidia-smi/4xa100.output @@ -0,0 +1 @@ +accel/nvidia/cc80 diff --git a/tests/archdetect/nvidia-smi/4xa100.sh b/tests/archdetect/nvidia-smi/4xa100.sh new file mode 100755 index 0000000000..45458ea7bd --- /dev/null +++ b/tests/archdetect/nvidia-smi/4xa100.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# output from NVIDIA A100 system, +# produced by: nvidia-smi --query-gpu=gpu_name,count,driver_version,compute_cap --format=csv,noheader +echo "NVIDIA A100-SXM4-80GB, 4, 545.23.08, 8.0" +echo "NVIDIA A100-SXM4-80GB, 4, 545.23.08, 8.0" +echo "NVIDIA A100-SXM4-80GB, 4, 545.23.08, 8.0" +echo "NVIDIA A100-SXM4-80GB, 4, 545.23.08, 8.0" +exit 0 diff --git a/tests/archdetect/nvidia-smi/cc01.output b/tests/archdetect/nvidia-smi/cc01.output new file mode 100644 index 0000000000..9cbf66a131 --- /dev/null +++ b/tests/archdetect/nvidia-smi/cc01.output @@ -0,0 +1 @@ +accel/nvidia/cc01 diff --git a/tests/archdetect/nvidia-smi/cc01.sh b/tests/archdetect/nvidia-smi/cc01.sh new file mode 100755 index 0000000000..81011a1d16 --- /dev/null +++ b/tests/archdetect/nvidia-smi/cc01.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# output from non-existing NVIDIA GPU system, +# to test handling of unknown GPU model +# (supposedly) produced by: nvidia-smi --query-gpu=gpu_name,count,driver_version,compute_cap --format=csv,noheader +echo "NVIDIA does-not-exist, 1, 000.00.00, 0.1" +exit 0 diff --git a/tests/archdetect/nvidia-smi/no_devices.output b/tests/archdetect/nvidia-smi/no_devices.output new file mode 100644 index 0000000000..b251bfc837 --- /dev/null +++ b/tests/archdetect/nvidia-smi/no_devices.output @@ -0,0 +1 @@ +non-zero exit code: 3 diff --git a/tests/archdetect/nvidia-smi/no_devices.sh b/tests/archdetect/nvidia-smi/no_devices.sh new file mode 100755 index 0000000000..0bc26dcddc --- /dev/null +++ b/tests/archdetect/nvidia-smi/no_devices.sh @@ -0,0 +1,3 @@ +#!/bin/bash +echo "No devices were found" +exit 6 diff --git a/tests/archdetect/nvidia-smi/none.output b/tests/archdetect/nvidia-smi/none.output new file mode 100644 index 0000000000..e287574cc3 --- /dev/null +++ b/tests/archdetect/nvidia-smi/none.output @@ -0,0 +1 @@ +non-zero exit code: 2 diff --git a/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.all.output b/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.all.output new file mode 100644 index 0000000000..e1bbd79e4a --- /dev/null +++ b/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.all.output @@ -0,0 +1 @@ +x86_64/amd/zen4:x86_64/amd/zen3:x86_64/amd/zen2:x86_64/generic diff --git a/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.cpuinfo b/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.cpuinfo new file mode 100644 index 0000000000..4a97da862c --- /dev/null +++ b/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.cpuinfo @@ -0,0 +1,27 @@ +processor : 0 +vendor_id : AuthenticAMD +cpu family : 25 +model : 17 +model name : AMD EPYC 9V33X 96-Core Processor +stepping : 1 +microcode : 0xffffffff +cpu MHz : 3705.853 +cache size : 1024 KB +physical id : 0 +siblings : 88 +core id : 0 +cpu cores : 88 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl tsc_reliable nonstop_tsc cpuid extd_apicid aperfmperf pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core invpcid_single vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx512_bf16 clzero xsaveerptr arat npt nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold v_vmsave_vmload avx512vbmi umip avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid fsrm +bugs : sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass +bogomips : 5100.08 +TLB size : 3584 4K pages +clflush size : 64 +cache_alignment : 64 +address sizes : 48 bits physical, 48 bits virtual +power management: diff --git a/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.output b/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.output new file mode 100644 index 0000000000..950740a78c --- /dev/null +++ b/tests/archdetect/x86_64/amd/zen4/Azure-Alma8-9V33X.output @@ -0,0 +1 @@ +x86_64/amd/zen4 diff --git a/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.all.output b/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.all.output new file mode 100644 index 0000000000..e1bbd79e4a --- /dev/null +++ b/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.all.output @@ -0,0 +1 @@ +x86_64/amd/zen4:x86_64/amd/zen3:x86_64/amd/zen2:x86_64/generic diff --git a/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.cpuinfo b/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.cpuinfo new file mode 100644 index 0000000000..f28381d7a2 --- /dev/null +++ b/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.cpuinfo @@ -0,0 +1,27 @@ +processor : 0 +vendor_id : AuthenticAMD +cpu family : 25 +model : 17 +model name : AMD EPYC 9654 96-Core Processor +stepping : 1 +microcode : 0xa10113e +cpu MHz : 3699.993 +cache size : 1024 KB +physical id : 0 +siblings : 96 +core id : 0 +cpu cores : 96 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 16 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 invpcid_single hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local avx512_bf16 clzero irperf xsaveerptr wbnoinvd amd_ppin cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq la57 rdpid overflow_recov succor smca fsrm flush_l1d +bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass +bogomips : 4799.99 +TLB size : 3584 4K pages +clflush size : 64 +cache_alignment : 64 +address sizes : 52 bits physical, 57 bits virtual +power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14] diff --git a/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.output b/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.output new file mode 100644 index 0000000000..950740a78c --- /dev/null +++ b/tests/archdetect/x86_64/amd/zen4/Shinx-RHEL8-9654.output @@ -0,0 +1 @@ +x86_64/amd/zen4 diff --git a/tests/eessi_test_mapping/map_software_to_test.py b/tests/eessi_test_mapping/map_software_to_test.py new file mode 100644 index 0000000000..a0da6258c8 --- /dev/null +++ b/tests/eessi_test_mapping/map_software_to_test.py @@ -0,0 +1,95 @@ +import yaml +import re +import os +import argparse + +def load_mappings(file_path): + """Load the YAML mappings from a file.""" + if not os.path.exists(file_path): + raise FileNotFoundError(f"Error: {file_path} does not exist.") + with open(file_path, 'r') as file: + config = yaml.safe_load(file) + return config['mappings'] + +def read_software_names(file_path): + """Read software names from the module_files.list.txt file.""" + if not os.path.exists(file_path): + raise FileNotFoundError(f"Error: {file_path} does not exist.") + with open(file_path, 'r') as file: + software_names = [line.strip() for line in file if line.strip()] + return software_names + +def get_tests_for_software(software_name, mappings): + """Get the list of tests for a given software name based on the first matching regex pattern.""" + + # Iterate over patterns in the order they appear in the YAML file + for pattern, tests in mappings.items(): + if re.match(pattern, software_name): + return tests + + # If no matches are found, return the default tests if they exist + if 'default_tests' in mappings: + return mappings['default_tests'] + + return [] + +def main(yaml_file, module_file, debug, defaults_only): + """Main function to process software names and their tests.""" + mappings = load_mappings(yaml_file) + if debug: + print(f"Loaded mappings from '{yaml_file}'") + + if not defaults_only: + software_names = read_software_names(module_file) + if debug: + print(f"Read software names from '{module_file}'") + + tests_to_run = [] + arg_string = "" + + if not defaults_only: + # For each module name, get the relevant set of tests + for software_name in software_names: + additional_tests = get_tests_for_software(software_name, mappings) + for test in additional_tests: + if test not in tests_to_run: + tests_to_run.append(test) + + if additional_tests and debug: + print(f"Software: {software_name} -> Tests: {additional_tests}") + elif debug: + print(f"Software: {software_name} -> No tests found") + + # Always add the default set of tests, if default_tests is specified + if 'default_tests' in mappings: + additional_tests = mappings['default_tests'] + for test in additional_tests: + if test not in tests_to_run: + tests_to_run.append(test) + + if additional_tests and debug: + print(f"Adding default set of tests: {additional_tests}") + + # Create argument string out of the list of tests to run + if tests_to_run: + arg_string = " ".join([f"-n {test_name}" for test_name in tests_to_run]) + + # Print final lists & argument string + if debug: + print(f"Full list of tests to run: {tests_to_run}") + print(f"Argument string: {arg_string}") + else: + # This is the only thing this script should print, unless run with --debug + print(f"{arg_string}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Map software names to their tests based on a YAML configuration.") + parser.add_argument('--mapping-file', type=str, help='Path to the YAML file containing the test mappings.') + parser.add_argument('--module-list', type=str, help='Path to the file containing the list of software names.') + defaults_help = "Don't consider the module-list file, only return the default tests from the mapping file" + parser.add_argument('--defaults-only', action='store_true', default=False, help=defaults_help) + parser.add_argument('--debug', action='store_true', default=False, help='Enable debug output.') + + args = parser.parse_args() + + main(args.mapping_file, args.module_list, args.debug, args.defaults_only) diff --git a/tests/eessi_test_mapping/software_to_tests.yml b/tests/eessi_test_mapping/software_to_tests.yml new file mode 100644 index 0000000000..3a162666fc --- /dev/null +++ b/tests/eessi_test_mapping/software_to_tests.yml @@ -0,0 +1,35 @@ +# This file creates a mapping between (regular expressions for) module names and test names from the EESSI test suite +# If a module name matches one of the regular expressions, the listed set of tests will be run in the test step +# For a given module name, the test list for the first matching regular expression is returned +# E.g. for +# mappings: +# foo-v1: +# - bar +# foo-* +# - bar2 +# only the bar test will be run for foo-v1 (even though it also matches the pattern (foo-*) +# If a module name does not match anything, the default_tests will be run +# Note that to list all available tests by name, one can do execute +# reframe -R -c /path/to/eessi/test-suite/ --list | grep -Po "\bEESSI_\S+?(?=[\s'])" | uniq +# Note that this regular expression is a bit sensitive to changes in the structure of ReFrame's output, +# but is confirmed to work for ReFrame version 4.6.1 +mappings: + PyTorch-Bundle/*: + - EESSI_PyTorch_torchvision + QuantumESPRESSO/*: + - EESSI_QuantumESPRESSO + CP2K/*: + - EESSI_CP2K + ESPResSo/*: + - EESSI_ESPRESSO + LAMMPS/*: + - EESSI_LAMMPS + OSU-Micro-Benchmarks/*: + - EESSI_OSU + GROMACS/*: + - EESSI_GROMACS + default_tests: + # Low level tests + - EESSI_OSU + # A very quick-to-run high level application test + - EESSI_LAMMPS