예제 #1
0
 def getSite4Region(self, regions):
     regs = None
     if utils.isValid(regions):
         rgs = utils.parseArray(regions)
         regs = []
         for r in rgs:
             regs += self._site4regions[r]
     return regs
예제 #2
0
 def getSite4Region(self, regions):
     regs = None
     if utils.isValid(regions):
         rgs = utils.parseArray(regions)
         regs = []
         for r in rgs:
             regs += self._site4regions[r]
     return regs
예제 #3
0
파일: wnlist.py 프로젝트: vfine/webplatform
 def __init__(self,name=None,parent=None,obj=None):
    pmModule.__init__(self,name,parent,obj)
    
    self._jobstates = utils.jobStates
    self._lstates = len(self._jobstates)
    actIndex = utils.name2Index(self._jobstates,'activated')+1
    canIndex = utils.name2Index(self._jobstates,'cancelled')+1
    self._jobsFactoryStates = utils.parseArray(self._jobstates[:actIndex])
    self._jobsWNStates = utils.parseArray(self._jobstates[actIndex:canIndex-1])
    self._jobsCaneledStates = utils.parseArray(self._jobstates[canIndex:])
    shift = 1
    self._shift = shift
    self._ifailed =  utils.name2Index(self._jobstates,'failed')+shift
    self._itotal = self._lstates+shift
    self._ifail = 0
    self._description,params = utils.normalizeDbSchema(pmt,'jobsarchived4')
    self.publishUI(self.doQuery,params = params)
예제 #4
0
 def doJson(self,
            pandaid,
            message=None,
            host=None,
            timestamp=None,
            errorcode=None,
            test=None):
     """  Contact Us Panda Monitor Modules """
     usr = self.server().user()
     pandaid = utils.parseArray(pandaid)
     plid = len(pandaid)
     main = {}
     if plid >= 1: main['pandaid'] = pandaid[0]
     if plid >= 2:
         main['taskid'] = pandaid[1]
         if plid == 2 and usr != None:
             pandaid.append(usr)
     plid = len(pandaid)
     if plid >= 3:
         pandaid[2] = pmt.cleanUserID(pandaid[2]).replace(' ', '+')
         main['user'] = pandaid[2]
     if usr != None:
         mail = self.server().email()
         if mail == None and test != None:
             mail = '*****@*****.**'
         main['username'] = usr
         if mail != None:
             main['mail'] = mail
             msg = self.message(pandaid, message, host, timestamp,
                                errorcode)
             msg += self.signature()
             subject = self.subject(pandaid)
             toaddrs = ''
             if test == None:
                 toaddrs = '[email protected] [email protected] '
             #            toaddrs+='%s %s %s' % ('*****@*****.**', '*****@*****.**', mail)
             toaddrs += '%s %s' % ('*****@*****.**', mail)
             main['message'] = msg
             main[
                 'subject'] = subject if test == None else 'Test: %s ' % subject
             main['toaddrs'] = toaddrs
             response = pmt.sendmail(msg, subject, toaddrs, fromaddr=mail)
             main['response'] = response
             self.publishTitle("User %s sent support mail from %s" %
                               (usr, mail))
         else:
             self.publishTitle("User %s wanted to send the support mail " %
                               usr)
             self.publish(main)
     else:
         self.publishTitle(
             "Unknown user, please use the Web https protocol.")
     self.publish(main)
     self.publish({'s-maxage': 0, 'max-age': 0}, role=pmRoles.cache())
예제 #5
0
 def isValid(self, params, exceptions=None):
     """ Check whether the extra parameters are valid """
     if params != None:
         p = utils.parseArray(params)
         ex = self.extraParams()
         for nxp in p:
             if exceptions != None and nxp in exceptions: continue
             if ex == None or not nxp in ex:
                 raise ValueError(
                     "Unexpected module parameter : '%s' from : \n\t '%s' \n"
                     % (nxp, "'\n\t'".join(sorted(ex.keys()))))
     return True
예제 #6
0
 def isValid(self, params, exceptions=None):
     """ Check whether the extra parameters are valid """
     if params != None:
         p = utils.parseArray(params)
         ex = self.extraParams()
         for nxp in p:
             if exceptions != None and nxp in exceptions:
                 continue
             if ex == None or not nxp in ex:
                 raise ValueError(
                     "Unexpected module parameter : '%s' from : \n\t '%s' \n"
                     % (nxp, "'\n\t'".join(sorted(ex.keys())))
                 )
     return True
