Beispiel #1
0
 def __init__(self, script_name, level=logging.WARN, logger=None):
     logging.Handler.__init__(self, level)
     # Context for OOPS reports.
     self.request = ScriptRequest([('script_name', script_name),
                                   ('path', sys.argv[0])])
     self.setFormatter(LaunchpadFormatter())
     self.logger = logger
Beispiel #2
0
def report_oops(file_alias_url=None, error_msg=None):
    """Record an OOPS for the current exception and return the OOPS ID."""
    info = sys.exc_info()
    properties = []
    if file_alias_url is not None:
        properties.append(('Sent message', file_alias_url))
    if error_msg is not None:
        properties.append(('Error message', error_msg))
    request = ScriptRequest(properties)
    request.principal = get_current_principal()
    errorUtility = ErrorReportingUtility()
    # Report all exceptions: the mail handling code doesn't expect any in
    # normal operation.
    errorUtility._ignored_exceptions = set()
    report = errorUtility.raising(info, request)
    # Note that this assert is arguably bogus: raising is permitted to filter
    # reports.
    assert report is not None, ('No OOPS generated.')
    return report['id']
Beispiel #3
0
 def test_raising_unauthorized_without_principal(self):
     """Unauthorized exceptions are logged when the request has no
     principal."""
     utility = ErrorReportingUtility()
     utility._oops_config.publisher = None
     request = ScriptRequest([('name2', 'value2')])
     try:
         raise Unauthorized('xyz')
     except Unauthorized:
         self.assertNotEqual(None, utility.raising(sys.exc_info(), request))
Beispiel #4
0
def report_oops(file_alias_url=None, error_msg=None):
    """Record an OOPS for the current exception and return the OOPS ID."""
    info = sys.exc_info()
    properties = []
    if file_alias_url is not None:
        properties.append(('Sent message', file_alias_url))
    if error_msg is not None:
        properties.append(('Error message', error_msg))
    request = ScriptRequest(properties)
    request.principal = get_current_principal()
    errorUtility = ErrorReportingUtility()
    # Report all exceptions: the mail handling code doesn't expect any in
    # normal operation.
    errorUtility._ignored_exceptions = set()
    report = errorUtility.raising(info, request)
    # Note that this assert is arguably bogus: raising is permitted to filter
    # reports.
    assert report is not None, ('No OOPS generated.')
    return report['id']
Beispiel #5
0
 def _reportError(self, path, exception, hosting_path=None):
     properties = [
         ("path", path),
         ("error-explanation", unicode(exception)),
         ]
     if hosting_path is not None:
         properties.append(("hosting_path", hosting_path))
     request = ScriptRequest(properties)
     getUtility(IErrorReportingUtility).raising(sys.exc_info(), request)
     raise faults.OopsOccurred("creating a Git repository", request.oopsid)
Beispiel #6
0
    def process(self):
        """Process an upload that is the result of a build.

        The name of the leaf is the build id of the build.
        Build uploads always contain a single package per leaf.
        """
        logger = BufferLogger()
        if self.build.status != BuildStatus.UPLOADING:
            self.processor.log.warn(
                "Expected build status to be 'UPLOADING', was %s. Ignoring." %
                self.build.status.name)
            return
        try:
            # The recipe may have been deleted so we need to flag that here
            # and will handle below. We check so that we don't go to the
            # expense of doing an unnecessary upload. We don't just exit here
            # because we want the standard cleanup to occur.
            recipe_deleted = (ISourcePackageRecipeBuild.providedBy(self.build)
                              and self.build.recipe is None)
            if recipe_deleted:
                result = UploadStatusEnum.FAILED
            else:
                self.processor.log.debug("Build %s found" % self.build.id)
                [changes_file] = self.locateChangesFiles()
                logger.debug("Considering changefile %s" % changes_file)
                result = self.processChangesFile(changes_file, logger)
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            info = sys.exc_info()
            message = ('Exception while processing upload %s' %
                       self.upload_path)
            properties = [('error-explanation', message)]
            request = ScriptRequest(properties)
            error_utility = ErrorReportingUtility()
            error_utility.raising(info, request)
            logger.error('%s (%s)' % (message, request.oopsid))
            result = UploadStatusEnum.FAILED
        if (result != UploadStatusEnum.ACCEPTED
                or not self.build.verifySuccessfulUpload()):
            self.build.updateStatus(BuildStatus.FAILEDTOUPLOAD)
        if self.build.status != BuildStatus.FULLYBUILT:
            if recipe_deleted:
                # For a deleted recipe, no need to notify that uploading has
                # failed - we just log a warning.
                self.processor.log.warn(
                    "Recipe for build %s was deleted. Ignoring." % self.upload)
            else:
                self.build.storeUploadLog(logger.getLogBuffer())
                self.build.notify(extra_info="Uploading build %s failed." %
                                  self.upload)
        else:
            self.build.notify()
        self.processor.ztm.commit()
        self.moveProcessedUpload(result, logger)
