Beispiel #1
0
    def cancel(self, build_id):
        """Cancels build. Does not require a lease key.

    The current user has to have a permission to cancel a build in the
    bucket.

    Returns:
      Canceled Build.
    """
        build = model.Build.get_by_id(build_id)
        if build is None:
            raise errors.BuildNotFoundError()
        if not acl.can_cancel_build(build):
            raise current_identity_cannot('cancel build %s', build.key.id())
        if build.status == model.BuildStatus.COMPLETED:
            if build.result == model.BuildResult.CANCELED:
                return build
            raise errors.BuildIsCompletedError(
                'Cannot cancel a completed build')
        build.status = model.BuildStatus.COMPLETED
        build.status_changed_time = utils.utcnow()
        build.result = model.BuildResult.CANCELED
        build.cancelation_reason = model.CancelationReason.CANCELED_EXPLICITLY
        self._clear_lease(build)
        build.put()
        logging.info('Build %s was cancelled by %s', build.key.id(),
                     auth.get_current_identity().to_bytes())
        return build
Beispiel #2
0
    def txn():
        build = _get_leasable_build(build_id)

        if build.is_ended:
            if (build.proto.status == status
                    and build.result_details == result_details
                    and build.url == url):
                return False, build
            raise errors.BuildIsCompletedError(
                'Build %s has already completed' % build_id)
        _check_lease(build, lease_key)

        now = utils.utcnow()
        build.proto.status = status
        build.status_changed_time = now
        build.proto.end_time.FromDatetime(now)
        if url is not None:  # pragma: no branch
            build.url = url
        build.result_details = result_details
        if new_tags:
            build.tags.extend(new_tags)
            build.tags = sorted(set(build.tags))
        build.clear_lease()

        _fut_results(
            build.put_async(),
            events.on_build_completing_async(build),
            _put_output_properties_async(build.key, result_details),
        )
        return True, build
Beispiel #3
0
    def txn():
        build = _get_leasable_build(build_id)

        if build.proto.status == common_pb2.STARTED:
            if build.url == url:
                return False, build
            build.url = url
            build.put()
            return True, build

        if build.is_ended:
            raise errors.BuildIsCompletedError(
                'Cannot start a completed build')

        assert build.proto.status == common_pb2.SCHEDULED

        _check_lease(build, lease_key)

        now = utils.utcnow()
        build.proto.start_time.FromDatetime(now)
        build.proto.status = common_pb2.STARTED
        build.status_changed_time = now
        build.url = url
        _fut_results(build.put_async(), events.on_build_starting_async(build))
        return True, build
Beispiel #4
0
    def heartbeat_async(self, build_id, lease_key, lease_expiration_date):
        """Extends build lease.

    Args:
      build_id: id of the build.
      lease_key: current lease key.
      lease_expiration_date (datetime.timedelta): new lease expiration date.

    Returns:
      The updated Build as Future.
    """
        try:
            validate_lease_key(lease_key)
            if lease_expiration_date is None:
                raise errors.InvalidInputError(
                    'Lease expiration date not specified')
            validate_lease_expiration_date(lease_expiration_date)
            build = yield model.Build.get_by_id_async(build_id)
            if build is None:
                raise errors.BuildNotFoundError()
            if build.status == model.BuildStatus.COMPLETED:
                raise errors.BuildIsCompletedError()
            self._check_lease(build, lease_key)
            build.lease_expiration_date = lease_expiration_date
            yield build.put_async()
        except Exception as ex:
            logging.warning('Heartbeat for build %s failed: %s', build_id, ex)
            raise
        raise ndb.Return(build)
Beispiel #5
0
    def start(self, build_id, lease_key, url=None):
        """Marks build as STARTED. Idempotent.

    Args:
      build_id: id of the started build.
      lease_key: current lease key.
      url (str): a URL to a build-system-specific build, viewable by a human.

    Returns:
      The updated Build.
    """
        validate_lease_key(lease_key)
        validate_url(url)
        build = self._get_leasable_build(build_id)

        if build.status == model.BuildStatus.STARTED:
            if build.url != url:
                build.url = url
                build.put()
            return build
        elif build.status == model.BuildStatus.COMPLETED:
            raise errors.BuildIsCompletedError(
                'Cannot start a completed build')
        assert build.status == model.BuildStatus.SCHEDULED
        self._check_lease(build, lease_key)

        build.status = model.BuildStatus.STARTED
        build.status_changed_time = utils.utcnow()
        build.url = url
        build.put()
        logging.info('Build %s was started. URL: %s', build.key.id(), url)
        self._enqueue_callback_task_if_needed(build)
        return build