예제 #7
0
   def doJson(self, pandaid, message=None,host=None,timestamp=None,errorcode=None,test=None):
      """  Contact Us Panda Monitor Modules """ 
      usr = self.server().user()
      pandaid = utils.parseArray(pandaid)
      plid =  len(pandaid)
      main = {}
      if plid >= 1:  main['pandaid'] = pandaid[0]
      if plid >= 2:  
         main['taskid']  = pandaid[1]
         if plid == 2 and usr != None:
             pandaid.append(usr)
      plid =  len(pandaid)
      if plid >= 3:
         pandaid[2] = pmt.cleanUserID(pandaid[2]).replace(' ','+')
         main['user']    = pandaid[2]
      if usr != None:
         mail = self.server().email()
         if mail == None and test != None: 
            mail = '*****@*****.**'
         main['username']= usr
         if mail != None:
            main['mail']= mail
            msg = self.message(pandaid, message, host,timestamp,errorcode);
            msg += self.signature()
            subject = self.subject(pandaid)
            toaddrs = ''
            if test == None: toaddrs = '[email protected] [email protected] '
#            toaddrs+='%s %s %s' % ('*****@*****.**', '*****@*****.**', mail)
            toaddrs+='%s %s' % ( '*****@*****.**', mail)
            main['message'] = msg;
            main['subject'] = subject if test==None else 'Test: %s ' % subject
            main['toaddrs'] = toaddrs
            response = pmt.sendmail(msg,subject,toaddrs,fromaddr=mail)
            main['response'] = response
            self.publishTitle("User %s sent support mail from %s" % (usr,mail) )
         else:   
            self.publishTitle("User %s wanted to send the support mail " % usr )
            self.publish(main)
      else:
         self.publishTitle("Unknown user, please use the Web https protocol.")
      self.publish(main)
      self.publish( {'s-maxage':0,'max-age': 0}, role=pmRoles.cache())