Beispiel #7
0
    def main(self):
        notifications_sent = False
        bug_notification_set = getUtility(IBugNotificationSet)
        deferred_notifications = \
            bug_notification_set.getDeferredNotifications()
        process_deferred_notifications(deferred_notifications)
        pending_notifications = get_email_notifications(
            bug_notification_set.getNotificationsToSend())
        for (bug_notifications,
             omitted_notifications,
             messages) in pending_notifications:
            try:
                for message in messages:
                    try:
                        self.logger.info("Notifying %s about bug %d." % (
                            message['To'], bug_notifications[0].bug.id))
                        sendmail(message)
                        self.logger.debug(message.as_string())
                    except SMTPException:
                        request = ScriptRequest([
                            ("script_name", self.name),
                            ("path", sys.argv[0]),
                            ])
                        error_utility = getUtility(IErrorReportingUtility)
                        oops_vars = {
                            "message_id": message.get("Message-Id"),
                            "notification_type": "bug",
                            "recipient": message["To"],
                            "subject": message["Subject"],
                            }
                        with error_utility.oopsMessage(oops_vars):
                            error_utility.raising(sys.exc_info(), request)
                        self.logger.info(request.oopsid)
                        self.txn.abort()
                        # Re-raise to get out of this loop and go to the
                        # next iteration of the outer loop.
                        raise
            except SMTPException:
                continue
            for notification in bug_notifications:
                notification.date_emailed = UTC_NOW
                notification.status = BugNotificationStatus.SENT
            for notification in omitted_notifications:
                notification.date_emailed = UTC_NOW
                notification.status = BugNotificationStatus.OMITTED
            notifications_sent = True
            # Commit after each batch of email sent, so that we won't
            # re-mail the notifications in case of something going wrong
            # in the middle.
            self.txn.commit()

        if not notifications_sent:
            self.logger.debug("No notifications are pending to be sent.")
Beispiel #8
0
def report_oops(message=None,
                properties=None,
                info=None,
                transaction_manager=None):
    """Record an oops for the current exception.

    This must only be called while handling an exception.

    Searches for 'URL', 'url', or 'baseurl' properties, in order of
    preference, to use as the linked URL of the OOPS report.

    :param message: custom explanatory error message. Do not use
        str(exception) to fill in this parameter, it should only be
        set when a human readable error has been explicitly generated.

    :param properties: Properties to record in the OOPS report.
    :type properties: An iterable of (name, value) tuples.

    :param info: Exception info.
    :type info: The return value of `sys.exc_info()`.

    :param transaction_manager: A transaction manager. If specified,
        further commit() calls will be logged.
    """
    # Get the current exception info first of all.
    if info is None:
        info = sys.exc_info()

    # Collect properties to report.
    if properties is None:
        properties = []
    else:
        properties = list(properties)

    if message is not None:
        properties.append(('error-explanation', message))

    # Find a candidate for the request URL.
    def find_url():
        for name in 'URL', 'url', 'baseurl':
            for key, value in properties:
                if key == name:
                    return value
        return None

    url = find_url()

    # Create the dummy request object.
    request = ScriptRequest(properties, url)
    error_utility = ErrorReportingUtility()
    error_utility.configure(section_name='checkwatches')
    error_utility.raising(info, request)
    return request
