]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - PWGPP/QA/scripts/alienSync.sh
Merge branch 'feature-movesplit'
[u/mrichter/AliRoot.git] / PWGPP / QA / scripts / alienSync.sh
index 7bc2e22bb26fd6a61c2b48940e0ac20ec03a5d43..92aa5f2429c44a5a33b209b629db69be678d6e29 100755 (executable)
@@ -6,25 +6,44 @@
 #    (the local chache location and paths can be manipulated.)
 #  - needs a configured config file (by default alienSync.config)
 #    and a working alien environment (token and at least $ALIEN_DIR or $ALIEN_ROOT set)
+#  - can be also used without a config file
+#  
+# run the script without argument to see the examples
 #
 #  origin: Mikolaj Krzewicki, mikolaj.krzewicki@cern.ch
 #
+if [ ${BASH_VERSINFO} -lt 4 ]; then
+  echo "bash version >= 4 needed, you have ${BASH_VERSION}, exiting..."
+  exit 1
+fi
+
 main()
 {
   if [[ $# -lt 1 ]]; then
-    echo Usage: $0 configFile
+    echo "Usage:  ${0##*/} configFile=/path/to/config"
+    echo "expert: ${0##*/} alienFindCommand=\"alien_find /some/path/ file\" [opt=value]"
+    echo "        ${0##*/} alienFindCommand=\"alien_find /some/path/ file\" localPathPrefix=\${PWD}"
+    echo
+    echo "by default files are downloaded to current dir, or \${alienSync_localPathPrefix}, if set."
+    echo "At least specify alienFindCommand, either on command line or in the configFile."
+    echo "the logs go by default to localPathPrefix/alienSyncLogs"
     return
   fi
+  
+  #be nice and allow group members access as well (002 will create dirs with 775 and files with 664)
+  umask 0002
 
   # try to load the config file
-  [[ ! -f $1 ]] && echo "config file $1 not found, exiting..." | tee -a $logFile && exit 1
-  source $1
-  
+  #[[ ! -f $1 ]] && echo "config file $1 not found, exiting..." | tee -a $logFile && exit 1
+  if ! parseConfig "$@"; then return 1; fi
+
+  [[ -z ${alienFindCommand} ]] && echo "alienFindCommand not defined!" && return 1
+
   #if not set, use the default group
   [[ -z ${alienSyncFilesGroupOwnership} ]] && alienSyncFilesGroupOwnership=$(id -gn)
 
   # do some accounting
-  [[ ! -d $logOutputPath ]] && echo "logOutputPath not available, creating..." && sg ${alienSyncFilesGroupOwnership} "mkdir -p $logOutputPath"
+  [[ ! -d $logOutputPath ]] && echo "logOutputPath not available, creating..." && mkdir -p $logOutputPath && chgrp ${alienSyncFilesGroupOwnership} ${logOutputPath}
   [[ ! -d $logOutputPath ]] && echo "could not create log dir, exiting..." && exit 1
   dateString=$(date +%Y-%m-%d-%H-%M)
   logFile=$logOutputPath/alienSync-$dateString.log
@@ -32,12 +51,9 @@ main()
   echo ""|tee -a $logFile
   echo log: $logFile
   
-  #be nice and allow group members access as well (002 will create dirs with 775 and files with 664)
-  umask 0002
-
   #lock
   lockFile=$logOutputPath/runningNow.lock
-  [[ -f $lockFile ]] && echo "locked. Another process running? ($lockFile)" | tee -a $logFile && exit 1
+  [[ -f $lockFile && ${allowConcurrent} -ne 1 ]] && echo "locked. Another process running? ($lockFile)" | tee -a $logFile && exit 1
   touch $lockFile
   [[ ! -f $lockFile ]] && echo "unable to create lock. exiting..." | tee -a $logFile && exit 1
 
@@ -46,7 +62,7 @@ main()
     exec 6>&1
     exec 1>$logFile 2>&1
   fi
-
+  
   newFilesList=$logOutputPath/"newFiles.list"
   rm -f $newFilesList
   touch $newFilesList
@@ -54,6 +70,9 @@ main()
   rm -f $redoneFilesList
   touch $redoneFilesList
   updatedFilesList="${logOutputPath}/updatedFiles.list"
+  failedDownloadList="${logOutputPath}/failedDownload.list"
+  touch ${failedDownloadList}
+
 
   # check the config
   [[ -z $alienFindCommand ]] && echo "alienFindCommand not defined, exiting..." && exitScript 1
@@ -146,6 +165,12 @@ main()
     destinationdir=${destination%/*}
     [[ -n $softLinkName ]] && softlinktodestination=${destinationdir}/${softLinkName}
     tmpdestination="${destination}.aliensyncTMP"
+    
+    #if we allow concurrent running (DANGEROUS) check if somebody is already trying to process this file
+    if [[ -f ${tmpdestination} && ${allowConcurrent} -eq 1 ]]; then 
+      echo "$tmpdestination exists - concurrent donwload? skipping..."
+      continue
+    fi
 
     if [[ -n ${destinationModifyCommand} ]]; then
       #find the candidate in the database, in case there are more files trying to go to the same
@@ -159,7 +184,7 @@ main()
       originalEntryIndex=${candidateDBrecord[0]}
       [[ $lineNumber -ne $originalEntryIndex ]] && continue
     fi
-
+    
     redownloading=""
     if [[ -f ${destination} ]]; then
       #soft link the downloaded file (maybe to provide a consistent link to the latest version)
@@ -176,8 +201,7 @@ main()
       [[ "$md5local" =~ "." ]] && md5local=""
 
       if [[ $forceLocalMD5recalculation -eq 1 || -z $md5local ]]; then
-        tmparrayMD5=($(md5sum ${destination}))
-        md5recalculated=${tmparrayMD5[0]}
+        md5recalculated=$(checkMD5sum ${destination})
         [[ "$md5local" != "$md5recalculated" ]] && echo "WARNING: local copy change ${destination}"
         md5local=${md5recalculated}
       fi
@@ -202,7 +226,7 @@ main()
     
     [[ -f $tmpdestination ]] && echo "WARNING: stale $tmpdestination, removing" && rm $tmpdestination
     
-    sg ${alienSyncFilesGroupOwnership} "mkdir -p ${destinationdir}"
+    mkdir -p ${destinationdir} && chgrp ${alienSyncFilesGroupOwnership} ${destinationdir}
     [[ ! -d $destinationdir ]] && echo cannot access $destinationdir && continue
 
     #check token
@@ -210,9 +234,8 @@ main()
     #  $ALIEN_ROOT/api/bin/alien-token-init $alienUserName
     #  #source /tmp/gclient_env_$UID
     #fi
-
+    
     export copyMethod
-    export copyScript
     export copyTimeout
     export copyTimeoutHard
     echo copyFromAlien "$alienFile" "$tmpdestination"
@@ -227,7 +250,8 @@ main()
     downloadOK=0
     #verify the downloaded md5 if available, validate otherwise...
     if [[ -n $md5alien ]]; then
-      if (echo "$md5alien  $tmpdestination"|md5sum -c --status -); then
+      md5recalculated=$(checkMD5sum ${tmpdestination})
+      if [[ ${md5alien} == ${md5recalculated} ]]; then
         echo "OK md5 after download"
         downloadOK=1
       else
@@ -262,32 +286,39 @@ main()
         echo ${destination} >> $localFileList
       fi
       [[ -n ${postCommand} ]] && ( cd ${destinationdir}; eval "${postCommand}" )
+      if grep -q ${alienFile} ${failedDownloadList}; then
+        echo "removing ${alienFile} from ${failedDownloadList}"
+        grep -v ${alienFile} ${failedDownloadList} >tmpUpdatedFailed
+        mv tmpUpdatedFailed ${failedDownloadList}
+      fi
     else
       echo "download not validated, NOT moving to ${destination}..."
       echo "removing $tmpdestination"
       rm -f $tmpdestination
+      echo ${alienFile} >> ${failedDownloadList}
       continue
     fi
 
+    [[ -f $tmpdestination ]] && echo "WARNING: tmpdestination should not still be here! removing..." && rm -r ${tmpdestination}
+
     if [[ $unzipFiles -eq 1 ]]; then
-      echo unzip $tmpdestination -d $destinationdir
-      unzip $tmpdestination -d $destinationdir
+      echo unzip -o ${destination} -d ${destinationdir}
+      unzip -o ${destination} -d ${destinationdir}
     fi
 
     echo
   done < ${alienFileListCurrent}
 
   [[ $alienFileCounter -gt 0 ]] && mv -f $alienFileListCurrent $localAlienDatabase
-  
-  echo ${0##*/} DONE
+
+  echo "${0##*/} DONE"
  
   if [[ $allOutputToLog -eq 1 ]]; then
     exec 1>&6 6>&-
   fi
  
   cat ${newFilesList} ${redoneFilesList} > ${updatedFilesList}
-  eval "${executeEnd}"
-
+  
   echo alienFindCommand:
   echo "  $alienFindCommand"
   echo
@@ -302,8 +333,25 @@ main()
   echo "redone files:"
   echo
   cat $redoneFilesList
+  echo
+  echo
+  
+  #output the list of failed files to stdout, so the cronjob can mail it
+  echo '###############################'
+  echo "failed to download from alien:"
+  echo
+  local tmpfailed=$(mktemp)
+  [[ "$(cat ${failedDownloadList} | wc -l)" -gt 0 ]] && sort ${failedDownloadList} | uniq -c | awk 'BEGIN{print "#tries\t file" }{print $1 "\t " $2}' | tee ${tmpfailed}
+  
+  [[ -n ${MAILTO} ]] && echo $logFile | mail -s "alienSync ${alienFindCommand} done" ${MAILTO}
 
-  [[ -n $sendMailTo ]] && echo $logFile | mail -s "alienSync $alienFindCommand done" $sendMailTo
+  if [[ -n ${executeEnd} ]]; then
+    echo
+    echo
+    echo '###############################'
+    echo "eval ${executeEnd}"
+    eval "${executeEnd}"
+  fi
 
   exitScript 0
 }
@@ -321,7 +369,7 @@ exitScript()
 alien_find()
 {
   # like a regular alien_find command
-  # output is a list with md5sums and ctimes
+  # output is a list with md5 sums and ctimes
   executable="$ALIEN_ROOT/api/bin/gbbox find"
   [[ ! -x ${executable% *} ]] && echo "### error, no $executable..." && return 1
   [[ -z $logOutputPath ]] && logOutputPath="./"
@@ -456,12 +504,88 @@ copyFromAlien()
   src="alien://${src}"
   dst=$2
   if [[ "$copyMethod" == "tfilecp" ]]; then
-    echo timeout $copyTimeout root -b -q "$copyScript(\"$src\",\"$dst\")"
-    timeout $copyTimeout root -b -q "$copyScript(\"$src\",\"$dst\")"
+    if which timeout &>/dev/null; then
+      echo timeout $copyTimeout "TFile::Cp(\"$src\",\"$dst\")"
+      timeout $copyTimeout root -b <<EOF
+TGrid::Connect("alien://");
+TFile::Cp("${src}","${dst}");
+EOF
+
+    else
+      echo "TFile::Cp(\"$src\",\"$dst\")"
+      root -b <<EOF
+TGrid::Connect("alien://");
+TFile::Cp("${src}","${dst}");
+EOF
+    fi
   else
-    echo timeout $copyTimeout $ALIEN_ROOT/api/bin/alien_cp $src $dst
-    timeout $copyTimeout $ALIEN_ROOT/api/bin/alien_cp $src $dst
+    if which timeout &>/dev/null; then
+      echo timeout $copyTimeout $ALIEN_ROOT/api/bin/alien_cp $src $dst
+      timeout $copyTimeout $ALIEN_ROOT/api/bin/alien_cp $src $dst
+    else
+      echo $ALIEN_ROOT/api/bin/alien_cp $src $dst
+      $ALIEN_ROOT/api/bin/alien_cp $src $dst
+    fi
+  fi
+}
+
+parseConfig()
+{
+  #config file
+  configFile=""
+  alienFindCommand=""
+  secondsToSuicide=$(( 10*3600 ))
+  localPathPrefix="${PWD}"
+  #define alienSync_localPathPrefix in your env to have a default central location
+  [[ -n ${alienSync_localPathPrefix} ]] && localPathPrefix=${alienSync_localPathPrefix}
+  unzipFiles=0
+  allOutputToLog=0
+
+  args=("$@")
+
+  #first, check if the config file is configured
+  #is yes - source it so that other options can override it
+  #if any
+  for opt in "${args[@]}"; do
+    if [[ ${opt} =~ configFile=.* ]]; then
+      eval "${opt}"
+      [[ ! -f ${configFile} ]] && echo "configFile ${configFile} not found, exiting..." && return 1
+      echo "using config file: ${configFile}"
+      source "${configFile}"
+      break
+    fi
+  done
+
+  #then, parse the options as they override the options from file
+  for opt in "${args[@]}"; do
+    if [[ ! "${opt}" =~ .*=.* ]]; then
+      echo "badly formatted option ${var}, should be: option=value, stopping..."
+      return 1
+    fi
+    local var="${opt%%=*}"
+    local value="${opt#*=}"
+    echo "${var} = ${value}"
+    export ${var}="${value}"
+  done
+
+  #things that by default depend on other variables should be set here, after the dependencies
+  [[ -z ${logOutputPath} ]] && logOutputPath="${localPathPrefix}/alienSyncLogs"
+  return 0
+}
+
+checkMD5sum()
+{
+  local file="${1}"
+  local md5=""
+  [[ ! -f ${file} ]] && return 1
+  if which md5sum &>/dev/null; then
+    local tmp=($(md5sum ${file}))
+    md5=${tmp[0]}
+  elif which md5 &>/dev/null; then
+    local tmp=($(md5 ${file}))
+    md5=${tmp[3]}
   fi
+  echo ${md5}
 }
 
 main "$@"