예제 #8
0
파일: joblfn.py 프로젝트: vfine/webplatform
 def doJson(self,lfn=None, jobs=None,type='input',ds=None,table='new',limit=1000,jobstatus=None,site=None,jobtype='production',days=1,user=None,select=None):
    """ 
       Show  the list of Panda id with LFN or versa verse LFNs by Panda IDs
       <ul>
       <li><code>lfn</code>   - the list of the comma separated files 
       <li><code>ds</code>    - the list of the comma separated datasets 
       <li><code>jobs</code>  - the list of the comma separated Panda's job IDs
       <li><code>table</code>  = "new" (default) look up the records for last 3 days
                      <br> ="old" - look up the records those more than 3 days old (slow)
                      <br> ="deep" - look up the "old" and "new" tables (slow)
       <li><code>type</code>  - the type selector. <br>
                             =  'input - the default value<br>
                             =  '*' | 'all' - list all types available.
        <li><code>jobstatus</code> = the comma separated list of the job status to filter
        <br>For example: 'defined, waiting,assigned,activated,sent,starting,running'
        <li><code>site</code> = the comma separated list of the sizte to list the jobs from         
        <br> For example 'UTA_SWT2'
        <li><code>jobtype</code> = the comma separated list of the job type to filter
        <br> For example, "analysis, production"
        <li><code>days</code> = the number of the days to look up the list of the jobs if either 'jobstatus' or 'site'  parameter is defined
        <li><code>user</code> = the comma separated list of the usernames . 
        <br>NB. The names may contain the the wildcard symbol '*'. Be aware the wildcard slows the search down
       </ul>
    """ 
    title = 'The list of files for the  '
    if jobstatus and jobstatus.strip()   =='': jobstatus = None
    if site and site.strip()   =='':        site = None
    if lfn and lfn.strip()   =='': lfn = None
    if jobs and isinstance(jobs,str) and jobs.strip() =='': jobs = None
    if ds and ds.strip()     =='': ds=None
    if type and type.strip() =='': type='all'
    if  lfn==None and jobs==None and ds==None and jobstatus==None and site==None:
         self.publishTitle("Ambigios query: lfn=%(lfn)s; pandaid=%(pandaid)s either lfn or padaid can be defined. One can not define lfn and pandaid at once" % { 'lfn': lfn, 'pandaid' : jobs} )
         self.publish('<h2>Check the input parameters. Click the "?" to see the API documentaion<h2>', role=pmRoles.html())
    else:
       nav = ''
       if limit:
           nav += "Limit %s rows." % limit
       if type=='*' or type==None: type = 'all'
       if lfn != None:
          self.publishTitle("The list of the PANDA jobs with the LFN of the '%s' type provided" % type)
          if not '*' in lfn:  # disregard the jobtype parameter
             if utils.isFilled(jobtype): 
                nav += " Disregarding the jobtype='%s' default parameter" % jobtype 
                jobtype = None
       if ds != None:   
          self.publishTitle("The list of the PANDA jobs with the DATASETs of the '%s' type provided" % type)
       if jobs!=None:
          self.publishTitle("The list of the '%s' LFN with the PANDA Job IDs provided" % type)
       if utils.isFilled(nav):
          self.publishNav(nav)
       main = {}
       main["buffer"] = {}
       main["buffer"]["method"] = "joblfn"
       main["buffer"]["params"] = (lfn if lfn!=None else '',jobs if jobs!= None else '' ) 
       if jobs != None: main["buffer"]["jobs"] = jobs
       main["buffer"]["type"] = False
       if (utils.isFilled(jobstatus) or utils.isFilled(site) or utils.isFilled(user)) and  not utils.isFilled(jobs):
           tables = ['atlas_panda.jobsArchived4','atlas_panda.jobsActive4','atlas_panda.jobsWaiting4','atlas_panda.jobsDefined4']
           r = pmt.getJobIds(site, jobtype,jobstatus,table=tables,days=days,username=user)
           jobs = [i[0] for i in r['rows']]
       if not utils.isFilled(select):
          select = []    
          if jobs == None or ( not isinstance(jobs,int) and len(jobs) > 1): select.append('pandaid');
          select += ['type', 'lfn', 'fsize', 'dataset', 'guid', 'scope', 'destinationse']
       else:
          select = utils.parseArray(select);         
       main["buffer"]["data"] = pmt.getJobLFN(select=','.join(select),table=table,lfn=lfn,pandaid=jobs,type=type,ds=ds,limit=limit)
       self.publish(main)
       self.publish( "%s/%s" % (self.server().fileScriptURL(),"taskBuffer/%s.js" % "getJobLFN"),role=pmRoles.script())
