Exemple #1
0
    def execute(self, runid):
        """Send files as an email.
        
        Keyword arguments:
        runid -- A UTC ID string which identifies the run.
        
        The following parameters are loaded from the Robot configuration:
        FileEmailer_Host e.g. localhost or localhost:25
        FileEmailer_Type e.g. text or html
        FileEmailer_From e.g. [email protected]
        FileEmailer_Recipients e.g. [email protected], [email protected]
        FileEmailer_Subject e.g. Report ${runid}.
        FileEmailer_TextFile e.g. ~/gangadir/robot/report/${runid}.txt
        FileEmailer_HtmlFile e.g. ~/gangadir/robot/report/${runid}.html
        
        If Recipients are not specified then no email is sent.
        In Subject, TextFile and HtmlFile the token ${runid} is replaced by the
        runid argument.
        If Type is text, then TextFile is sent.
        If Type is html, then HtmlFile is sent, or if TextFile is also specified
        then a multipart message is sent containing TextFile and HtmlFile.
        
        """
        # get configuration properties
        host = self.getoption('FileEmailer_Host')
        type = self.getoption('FileEmailer_Type')
        from_ = self.getoption('FileEmailer_From')
        # extract recipients ignoring blank entries
        recipients = [recipient.strip() for recipient in \
                      self.getoption('FileEmailer_Recipients').split(',') \
                      if recipient.strip()]
        subject = Utility.expand(self.getoption('FileEmailer_Subject'), runid = runid)
        textfilename = Utility.expand(self.getoption('FileEmailer_TextFile'), runid = runid)
        htmlfilename = Utility.expand(self.getoption('FileEmailer_HtmlFile'), runid = runid)
        
        if not recipients:
            logger.warn('No recipients specified. Email will not be sent.')
            return
        
        logger.info('Emailing files to %s.', recipients)

        # build message
        if type == 'html':
            msg = self._gethtmlmsg(textfilename, htmlfilename)
        else:
            msg = self._gettextmsg(textfilename)
        msg['Subject'] = subject
        msg['From'] = from_
        msg['To'] = ', '.join(recipients)

        # send message
        session = SMTP()
        try:
            session.connect(host)
            session.sendmail(from_, recipients, msg.as_string())
            session.quit()
        finally:
            session.close()

        logger.info('Files emailed.')
Exemple #2
0
 def test_utctime_from_utcid(self):
     """Test utctime() returns utctime corresponding to utcid parameter."""
     utcid = Utility.utcid()
     utctime = Utility.utctime(utcid)
     assert isinstance(utctime, str), 'utctime is not a string'
     assert utcid == Utility.utcid(
         utctime), 'utcid -> utctime -> utcid conversion fails'
Exemple #3
0
    def setUp(self):
        """Create test actions."""
        super(TestCore, self).setUp()
        self.runid = Utility.utcid()
        self.submitter = CoreSubmitter()
        #force submitter patterns
        self.submitter.options = {
            'CoreSubmitter_Patterns':
            ['GangaRobot/old_test/Lib/Core/test-jobs.txt']
        }
        self.finisher = CoreFinisher()
        #force finisher timeout to 5 mins
        self.finisher.options = {'BaseFinisher_Timeout': 300}

        #test extractor fakes save
        class TestCoreExtractor(CoreExtractor):
            def _saveextract(self, runnode, runid):
                self.runnode = runnode  #can be accessed in the test

        self.extractor = TestCoreExtractor()

        #test reporter fakes load and save
        class TestCoreReporter(CoreReporter):
            def _loadextract(self, runid):
                return self.runnode  #must be set in the test

            def _savereport(self, report, runid):
                self.report = report  #can be accessed in the test

        self.reporter = TestCoreReporter()
