Skip to content

Commit 39ee30b

Browse files
sawenzelclaude
andcommitted
Harden module setup and async environment handling in anchorMC
This addresses review comments on the 2-tag subshell change. - The modulecmd probe now checks 'bash list' instead of 'savelist', since save/restore is no longer used. - anchorMC_DataEmbedding.sh now uses the same modulecmd resolution as anchorMC.sh. - A failing 'alienv printenv' of the async tag now stops with a clear error. - The embedding script passes env_async.env with the path of the top directory, not the per-timeframe one. - '2&>' is replaced by '&>' when calling async_pass.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 6d163ef commit 39ee30b

2 files changed

Lines changed: 63 additions & 9 deletions

File tree

MC/run/ANCHOR/anchorMC.sh

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export > env_base.env
183183
# The 2-tag / alternative-reco setup below uses 'module purge' to swap the software
184184
# environment inside a subshell. If the shell provides no 'module' function, build
185185
# one on a 'modulecmd' binary. Its location varies by version, so resolve it flexibly
186-
# (was hardwired to /usr/bin/modulecmd) and verify it supports saved collections. Fail
186+
# (was hardwired to /usr/bin/modulecmd) and verify that it runs. Fail
187187
# hard -- but only when an alternative-reco tag is set, since single-tag jobs never call
188188
# 'module' -- instead of silently no-op'ing every 'module' call (cf. O2-7070).
189189
# The candidate list also resolves symlinks ('readlink -f') and probes the canonical
@@ -198,7 +198,7 @@ if ! declare -F module > /dev/null; then
198198
"${MODULESHOME:+${MODULESHOME}/libexec/modulecmd}" \
199199
"$(readlink -f /usr/bin/modulecmd 2>/dev/null)" \
200200
/usr/share/Modules/libexec/modulecmd* /usr/share/Modules/*/libexec/modulecmd*; do
201-
if [ -n "${_cand}" ] && [ -x "${_cand}" ] && "${_cand}" bash savelist > /dev/null 2>&1; then
201+
if [ -n "${_cand}" ] && [ -x "${_cand}" ] && "${_cand}" bash list > /dev/null 2>&1; then
202202
MODULECMD_BIN="${_cand}"
203203
break
204204
fi
@@ -207,7 +207,7 @@ if ! declare -F module > /dev/null; then
207207
echo_info "Using modulecmd at ${MODULECMD_BIN}"
208208
elif [ "${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}" ]; then
209209
echo_error "Alternative-reco (2-tag) requested (ALIEN_JDL_O2DPG_ASYNC_RECO_TAG=${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG})"
210-
echo_error "but no 'modulecmd' supporting saved collections (save/restore) was found."
210+
echo_error "but no working 'modulecmd' (needed for 'module purge') was found."
211211
echo_error " Looked at: \$MODULECMD='${MODULECMD}', /usr/bin/modulecmd (+readlink -f), PATH,"
212212
echo_error " \$MODULESHOME/libexec/modulecmd, /usr/share/Modules/{,*/}libexec/modulecmd*."
213213
echo_error " Diagnostics: MODULESHOME='${MODULESHOME}' /usr/bin/modulecmd -> '$(readlink -f /usr/bin/modulecmd 2>/dev/null)' PATH='${PATH}'"
@@ -246,7 +246,13 @@ fi
246246
module purge --no-pager
247247
fi
248248
echo_info "Using tag ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG} to setup anchored MC"
249-
/cvmfs/alice.cern.ch/bin/alienv printenv "${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}" &> async_environment.env
249+
/cvmfs/alice.cern.ch/bin/alienv printenv "${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}" > async_environment.env 2> async_environment.err
250+
# alienv printenv returns 0 also for an unknown tag, so check its output instead
251+
if [ ! -s async_environment.env ] || grep -q "ERROR" async_environment.err; then
252+
echo_error "Could not set up the software environment for ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}:"
253+
cat async_environment.err
254+
exit 1
255+
fi
250256
source async_environment.env
251257
export > env_async.env
252258
fi
@@ -285,7 +291,7 @@ fi
285291
touch list.list
286292

287293
# run the async_pass.sh and store output to log file for later inspection and extraction of information
288-
./async_pass.sh ${CTF_TEST_FILE:-""} 2&> async_pass_log.log
294+
./async_pass.sh ${CTF_TEST_FILE:-""} &> async_pass_log.log
289295
RECO_RC=$?
290296

291297
echo_info "async_pass.sh finished with ${RECO_RC}"

MC/run/ANCHOR/anchorMC_DataEmbedding.sh

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,48 @@ fi
178178

179179
export > env_base.env
180180