예제 #9
0
    def doJobs(
        self,
        pandaid=None,
        params=None,
        jobparam=None,
        table=None,
        hours=None,
        tstart=None,
        tend=None,
        field="modificationTime",
        days=None,
        format=None,
        jobtype=None,
        testsite=None,
        limit=1500,
        summary=None,
        minjob=1,
        dump=None,
        region=None,
        lfn=None,
        showcpu=None,
    ):
        ## Perform the query
        main = {}
        errorcolcheck = False
        selection = "*"
        vals = self.extraValuesFilled(self._alias)

        title = "PanDA Job(s)"
        if utils.isFilled(pandaid):
            hours = None
            days = None
            title += " %s " % pandaid
        if days != None:
            title += " for %.2f Day" % float(days)
            if days > 1:
                title += "s"
        if hours != None:
            if days == None:
                title += " for "
            title += " %d Hour" % int(hours)
            if hours > 1:
                title += "s"

        if vals != None:
            for k in vals.keys():
                if vals[k] == "undefined":
                    vals[k] = None
                elif (
                    vals[k] != None
                    and k.lower() == "jobstatus"
                    and (
                        vals[k].lower().find("prerun") >= 0
                        or vals[k].lower().find("finishing") >= 0
                        or vals[k].lower().find("unassigned") >= 0
                        or vals[k].lower().find("retried") >= 0
                    )
                ):
                    stvals = utils.parseArray(vals[k])
                    statvals = []
                    for v in stvals:
                        if v.lower() == "prerun":
                            statvals += ["defined", "assigned", "waiting", "activated", "pending", "sent", "starting"]
                        elif v.lower() == "finishing":
                            statvals += ["holding", "transferring"]
                        elif v.lower() == "unassigned":
                            vals["computingSite"] = "NULL"
                            statvals += ["cancelled"]
                        elif v.lower() == "retried":
                            # See the slide 3 from Tadashi: https://indico.cern.ch/getFile.py/access?contribId=13&sessionId=11&resId=0&materialId=slides&confId=119171
                            vals["taskBufferErrorCode"] = [106, 107]
                            statvals += ["failed"]
                        else:
                            statvals += [v]
                        vals[k] = ",".join(statvals)
            cleanVal = dict((k, v) for k, v in vals.iteritems() if v is not None)
            vals = cleanVal
        if vals == None:
            vals = {}
        nav = ""
        certificate = None
        certusr = None
        try:
            cert = self.server().certificate()
            if cert != None:
                certusr = pmt.cleanUserID(cert)
                main["ceruser"] = certusr
        except:
            pass
        if vals.get("prodUserName") == "auto" and certusr != None:
            if cert != None:
                vals["prodUserName"] = certusr
        for v in vals:
            nav += "<b>%s</b>=%s " % (v, vals[v])
        # nav += "<span id=linkjobid  stule='display:inline'></span>"
        # nav +="<script>$(document).ready(function(){$('#linkjobid').html(utils().linkJobs(s.cloud,jobtype"
        # nav += jobtype if jobtype!=None else "undefined"
        # nav += ", s.jobStatus, "
        # nav += "%d" % hours if hours!=None else "undefined"
        # nav += ", s.computingSite,'Classic Page' ))});</script>";
        if not utils.isFilled(summary):
            nav += "<b>%s</b>=%s " % ("limit", limit)

        self.publishNav(nav)
        if len(vals) == 0:
            vals = None
        if vals == None and jobparam == None:
            main["Description"] = self.description()
        else:
            if lfn != None and lfn != "undefined":
                lfnselect = "pandaid,lfn"
                lfnjobs = pmt.getJobLFN(select=lfnselect, table="new", lfn=lfn, pandaid=pandaid, type="*", limit=limit)
                if lfnjobs["rows"] > 0:
                    pandaid = [ljobs[0] for ljobs in lfnjobs["rows"]]
            selection = {}
            if vals != None:
                selection.update(vals)
            if pandaid != None:
                selection.update({nmap.get("pandaid"): pandaid})
            if region != None:
                selection.update({"region": region})
            main["Selection"] = selection
            conditions = vals
            if conditions == None:
                conditions = {}
            cs = conditions.get("computingSite")
            if cs == None:
                site4region = self.getSite4Region(region)
                if site4region != None and len(site4region) > 0:
                    conditions["computingSite"] = site4region
            else:
                pass  # ignore the region parameter
            if utils.isValid(summary):
                jobtype = (
                    "production"
                    if jobtype == None
                    and jobparam.lower().find("taskid") >= 0
                    and jobparam.lower().find("jeditaskid") < 0
                    else jobtype
                )
                jobs = pmt.getJobsAtt(
                    pandaid,
                    jobparam,
                    conditions,
                    None,
                    hours,
                    tstart,
                    tend,
                    field,
                    days,
                    format,
                    jobtype,
                    testsite,
                    None,
                    True,
                )
                rows = jobs["rows"]
                indx = []
                if len(rows) > 30:
                    for i, r in enumerate(rows):
                        try:
                            if r[1] > minjob:
                                indx.append(i)
                                continue
                        except:
                            pass
                    cleanrows = [rows[i] for i in indx]
                    jobs["rows"] = cleanrows
                istatus = utils.name2Index(jobs["header"], "jobstatus")
                if istatus != None:
                    statOrder = utils.name2Index(utils.jobStates)

                    def byStatus(a, b):
                        return statOrder[a[istatus]] - statOrder[b[istatus]]

                    jobs["rows"] = sorted(jobs["rows"], cmp=byStatus)
            else:
                if jobparam == self._allparams and conditions.get(self._jobParametersName) == None:
                    conditions[self._jobParametersName] = "any"
                jobs = pmt.getJobsAtt(
                    pandaid,
                    "PandaID," + jobparam,
                    conditions,
                    None,
                    hours,
                    tstart,
                    tend,
                    field,
                    days,
                    format,
                    jobtype,
                    testsite,
                    limit,
                )
                errorcolcheck = True
            if len(jobs) > 0:
                header = [nmap.get(h) for h in jobs["header"]]
                info = jobs["rows"]
                main["header"] = header  #  + self._extraFields
                timecols = []
                errdict = None
                errorcol = not errorcolcheck
                for i, h in enumerate(header):
                    if "time" in h.lower() and "cpuconsumptiontime" != h.lower():
                        timecols.append(i)
                    if not errorcol and "error" in h.lower():
                        errorcol = True
                ##               # add an artificial retryID
                ##               header += ['retryID']
                headindx = utils.name2Index(header)
                creationtDict = {}
                histograms = {}
                prodSourceLabel = headindx.get("prodSourceLabel")
                jobStatus = headindx.get("jobStatus")
                status4title = conditions.get("jobStatus")
                if not utils.isFilled(status4title):
                    if len(info) == 1 and jobStatus != None:
                        status4title = info[0][jobStatus]
                if utils.isFilled(status4title):
                    title = status4title[0].upper() + status4title[1:] + " " + title
                prodtype = "production" in jobtype.lower() if jobtype != None else True
                taskidsum = prodtype
                if not utils.isValid(summary) and dump != "yes":
                    jsets = setutils.factory(header, info, self._errorCodes, self._siteId, self._siteNicks)
                    main["jobset"] = jsets.jobsets()
                for r in info:
                    if not taskidsum and ((prodSourceLabel and r[prodSourceLabel] == "managed") and prodtype):
                        taskidsum = True
                    if errorcol and errorcolcheck:
                        errdict = self.getErrors(r, headindx, errdict)
                    for t in timecols:
                        r[t] = utils.epochTime(r[t])
                ##                  r += [None] # retryID
                # row = self.jobsetTime(utils.zip(header(info[r])),creationtDict,histograms)
                # info[r] = self.addFields(utils.zip(header(info[r])),creationtDict,histograms)
                # Action            cleanUserID SSL_CLIENT_S_DN
                main["info"] = info
                if errorcolcheck:
                    main["errorCodes"] = errdict
                main["colNames"] = sorted(header)
                main["jobsummary"] = copy.copy(self._jobSum)
                if taskidsum:
                    main["jobsummary"] += [["Task ID", "taskID"]]
                #               print utils.lineInfo(), "===============", self._description.get("JEDITASKID"), self._description.get("JediTaskID")
                #               if self._description.get("JEDITASKID") or self._description.get("JediTaskID"):
                #                  main['jobsummary'] += [['Jedi ID','JediTaskID']]
                elif jobtype != "jedi":
                    main["jobsummary"] += [["Jobsets", "jobsetID"]]  #  need constrain
                elif jobtype == "analysis":
                    main["jobsummary"] += [["Analysis Tasks", "destinationDBlock"]]
                if showcpu == "yes":
                    main["jobsummary"] += [["CPU Type", "cpuConsumptionUnit"]]
        self.publishTitle(title)
        return main