Exemple #4
0
    def execute(self, runid):
        """Invoke each of the extractors in the chain.
        
        Keyword arguments:
        runid -- A UTC ID string which identifies the run.

        An empty run node is created as an instance of Extract.Node and passed
        to the handlerunnode() method of each extractor in the chain.
        
        An empty job node is created, as a subnode of the run node, for each job
        in the jobtree directory named by the runid, e.g. /2007-06-25_09.18.46,
        and passed to the handlejobnode() method of each extractor in the chain.
        
        The run node is saved as XML to the configurable BaseExtractor_XmlFile,
        replacing ${runid} with the current run id.
        e.g. ~/gangadir/robot/extract/${runid}.xml
        
        """
        logger.info("Extracting data for run '%s'.", runid)
        runnode = Node('run')
        for extractor in self.chain:
            extractor.handlerunnode(runnode, runid)
        path = Utility.jobtreepath(runid)
        ids = jobtree.listjobs(path)
        ids.sort()
        for id in ids:
            jobnode = Node('job')
            job = jobs(id)
            for extractor in self.chain:
                extractor.handlejobnode(jobnode, job)
            runnode.nodes.append(jobnode)
        self._saveextract(runnode, runid)
        logger.info('Extract data saved.')
Exemple #5
0
 def dorun(self):
     """Executes a run of actions and sleep periods.
     
     Initialises runid to the current UTC ID.
     
     """
     self.runid = Utility.utcid()
     while 1:
         logger.info("Start run %s with id '%s'.", self.run, self.runid)
         for action in self.run:
             try:
                 self._doaction(action)
             except GangaRobotContinueError as e:
                 logger.warning("Continue Error in Action '%s' with message '%s'. Run continued", action, e)
             except GangaRobotBreakError as e:
                 logger.warning("Break Error in Action '%s' with message '%s'. Run ended", action, e)
                 break
             except GangaRobotFatalError as e:
                 logger.error("Fatal Error in Action '%s' with message '%s'. Run aborted", action, e)
                 raise
             except Exception as e:
                 config = getConfig('Robot')
                 if (config['ExceptionBehaviour'] == 'Continue'):
                     logger.error("Error in Action '%s' with message '%s'. Run continued", action, e)
                 elif (config['ExceptionBehaviour'] == 'Break'):
                     logger.error("Error in Action '%s' with message '%s'. Run continued", action, e)
                     break
                 else:
                     logger.error("Abort run id '%s'. Action '%s' failed with message %s.", self.runid, action, e)
                     raise
         logger.info("Finish run id '%s'.", self.runid)
         if not self.repeat: 
             break
Exemple #6
0
 def test_submitter(self):
     """Test submitter submits 3 jobs and adds them to the jobtree."""
     #execute action
     self.submitter.execute(self.runid)
     #check jobs are added to jobtree
     path = Utility.jobtreepath(self.runid)
     js = jobtree.getjobs(path)
     assert len(js) == 3, 'number of jobs added to jobtree path is not 3'
     for j in js:
         assert j.status != 'new', 'job status is new indicating that it may not have been submitted'
Exemple #7
0
 def test_submitter(self):
     """Test submitter submits 3 jobs and adds them to the jobtree."""
     #execute action
     self.submitter.execute(self.runid)
     #check jobs are added to jobtree
     path = Utility.jobtreepath(self.runid)
     js = jobtree.getjobs(path)
     assert len(js) == 3, 'number of jobs added to jobtree path is not 3'
     for j in js:
         assert j.status != 'new', 'job status is new indicating that it may not have been submitted'
Exemple #8
0
 def _gethtmlmsg(self, textfilename, htmlfilename):
     html = Utility.readfile(htmlfilename)
     htmlmsg = MIMEText(html, 'html')
     if textfilename:
         textmsg = self._gettextmsg(textfilename)
         multimsg = MIMEMultipart('alternative')
         multimsg.attach(textmsg)
         multimsg.attach(htmlmsg)
         return multimsg
     else:
         return htmlmsg
Exemple #9
0
 def _gethtmlmsg(self, textfilename, htmlfilename):
     html = Utility.readfile(htmlfilename)
     htmlmsg = MIMEText(html, 'html')
     if textfilename:
         textmsg = self._gettextmsg(textfilename)
         multimsg = MIMEMultipart('alternative')
         multimsg.attach(textmsg)
         multimsg.attach(htmlmsg)
         return multimsg
     else:
         return htmlmsg
