Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
#!/usr/bin/env python3
import os, time, sys, glob, re, smtplib, socket
from email.MIMEText import MIMEText
from traceback import print_exc, format_exc
from datetime import datetime
from subprocess import Popen,PIPE
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

EMAIL = sys.argv[1]
TFILEDONEDIR = sys.argv[2]
COLLECTDIR = sys.argv[3]
ORIGINALDONEDIR =sys.argv[4]

#Constans
PRODUCER_DU_TOP= 90.0  #0% a 100%
PRODUCER_DU_BOT= 50.0  #0% a 100%
WAITTIME = 3600 * 4
EMAILINTERVAL = 15 * 60 # Time between sent emails 
SENDMAIL = "/usr/sbin/sendmail" # sendmail location
HOSTNAME = socket.gethostname().lower()
EXEDIR = os.path.dirname(__file__)
STOP_FILE = "%s/.stop" % EXEDIR

# Control variables
lastEmailSent = 0

# --------------------------------------------------------------------
def logme(msg, *args):
  procid = "[%s/%d]" % (__file__.rsplit("/", 1)[-1], os.getpid())
  print(datetime.now(), procid, msg % args)
  
def getDiskUsage(path):
  fsStats=os.statvfs(path)
  size=fsStats.f_bsize*fsStats.f_blocks
  available=fsStats.f_bavail*fsStats.f_bsize
  used=size-available
  usedPer=float(used)/size
  return (size,available,used,usedPer)
  
def getDirSize(path): 
  import stat
  size=os.stat(path).st_blksize
  for directory,subdirs,files in os.walk(path):
    dStats=os.lstat(directory)
    size+=(dStats[stat.ST_NLINK]-1)*dStats[stat.ST_SIZE]
    for f in files:  
      fStats=os.lstat("%s/%s" % (directory,f))
      fSize=fStats[stat.ST_SIZE]
      size+=fSize
      
  return size
  
def sendmail(body="Hello from producerFileCleanner",subject= "Hello!"):
  scall = Popen("%s -t" % SENDMAIL, shell=True, stdin=PIPE)
  scall.stdin.write("To: %s\n" % EMAIL)
  scall.stdin.write("Subject: producerFileCleaner problem on server %s\n" %
                     HOSTNAME)
  scall.stdin.write("\n") # blank line separating headers from body
  scall.stdin.write("%s\n" % body)
  scall.stdin.close()
  rc = scall.wait()
  if rc != 0:
     logme("ERROR: Sendmail exit with status %s", rc)
  
