Skip to content

Commit

Permalink
build compat layer software.eessi.io/2023.06
Browse files Browse the repository at this point in the history
- changed repository name to software.eessi.io
- fixed creation of tarball at the end of `bot/build.sh`
 - should be improved to handle errors when some tmp directory couldn't be
   determined
- added `bot/check-build.sh` that prepares `.result` file including a status
  update for the PR comment
- added a bit more debug output in `install_compatibility_layer.sh`, should help
  with setting up debug sessions

Not changed CI `pilot_repo.yml` yet.
  • Loading branch information
truib committed Sep 9, 2023
1 parent 2be6503 commit 9023092
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}

Expand Down
17 changes: 11 additions & 6 deletions bot/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
300 changes: 300 additions & 0 deletions bot/check-build.sh
Original file line number Diff line number Diff line change
@@ -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="<details>__SUMMARY_FMT__<dl>__DETAILS_FMT____ARTEFACTS_FMT__</dl></details>"
comment_summary_fmt="<summary>__SUMMARY__ _(click triangle for details)_</summary>"
comment_details_fmt="<dt>_Details_</dt><dd>__DETAILS_LIST__</dd>"
comment_success_item_fmt=":white_check_mark: __ITEM__"
comment_failure_item_fmt=":x: __ITEM__"
comment_artefacts_fmt="<dt>_Artefacts_</dt><dd>__ARTEFACTS_LIST__</dd>"
comment_artefact_details_fmt="<details>__ARTEFACT_SUMMARY____ARTEFACT_DETAILS__</details>"

function print_br_item() {
format="${1}"
item="${2}"
echo -n "${format//__ITEM__/${item}}<br/>"
}

function print_br_item2() {
format="${1}"
item="${2}"
item2="${3}"
format1="${format//__ITEM__/${item}}"
echo -n "${format1//__ITEM2__/${item2}}<br/>"
}

function print_code_item() {
format="${1}"
item="${2}"
echo -n "<code>${format//__ITEM__/${item}}</code>"
}

function print_dd_item() {
format="${1}"
item="${2}"
echo -n "<dd>${format//__ITEM__/${item}}</dd>"
}

function print_list_item() {
format="${1}"
item="${2}"
echo -n "<li>${format//__ITEM__/${item}}</li>"
}

function print_pre_item() {
format="${1}"
item="${2}"
echo -n "<pre>${format//__ITEM__/${item}}</pre>"
}

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 <code>${job_out_file}</code>"
failure_msg="no job output file <code>${job_out_file}</code>"
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="<summary>$(print_code_item '__ITEM__' ${tarballs})</summary>"
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 $?
11 changes: 9 additions & 2 deletions install_compatibility_layer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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)"
Expand Down
2 changes: 1 addition & 1 deletion test/compat_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9023092

Please sign in to comment.