Exemple #10
0
 def test_finisher(self):
     """Test finisher waits for jobs to finish."""
     #submit jobs
     self.submitter.execute(self.runid)
     #execute action
     self.finisher.execute(self.runid)
     #get jobs from jobtree
     path = Utility.jobtreepath(self.runid)
     js = jobtree.getjobs(path)
     #check jobs are finished
     for j in js:
         assert j.status == 'completed', 'job status is not completed indicating that it may not have finished'
Exemple #11
0
 def handlerunnode(self, runnode, runid):
     """Extracts generic data for the given run.
     
     Keyword arguments:
     runnode -- An Extract.Node for the run.
     runid -- A UTC ID string which identifies the run.
     
     Example of nodes added to the run node:
     <core>
         <id>2007-06-22_13.17.51</id>
         <start-time>2007/06/22 13:17:51</start-time>
         <extract-time>2007/06/22 13:18:55</extract-time>
     </core>
     
     All nodes are guaranteed to be present. All times are in UTC.
     
     """
     corenode = runnode.addnode('core')
     corenode.addnode('id', runid)
     corenode.addnode('start-time', Utility.utctime(runid))
     corenode.addnode('extract-time', Utility.utctime())
Exemple #12
0
 def handlerunnode(self, runnode, runid):
     """Extracts generic data for the given run.
     
     Keyword arguments:
     runnode -- An Extract.Node for the run.
     runid -- A UTC ID string which identifies the run.
     
     Example of nodes added to the run node:
     <core>
         <id>2007-06-22_13.17.51</id>
         <start-time>2007/06/22 13:17:51</start-time>
         <extract-time>2007/06/22 13:18:55</extract-time>
     </core>
     
     All nodes are guaranteed to be present. All times are in UTC.
     
     """
     corenode = runnode.addnode('core')
     corenode.addnode('id', runid)
     corenode.addnode('start-time', Utility.utctime(runid))
     corenode.addnode('extract-time', Utility.utctime())
Exemple #13
0
 def test_finisher(self):
     """Test finisher waits for jobs to finish."""
     #submit jobs
     self.submitter.execute(self.runid)
     #execute action
     self.finisher.execute(self.runid)
     #get jobs from jobtree
     path = Utility.jobtreepath(self.runid)
     js = jobtree.getjobs(path)
     #check jobs are finished
     for j in js:
         assert j.status == 'completed', 'job status is not completed indicating that it may not have finished'
Exemple #14
0
    def execute(self, runid):
        """Invoke each of the finishers in the chain.
        
        Keyword arguments:
        runid -- A UTC ID string which identifies the run.
        
        Loops until the run is finished or the elapsed time exceeds the
        configurable BaseFinisher_Timeout (seconds).
        
        Each job in the jobtree directory named by the runid, e.g.
        /2007-06-25_09.18.46, is passed to the handleisfinished() method of each
        finisher in the chain. If any finisher returns False, for any job,
        then the run is considered unfinished.
        
        The sleep period in the loop is 1/10th the timeout, constrained to the
        range [10, 60] seconds.
        
        """
        logger.info("Finishing jobs for run '%s'.", runid)
        startsecs = time.time()
        timeoutsecs = self.getoption('BaseFinisher_Timeout')
        sleepsecs = timeoutsecs / 10
        if sleepsecs < 10: sleepsecs = 10
        if sleepsecs > 60: sleepsecs = 60
        
        logger.info('Waiting for jobs to finish. Timeout %d seconds.'
                    ' Sleep period %d seconds', timeoutsecs, sleepsecs)

        path = Utility.jobtreepath(runid)
        jobs = jobtree.getjobs(path)
        
        while True:
            #suppose finished is True
            finished = True
            for j in jobs:
                #if one job not finished then finished is False
                for finisher in self.chain:
                    if not finisher.handleisfinished(j):
                        finished = False
                        break
            elapsedsecs = time.time() - startsecs
            # test break condition here to avoid sleep after satisfied condition
            if finished or timeoutsecs < elapsedsecs:
                break
            # break condition on satisfied, so sleep
            time.sleep(sleepsecs)
        
        if finished:
            logger.info('All jobs finished after %d seconds.', elapsedsecs)
        else:
            logger.info('Timeout after %d seconds.', elapsedsecs)