Beispiel #9
0
 def test__makeErrorReport_combines_request_and_error_vars(self):
     """The oops messages should be distinct from real request vars."""
     utility = ErrorReportingUtility()
     utility._oops_config.publisher = None
     request = ScriptRequest([('c', 'd')])
     with utility.oopsMessage(dict(a='b')):
         try:
             raise ArbitraryException('foo')
         except ArbitraryException:
             info = sys.exc_info()
             oops = utility._oops_config.create(
                 dict(exc_info=info, http_request=request))
             self.assertEqual({
                 '<oops-message-0>': "{'a': 'b'}",
                 'c': 'd'
             }, oops['req_vars'])
Beispiel #10
0
    def process(self):
        """Process an upload's changes files, and move it to a new directory.

        The destination directory depends on the result of the processing
        of the changes files. If there are no changes files, the result
        is 'failed', otherwise it is the worst of the results from the
        individual changes files, in order 'failed', 'rejected', 'accepted'.
        """
        changes_files = self.locateChangesFiles()

        results = set()

        for changes_file in changes_files:
            self.processor.log.debug("Considering changefile %s" %
                                     changes_file)
            try:
                results.add(
                    self.processChangesFile(changes_file, self.processor.log))
            except (KeyboardInterrupt, SystemExit):
                raise
            except:
                info = sys.exc_info()
                message = ('Exception while processing upload %s' %
                           self.upload_path)
                properties = [('error-explanation', message)]
                request = ScriptRequest(properties)
                error_utility = ErrorReportingUtility()
                error_utility.raising(info, request)
                self.processor.log.error('%s (%s)' % (message, request.oopsid))
                results.add(UploadStatusEnum.FAILED)
        if len(results) == 0:
            destination = UploadStatusEnum.FAILED
        else:
            for destination in [
                    UploadStatusEnum.FAILED, UploadStatusEnum.REJECTED,
                    UploadStatusEnum.ACCEPTED
            ]:
                if destination in results:
                    break
        self.moveProcessedUpload(destination, self.processor.log)
    def processQueueItem(self, queue_item):
        """Attempt to process `queue_item`.

        This method swallows exceptions that occur while processing the
        item.

        :param queue_item: A `PackageUpload` to process.
        :return: True on success, or False on failure.
        """
        self.logger.debug("Processing queue item %d" % queue_item.id)
        try:
            queue_item.realiseUpload(self.logger)
        except Exception:
            message = "Failure processing queue_item %d" % queue_item.id
            properties = [('error-explanation', message)]
            request = ScriptRequest(properties)
            ErrorReportingUtility().raising(sys.exc_info(), request)
            self.logger.error('%s (%s)', message, request.oopsid)
            return False
        else:
            self.logger.debug("Successfully processed queue item %d",
                              queue_item.id)
            return True
Beispiel #12
0
    def test_raising_for_script(self):
        """Test ErrorReportingUtility.raising with a ScriptRequest."""
        utility = ErrorReportingUtility()
        utility._oops_config.publisher = None

        # A list because code using ScriptRequest expects that - ScriptRequest
        # translates it to a dict for now.
        req_vars = [
            ('name2', 'value2'),
            ('name1', 'value1'),
            ('name1', 'value3'),
        ]
        url = 'https://launchpad.net/example'
        try:
            raise ArbitraryException('xyz\nabc')
        except ArbitraryException:
            # Do not test escaping of request vars here, it is already tested
            # in test_raising_with_request.
            request = ScriptRequest(req_vars, URL=url)
            report = utility.raising(sys.exc_info(), request)

        self.assertEqual(url, report['url'])
        self.assertEqual(dict(req_vars), report['req_vars'])