181+
# The 2-tag / alternative-reco setup below uses 'module purge' to swap the software
182+
# environment inside a subshell. If the shell provides no 'module' function, build
183+
# one on a 'modulecmd' binary. Its location varies by version, so resolve it flexibly
184+
# (was hardwired to /usr/bin/modulecmd) and verify that it runs. Fail
185+
# hard -- but only when an alternative-reco tag is set, since single-tag jobs never call
186+
# 'module' -- instead of silently no-op'ing every 'module' call (cf. O2-7070).
187+
# The candidate list also resolves symlinks ('readlink -f') and probes the canonical
188+
# environment-modules install (/usr/share/Modules): on some HPC/container setups
189+
# /usr/bin/modulecmd is a *dangling* symlink (-> /etc/alternatives -> the real .tcl),
190+
# which exec's as "No such file or directory"; this recovers when the real binary is
191+
# still reachable, and otherwise still fails hard (a genuinely missing Modules tree in
192+
# the job's mount namespace is a site-side problem).
181193
if ! declare -F module > /dev/null; then
194+
MODULECMD_BIN=""
195+
for _cand in "${MODULECMD}" "/usr/bin/modulecmd" "$(command -v modulecmd 2>/dev/null)" \
196+
"${MODULESHOME:+${MODULESHOME}/libexec/modulecmd}" \
197+
"$(readlink -f /usr/bin/modulecmd 2>/dev/null)" \
198+
/usr/share/Modules/libexec/modulecmd* /usr/share/Modules/*/libexec/modulecmd*; do
199+
if [ -n "${_cand}" ] && [ -x "${_cand}" ] && "${_cand}" bash list > /dev/null 2>&1; then
200+
MODULECMD_BIN="${_cand}"
201+
break
202+
fi
203+
done
204+
if [ -n "${MODULECMD_BIN}" ]; then
205+
echo_info "Using modulecmd at ${MODULECMD_BIN}"
206+
elif [ "${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}" ]; then
207+
echo_error "Alternative-reco (2-tag) requested (ALIEN_JDL_O2DPG_ASYNC_RECO_TAG=${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG})"
208+
echo_error "but no working 'modulecmd' (needed for 'module purge') was found."
209+
echo_error " Looked at: \$MODULECMD='${MODULECMD}', /usr/bin/modulecmd (+readlink -f), PATH,"
210+
echo_error " \$MODULESHOME/libexec/modulecmd, /usr/share/Modules/{,*/}libexec/modulecmd*."
211+
echo_error " Diagnostics: MODULESHOME='${MODULESHOME}' /usr/bin/modulecmd -> '$(readlink -f /usr/bin/modulecmd 2>/dev/null)' PATH='${PATH}'"
212+
exit 1
213+
else
214+
echo_info "No 'modulecmd' found, but no alternative-reco tag is set, so 'module' is not needed; continuing."
215+
fi
216+
export MODULECMD_BIN
182217
module() {
183-
eval "$(/usr/bin/modulecmd bash "$@")";
218+
if [ -z "${MODULECMD_BIN}" ]; then
219+
echo_error "'module ${*}' invoked but no usable 'modulecmd' was found (see earlier diagnostics)."
220+
return 127
221+
fi
222+
eval "$("${MODULECMD_BIN}" bash "$@")";
184223
}
185224
export -f module
186225
fi
@@ -205,7 +244,13 @@ fi
205244
module purge --no-pager
206245
fi
207246
echo_info "Using tag ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG} to setup anchored MC"
208-
/cvmfs/alice.cern.ch/bin/alienv printenv "${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}" &> async_environment.env
247+
/cvmfs/alice.cern.ch/bin/alienv printenv "${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}" > async_environment.env 2> async_environment.err
248+
# alienv printenv returns 0 also for an unknown tag, so check its output instead
249+
if [ ! -s async_environment.env ] || grep -q "ERROR" async_environment.err; then
250+
echo_error "Could not set up the software environment for ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}:"
251+
cat async_environment.err
252+
exit 1
253+
fi
209254
source async_environment.env
210255
export > env_async.env
211256
fi
@@ -244,7 +289,7 @@ fi
244289
touch list.list
245290

246291
# run the async_pass.sh and store output to log file for later inspection and extraction of information
247-
./async_pass.sh ${CTF_TEST_FILE:-""} 2&> async_pass_log.log
292+
./async_pass.sh ${CTF_TEST_FILE:-""} &> async_pass_log.log
248293
RECO_RC=$?
249294

250295
echo_info "async_pass.sh finished with ${RECO_RC}"
@@ -266,6 +311,9 @@ export ALIEN_JDL_LPMPRODUCTIONTAG=$ALIEN_JDL_LPMPRODUCTIONTAG_KEEP
266311
echo_info "Setting back ALIEN_JDL_LPMPRODUCTIONTAG to $ALIEN_JDL_LPMPRODUCTIONTAG"
267312
#<----- END OF part that should run under a clean alternative software environment if this was given ------
268313

314+
# the async software environment, referenced from within the per-timeframe workspaces below
315+
ASYNC_ENV_FILE=${PWD}/env_async.env
316+
269317
# now create the local MC config file --> config-json.json
270318
# we create the new config output with blacklist functionality
271319
ASYNC_CONFIG_BLACKLIST=${ASYNC_CONFIG_BLACKLIST:-${O2DPG_ROOT}/MC/run/ANCHOR/anchor-dpl-options-blacklist.json}
@@ -346,7 +394,7 @@ for external_context in collission_context_*.root; do
346394
# apply software tagging choice
347395
# remainingargs="${remainingargs} ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG:+--alternative-reco-software ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG}}"
348396
ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE=${ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE:-RECO}
349-
remainingargs="${remainingargs} ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG:+--alternative-reco-software ${PWD}/env_async.env@${ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE}}"
397+
remainingargs="${remainingargs} ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG:+--alternative-reco-software ${ASYNC_ENV_FILE}@${ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE}}"
350398
# potentially add CCDB timemachine timestamp
351399
remainingargs="${remainingargs} ${ALIEN_JDL_CCDB_CONDITION_NOT_AFTER:+--condition-not-after ${ALIEN_JDL_CCDB_CONDITION_NOT_AFTER}}"
352400
# add external collision context injection

0 commit comments

Comments
 (0)