178178
179179export > 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).
181193if ! 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
186225fi
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
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
266311echo_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
271319ASYNC_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