From 2621372374b340f79a5652de86040761717fa497 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Apr 11 2019 05:15:47 +0000 Subject: Do not treat ODCSComposeNotReady as error which fails ArtifactBuild. When compose is not done yet, the BaseHandler raises ODCSComposeNotReady exception. This is supposed to be catched by the `start_to_build_images`, which pauses the rebuild until the ODCS compose is ready. The issue is that `fail_artifact_build_on_handler_exception` decorator also catches this ODCSComposeNotReady exception and marks the ArtifactBuild as FAILED. This is wrong, because ODCSComposeNotReady exception is expected and should not mark the build as FAILED. This commit fixes it by introducing the `whitelist` kwarg in the `fail_artifact_build_on_handler_exception` decorator and whitelists the `ODCSComposeNotReady` exception, so it does not move the build to FAILED state, but instead just re-raises the exception so it can be handled in `start_to_build_images`. --- diff --git a/freshmaker/handlers/__init__.py b/freshmaker/handlers/__init__.py index 44855f2..7ea08e3 100644 --- a/freshmaker/handlers/__init__.py +++ b/freshmaker/handlers/__init__.py @@ -81,37 +81,46 @@ def fail_event_on_handler_exception(func): return decorator -def fail_artifact_build_on_handler_exception(func): +def fail_artifact_build_on_handler_exception(whitelist=None): """ Decorator which marks the models.ArtifactBuild associated with handler by BaseHandler.set_context() as FAILED in case the `func` raises an exception. The exception is re-raised by this decorator once its finished. - """ - @wraps(func) - def decorator(handler, *args, **kwargs): - try: - return func(handler, *args, **kwargs) - except Exception as e: - err = 'Could not process message handler. See the traceback.' - log.exception(err) - - # In case the exception interrupted the database transaction, - # rollback it. - db.session.rollback() - # Mark the event as failed. - build_id = handler.current_db_artifact_build_id - build = db.session.query(ArtifactBuild).filter_by( - id=build_id).first() - if build: - build.transition( - ArtifactBuildState.FAILED.value, "Handling of " - "build failed with traceback: %s" % (str(e))) - db.session.commit() - raise - return decorator + :param list/set whitelist: When set, defines the whitelist of Exception + subclasses which do not cause the ArtifactBuild to fail but are instead + just re-raised. + """ + def wrapper(func): + @wraps(func) + def decorator(handler, *args, **kwargs): + try: + return func(handler, *args, **kwargs) + except Exception as e: + if whitelist and type(e) in whitelist: + raise + + err = 'Could not process message handler. See the traceback.' + log.exception(err) + + # In case the exception interrupted the database transaction, + # rollback it. + db.session.rollback() + + # Mark the event as failed. + build_id = handler.current_db_artifact_build_id + build = db.session.query(ArtifactBuild).filter_by( + id=build_id).first() + if build: + build.transition( + ArtifactBuildState.FAILED.value, "Handling of " + "build failed with traceback: %s" % (str(e))) + db.session.commit() + raise + return decorator + return wrapper class BaseHandler(object): @@ -445,7 +454,7 @@ class ContainerBuildHandler(BaseHandler): scratch=conf.koji_container_scratch_build, compose_ids=compose_ids) - @fail_artifact_build_on_handler_exception + @fail_artifact_build_on_handler_exception(whitelist=[ODCSComposeNotReady]) def build_image_artifact_build(self, build, repo_urls=[]): """ Submits ArtifactBuild of 'image' type to Koji. diff --git a/tests/test_handler.py b/tests/test_handler.py index 66cfdfb..6d7be04 100644 --- a/tests/test_handler.py +++ b/tests/test_handler.py @@ -243,6 +243,8 @@ class TestGetRepoURLs(helpers.ModelsTestCase): handler = MyHandler() handler.build_image_artifact_build(self.build_1, ["http://localhost/x.repo"]) + self.assertEqual(self.build_1.state, ArtifactBuildState.PLANNED.value) + class TestAllowBuildBasedOnWhitelist(helpers.FreshmakerTestCase): """Test BaseHandler.allow_build"""