Beispiel #6
0
 def get_build_async(check_access):
     build = yield model.Build.get_by_id_async(build_id)
     if build is None:
         raise errors.BuildNotFoundError()
     if check_access and not (yield user.can_cancel_build_async(build)):
         raise user.current_identity_cannot('cancel build %s',
                                            build.key.id())
     if build.proto.status == common_pb2.CANCELED:
         raise ndb.Return(build, False)
     if build.is_ended:
         raise errors.BuildIsCompletedError(
             'Cannot cancel a completed build')
     raise ndb.Return(build, True)
Beispiel #7
0
 def txn():
     build = _get_leasable_build(build_id)
     if not user.can_reset_build_async(build).get_result():
         raise user.current_identity_cannot('reset build %s',
                                            build.key.id())
     if build.is_ended:
         raise errors.BuildIsCompletedError(
             'Cannot reset a completed build')
     build.proto.status = common_pb2.SCHEDULED
     build.status_changed_time = utils.utcnow()
     build.clear_lease()
     build.url = None
     _fut_results(build.put_async(), events.on_build_resetting_async(build))
     return build
Beispiel #8
0
 def txn():
     validate_lease_key(lease_key)
     if lease_expiration_date is None:
         raise errors.InvalidInputError(
             'Lease expiration date not specified')
     errors.validate_lease_expiration_date(lease_expiration_date)
     build = yield model.Build.get_by_id_async(build_id)
     if build is None:
         raise errors.BuildNotFoundError()
     if build.is_ended:
         msg = ''
         if (build.result == model.BuildResult.CANCELED
                 and build.cancelation_reason
                 == model.CancelationReason.TIMEOUT):
             msg = ('Build was marked as timed out '
                    'because it did not complete for %s' %
                    model.BUILD_TIMEOUT)
         raise errors.BuildIsCompletedError(msg)
     _check_lease(build, lease_key)
     build.lease_expiration_date = lease_expiration_date
     yield build.put_async()
     raise ndb.Return(build)
Beispiel #9
0
    def reset(self, build_id):
        """Forcibly unleases the build and resets its state. Idempotent.

    Resets status, url and lease_key.

    Returns:
      The reset Build.
    """
        build = self._get_leasable_build(build_id)
        if not acl.can_reset_build(build):
            raise current_identity_cannot('reset build %s', build.key.id())
        if build.status == model.BuildStatus.COMPLETED:
            raise errors.BuildIsCompletedError(
                'Cannot reset a completed build')
        build.status = model.BuildStatus.SCHEDULED
        build.status_changed_time = utils.utcnow()
        self._clear_lease(build)
        build.url = None
        build.put()
        logging.info('Build %s was reset by %s', build.key.id(),
                     auth.get_current_identity().to_bytes())
        return build
Beispiel #10
0
    def test_cancel_batch(self, cancel):
        props = {'p': 0}
        build = test_util.build(
            id=1, output=dict(properties=bbutil.dict_to_struct(props)))
        cancel.side_effect = [
            future(build),
            future_exception(errors.BuildIsCompletedError()),
        ]
        req = {
            'build_ids': ['1', '2'],
            'result_details_json': json.dumps(build.result_details),
        }
        res = self.call_api('cancel_batch', req).json_body

        res0 = res['results'][0]
        self.assertEqual(res0['build_id'], '1')
        self.assertEqual(res0['build']['id'], '1')
        cancel.assert_any_call(1, result_details=build.result_details)

        res1 = res['results'][1]
        self.assertEqual(res1['build_id'], '2')
        self.assertEqual(res1['error']['reason'], 'BUILD_IS_COMPLETED')
        cancel.assert_any_call(2, result_details=build.result_details)
Beispiel #11
0
    def _complete(self,
                  build_id,
                  lease_key,
                  result,
                  result_details,
                  failure_reason=None,
                  url=None):
        """Marks a build as completed. Used by succeed and fail methods."""
        validate_lease_key(lease_key)
        validate_url(url)
        assert result in (model.BuildResult.SUCCESS, model.BuildResult.FAILURE)
        build = self._get_leasable_build(build_id)

        if build.status == model.BuildStatus.COMPLETED:
            if (build.result == result
                    and build.failure_reason == failure_reason
                    and build.result_details == result_details
                    and build.url == url):
                return build
            raise errors.BuildIsCompletedError(
                'Build %s has already completed' % build_id)
        self._check_lease(build, lease_key)

        build.status = model.BuildStatus.COMPLETED
        build.status_changed_time = utils.utcnow()
        build.complete_time = utils.utcnow()
        build.result = result
        if url is not None:  # pragma: no branch
            build.url = url
        build.result_details = result_details
        build.failure_reason = failure_reason
        self._clear_lease(build)
        build.put()
        logging.info('Build %s was completed. Status: %s. Result: %s',
                     build.key.id(), build.status, build.result)
        self._enqueue_callback_task_if_needed(build)
        return build
Beispiel #12
0
 def test_default_message(self):
     ex = errors.BuildIsCompletedError()
     self.assertEqual(ex.message,
                      'Build is complete and cannot be changed.')