Skip to content

Commit

Permalink
use alternative approach to remove software to be rebuilt
Browse files Browse the repository at this point in the history
  • Loading branch information
truib committed Nov 13, 2024
1 parent a83cde8 commit 16dce19
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 24 deletions.
123 changes: 123 additions & 0 deletions EESSI-determine-rebuilds.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/bin/bash
#
# Script to determine which parts of the EESSI software stack (version set through init/eessi_defaults)
# have to be rebuilt

# 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
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
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 --dry-run-short --rebuild --easystack ${easystack_file} | grep "^ \* \[R\]" | grep -o "module: .*[^)]" | awk '{print $2}')
for app in ${rebuild_apps}; do
app_dir=${EASYBUILD_INSTALLPATH}/software/${app}
app_module=${EASYBUILD_INSTALLPATH}/modules/all/${app}.lua
echo_yellow "Removing ${app_dir} and ${app_module}..."
find ${app_dir} -type d | sed -e 's/^/REMOVE_DIRECTORY /'
find ${app_dir} -type f | sed -e 's/^/REMOVE_FILE /'
echo "REMOVE_MODULE ${app_module}"
done
else
fatal_error "Easystack file ${easystack_file} not found!"
fi
done
fi
13 changes: 9 additions & 4 deletions EESSI-remove-software.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,26 @@ if [ $EUID -eq 0 ]; then
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..."
echo_green "Software rebuild(s) requested in ${easystack_file}, so"
echo_green " determining which existing installation have to be removed (assuming contents"
echo_green " have been made writable/deletable)..."
# 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}')
# 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}')
rebuild_apps=$(eb --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_module=${app_installprefix}/modules/all/${app}.lua
# app_dir=${EASYBUILD_INSTALLPATH}/software/${app}
# app_module=${EASYBUILD_INSTALLPATH}/modules/all/${app}.lua
echo_yellow "Removing ${app_dir} and ${app_module}..."
rm -rf ${app_dir}
rm -rf ${app_module}
rm -rdfv ${app_dir}
rm -rdfv ${app_module}
done
else
fatal_error "Easystack file ${easystack_file} not found!"
Expand Down
50 changes: 49 additions & 1 deletion bot/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,49 @@ changed_easystacks_rebuilds=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed
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
# determine which software packages (and modules) have to be removed
TARBALL_TMP_DETERMINE_STEP_DIR=${PREVIOUS_TMP_DIR}/determine_step
mkdir -p ${TARBALL_TMP_DETERMINE_STEP_DIR}

# prepare arguments to eessi_container.sh specific to determine step
declare -a DETERMINE_STEP_ARGS=()
DETERMINE_STEP_ARGS+=("--save" "${TARBALL_TMP_DETERMINE_STEP_DIR}")
DETERMINE_STEP_ARGS+=("--storage" "${STORAGE}")

# create tmp file for output of determine step
determine_outerr=$(mktemp determine.outerr.XXXX)

echo "Executing command to determine software to be removed:"
echo "${software_layer_dir}/eessi_container.sh ${COMMON_ARGS[@]} ${DETERMINE_STEP_ARGS[@]}"
echo " -- ${software_layer_dir}/EESSI-determine-rebuilds.sh \"${DETERMINE_SCRIPT_ARGS[@]}\" \"$@\" 2>&1 | tee -a ${determine_outerr}"
${software_layer_dir}/eessi_container.sh "${COMMON_ARGS[@]}" "${DETERMINE_STEP_ARGS[@]}" \
-- ${software_layer_dir}/EESSI-determine-rebuilds.sh "${DETERMINE_SCRIPT_ARGS[@]}" "$@" 2>&1 | tee -a ${determine_outerr}

# process output file
# for each line containing 'REMOVE_DIRECTORY some_path'
# create a new directory ${STORAGE}/lower_dirs/some_path_stripped
# where the prefix /cvmfs/repo_name is removed from some_path
# set permission of the directory to u+rwx
# for each line containing 'REMOVE_FILE some_file_path'
# touch a new file ${STORAGE}/lower_dirs/some_file_path_stripped
# where the prefix /cvmfs/repo_name is removed from some_file_path
# set permission of the file to u+rw

LOWER_DIRS="${STORAGE}/lower_dirs"
mkdir -p "${LOWER_DIRS}"

grep ^REMOVE_DIRECTORY ${determine_outerr} | cut -f4- -d'/' > ${determine_outerr}.rm_dirs
cat ${determine_outerr}.rm_dirs | while read remove_dir; do
mkdir -p ${STORAGE}/lower_dirs/${remove_dir}
chmod u+rwx ${STORAGE}/lower_dirs/${remove_dir}
done

grep ^REMOVE_FILE ${determine_outerr} | cut -f4- -d'/' > ${determine_outerr}.rm_files
cat ${determine_outerr}.rm_files | while read remove_file; do
touch ${STORAGE}/lower_dirs/${remove_file}
chmod u+rw ${STORAGE}/lower_dirs/${remove_file}
done

# 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}
Expand All @@ -208,9 +251,14 @@ else
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")
# REMOVAL_STEP_ARGS+=("--fakeroot")

if [[ ! -z ${LOWER_DIRS} ]]; then
REMOVAL_STEP_ARGS+=("--lower-dirs" "${LOWER_DIRS}")
fi

# create tmp file for output of removal step
removal_outerr=$(mktemp remove.outerr.XXXX)
Expand Down
54 changes: 35 additions & 19 deletions eessi_container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ display_help() {
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 " -o | --lower-dirs DIRS - list of ':' separated directories that are used"
echo " in front of the default lower dir (CVMFS repo);"
echo " fuse-overlayfs will merge all lower directories;"
echo " the option can be used to make certain directories"
echo " in the CVMFS repo writable [default: none]"
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"
Expand Down Expand Up @@ -125,6 +130,7 @@ FAKEROOT=0
VERBOSE=0
STORAGE=
LIST_REPOS=0
LOWER_DIRS=
MODE="shell"
SETUP_NVIDIA=0
REPOSITORIES=()
Expand Down Expand Up @@ -182,6 +188,10 @@ while [[ $# -gt 0 ]]; do
NVIDIA_MODE="$2"
shift 2
;;
-o|--lower-dirs)
LOWER_DIRS="$2"
shift 2
;;
-r|--repository)
REPOSITORIES+=("$2")
shift 2
Expand Down Expand Up @@ -753,10 +763,10 @@ do
echo " left-most directory in 'lowerdir' argument for fuse-overlayfs."

lowerdirs=/cvmfs_ro/${cvmfs_repo_name}
# check if there are more overlay-upper directories, e.g., with three digit suffix
for dir in $(ls ${EESSI_TMPDIR}/${cvmfs_repo_name} | grep -E "overlay-upper-[0-9]{3}" | cut -f3 -d- | sort -n); do
lowerdirs=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper-${dir}:${lowerdirs}
done
# # check if there are more overlay-upper directories, e.g., with three digit suffix
# for dir in $(ls ${EESSI_TMPDIR}/${cvmfs_repo_name} | grep -E "overlay-upper-[0-9]{3}" | cut -f3 -d- | sort -n); do
# lowerdirs=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper-${dir}:${lowerdirs}
# done
# finally add most recent overlay-upper to lowerdirs
lowerdirs=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper:${lowerdirs}
[[ ${VERBOSE} -eq 1 ]] && ls ${EESSI_TMPDIR}/${cvmfs_repo_name}
Expand Down Expand Up @@ -791,21 +801,21 @@ do
# starting with the lowest number first and preprending it to the lowerdir
# setting
lowerdirs=/cvmfs_ro/${cvmfs_repo_name}
if [ -d ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper ]; then
# determine next sequence number
last_seq_num=$(ls ${EESSI_TMPDIR}/${cvmfs_repo_name} | grep -E "overlay-upper-[0-9]{3}" | cut -f3 -d- | sort -n | tail -n 1 | sed -e 's/^0*//')
if [ -n ${last_seq_num} ]; then
last_seq_num=0
fi
next_seq_num=$(($last_seq_num + 1))
next_ovl_upper=$(printf "overlay-upper-%03d" ${next_seq_num})
mv ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper ${EESSI_TMPDIR}/${cvmfs_repo_name}/${next_ovl_upper}
for dir in $(ls ${EESSI_TMPDIR}/${cvmfs_repo_name} | grep -E "overlay-upper-[0-9]{3}" | cut -f3 -d- | sort -n); do
lowerdirs=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper-${dir}:${lowerdirs}
done
[[ ${VERBOSE} -eq 1 ]] && ls ${EESSI_TMPDIR}/${cvmfs_repo_name}
[[ ${VERBOSE} -eq 1 ]] && echo ${lowerdirs}
fi
# if [ -d ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper ]; then
# # determine next sequence number
# last_seq_num=$(ls ${EESSI_TMPDIR}/${cvmfs_repo_name} | grep -E "overlay-upper-[0-9]{3}" | cut -f3 -d- | sort -n | tail -n 1 | sed -e 's/^0*//')
# if [ -n ${last_seq_num} ]; then
# last_seq_num=0
# fi
# next_seq_num=$(($last_seq_num + 1))
# next_ovl_upper=$(printf "overlay-upper-%03d" ${next_seq_num})
# mv ${EESSI_TMPDIR}/${cvmfs_repo_name}/overlay-upper ${EESSI_TMPDIR}/${cvmfs_repo_name}/${next_ovl_upper}
# for dir in $(ls ${EESSI_TMPDIR}/${cvmfs_repo_name} | grep -E "overlay-upper-[0-9]{3}" | cut -f3 -d- | sort -n); do
# lowerdirs=${TMP_IN_CONTAINER}/${cvmfs_repo_name}/overlay-upper-${dir}:${lowerdirs}
# done
# [[ ${VERBOSE} -eq 1 ]] && ls ${EESSI_TMPDIR}/${cvmfs_repo_name}
# [[ ${VERBOSE} -eq 1 ]] && echo ${lowerdirs}
# fi
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})"
Expand All @@ -816,6 +826,12 @@ do
EESSI_FUSE_MOUNTS+=("--fusemount" "${EESSI_READONLY}")

EESSI_WRITABLE_OVERLAY="container:fuse-overlayfs"
if [[ ! -z ${LOWER_DIRS} ]]; then
# need to convert ':' in LOWER_DIRS to ',' because bind mounts use ',' as
# separator while the lowerdir overlayfs option uses ':'
export BIND_PATHS="${BIND_PATHS},${LOWER_DIRS/:/,}"
lowerdirs=${LOWER_DIRS}:${lowerdirs}"
fi
EESSI_WRITABLE_OVERLAY+=" -o lowerdir=${lowerdirs}"
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"
Expand Down

0 comments on commit 16dce19

Please sign in to comment.