コード例 #1
0
 def to_json(obj):
     if isinstance(obj, datetime):
         return format_datetime(obj)
     raise TypeError('Cannot JSON-encode object')
コード例 #2
0
    def job(self, id_, command=None, finishid=None,

            barerows=None, unfiltered=None, limit=None, enddate=None,

            submit_config=None, submit_relink=None,
            submit_confirm=None, submit_cancel=None,
            orphan=None, graceperiod=None, timeout=None,
            success_pattern=None, warning_pattern=None, fail_pattern=None,
            note=None, inhibit=None,
            crabid=None,

            submit_notify=None, **kwargs):
        """Displays information about a current job.

        Currently also supports showing the job output.
        If command='output' but the finishid is not provided, then
        it will find the most recent output for the given job."""

        try:
            id_ = int(id_)
        except ValueError:
            raise HTTPError(400, 'Job number not a number')

        info = self.store.get_job_info(id_)
        if info is None:
            raise HTTPError(404, 'Job not found')

        if command is None:
            if limit is None:
                limit = 100
            else:
                try:
                    limit = int(limit)
                except ValueError:
                    raise HTTPError(400, 'Limit is not a number')
                if limit < 1:
                    raise HTTPError(400, 'Limit should not be less than one')
                elif limit > 1000:
                    raise HTTPError(400, 'Limit greater than a thousand')

            if unfiltered is None:
                squash_start = True
            else:
                squash_start = False

            if enddate is not None:
                try:
                    enddate = parse_datetime(enddate)
                except ValueError:
                    raise HTTPError(400, 'Start date format is invalid')

            events = self.store.get_job_events(id_, limit, end=enddate)

            if events:
                lastdatetime = format_datetime(events[-1]['datetime'])
            else:
                lastdatetime = None

            # Filter the events.
            filter = CrabEventFilter(self.store, info['timezone'])
            events = filter(events, squash_start=squash_start,
                            skip_trivial=squash_start)

            if barerows is not None:
                return self._write_template(
                    'jobevents.html',
                    {'id': id_, 'events': events,
                     'lastdatetime': lastdatetime})

            # Try to convert the times to the timezone shown on the page.
            info['installed'] = filter.in_timezone(info['installed'])
            info['deleted'] = filter.in_timezone(info['deleted'])

            # Fetch configuration.
            config = self.store.get_job_config(id_)

            # Fetch job notifications.
            if config is not None:
                notification = self.store.get_job_notifications(
                                   config['configid'])
            else:
                notification = None

            return self._write_template(
                'job.html',
                {'id': id_, 'info': info, 'config': config,
                 'status': self.monitor.get_job_status(id_),
                 'notification': notification, 'events': events,
                 'lastdatetime': lastdatetime})

        elif command == 'clear':
            if submit_confirm:
                self.store.log_alarm(id_, CrabStatus.CLEARED)

                # Wait for the monitor to process new events so that
                # that the job is in an 'OK' state before we reload the page.
                with self.monitor.new_event:
                    self.monitor.new_event.wait(10)

                raise HTTPRedirect("/job/" + str(id_))

            elif submit_cancel:
                raise HTTPRedirect("/job/" + str(id_))

            else:
                return self._write_template(
                    'confirm.html',
                    {'id': id_, 'info': info,
                     'title': 'clear status',
                     'description': 'Reset the job status?',
                     'target': '/job/' + str(id_) + '/clear'})

        elif command == 'uninhibit':
            if submit_confirm:
                self.store.disable_inhibit(id_)
                raise HTTPRedirect('/job/' + str(id_))
            elif submit_cancel:
                raise HTTPRedirect('/job/' + str(id_))
            else:
                return self._write_template(
                    'confirm.html',
                    {'id': id_, 'info': info, 'title': 'resume',
                     'description': 'Resume inhibited job?',
                     'target': '/job/' + str(id_) + '/uninhibit'})

        elif command == 'delete':
            notdeleted = info['deleted'] is None
            if submit_confirm:
                if notdeleted:
                    self.store.delete_job(id_)
                else:
                    self.store.undelete_job(id_)

                raise HTTPRedirect('/job/' + str(id_))

            elif submit_cancel:
                raise HTTPRedirect('/job/' + str(id_))

            else:
                return self._write_template(
                    'confirm.html',
                    {'id': id_, 'info': info,
                     'title': 'delete' if notdeleted else 'undelete',
                     'description': (('Delete' if notdeleted else 'Undelete') +
                                     ' this job from the server?'),
                     'target': '/job/' + str(id_) + '/delete'})

        elif command == 'changeid':
            if submit_confirm:
                if crabid != '':
                    if self.store.get_jobs(
                            info['host'], info['user'],
                            include_deleted=True, crabid=crabid):
                        raise HTTPError(
                            400, 'Specified job ID already exists.')
                    else:
                        self.store.update_job(id_, crabid=crabid)
                        raise HTTPRedirect('/job/' + str(id_))
                else:
                    raise HTTPError(400, 'Specified job ID is blank.')

            elif submit_cancel:
                raise HTTPRedirect('/job/' + str(id_))

            else:
                return self._write_template(
                    'confirm.html',
                    {'id': id_, 'info': info,
                     'title': 'change identifier',
                     'description': 'Change Job ID for this job?  Please note '
                                    'that the ID which will be used to report '
                                    'events related to this job should be '
                                    'updated at the same time to ensure that '
                                    'the job continues to be correctly '
                                    'identified.  This should be done in the '
                                    'crontab if the CRABID variable is used, '
                                    'or in the cron job itself in the case '
                                    'of Crab-aware cron jobs.',
                     'target': '/job/' + str(id_) + '/changeid',
                     'data': {'crabid': crabid}})

        elif command == 'output':
            finishid_next = None
            finishid_prev = None

            if finishid is None:
                # If finishid is not specified, select the most recent
                # for this job.
                finishes = self.store.get_job_finishes(id_, limit=2)

                if not finishes:
                    raise HTTPError(404, 'No job output found')

                finish = finishes[0]
                finishid = finish['finishid']

                if len(finishes) > 1:
                    finishid_prev = finishes[1]['finishid']

            else:
                try:
                    finishid = int(finishid)
                except ValueError:
                    raise HTTPError(400, 'Finish ID is not a number')

                finishes = self.store.get_job_finishes(id_, finishid=finishid)
                if not finishes:
                    raise HTTPError(404, 'Finish ID not found or wrong job')
                finish = finishes[0]

                finishes = self.store.get_job_finishes(id_, 1, before=finishid)
                if finishes:
                    finishid_prev = finishes[0]['finishid']

                finishes = self.store.get_job_finishes(id_, 1, after=finishid)
                if finishes:
                    finishid_next = finishes[0]['finishid']

            (stdout, stderr) = self.store.get_job_output(
                finishid, info['host'], info['user'], id_, info['crabid'])

            filter = CrabEventFilter(self.store, info['timezone'])
            finish['datetime'] = filter.in_timezone(finish['datetime'])

            return self._write_template(
                'joboutput.html',
                {'id': id_, 'info': info, 'finish': finish,
                 'stdout': stdout, 'stderr': stderr,
                 'next': finishid_next, 'prev': finishid_prev})

        elif command == 'config':
            if submit_relink:
                try:
                    orphan = int(orphan)
                except ValueError:
                    raise HTTPError(400, 'Orphan number not a number')

                self.store.relink_job_config(orphan, id_)
                raise HTTPRedirect("/job/" + str(id_))

            elif submit_config:
                try:
                    if timeout == '':
                        timeout = None
                    elif timeout is not None:
                        timeout = int(timeout)
                    if graceperiod == '':
                        graceperiod = None
                    elif graceperiod is not None:
                        graceperiod = int(graceperiod)

                    if success_pattern == '':
                        success_pattern = None
                    if warning_pattern == '':
                        warning_pattern = None
                    if fail_pattern == '':
                        fail_pattern = None

                    if note is not None:
                        note = note.strip()
                        if note == '':
                            note = None

                    inhibit = inhibit is not None

                except ValueError:
                    raise HTTPError(400, 'Time not a number')

                self.store.write_job_config(
                    id_, graceperiod, timeout,
                    success_pattern, warning_pattern, fail_pattern, note,
                    inhibit)
                raise HTTPRedirect("/job/" + str(id_))

            else:
                config = self.store.get_job_config(id_)

                if config is None:
                    orphan = self.store.get_orphan_configs()
                else:
                    orphan = None

                return self._write_template(
                    'jobconfig.html',
                    {'id': id_, 'info': info, 'config': config,
                     'orphan': orphan})

        elif command == 'notify':
            if submit_notify:
                # Ensure that this job has a configuration entry
                # so that we can link to it.
                config = self.store.get_job_config(id_)

                if config is not None:
                    configid = config['configid']
                else:
                    configid = self.store.write_job_config(id_)

                # Make a list of notifications for this job
                # so that we can delete those which are not
                # included in the POST parameters.
                existing = set()
                for notification in self.store.get_job_notifications(configid):
                    existing.add(notification['notifyid'])

                # Update existing notifications.
                for kwarg in kwargs:
                    match = re.search('method_(new_)?(\d+)', kwarg)
                    if not match:
                        continue

                    if match.group(1):
                        key = ''.join(match.groups())
                        notifyid = None
                    else:
                        key = match.group(2)
                        notifyid = int(key)
                        existing.discard(notifyid)

                    self.store.write_notification(
                            notifyid, configid,
                            None, None,
                            kwargs['method_' + key],
                            kwargs['address_' + key],
                            empty_to_none(kwargs['time_' + key]),
                            empty_to_none(kwargs['timezone_' + key]),
                            'include_ok_' + key not in kwargs,
                            'include_warning_' + key not in kwargs,
                            'include_error_' + key not in kwargs,
                            'include_output_' + key in kwargs)

                # Delete existing notifications which were not present.
                for notifyid in existing:
                    self.store.delete_notification(notifyid)

                raise HTTPRedirect('/job/' + str(id_))
            else:
                config = self.store.get_job_config(id_)

                if config is not None:
                    notifications = self.store.get_job_notifications(
                                        config['configid'])
                else:
                    notifications = None

                return self._write_template(
                    'editnotify.html',
                    {'match_mode': False,
                     'id': id_, 'info': info,
                     'notifications': notifications})

        else:
            raise HTTPError(404, 'Unknown job command')