diff --git a/ansible/playbooks/roles/compatibility_layer/defaults/main.yml b/ansible/playbooks/roles/compatibility_layer/defaults/main.yml index 21a11ca6..a0705951 100644 --- a/ansible/playbooks/roles/compatibility_layer/defaults/main.yml +++ b/ansible/playbooks/roles/compatibility_layer/defaults/main.yml @@ -8,7 +8,7 @@ custom_overlays: url: https://github.com/EESSI/gentoo-overlay.git eclass-overrides: true -cvmfs_repository: pilot.eessi-hpc.org +cvmfs_repository: software.eessi.io gentoo_prefix_path: /cvmfs/{{ cvmfs_repository }}/versions/{{ eessi_version }}/compat/{{ eessi_host_os }}/{{ eessi_host_arch }} diff --git a/bot/build.sh b/bot/build.sh index 0bc2584b..55024619 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -83,7 +83,7 @@ eessi_os=linux job_version=$(cfg_get_value "repository" "repo_version") eessi_version=${job_version:-2023.06} job_repo=$(cfg_get_value "repository" "repo_name") -eessi_repo=${job_repo:-pilot.eessi-hpc.org} +eessi_repo=${job_repo:-software.eessi.io} tar_topdir=/cvmfs/${eessi_repo}/versions if [ "${eessi_arch}" != "${host_arch}" ]; then @@ -92,15 +92,20 @@ if [ "${eessi_arch}" != "${host_arch}" ]; then fi # option -k is used for retaining ${eessi_tmp} -./install_compatibility_layer.sh -a ${eessi_arch} -v ${eessi_version} -r ${eessi_repo} -g ${STORAGE} -k +# store output in local file such that the temporary directory ${STORAGE}/eessi.XXXXXXXXXX +# can be determined +script_out="install_stdout.log" +./install_compatibility_layer.sh -a ${eessi_arch} -v ${eessi_version} -r ${eessi_repo} -g ${STORAGE} -k 2>&1 | tee -a ${script_out} +# TODO handle errors (no outfile, no tmp directory found) +eessi_tmp=$(cat ${script_out} | grep 'To resume work add' | cut -f 2 -d \' | cut -f 2 -d ' ') # create tarball -> should go into a separate script when this is supported by the bot target_tgz=eessi-${eessi_version}-compat-linux-${eessi_arch}-$(date +%s).tar.gz -if [ -d ${eessi_tmp}/${tar_topdir}/${eessi_version} ]; then - echo ">> Creating tarball ${target_tgz} from ${eessi_tmp}/${tar_topdir}..." - tar cfvz ${target_tgz} -C ${eessi_tmp}/${tar_topdir} ${eessi_version}/compat/${eessi_os}/${eessi_arch} +if [ -d ${eessi_tmp}${tar_topdir}/${eessi_version} ]; then + echo ">> Creating tarball ${target_tgz} from ${eessi_tmp}${tar_topdir}..." + tar cfvz ${target_tgz} -C ${eessi_tmp}${tar_topdir} ${eessi_version}/compat/${eessi_os}/${eessi_arch} echo ${target_tgz} created! else - echo "Directory ${eessi_tmp}/${tar_topdir}/${eessi_version} was not created, not creating tarball." + echo "Directory ${eessi_tmp}${tar_topdir}/${eessi_version} was not created, not creating tarball." exit 1 fi diff --git a/bot/check-build.sh b/bot/check-build.sh new file mode 100755 index 00000000..6948e66b --- /dev/null +++ b/bot/check-build.sh @@ -0,0 +1,300 @@ +#!/bin/bash +# +# Script to check the result of building the EESSI compatibility layer. +# Intended use is that it is called by a (batch) job running on a compute +# node. +# +# This script is part of the EESSI compatibility layer, see +# https://github.com/EESSI/compatibility-layer.git +# +# author: Thomas Roeblitz (@trz42) +# +# license: GPLv2 +# + + +# stop as soon as something fails +# set -e + +TOPDIR=$(dirname $(realpath $0)) + +source ${TOPDIR}/../scripts/utils.sh +source ${TOPDIR}/../scripts/cfg_files.sh + +#source scripts/utils.sh +#source scripts/cfg_files.sh + +# defaults +export JOB_CFG_FILE="${JOB_CFG_FILE_OVERRIDE:=./cfg/job.cfg}" + +# check if ${JOB_CFG_FILE} exists +if [[ ! -r "${JOB_CFG_FILE}" ]]; then + echo_red "job config file (JOB_CFG_FILE=${JOB_CFG_FILE}) does not exist or not readable" +else + echo "bot/check-build.sh: showing ${JOB_CFG_FILE} from software-layer side" + cat ${JOB_CFG_FILE} + + echo "bot/check-build.sh: obtaining configuration settings from '${JOB_CFG_FILE}'" + cfg_load ${JOB_CFG_FILE} +fi + +display_help() { + echo "usage: $0 [OPTIONS]" + echo " OPTIONS:" + echo " -h | --help - display this usage information [default: false]" + echo " -v | --verbose - display more information [default: false]" +} + +# set defaults for command line arguments +VERBOSE=0 + +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + display_help + exit 0 + ;; + -v|--verbose) + VERBOSE=1 + shift 1 + ;; + --) + shift + POSITIONAL_ARGS+=("$@") # save positional args + break + ;; + -*|--*) + fatal_error "Unknown option: $1" "${CMDLINE_ARG_UNKNOWN_EXITCODE}" + ;; + *) # No more options + POSITIONAL_ARGS+=("$1") # save positional arg + shift + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" + +job_dir=${PWD} + +[[ ${VERBOSE} -ne 0 ]] && echo ">> analysing job in directory ${job_dir}" + +cpu_target_arch=$(cfg_get_value "architecture" "software_subdir" | cut -d/ -f1) +[[ ${VERBOSE} -ne 0 ]] && echo ">> cfg[architecture][software_subdir] = ${cpu_target_arch}" + +host_arch=$(uname -m) +eessi_arch=${cpu_target_arch:-${host_arch}} +# eessi_os=linux +job_version=$(cfg_get_value "repository" "repo_version") +eessi_version=${job_version:-2023.09} +# job_repo=$(cfg_get_value "repository" "repo_name") +# eessi_repo=${job_repo:-pilot.nessi.no} +# tar_topdir=/cvmfs/${eessi_repo}/versions + +# determine job output file +job_out_file=slurm-${SLURM_JOB_ID}.out +job_result_file=_bot_job${SLURM_JOB_ID}.result +if [[ ! -e ${job_out_file} ]]; then + SLURM=0 +else + SLURM=1 +fi + +# status of build job (SUCCESS/FAILURE) + details +# SUCCESS (all of) +# - last line with failed=0 +# - tarball +# FAILED (one of) +# - no last line with failed=0 +# - no tarball + +if [[ ${SLURM} -eq 1 ]]; then + play_recap=0 + PLAY_RECAP=$(grep -A1 "PLAY RECAP" ${job_out_file}) + ec=$? + [[ ${VERBOSE} -ne 0 ]] && echo "PLAY_RECAP.ec=${ec}" + [[ ${ec} -eq 0 ]] && play_recap=0 || play_recap=1 + [[ ${VERBOSE} -ne 0 ]] && echo "play_recap=${play_recap}" + + found_line_with_failed=0 + echo "${PLAY_RECAP}" | grep "failed=" > /dev/null + ec=$? + [[ ${VERBOSE} -ne 0 ]] && echo "FAILED=.ec=${ec}" + [[ ${ec} -eq 0 ]] && found_line_with_failed=0 || found_line_with_failed=1 + [[ ${VERBOSE} -ne 0 ]] && echo "found_line_with_failed=${found_line_with_failed}" + + failed_eq_zero=0 + echo "${PLAY_RECAP}" | grep "failed=0" > /dev/null + ec=$? + [[ ${VERBOSE} -ne 0 ]] && echo "FAILED=0.ec=${ec}" + [[ ${ec} -eq 0 ]] && failed_eq_zero=0 || failed_eq_zero=1 + [[ ${VERBOSE} -ne 0 ]] && echo "failed_eq_zero=${failed_eq_zero}" +fi + +found_tarballs=0 +tarballs=$(ls eessi-${eessi_version}-compat-linux-${eessi_arch}-*.tar.gz 2>&1) +ec=$? +[[ ${VERBOSE} -ne 0 ]] && echo "TARBALLS.ec=${ec}" +if [[ ${ec} -eq 0 ]]; then + found_tarballs=0 +else + found_tarballs=1 +fi +[[ ${VERBOSE} -ne 0 ]] && echo "found_tarballs=${found_tarballs}" + +# construct and write complete PR comment +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}" + item="${2}" + echo -n "${format//__ITEM__/${item}}
" +} + +function print_br_item2() { + format="${1}" + item="${2}" + item2="${3}" + format1="${format//__ITEM__/${item}}" + echo -n "${format1//__ITEM2__/${item2}}
" +} + +function print_code_item() { + format="${1}" + item="${2}" + echo -n "${format//__ITEM__/${item}}" +} + +function print_dd_item() { + format="${1}" + item="${2}" + echo -n "
${format//__ITEM__/${item}}
" +} + +function print_list_item() { + format="${1}" + item="${2}" + echo -n "
  • ${format//__ITEM__/${item}}
  • " +} + +function print_pre_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 +} + +if [[ ${failed_eq_zero} -eq 0 ]] && [[ ${found_tarballs} -eq 0 ]]; then + status="SUCCESS" + summary=":grin: SUCCESS" +else + status="FAILURE" + summary=":cry: FAILURE" +fi + +# TODO adjust format to what NESSI bot uses +echo "[RESULT]" > ${job_result_file} +echo -n "comment_description = " >> ${job_result_file} + +# construct values for placeholders in comment_template: +# - __SUMMARY_FMT__ -> variable $comment_summary +# - __DETAILS_FMT__ -> variable $comment_details +# - __ARTEFACTS_FMT__ -> variable $comment_artefacts + +comment_summary="${comment_summary_fmt/__SUMMARY__/${summary}}" + +# first construct comment_details_list, abbreviated CoDeList +# then use it to set comment_details +CoDeList="" + +success_msg="job output file ${job_out_file}" +failure_msg="no job output file ${job_out_file}" +CoDeList=${CoDeList}$(add_detail ${SLURM} 1 "${success_msg}" "${failure_msg}") + +success_msg="no task failed" +failure_msg="some task failed" +CoDeList=${CoDeList}$(add_detail ${failed_eq_zero} 0 "${success_msg}" "${failure_msg}") + +success_msg="found tarball" +failure_msg="no tarball found" +CoDeList=${CoDeList}$(add_detail ${found_tarballs} 0 "${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 ${tarballs} ]]; then + size="$(stat --dereference --printf=%s ${tarballs})" + size_mib=$((${size} >> 20)) + tmpfile=$(mktemp --tmpdir=. tarfiles.XXXX) + tar tf ${tarballs} > ${tmpfile} + entries=$(cat ${tmpfile} | wc -l) + artefact_summary="$(print_code_item '__ITEM__' ${tarballs})" + CoArList="" + CoArList="${CoArList}$(print_br_item2 'size: __ITEM__ MiB (__ITEM2__ bytes)' ${size_mib} ${size})" + CoArList="${CoArList}$(print_br_item 'entries: __ITEM__' ${entries})" +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}}" + +# 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}} + +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 "${tarballs}" | sed -e 's/^/ /g' >> ${job_result_file} + +# remove tmpfile +if [[ -f ${tmpfile} ]]; then + rm ${tmpfile} +fi + +# exit script with value that reflects overall job result: SUCCESS (0), FAILURE (1) +test "${status}" == "SUCCESS" +exit $? diff --git a/install_compatibility_layer.sh b/install_compatibility_layer.sh index b621dccb..c8cdc996 100755 --- a/install_compatibility_layer.sh +++ b/install_compatibility_layer.sh @@ -6,7 +6,7 @@ ARCH= CONTAINER=docker://ghcr.io/eessi/bootstrap-prefix:debian11 -REPOSITORY="pilot.eessi-hpc.org" +REPOSITORY="software.eessi.io" RESUME= RETAIN_TMP=0 STORAGE= @@ -145,23 +145,30 @@ mkdir -p ${EESSI_TMPDIR}/tmp RUNTIME=$(get_container_runtime) exit_code=$? -echo "RUNTIME='${RUNTIME}'" +[[ ${VERBOSE} == '-vvv' ]] && echo "RUNTIME='${RUNTIME}'" check_exit_code ${exit_code} "using runtime ${RUNTIME}" "oh no, neither apptainer nor singularity available" # Set up paths and mount points for Apptainer if [[ -z ${APPTAINER_CACHEDIR} ]]; then export APPTAINER_CACHEDIR=${EESSI_TMPDIR}/apptainer_cache + [[ ${VERBOSE} == '-vvv' ]] && echo "APPTAINER_CACHEDIR='${APPTAINER_CACHEDIR}'" fi export APPTAINER_BIND="${EESSI_TMPDIR}/cvmfs:/cvmfs,${SCRIPT_DIR}:/compatibility-layer" export APPTAINER_BIND="${APPTAINER_BIND},${EESSI_TMPDIR}/tmp:/tmp" +[[ ${VERBOSE} == '-vvv' ]] && echo "APPTAINER_BIND='${APPTAINER_BIND}'" export APPTAINER_HOME="${EESSI_TMPDIR}/home:/home/${USER}" +[[ ${VERBOSE} == '-vvv' ]] && echo "APPTAINER_HOME='${APPTAINER_HOME}'" + # also define SINGULARITY_* env vars if [[ -z ${SINGULARITY_CACHEDIR} ]]; then export SINGULARITY_CACHEDIR=${EESSI_TMPDIR}/apptainer_cache + [[ ${VERBOSE} == '-vvv' ]] && echo "SINGULARITY_CACHEDIR='${SINGULARITY_CACHEDIR}'" fi export SINGULARITY_BIND="${EESSI_TMPDIR}/cvmfs:/cvmfs,${SCRIPT_DIR}:/compatibility-layer" export SINGULARITY_BIND="${SINGULARITY_BIND},${EESSI_TMPDIR}/tmp:/tmp" +[[ ${VERBOSE} == '-vvv' ]] && echo "SINGULARITY_BIND='${SINGULARITY_BIND}'" export SINGULARITY_HOME="${EESSI_TMPDIR}/home:/home/${USER}" +[[ ${VERBOSE} == '-vvv' ]] && echo "SINGULARITY_HOME='${SINGULARITY_HOME}'" # Construct the Ansible playbook command ANSIBLE_OPTIONS="-e eessi_host_os=linux -e eessi_host_arch=$(uname -m)" diff --git a/test/compat_layer.py b/test/compat_layer.py index 1cb2fb3b..c0ce726a 100644 --- a/test/compat_layer.py +++ b/test/compat_layer.py @@ -4,7 +4,7 @@ import reframe.utility.sanity as sn -EESSI_REPO_DIR = '/cvmfs/pilot.eessi-hpc.org' +EESSI_REPO_DIR = '/cvmfs/software.eessi.io' class RunInGentooPrefixTestError(rfm.core.exceptions.ReframeError): pass