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
#!/usr/bin/env python3
'''
Main Script to run all SiStrip DAQ O2Os at the same time.
@author: Huilin Qu
'''

import os
import sys
import atexit
import logging
import argparse
import subprocess
import traceback
import json
from functools import partial

import CondTools.SiStrip.o2o_helper as helper

logDirVar = 'O2O_LOG_FOLDER'

def run(args):
    logging.debug(args)

    is_ok = True
    status = {}
    processes = {}

    for analyzer in args.analyzers:
        o2ocmd = 'SiStripDAQPopCon.py {analyzer} {since} {cfgfile}'.format(
            analyzer=analyzer, since=args.since, cfgfile=args.cfgfile)
        o2ocmd += ' --destTags {destTags}'
        o2ocmd += ' --destDb {destDb}'
        o2ocmd += ' --inputTag {inputTag}'
        o2ocmd += ' --condDbRead {condDbRead}'
        o2ocmd += ' --hashmapDb {hashmapDb}'
        if args.skiplistFile:
            o2ocmd += ' --skiplistFile %s' % args.skiplistFile
        if args.whitelistFile:
            o2ocmd += ' --whitelistFile %s' % args.whitelistFile
        if args.debug:
            o2ocmd += ' --debug'

        jobname = analyzer.replace('O2O', '')
        cmd = 'o2o --db {db} -v run -n {jobname} "{o2ocmd}"'.format(db=args.db, jobname=jobname, o2ocmd=o2ocmd)
        logging.info('Start running command:\n %s' % cmd)

        processes[jobname] = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        atexit.register(partial(helper.kill_subproc_noexcept, processes[jobname]))

    for jobname in processes:
        status[jobname] = {'job':None, 'upload':None, 'fast':None, 'changed':None}
        p = processes[jobname]
        log = p.communicate()[0].decode()
        logging.debug('=== log from o2o run ===\n%s' % log)
        if p.returncode == 0:
            logging.info('Job for %s finished successfully!' % jobname)
            status[jobname]['job'] = True
            status[jobname]['upload'] = True
            for line in log.split('\n'):
                if '@@@' not in line:
                    continue
                if 'FastO2O' in line:
                    status[jobname]['fast'] = ('true' in line)
                if 'PayloadChange' in line:
                    status[jobname]['changed'] = ('true' in line)
        else:
            logging.error('Job %s FAILED!' % jobname)
            status[jobname]['job'] = '@@@CMSSW job return code = 0@@@' in log
            status[jobname]['upload'] = '@@@Upload return code = 0@@@' in log
            is_ok = False
            
    return is_ok, status

def summary(args, is_ok, status, logfile):
    summary = json.dumps(status, sort_keys=True, indent=2)
    if is_ok:
        logging.info('O2O finished successfully! Summary: %s' % summary)
    else:
        logging.error('O2O FAILED! Summary: %s' % summary)

    debugLabel = '[TEST] ' if args.debug else ''

    # send the summary email
    helper.send_mail(subject='%sNew O2O, IOV: %s' % (debugLabel, args.since),
             message=summary,
             send_to=args.mail_to,
             send_from=args.mail_from)
    # send the detailed log
    with open(logfile, 'r') as log:
        helper.send_mail(subject='%sNew O2O Log, IOV: %s' % (debugLabel, args.since),
                 message=log.read(),
                 send_to=args.mail_log_to,
                 send_from=args.mail_from)


def main():
    parser = argparse.ArgumentParser(description='Run all SiStrip DAQ O2Os at the same time.')
    parser.add_argument('since', metavar='SINCE', type=str, help='Run number.')
    parser.add_argument('cfgfile', metavar='CFGLINES', help='File containing configuration lines.')
    parser.add_argument('--skiplistFile', default='', help='File containing the devices to be skipped in G1 O2O.')
    parser.add_argument('--whitelistFile', default='', help='File of the whitelisted devices in G1 O2O.')

    parser.add_argument('--analyzers',
                        default='SiStripO2OBadStrip,SiStripO2OFedCabling,SiStripO2OLatency,SiStripO2ONoises,SiStripO2OPedestals,SiStripO2OThreshold',
                        help='Which EDAnalyzers to run.')
    parser.add_argument('--mail-from', default='trk.o2o@cern.ch', help='Account to send email notification.')
    parser.add_argument('--mail-to', default='cms-tracker-o2o-notification@cern.ch', help='List of O2O notification recipients.')
    parser.add_argument('--mail-log-to', default='trk.o2o@cern.ch', help='List of O2O log recipients.')
    parser.add_argument('--db', default='pro', help='The database for o2o job management: pro ( for prod ) or dev ( for prep ). Default: %(default)s.')
    parser.add_argument('--debug', action="store_true", default=False, help='Switch on debug mode. Default: %(default)s.')

    args = parser.parse_args()
    if args.debug:
        args.mail_to = args.mail_log_to

    args.analyzers = args.analyzers.strip().split(',')
    args.mail_to = args.mail_to.strip().split(',')
    args.mail_log_to = args.mail_log_to.strip().split(',')

    # Should NOT use logging before it's set up
    try:
        logdir = os.environ[logDirVar] if logDirVar in os.environ else '/tmp'
        if not os.path.exists(logdir):
            os.makedirs(logdir)
        logfile = os.path.join(logdir, 'SiStripsO2O_Run%s.log' % str(args.since))
        loglevel = logging.DEBUG if args.debug else logging.INFO
        helper.configLogger(logfile, loglevel)
    except Exception:
        # in case we failed before logging is set up
        # print the error, send an email, and exit
        helper.send_mail('O2O Failure, IOV: %s' % args.since, traceback.format_exc(), args.mail_to, args.mail_from)
        raise

    try:
        is_ok, status = run(args)
        summary(args, is_ok, status, logfile)
    except Exception:
        # in case we failed before logging is set up
        # print the error, send an email, and exit
        helper.send_mail('O2O Failure, IOV: %s' % args.since, traceback.format_exc(), args.mail_to, args.mail_from)
        raise

    if not is_ok:
        return ' --- O2O FAILED! ---'

if __name__ == '__main__':
    sys.exit(main())