# --------------------------------------------------------------------    
while True:
  #Check if you need to stop.
  if os.path.exists(STOP_FILE):
    logme("INFO: Stop file found, quitting")
    sys.exit(0)

  try:
    try:
      doneSize=getDirSize(TFILEDONEDIR)
      diskSize,userAvailable,diskUsed,diskPUsage=getDiskUsage(TFILEDONEDIR)
      
    except:
      doneSize=0
      diskSize,userAvailable,diskUsed,diskPUsage=getDiskUsage("/home")
      
    diskPUsage*=100
    if diskPUsage < PRODUCER_DU_TOP:
      time.sleep(WAITTIME)
      continue
      
    quota=int(diskSize*PRODUCER_DU_BOT/100)
    delQuota=diskUsed-quota
    if delQuota > doneSize:
      now = time.time()
      if now - EMAILINTERVAL > lastEmailSent:
        msg="ERROR: Something is filling up the disks, %s does not" \
          " have enough files to get to the Bottom Boundary of" \
          " %.2f%%" % (TFILEDONEDIR,PRODUCER_DU_BOT)
        sendmail(msg)
        lastEmailSent = now
        
      logme("ERROR: Something is filling up the disks, %s does not" \
          " have enough files to get to the Bottom Boundary of" \
          " %.2f%%", TFILEDONEDIR, PRODUCER_DU_BOT)
      
    aDelQuota=0
    FILE_LIST=[]
    for directory,subdirs,files in os.walk(TFILEDONEDIR):
      subdirs.sort()
      for f in sorted(files,key=lambda a: a[a.rfind("_R",1)+2:a.rfind("_R",1)+11]):
        fMatch=re.match(r"(DQM|Playback|Playback_full)_V[0-9]{4}_([0-9a-zA-Z]+)_R([0-9]{9})(_T[0-9]{8}|)\.root",f)
        if fMatch:
          subSystem=fMatch.group(2)
          run=fMatch.group(3)
          destDir="%s/%sxxxx/%sxx/DQM_V0001_%s_R%s.root" % (ORIGINALDONEDIR,run[0:5],run[0:7],subSystem,run)
          fullFName="%s/%s" % (directory,f)
          if os.stat(fullFName).st_size+aDelQuota > delQuota:
            break
          
          FILE_LIST.append(fullFName)
          aDelQuota+=os.stat(fullFName).st_size
          if not os.path.exists(destDir):
            logme("WARNING: No subsystem file in repository %s for"
                  " file %s, deleting any way" % 
                  (ORIGINALDONEDIR, fullFName))
            
    if len(FILE_LIST):
      logme("INFO: Found %d files to be deleted", len(FILE_LIST))
      
    #Cleanning ouput directory
    for directory,subdirs,files in os.walk(COLLECTDIR):
      #no subdiretories allowed in COLLECTDIR the  directory
      if subdirs:
        logme("ERROR: Output directory %s, must not contain"
              " subdirectories, cleanning", COLLECTDIR)
        
      for sd in subdirs:
        fullSdName="%s/%s" % (directory,sd)
        for sdRoot,sdDirs,sdFiles in os.walk(fullSdName,topdown=False):
          for f in sdFiles:
            try:
              os.remove(f)
              logme("INFO: File %s has been removed", f)
            except Exception as e:
              logme("ERROR: Problem deleting file: [Errno %d] %s, '%s'",
                      e.errno, e.strerror, e.filename)
              
          try:
            os.removedir(sdRoot)
            logme("INFO: File %s has been removed" , sdRoot)
          except Exception as e:
            logme("ERROR: Problem deleting directory: [Errno %d] %s, '%s'",
                      e.errno, e.strerror, e.filename)
                      
      for f in files:
        if re.match(r"(DQM|Playback|Playback_full)_V[0-9]{4}_([a-zA-Z]+)_R([0-9]{9})_T[0-9]{8}\.root", f):
          continue
          
        if re.match(r".*\.tmp",f):
          continue
          
        fullFName="%s/%s" % (directory, f)
        FILE_LIST.append(fullFName)
        
      #cleaning tmp files:
      TMP_LIST=glob.glob("%s/*.tmp" % COLLECTDIR)
      TMP_LIST.sort(reverse=True,key=lambda x: os.stat(x).st_mtime)
      len(TMP_LIST) > 0 and TMP_LIST.pop(0)
      FILE_LIST.extend(TMP_LIST)
      
    #remove files
    DIR_LIST=[]
    for f in FILE_LIST:
      try:
        os.remove(f)
        logme("INFO: File %s has been removed", f)
      except Exception as e:
        logme("ERROR: Problem deleting file: [Errno %d] %s, '%s'",
                e.errno, e.strerror, e.filename)
      if os.path.dirname(f) not in DIR_LIST and COLLECTDIR not in os.path.dirname(f):
        DIR_LIST.append(os.path.dirname(f))
        
    #remove emprty directories
    for d in DIR_LIST:
      try:
        os.removedirs(d)
        logme("INFO: Directory %s has been removed", d)
      except Exception as e:
        logme("ERROR: Directory delition failed: [Errno %d] %s, '%s'",
                e.errno, e.strerror, e.filename)

  except KeyboardInterrupt as e:
    sys.exit(0)

  except Exception as e:
    logme('ERROR: %s', e)
    sendmail ('ERROR: %s\n%s' % (e, format_exc()))
    now = time.time()
    if now - EMAILINTERVAL > lastEmailSent:
      sendmail ('ERROR: %s\n%s' % (e, format_exc()))
      lastEmailSent = now
    
    print_exc() 
  
  time.sleep(WAITTIME)