Exemple #15
0
 def _savereport(self, report, runid):
     #text
     textfilename = Utility.expand(self.getoption('BaseReporter_TextFile'), runid = runid)
     textcontent = str(report)
     Utility.writefile(textfilename, textcontent)
     #html
     htmlfilename = Utility.expand(self.getoption('BaseReporter_HtmlFile'), runid = runid)
     htmlcontent = report.tohtml()
     Utility.writefile(htmlfilename, htmlcontent)
Exemple #16
0
 def _savereport(self, report, runid):
     #text
     textfilename = Utility.expand(self.getoption('BaseReporter_TextFile'),
                                   runid=runid)
     textcontent = str(report)
     Utility.writefile(textfilename, textcontent)
     #html
     htmlfilename = Utility.expand(self.getoption('BaseReporter_HtmlFile'),
                                   runid=runid)
     htmlcontent = report.tohtml()
     Utility.writefile(htmlfilename, htmlcontent)
Exemple #17
0
 def dorun(self):
     """Executes a run of actions and sleep periods.
     
     Initialises runid to the current UTC ID.
     
     """
     self.runid = Utility.utcid()
     while 1:
         logger.info("Start run %s with id '%s'.", self.run, self.runid)
         for action in self.run:
             try:
                 self._doaction(action)
             except GangaRobotContinueError as e:
                 logger.warning(
                     "Continue Error in Action '%s' with message '%s'. Run continued",
                     action, e)
             except GangaRobotBreakError as e:
                 logger.warning(
                     "Break Error in Action '%s' with message '%s'. Run ended",
                     action, e)
                 break
             except GangaRobotFatalError as e:
                 logger.error(
                     "Fatal Error in Action '%s' with message '%s'. Run aborted",
                     action, e)
                 raise
             except Exception as e:
                 config = getConfig('Robot')
                 if (config['ExceptionBehaviour'] == 'Continue'):
                     logger.error(
                         "Error in Action '%s' with message '%s'. Run continued",
                         action, e)
                 elif (config['ExceptionBehaviour'] == 'Break'):
                     logger.error(
                         "Error in Action '%s' with message '%s'. Run continued",
                         action, e)
                     break
                 else:
                     logger.error(
                         "Abort run id '%s'. Action '%s' failed with message %s.",
                         self.runid, action, e)
                     raise
         logger.info("Finish run id '%s'.", self.runid)
         if not self.repeat:
             break
Exemple #18
0
def loaddriver():
    """Create new driver based on Robot configuration options.

    Example of relevant configuration options:
    [Robot]
    Driver_Run = ['submit', 30, 'extract', 'report']
    Driver_Repeat = False
    Driver_Action_submit = GangaRobot.Lib.Core.CoreSubmitter.CoreSubmitter
    Driver_Action_extract = GangaRobot.Lib.Core.CoreExtractor.CoreExtractor
    Driver_Action_report = GangaRobot.Lib.Core.CoreReporter.CoreReporter
    
    """
    KEY_RUN = 'Driver_Run'
    KEY_REPEAT = 'Driver_Repeat'
    KEY_ACTION_PREFIX = 'Driver_Action_'
    
    config = Utility.getconfig()
    run = config[KEY_RUN]
    repeat = config[KEY_REPEAT]
    actions = {}
    #load action classes
    for key in config:
        if key.startswith(KEY_ACTION_PREFIX):
            action = key[len(KEY_ACTION_PREFIX):]
            fqcn = config[key]
            try:
                actions[action] = _loadclass(fqcn)
            except Exception as e:
                raise ApplicationConfigurationError(e, "Cannot load class '%s'." % fqcn)
    #check actions exist for run
    for action in run:
        if not action in actions:
            try:
                int(action)
            except ValueError as e:
                raise ApplicationConfigurationError(e, "Unknown action '%s'." % action)
            
            

    return Driver(run = run, actions = actions, repeat = repeat)