예제 #10
0
파일: wnlist.py 프로젝트: vfine/webplatform
 def doQuery(self,site='all',jobtype='all',days=1,hostonly='yes',plot='finished,failed',style='SB', details=None,deep='no'):
    """ Get the list of the  jobs' status per worker node for selected site for upto 3 last days
      <ol>
      <li><code>site</code> - site to get the information about or "all"
      <li><code>jobtype</code> = 'production" or " analysis" or "all"
      <li><code>days</code> - number of days we want to fetch the information for. This parameter must be less or equal 3. 
      <li><code>hostonly</code> - "yes" . "no" - means provide the information 'per CPU' rather 'per host'
      <li><code>plot</code> - the comma separated list of the <a href='https://twiki.cern.ch/twiki/bin/viewauth/Atlas/PandaShiftGuide#Job_state_definitions_in_Panda'>job status names</a> to generate the plot for 
      <li><code>style</code>  the combination of the symbols: 'H' - histogram, 'B' - bar , 'L' - line, 'P' - points, 'S' - stacked<br>
           = 'BS' - 'by default'
      <li><code>details</code> - 'yes' - provide   the status per host<br>
      <br>  = 'summary' - provide the summary only <br>
           default = 'yes' if not site == 'all' else 'no'
      <li><code>deep</code> - do not look up the "long job table" . It can be very slow.
           default = 'no'       
      <li> <b><a title='Click to see the full list of the  parameters available' href='http://pandamon.cern.ch/describe?table=^JOBSARCHIVED4&doc=*'>PARAM</a>=value</b> - comma-separated list of the value <a href ='https://twiki.cern.ch/twiki/bin/view/PanDA/PandaPlatform#API_parameter_value_format'> patterns</a> to filter the job records.
      <li><code>jobStatus</code> - it can be any comma-separated list of the Panda Jobs states patterns or / and <br>
      two 'meta' states: "factory" to list the "factory" nodes and "wn" to list the the Worker Nodes
      </ol>
    """
    vals = self.extraValuesFilled()
    if site == None: site='all'
    factory = None
    wn = None
    titletype = "PanDA"
    jobStatus = None
    if vals != None:
       jstat = vals.get('jobStatus')
       jobStatus  =  jstat
       if jstat != None:
          jstat = [x.lower() for x in utils.parseArray(jstat)]
          print utils.lineInfo(), jstat, 'factory' in jstat
          if 'factory' in jstat:
             factory = self.factory()
             jstat += factory
             titletype = "Factory"
          if 'wn' in jstat:
             wn = self.wn()
             jstat += wn
             titletype = "Worker"
          jstat = list(set(jstat))
          vals['jobStatus'] = ','.join(jstat)
    if deep == None or deep == False: deep =  'no'
    deep = not deep.lower() == 'no'
    title = ''
    hours =  (float(days))*24
    Deep = 'Deep' if deep else ''
    if float(days) > 3 and False and not deep: 
       days = 3.0
       hours = 24*days
       title = 'The List of the %s Nodes Activity for the Last %s Hours Only.' % (titletype, int(hours))
    else:
       title = 'The %s List of the %s  Nodes Activity for the %s Hours' % (Deep, titletype,int(hours)  )
       days = float(days)
    try:
      if jobtype.lower() == 'all': jobtype=None
    except:
       pass
    self.publishTitle(title)
    modes = ( 'Defined', 'Waiting', 'Active', 'Archived' )
    tables = []
    for mode in modes: tables += ['ATLAS_PANDA.jobs%s4' % mode]
    if days>3 and deep: tables += ['ATLAS_PANDAARCH.JOBSARCHIVED'] 
    q = pmt.wnList(site, jobtype, table=tables, days=days,conditions = vals)
    try:
       if details == None: 
          details = not (site == None or site == 'None' or site.lower() == 'all' or site == '*' )
       # else:
          # details = isinstance(details,str) and details.lower() == 'yes'
    except:
       details = False       
    ## Publish the result
    main = {}
    main['data'] = self.do(q['header'],q['rows'],site,hostonly,details,factory,wn)
    main['params'] = { 'jobtype': jobtype,'days': days,'site': site,'hostonly':hostonly,'jobStatus':jobStatus}
    plotpars = []
    if plot:
       for p in plot.split(","):
          if p.lower() == 'prerun' or factory != None: 
             if wn == None: plotpars += self.factory()
             if factory == None:
                plotpars += ['pending','sent','starting']
          elif p.lower() == 'finishing' and factory == None: 
             plotpars += ['holding','transferring']
          else:
             plotpars += [p]
       main['params']['plot'] = list(set(plotpars)) # remove duplicates
    if style: main['params']['style'] = style
    self.publish(main)
    self.publishNav(' type=%s days= last %s '  % (jobtype, days ) )
    self.publish( "%s/%s" % ( self.server().fileScriptURL(),"monitor/%s.js" % "wnlist" ),role=pmRoles.script())
    self.publish( {'s-maxage':600,'max-age': 600}, role=pmRoles.cache())
