From 07d56c19e28562d70fb9a3ca53388657c7804a39 Mon Sep 17 00:00:00 2001 From: Fabrice Le Goff <fabrice.le.goff@cern.ch> Date: Tue, 26 Sep 2023 15:47:07 +0200 Subject: [PATCH] added noop backend and very basic test for CI --- .gitlab-ci.yml | 9 ++- DeploymentTest/tbed.test.bash | 123 ++++++++++++++++++++++++++++++ DeploymentTest/tbed_noop.cfg | 22 ++++++ Script/cs/StorageBackends/noop.py | 72 +++++++++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) create mode 100755 DeploymentTest/tbed.test.bash create mode 100644 DeploymentTest/tbed_noop.cfg create mode 100644 Script/cs/StorageBackends/noop.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f245087..4c8569f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,5 +17,12 @@ compilation: tags: - cvmfs script: - - source /cvmfs/atlas.cern.ch/repo/sw/tdaq/tools/cmake_tdaq/bin/cm_setup.sh tdaq-09-04-00 + - source /cvmfs/atlas.cern.ch/repo/sw/tdaq/tools/cmake_tdaq/bin/cm_setup.sh tdaq-10-00-00 - python -m compileall . + +basictest: + image: gitlab-registry.cern.ch/atlas-tdaq-software/tdaq_ci:centos7 + tags: + - cvmfs + script: + - DeploymentTest/tbed.test.bash || exit 1 diff --git a/DeploymentTest/tbed.test.bash b/DeploymentTest/tbed.test.bash new file mode 100755 index 0000000..20a3add --- /dev/null +++ b/DeploymentTest/tbed.test.bash @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +DEFAULT_CONFIG=./tbed_noop.cfg + +function usage { + echo "usage: $EXECNAME [path to config file; default: $DEFAULT_CONFIG]" +} + +EXECNAME=`basename $0` +CS_CONFIG_FILE=$DEFAULT_CONFIG +TESTHOST=localhost + +if [ x"$1" != x ]; then + CS_CONFIG_FILE=$1 + shift +fi +if [ x"$1" != x ]; then + echo "error: too many arguments" + usage + exit 1 +fi + +cd `dirname $0` + +running_cs=`ps -ef | grep CastorScript | grep -v -c grep` + +if [ "$running_cs" != "0" ]; then + echo "error: there seems to be some CastorScript running on $TESTHOST" + exit 2 +else + echo "OK: no running CastorScript instances on $TESTHOST" +fi + +SOURCE_DIR=`pwd`/.. +REMOTE_DIR=$(sed -rn "s/^CopyDir: '(.*)'/\1/p" $CS_CONFIG_FILE) +BASEFILENAME="dummy" + +COPY_ENABLED=True +TMP_CE=$(sed -rn "s/^CopyEnabled: (.*)/\1/p" $CS_CONFIG_FILE) +if [[ "x$TMP_CE" != "x" ]]; then + COPY_ENABLED=$TMP_CE +fi + +RECURSIVE_SOURCE=True +TMP_RSF=$(sed -rn "s/^RecursiveSourceFolder: (.*)/\1/p" $CS_CONFIG_FILE) +if [[ "x$TMP_RSF" != "x" ]]; then + RECURSIVE_SOURCE=$TMP_RSF +fi + +TMP_DIR=/tmp/castorscripttest +echo "Cleaning tmp directory: $TMP_DIR" +rm -rf $TMP_DIR +mkdir -p $TMP_DIR/logs + +echo "Creating dummy data files" +for i in `seq 0 7`; do + dd if=/dev/zero of=$TMP_DIR/${BASEFILENAME}$i.data bs=1k count=1 &>/dev/null + if [ $? -ne 0 ]; then + echo "error creating file: $TMP_DIR/${BASEFILENAME}$i.data" + fi +done +mkdir -p $TMP_DIR/subdir1/subdir2 +dd if=/dev/zero of=$TMP_DIR/subdir1/${BASEFILENAME}8.data bs=1k count=1 &>/dev/null +if [ $? -ne 0 ]; then + echo "error creating file: $TMP_DIR/${BASEFILENAME}8.data" +fi +dd if=/dev/zero of=$TMP_DIR/subdir1/subdir2/${BASEFILENAME}9.data bs=1k count=1 &>/dev/null +if [ $? -ne 0 ]; then + echo "error creating file: $TMP_DIR/${BASEFILENAME}9.data" +fi + +echo "Starting CastorScript with config file: $CS_CONFIG_FILE" +source $SOURCE_DIR/script_setup.sh +python -u $SOURCE_DIR/Script/CastorScript.py $CS_CONFIG_FILE &>$TMP_DIR/logs/stdouterr & + +echo "Watching files to transfer" +if [[ $RECURSIVE_SOURCE == True ]]; then + LISTING_COMMAND="find $TMP_DIR -name ${BASEFILENAME}* | sort" +else + LISTING_COMMAND="find $TMP_DIR -maxdepth 1 -name ${BASEFILENAME}* | sort" +fi + +LISTING_OUTPUT=`eval $LISTING_COMMAND` +NL=`echo "$LISTING_OUTPUT" | wc -l` +for i in `seq 0 $NL`; do echo; done +for i in `seq 0 $NL`; do tput cuu1; done + +while [ "x$LISTING_OUTPUT" != x ]; do + echo "$LISTING_OUTPUT" + sleep 1 + + for i in `seq 0 $NL`; do tput cuu1; done + NCOLS=`tput cols` + for i in `seq 0 $NL`; do + for ((i=0; i<NCOLS; i++));do printf " "; done; + echo + done + for i in `seq 0 $((NL-1))`; do tput cuu1; done + + # Check that the CastorScript instance is still running + NB_RUNNING_PROCESSES=`ps -ef | grep "CastorScript.py $CS_CONFIG_FILE" | grep -v grep | wc -l` + if [ $NB_RUNNING_PROCESSES -ne 1 ]; then + echo "number of running CastorScript: $NB_RUNNING_PROCESSES, =!1 => exiting" + exit + fi + + LISTING_OUTPUT=`eval $LISTING_COMMAND` + NL=`echo "$LISTING_OUTPUT" | wc -l` +done + +echo "Stopping CastorScript" +$SOURCE_DIR/ProductionTools/installed/castor.signal 12 + +NB_ERR=$(grep -c -e WARNING -e ERROR -r $TMP_DIR/logs | awk -F: 'BEGIN{sum=0} //{sum += $2} END{print sum}') +echo "number of errors and warnings in the log files: $NB_ERR" + +if [ $NB_ERR -eq 0 ]; then + echo "deleting tmp dir (including logs)" + #rm -rf $TMP_DIR +else + echo "Check logs: grep -e WARNING -e ERROR -r $TMP_DIR/logs" + echo "Don't forget to: rm -rf $TMP_DIR" +fi diff --git a/DeploymentTest/tbed_noop.cfg b/DeploymentTest/tbed_noop.cfg new file mode 100644 index 0000000..9a22a19 --- /dev/null +++ b/DeploymentTest/tbed_noop.cfg @@ -0,0 +1,22 @@ +LogDir: '/tmp/castorscripttest/logs/' +LogLevel: 'debug' +EmailLogList: ['flegoff@cern.ch'] +EmailLogLevel: 'ERROR' +EmailLogSender: 'testcastorscript@cern.ch' + +MainThreadEventTimeout: 1 +ManagerThreadEventTimeout: 1 +CopyThreadEventTimeout: 1 +DeleteThreadEventTimeout: 1 + +BackendModule: 'noop' +SrcDirs: ['/tmp/castorscripttest'] +DataFilePattern: ['*.data',] +CopyDir: '/tmp/castorscripttest' +EOSInstance: 'unused' +TransferTimeout: 1 + +#DBURL: 'oracle://int8r/ATLAS_SFO_T0' +#DBFileTable: 'SFO_TZ_FILE' +#DBLBTable: 'SFO_TZ_LUMIBLOCK' +#DBRunTable: 'SFO_TZ_RUN' diff --git a/Script/cs/StorageBackends/noop.py b/Script/cs/StorageBackends/noop.py new file mode 100644 index 0000000..20d0b4d --- /dev/null +++ b/Script/cs/StorageBackends/noop.py @@ -0,0 +1,72 @@ +import subprocess + +# if this file runs as a script instead of as a module. +# add /../../CastorScript/Script to path so imports keeps working +if __name__=='__main__': + from os.path import dirname, abspath, join + import sys + + # Very crude implementation + SCRIPT_DIR = abspath(join(dirname(__file__), '..','..')) + sys.path.append(SCRIPT_DIR) + +from cs.Tools.utils import adler32 + +def sizechecksum(filename, stager, logger=None): + """ + This still needs to return the size and checksum of the original file + otherwise transfers fail inevitably. + """ + del stager + + ls = subprocess.Popen(['ls', '-l1', filename], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + ret = ls.wait() + ls_output = ls.stdout.read().decode() + + if logger: + logger.debug(ls_output) + + size = checksum = None + if ret == 0: + size = int(ls_output.split()[4]) + checksum = adler32(filename) + + return size, checksum + +def listdir(directory, stager, logger=None): + del directory, stager, logger + return (True, []) + +def migrated(filename, stager, logger=None): + del filename, stager, logger + return True + +def mkdir(directory, stager, logger=None): + del directory, stager, logger + return 0 + +def remove(dstfile, stager, logger=None): + del dstfile, stager, logger + return 0 + +def backgroundcopy(srcfile, dstfile, stager, logger=None): + """ + This still needs to return a process (subprocess object) so it spawns the + simplest process that succeeds. + """ + del srcfile, dstfile, stager, logger # unused args + cp = subprocess.Popen(['true'], stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return cp, cp.pid + +def copystate(proc): + return proc.poll() + +def copystdout(proc): + return proc.stdout.read().decode() + +if __name__=='__main__': + import sys + import cs.StorageBackends.storagetester as storagetester + storagetester.execute(sys.modules[__name__]) -- GitLab