Exemple #19
0
def loaddriver():
    """Create new driver based on Robot configuration options.

    Example of relevant configuration options:
    [Robot]
    Driver_Run = ['submit', 30, 'extract', 'report']
    Driver_Repeat = False
    Driver_Action_submit = GangaRobot.Lib.Core.CoreSubmitter.CoreSubmitter
    Driver_Action_extract = GangaRobot.Lib.Core.CoreExtractor.CoreExtractor
    Driver_Action_report = GangaRobot.Lib.Core.CoreReporter.CoreReporter
    
    """
    KEY_RUN = 'Driver_Run'
    KEY_REPEAT = 'Driver_Repeat'
    KEY_ACTION_PREFIX = 'Driver_Action_'

    config = Utility.getconfig()
    run = config[KEY_RUN]
    repeat = config[KEY_REPEAT]
    actions = {}
    #load action classes
    for key in config:
        if key.startswith(KEY_ACTION_PREFIX):
            action = key[len(KEY_ACTION_PREFIX):]
            fqcn = config[key]
            try:
                actions[action] = _loadclass(fqcn)
            except Exception as e:
                raise ApplicationConfigurationError(
                    "Cannot load class '%s'. Exception: '%s'" % (fqcn, e))
    #check actions exist for run
    for action in run:
        if not action in actions:
            try:
                int(action)
            except ValueError as e:
                raise ApplicationConfigurationError(
                    "Unknown action '%s'. Exception: '%s'" % (action, e))

    return Driver(run=run, actions=actions, repeat=repeat)
Exemple #20
0
 def setUp(self):
     """Create test actions."""
     super(TestCore, self).setUp()
     self.runid = Utility.utcid()
     self.submitter = CoreSubmitter()
     #force submitter patterns
     self.submitter.options = {'CoreSubmitter_Patterns':['GangaRobot/old_test/Lib/Core/test-jobs.txt']}
     self.finisher = CoreFinisher()
     #force finisher timeout to 5 mins
     self.finisher.options = {'BaseFinisher_Timeout':300}
     #test extractor fakes save
     class TestCoreExtractor(CoreExtractor):
         def _saveextract(self, runnode, runid):
             self.runnode = runnode #can be accessed in the test
     self.extractor = TestCoreExtractor()
     #test reporter fakes load and save
     class TestCoreReporter(CoreReporter):
         def _loadextract(self, runid):
             return self.runnode #must be set in the test
         def _savereport(self, report, runid):
             self.report = report #can be accessed in the test 
     self.reporter = TestCoreReporter()
Exemple #21
0
 def getoption(self, key):
     """Return the configuration option value.
     
     If the instance has an attribute 'options' containing the given key,
     then the corresponding value is returned, otherwise the value is
     retrieved from the [Robot] section of the global configuration.
     
     This provides a single point of access to configuration options and
     allows users the possibility to override options programmatically for a
     given instance.
     
     Example:
     c = CoreFinisher()
     c.options = {'BaseFinisher_Timeout':3600}
     
     """
     if hasattr(self, 'options') and key in self.options:
         return self.options[key]
     else:
         try:        
             return Utility.getconfig()[key]
         except ConfigError:         
             return ''
    def execute(self, runid):
        """Invoke each of the submitters in the chain.
        
        Keyword arguments:
        runid -- A UTC ID string which identifies the run.
        
        An empty list of jobids is created and passed to the handlesubmit()
        method of each the submitter in the chain.
        
        Any job, whose id is added to the argument jobids, is added to the
        jobtree in the directory named by the runid, e.g. /2007-06-25_09.18.46.

        """
        logger.info("Submitting jobs for run '%s'.", runid)
        jobids = []
        for submitter in self.chain:
            submitter.handlesubmit(jobids, runid)
        path = Utility.jobtreepath(runid)
        jobtree.mkdir(path)
        for id in jobids:
            jobtree.add(jobs(id), path)

        logger.info("%d submitted jobs added to jobtree path '%s'.", len(jobids), path)