예제 #11
0
    def doJobs(self,
               pandaid=None,
               params=None,
               jobparam=None,
               table=None,
               hours=None,
               tstart=None,
               tend=None,
               field='modificationTime',
               days=None,
               format=None,
               jobtype=None,
               testsite=None,
               limit=1500,
               summary=None,
               minjob=1,
               dump=None,
               region=None,
               lfn=None,
               showcpu=None):
        ## Perform the query
        main = {}
        errorcolcheck = False
        selection = '*'
        vals = self.extraValuesFilled(self._alias)

        title = 'PanDA Job(s)'
        if utils.isFilled(pandaid):
            hours = None
            days = None
            title += " %s " % pandaid
        if days != None:
            title += ' for %.2f Day' % float(days)
            if days > 1: title += "s"
        if hours != None:
            if days == None: title += " for "
            title += ' %d Hour' % int(hours)
            if hours > 1: title += "s"

        if vals != None:
            for k in vals.keys():
                if vals[k] == 'undefined': vals[k] = None
                elif vals[k] != None and k.lower() == 'jobstatus' and (
                        vals[k].lower().find('prerun') >= 0
                        or vals[k].lower().find('finishing') >= 0
                        or vals[k].lower().find('unassigned') >= 0
                        or vals[k].lower().find('retried') >= 0):
                    stvals = utils.parseArray(vals[k])
                    statvals = []
                    for v in stvals:
                        if v.lower() == 'prerun':
                            statvals += [
                                'defined', 'assigned', 'waiting', 'activated',
                                'pending', 'sent', 'starting'
                            ]
                        elif v.lower() == 'finishing':
                            statvals += ['holding', 'transferring']
                        elif v.lower() == 'unassigned':
                            vals['computingSite'] = 'NULL'
                            statvals += ['cancelled']
                        elif v.lower() == 'retried':
                            # See the slide 3 from Tadashi: https://indico.cern.ch/getFile.py/access?contribId=13&sessionId=11&resId=0&materialId=slides&confId=119171
                            vals['taskBufferErrorCode'] = [106, 107]
                            statvals += ['failed']
                        else:
                            statvals += [v]
                        vals[k] = ','.join(statvals)
            cleanVal = dict(
                (k, v) for k, v in vals.iteritems() if v is not None)
            vals = cleanVal
        if vals == None: vals = {}
        nav = ''
        certificate = None
        certusr = None
        try:
            cert = self.server().certificate()
            if cert != None:
                certusr = pmt.cleanUserID(cert)
                main['ceruser'] = certusr
        except:
            pass
        if vals.get('prodUserName') == 'auto' and certusr != None:
            if cert != None: vals['prodUserName'] = certusr
        for v in vals:
            nav += "<b>%s</b>=%s " % (v, vals[v])
        # nav += "<span id=linkjobid  stule='display:inline'></span>"
        # nav +="<script>$(document).ready(function(){$('#linkjobid').html(utils().linkJobs(s.cloud,jobtype"
        # nav += jobtype if jobtype!=None else "undefined"
        # nav += ", s.jobStatus, "
        # nav += "%d" % hours if hours!=None else "undefined"
        # nav += ", s.computingSite,'Classic Page' ))});</script>";
        if not utils.isFilled(summary):
            nav += "<b>%s</b>=%s " % ('limit', limit)

        self.publishNav(nav)
        if len(vals) == 0: vals = None
        if vals == None and jobparam == None:
            main['Description'] = self.description()
        else:
            if lfn != None and lfn != "undefined":
                lfnselect = 'pandaid,lfn'
                lfnjobs = pmt.getJobLFN(select=lfnselect,
                                        table='new',
                                        lfn=lfn,
                                        pandaid=pandaid,
                                        type='*',
                                        limit=limit)
                if lfnjobs['rows'] > 0:
                    pandaid = [ljobs[0] for ljobs in lfnjobs['rows']]
            selection = {}
            if vals != None: selection.update(vals)
            if pandaid != None:
                selection.update({nmap.get('pandaid'): pandaid})
            if region != None: selection.update({'region': region})
            main['Selection'] = selection
            conditions = vals
            if conditions == None: conditions = {}
            cs = conditions.get('computingSite')
            if cs == None:
                site4region = self.getSite4Region(region)
                if site4region != None and len(site4region) > 0:
                    conditions['computingSite'] = site4region
            else:
                pass  # ignore the region parameter
            if utils.isValid(summary):
                jobtype = 'production' if jobtype == None and jobparam.lower(
                ).find('taskid') >= 0 and jobparam.lower().find(
                    'jeditaskid') < 0 else jobtype
                jobs = pmt.getJobsAtt(pandaid, jobparam, conditions, None,
                                      hours, tstart, tend, field, days, format,
                                      jobtype, testsite, None, True)
                rows = jobs['rows']
                indx = []
                if len(rows) > 30:
                    for i, r in enumerate(rows):
                        try:
                            if r[1] > minjob:
                                indx.append(i)
                                continue
                        except:
                            pass
                    cleanrows = [rows[i] for i in indx]
                    jobs['rows'] = cleanrows
                istatus = utils.name2Index(jobs['header'], 'jobstatus')
                if istatus != None:
                    statOrder = utils.name2Index(utils.jobStates)

                    def byStatus(a, b):
                        return statOrder[a[istatus]] - statOrder[b[istatus]]

                    jobs['rows'] = sorted(jobs['rows'], cmp=byStatus)
            else:
                if jobparam == self._allparams and conditions.get(
                        self._jobParametersName) == None:
                    conditions[self._jobParametersName] = 'any'
                jobs = pmt.getJobsAtt(pandaid, 'PandaID,' + jobparam,
                                      conditions, None, hours, tstart, tend,
                                      field, days, format, jobtype, testsite,
                                      limit)
                errorcolcheck = True
            if len(jobs) > 0:
                header = [nmap.get(h) for h in jobs['header']]
                info = jobs['rows']
                main['header'] = header  #  + self._extraFields
                timecols = []
                errdict = None
                errorcol = not errorcolcheck
                for i, h in enumerate(header):
                    if 'time' in h.lower(
                    ) and 'cpuconsumptiontime' != h.lower():
                        timecols.append(i)
                    if not errorcol and 'error' in h.lower():
                        errorcol = True
