From d1ab5b8c6dd5e84fbe017b9f87dc4a72e8748fc2 Mon Sep 17 00:00:00 2001
From: Chenxiong Qi <cqi@redhat.com>
Date: Feb 13 2020 11:01:38 +0000
Subject: Add async rebuild handler


Event and event parser are also added accordingly.

Signed-off-by: Chenxiong Qi <cqi@redhat.com>

---

diff --git a/freshmaker/config.py b/freshmaker/config.py
index 5e09906..4be92c5 100644
--- a/freshmaker/config.py
+++ b/freshmaker/config.py
@@ -160,6 +160,7 @@ class Config(object):
         'parsers': {
             'type': list,
             'default': [
+                'freshmaker.parsers.internal:FreshmakerAsyncManualbuildParser',
                 'freshmaker.parsers.internal:FreshmakerManualRebuildParser',
                 'freshmaker.parsers.brew:BrewTaskStateChangeParser',
                 'freshmaker.parsers.errata:ErrataAdvisoryStateChangedParser',
@@ -174,6 +175,7 @@ class Config(object):
                 'freshmaker.handlers.internal:UpdateDBOnAdvisoryChange',
                 'freshmaker.handlers.koji:RebuildImagesOnODCSComposeDone',
                 'freshmaker.handlers.bob:RebuildImagesOnImageAdvisoryChange',
+                'freshmaker.handlers.internal:FreshmakerAsyncManualBuild',
             ],
             'desc': 'List of enabled handlers.'},
         'polling_interval': {
diff --git a/freshmaker/events.py b/freshmaker/events.py
index 77b6181..3c8aae5 100644
--- a/freshmaker/events.py
+++ b/freshmaker/events.py
@@ -410,3 +410,34 @@ class FreshmakerManageEvent(BaseEvent):
         if instance.try_count > FreshmakerManageEvent._max_tries:
             return None
         return instance
+
+
+class FreshmakerAsyncManualBuildEvent(BaseEvent):
+    """Event triggered via API endpoint /async-builds"""
+
+    def __init__(self, msg_id, dist_git_branch, container_images,
+                 freshmaker_event_id=None, brew_target=None, dry_run=False):
+        """Initialize this event
+
+        :param str msg_id: the message id.
+        :param str dist_git_branch: name of the branch in container dist-git
+            repository from which to rebuild images.
+        :param container_images: list of image names, for example,
+            ``['image1', 'image2']``. Please note that each of the element is
+            the N part of image's N-V-R.
+        :type container_images: list[str]
+        :param freshmaker_event_id: a Freshmaker event ID. If set, it will be
+            used as a dependent event. Successful builds from this Event will
+            be reused in the newly created Event instead of building all the
+            artifacts from scratch.
+        :type freshmaker_event_id: int or None
+        :param brew_target: the Brew target for the build. If not set, the
+            previous ``buildContainer`` task build target will be used.
+        :type brew_target: str or None
+        """
+        super(FreshmakerAsyncManualBuildEvent, self).__init__(
+            msg_id, manual=True, dry_run=dry_run)
+        self.dist_git_branch = dist_git_branch
+        self.container_images = container_images
+        self.freshmaker_event_id = freshmaker_event_id
+        self.brew_target = brew_target
diff --git a/freshmaker/handlers/internal/__init__.py b/freshmaker/handlers/internal/__init__.py
index f701278..0bc806c 100644
--- a/freshmaker/handlers/internal/__init__.py
+++ b/freshmaker/handlers/internal/__init__.py
@@ -23,3 +23,4 @@ from .update_db_on_advisory_change import UpdateDBOnAdvisoryChange  # noqa
 from .generate_advisory_signed_event_on_rpm_sign import GenerateAdvisorySignedEventOnRPMSign  # noqa
 from .update_db_on_odcs_compose_fail import UpdateDBOnODCSComposeFail  # noqa
 from .cancel_event_on_freshmaker_manage_request import CancelEventOnFreshmakerManageRequest  # noqa
+from .rebuild_images_on_async_manual_build import RebuildOnAsyncManualBuild  # noqa
\ No newline at end of file
diff --git a/freshmaker/handlers/internal/rebuild_images_on_async_manual_build.py b/freshmaker/handlers/internal/rebuild_images_on_async_manual_build.py
new file mode 100644
index 0000000..60eb4fe
--- /dev/null
+++ b/freshmaker/handlers/internal/rebuild_images_on_async_manual_build.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020  Red Hat, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from freshmaker.handlers import BaseHandler
+from freshmaker.events import FreshmakerAsyncManualBuildEvent
+
+
+class RebuildOnAsyncManualBuild(BaseHandler):
+    """Rebuild images on async.manual.build"""
+
+    def can_handle(self, event):
+        return isinstance(event, FreshmakerAsyncManualBuildEvent)
+
+    def handle(self, event):
+        """ TODO: """
diff --git a/freshmaker/parsers/internal/__init__.py b/freshmaker/parsers/internal/__init__.py
index 1f08864..41a271c 100644
--- a/freshmaker/parsers/internal/__init__.py
+++ b/freshmaker/parsers/internal/__init__.py
@@ -21,3 +21,4 @@
 
 from .manual_rebuild import FreshmakerManualRebuildParser  # noqa
 from .freshmaker_manage_request import FreshmakerManageRequestParser  # noqa
+from .async_manual_build import FreshmakerAsyncManualbuildParser  # noqa
diff --git a/freshmaker/parsers/internal/async_manual_build.py b/freshmaker/parsers/internal/async_manual_build.py
new file mode 100644
index 0000000..8fcc1ba
--- /dev/null
+++ b/freshmaker/parsers/internal/async_manual_build.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020  Red Hat, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from freshmaker.parsers import BaseParser
+from freshmaker.events import FreshmakerAsyncManualBuildEvent
+
+
+class FreshmakerAsyncManualbuildParser(BaseParser):
+    """Parser of event async.manual.build"""
+
+    name = 'FreshmakerAsyncManualbuildParser'
+    topic_suffixes = ['freshmaker.async.manual.build']
+
+    def can_parse(self, topic, msg):
+        return any([topic.endswith(s) for s in self.topic_suffixes])
+
+    def parse(self, topic, msg):
+        inner_msg = msg['msg']
+
+        return FreshmakerAsyncManualBuildEvent(
+            inner_msg['msg_id'],
+            inner_msg['dist_git_branch'],
+            inner_msg['container_images'],
+            freshmaker_event_id=inner_msg.get('freshmaker_event_id'),
+            brew_target=inner_msg.get('brew_target'),
+            dry_run=inner_msg.get('dry_run'),
+        )
diff --git a/tests/handlers/internal/test_rebuild_images_on_async_manual_build.py b/tests/handlers/internal/test_rebuild_images_on_async_manual_build.py
new file mode 100644
index 0000000..2682a85
--- /dev/null
+++ b/tests/handlers/internal/test_rebuild_images_on_async_manual_build.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020  Red Hat, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from unittest import TestCase
+
+from freshmaker.handlers.internal import RebuildOnAsyncManualBuild
+from freshmaker.events import FreshmakerAsyncManualBuildEvent
+
+
+class TestRebuildOnAsyncManualBuild(TestCase):
+
+    def test_can_handle_event(self):
+        event = FreshmakerAsyncManualBuildEvent(
+            'msg-id-01', 'repo-branch', ['image1', 'image2'])
+        handler = RebuildOnAsyncManualBuild()
+        self.assertTrue(handler.can_handle(event))