Exemple #23
0
    def execute(self, runid):
        """Invoke each of the submitters in the chain.
        
        Keyword arguments:
        runid -- A UTC ID string which identifies the run.
        
        An empty list of jobids is created and passed to the handlesubmit()
        method of each the submitter in the chain.
        
        Any job, whose id is added to the argument jobids, is added to the
        jobtree in the directory named by the runid, e.g. /2007-06-25_09.18.46.

        """
        logger.info("Submitting jobs for run '%s'.", runid)
        jobids = []
        for submitter in self.chain:
            submitter.handlesubmit(jobids, runid)
        path = Utility.jobtreepath(runid)
        jobtree.mkdir(path)
        for id in jobids:
            jobtree.add(jobs(id), path)

        logger.info("%d submitted jobs added to jobtree path '%s'.",
                    len(jobids), path)
Exemple #24
0
 def _gettextmsg(self, textfilename):
     text = Utility.readfile(textfilename)
     textmsg = MIMEText(text)
     return textmsg
Exemple #25
0
 def _loadextract(self, runid):
     filename = Utility.expand(self.getoption('BaseExtractor_XmlFile'), runid = runid)
     content = Utility.readfile(filename)
     return Node.fromxml(content)
Exemple #26
0
 def test_expand_multiple_occurrences(self):
     """Test expand() replaces multiple tokens in text."""
     text = 'The following token ${mytoken1} should be replaced, as should ${mytoken2}.'
     expected = 'The following token 1111 should be replaced, as should 2222.'
     actual = Utility.expand(text, mytoken1='1111', mytoken2='2222')
     assert expected == actual, 'the text was not modified as expected'
Exemple #27
0
 def test_expand_repeated_occurrences(self):
     """Test expand() replaces repeated tokens in text."""
     text = 'The following token ${mytoken1} should be replaced, as should ${mytoken1}.'
     expected = 'The following token 1111 should be replaced, as should 1111.'
     actual = Utility.expand(text, mytoken1='1111')
     assert expected == actual, 'the text was not modified as expected'
Exemple #28
0
 def test_expand_no_replacements(self):
     """Test expand() does not replace tokens in text when no replacements parameter."""
     text = 'The following token ${runid} should not be replaced.'
     expected = text
     actual = Utility.expand(text)
     assert expected == actual, 'the text was modified'
Exemple #29
0
 def _gettextmsg(self, textfilename):
     text = Utility.readfile(textfilename)
     textmsg = MIMEText(text)
     return textmsg
Exemple #30
0
 def test_utctime(self):
     """Test utctime() returns a string value when no parameter."""
     utctime = Utility.utctime()
     assert isinstance(utctime, str), 'utctime is not a string'
Exemple #31
0
    def handlereport(self, report, runnode):
        """Add statistics on generic data to the report.
        
        Keyword arguments:
        report -- A Report.Report for the run, to be emailed.
        runnode -- A the extracted data for the run.
        
        If the report title is undefined a title 'CoreReporter ${runid}' is set.

        If the configurable option CoreReporter_ExtractUrl is defined then a
        link is added from 'Run id', replacing ${runid} with the current run id.
        e.g. http://localhost/robot/extract/${runid}.xml
        
        Example of report generated (plain text version):
        CoreReporter 2007-06-27_10.49.40
        ********************************
        
        Core Analysis
        *************
        
        Run id       : 2007-06-27_10.49.40 (http://localhost/robot/extract/2007-06-27_10.49.40.xml)
        Start time   : 2007/06/27 10:49:40
        Extract time : 2007/06/27 10:49:55
        
        Status               | Subtotal
        -------------------------------
        completed            |        3
        submitted            |        1
        failed               |        1
        Total                |        5
        
        ActualCE                                                    | Completed | Total
        -------------------------------------------------------------------------------
        lx09.hep.ph.ic.ac.uk                                        |         3 |     5
        
        Non-completed Jobs
        ==================
        Id    | Status     | Backend  | Backend.id             | ActualCE              
        -------------------------------------------------------------------------------
        51    | failed     | Local    | 13418                  | lx09.hep.ph.ic.ac.uk  
        53    | submitted  | Local    | None                   | lx09.hep.ph.ic.ac.uk  
        
        """
        runid = runnode.getvalue('core.id')

        # get configuration options
        extracturl = Utility.expand(self.getoption('CoreReporter_ExtractUrl'),
                                    runid=runid)

        #CoreReporter id
        if not report.title:
            report.title = 'CoreReporter ' + runid

        #Core Analysis
        report.addline(Heading('Core Analysis', 2))
        report.addline()

        #Run id       : ...
        report.addline('Run id       :')
        if extracturl:
            report.addelement(Link(runid, extracturl))
        else:
            report.addelement(runid)
        #Start time   : ...
        #Extract time : ...
        report.addline('Start time   : ' + runnode.getvalue('core.start-time'))
        report.addline('Extract time : ' +
                       runnode.getvalue('core.extract-time'))
        report.addline()

        #Status | Subtotal
        #...
        #Total          10
        report.addline(self._getstatustable(runnode))
        report.addline()

        #ActualCE | Completed | Total
        #...
        report.addline(self._getcetable(runnode))
        report.addline()

        #Non-completed Jobs
        report.addline(Heading('Non-completed Jobs'))
        #Id | Status | Backend | Backend.id | ActualCE
        #...
        report.addline(self._getnoncompletedtable(runnode))
        report.addline()