##               # add an artificial retryID
##               header += ['retryID']
                headindx = utils.name2Index(header)
                creationtDict = {}
                histograms = {}
                prodSourceLabel = headindx.get('prodSourceLabel')
                jobStatus = headindx.get('jobStatus')
                status4title = conditions.get('jobStatus')
                if not utils.isFilled(status4title):
                    if len(info) == 1 and jobStatus != None:
                        status4title = info[0][jobStatus]
                if utils.isFilled(status4title):
                    title = status4title[0].upper(
                    ) + status4title[1:] + " " + title
                prodtype = 'production' in jobtype.lower(
                ) if jobtype != None else True
                taskidsum = prodtype
                if not utils.isValid(summary) and dump != 'yes':
                    jsets = setutils.factory(header, info, self._errorCodes,
                                             self._siteId, self._siteNicks)
                    main['jobset'] = jsets.jobsets()
                for r in info:
                    if not taskidsum and (
                        (prodSourceLabel and r[prodSourceLabel] == 'managed')
                            and prodtype):
                        taskidsum = True
                    if errorcol and errorcolcheck:
                        errdict = self.getErrors(r, headindx, errdict)
                    for t in timecols:
                        r[t] = utils.epochTime(r[t])
##                  r += [None] # retryID
# row = self.jobsetTime(utils.zip(header(info[r])),creationtDict,histograms)
# info[r] = self.addFields(utils.zip(header(info[r])),creationtDict,histograms)
# Action            cleanUserID SSL_CLIENT_S_DN
                main['info'] = info
                if errorcolcheck:
                    main['errorCodes'] = errdict
                main['colNames'] = sorted(header)
                main['jobsummary'] = copy.copy(self._jobSum)
                if taskidsum:
                    main['jobsummary'] += [['Task ID', 'taskID']]


#               print utils.lineInfo(), "===============", self._description.get("JEDITASKID"), self._description.get("JediTaskID")
#               if self._description.get("JEDITASKID") or self._description.get("JediTaskID"):
#                  main['jobsummary'] += [['Jedi ID','JediTaskID']]
                elif jobtype != 'jedi':
                    main['jobsummary'] += [['Jobsets',
                                            'jobsetID']]  #  need constrain
                elif jobtype == 'analysis':
                    main['jobsummary'] += [[
                        'Analysis Tasks', 'destinationDBlock'
                    ]]
                if showcpu == 'yes':
                    main['jobsummary'] += [['CPU Type', 'cpuConsumptionUnit']]
        self.publishTitle(title)
        return main