Exemple #32
0
 def test_expand_multiple_occurrences(self):
     """Test expand() replaces multiple tokens in text."""
     text = 'The following token ${mytoken1} should be replaced, as should ${mytoken2}.'
     expected = 'The following token 1111 should be replaced, as should 2222.'
     actual = Utility.expand(text, mytoken1 = '1111', mytoken2 = '2222')
     assert expected == actual, 'the text was not modified as expected'
Exemple #33
0
 def test_utctime(self):
     """Test utctime() returns a string value when no parameter."""
     utctime = Utility.utctime()
     assert isinstance(utctime, str), 'utctime is not a string'
Exemple #34
0
 def test_expand_repeated_occurrences(self):
     """Test expand() replaces repeated tokens in text."""
     text = 'The following token ${mytoken1} should be replaced, as should ${mytoken1}.'
     expected = 'The following token 1111 should be replaced, as should 1111.'
     actual = Utility.expand(text, mytoken1 = '1111')
     assert expected == actual, 'the text was not modified as expected'
Exemple #35
0
    def execute(self, runid):
        """Send files as an email.
        
        Keyword arguments:
        runid -- A UTC ID string which identifies the run.
        
        The following parameters are loaded from the Robot configuration:
        FileEmailer_Host e.g. localhost or localhost:25
        FileEmailer_Type e.g. text or html
        FileEmailer_From e.g. [email protected]
        FileEmailer_Recipients e.g. [email protected], [email protected]
        FileEmailer_Subject e.g. Report ${runid}.
        FileEmailer_TextFile e.g. ~/gangadir/robot/report/${runid}.txt
        FileEmailer_HtmlFile e.g. ~/gangadir/robot/report/${runid}.html
        
        If Recipients are not specified then no email is sent.
        In Subject, TextFile and HtmlFile the token ${runid} is replaced by the
        runid argument.
        If Type is text, then TextFile is sent.
        If Type is html, then HtmlFile is sent, or if TextFile is also specified
        then a multipart message is sent containing TextFile and HtmlFile.
        
        """
        # get configuration properties
        host = self.getoption('FileEmailer_Host')
        type = self.getoption('FileEmailer_Type')
        from_ = self.getoption('FileEmailer_From')
        # extract recipients ignoring blank entries
        recipients = [recipient.strip() for recipient in \
                      self.getoption('FileEmailer_Recipients').split(',') \
                      if recipient.strip()]
        subject = Utility.expand(self.getoption('FileEmailer_Subject'),
                                 runid=runid)
        textfilename = Utility.expand(self.getoption('FileEmailer_TextFile'),
                                      runid=runid)
        htmlfilename = Utility.expand(self.getoption('FileEmailer_HtmlFile'),
                                      runid=runid)

        if not recipients:
            logger.warn('No recipients specified. Email will not be sent.')
            return

        logger.info('Emailing files to %s.', recipients)

        # build message
        if type == 'html':
            msg = self._gethtmlmsg(textfilename, htmlfilename)
        else:
            msg = self._gettextmsg(textfilename)
        msg['Subject'] = subject
        msg['From'] = from_
        msg['To'] = ', '.join(recipients)

        # send message
        session = SMTP()
        try:
            session.connect(host)
            session.sendmail(from_, recipients, msg.as_string())
            session.quit()
        finally:
            session.close()

        logger.info('Files emailed.')
Exemple #36
0
 def _loadextract(self, runid):
     filename = Utility.expand(self.getoption('BaseExtractor_XmlFile'),
                               runid=runid)
     content = Utility.readfile(filename)
     return Node.fromxml(content)
Exemple #37
0
 def test_utctime_from_utcid(self):
     """Test utctime() returns utctime corresponding to utcid parameter."""
     utcid = Utility.utcid()
     utctime = Utility.utctime(utcid)
     assert isinstance(utctime, str), 'utctime is not a string'
     assert utcid == Utility.utcid(utctime), 'utcid -> utctime -> utcid conversion fails'
Exemple #38
0
 def _saveextract(self, runnode, runid):
     filename = Utility.expand(self.getoption('BaseExtractor_XmlFile'), runid = runid)
     content = runnode.toprettyxml()
     Utility.writefile(filename, content)
Exemple #39
0
 def test_expand_no_replacements(self):
     """Test expand() does not replace tokens in text when no replacements parameter."""
     text = 'The following token ${runid} should not be replaced.'
     expected = text
     actual = Utility.expand(text)
     assert expected == actual, 'the text was modified'
Exemple #40
0
    def handlereport(self, report, runnode):
        """Add statistics on generic data to the report.
        
        Keyword arguments:
        report -- A Report.Report for the run, to be emailed.
        runnode -- A the extracted data for the run.
        
        If the report title is undefined a title 'CoreReporter ${runid}' is set.

        If the configurable option CoreReporter_ExtractUrl is defined then a
        link is added from 'Run id', replacing ${runid} with the current run id.
        e.g. http://localhost/robot/extract/${runid}.xml
        
        Example of report generated (plain text version):
        CoreReporter 2007-06-27_10.49.40
        ********************************
        
        Core Analysis
        *************
        
        Run id       : 2007-06-27_10.49.40 (http://localhost/robot/extract/2007-06-27_10.49.40.xml)
        Start time   : 2007/06/27 10:49:40
        Extract time : 2007/06/27 10:49:55
        
        Status               | Subtotal
        -------------------------------
        completed            |        3
        submitted            |        1
        failed               |        1
        Total                |        5
        
        ActualCE                                                    | Completed | Total
        -------------------------------------------------------------------------------
        lx09.hep.ph.ic.ac.uk                                        |         3 |     5
        
        Non-completed Jobs
        ==================
        Id    | Status     | Backend  | Backend.id             | ActualCE              
        -------------------------------------------------------------------------------
        51    | failed     | Local    | 13418                  | lx09.hep.ph.ic.ac.uk  
        53    | submitted  | Local    | None                   | lx09.hep.ph.ic.ac.uk  
        
        """
        runid = runnode.getvalue('core.id')

        # get configuration options
        extracturl = Utility.expand(self.getoption('CoreReporter_ExtractUrl'), runid = runid)
        
        #CoreReporter id
        if not report.title:
            report.title = 'CoreReporter ' + runid

        #Core Analysis
        report.addline(Heading('Core Analysis', 2))
        report.addline()
        
        #Run id       : ...
        report.addline('Run id       :')
        if extracturl:
            report.addelement(Link(runid, extracturl))
        else:
            report.addelement(runid)
        #Start time   : ...
        #Extract time : ...
        report.addline('Start time   : ' + runnode.getvalue('core.start-time'))
        report.addline('Extract time : ' + runnode.getvalue('core.extract-time'))
        report.addline()
        
        #Status | Subtotal
        #...
        #Total          10
        report.addline(self._getstatustable(runnode))
        report.addline()
        
        #ActualCE | Completed | Total
        #...
        report.addline(self._getcetable(runnode))
        report.addline()
        
        #Non-completed Jobs
        report.addline(Heading('Non-completed Jobs'))
        #Id | Status | Backend | Backend.id | ActualCE
        #...
        report.addline(self._getnoncompletedtable(runnode))
        report.addline()