From 15fbe1a07c78eb698b942d05e29d2ad95c2f50ba Mon Sep 17 00:00:00 2001
From: Jan Kaluza <jkaluza@redhat.com>
Date: Oct 02 2017 08:13:27 +0000
Subject: Allow filtering container images builds by their names


---

diff --git a/freshmaker/handlers/errata/errata_advisory_rpms_signed.py b/freshmaker/handlers/errata/errata_advisory_rpms_signed.py
index 2c2095a..c039ba8 100644
--- a/freshmaker/handlers/errata/errata_advisory_rpms_signed.py
+++ b/freshmaker/handlers/errata/errata_advisory_rpms_signed.py
@@ -372,6 +372,25 @@ class ErrataAdvisoryRPMsSignedHandler(BaseHandler):
 
         return builds
 
+    def _filter_out_not_allowed_builds(self, image):
+        """
+        Helper method for _find_and_record_images_to_rebuild(...) to filter
+        out all images which are not allowed to build by configuration.
+
+        :param ContainerImage image: Image to be checked.
+        :rtype: bool
+        :return: True when image should be filtered out.
+        """
+
+        image_name = koji.parse_NVR(image["brew"]["build"])['name']
+
+        if not self.allow_build(
+                ArtifactType.IMAGE, image_name=image_name):
+            log.info("Skipping rebuild of image %s, not allowed by "
+                     "configuration", image_name)
+            return True
+        return False
+
     def _find_and_record_images_to_rebuild(self, db_event, event, builds=None):
         """
         Finds docker images to rebuild based on the particular
@@ -416,7 +435,9 @@ class ErrataAdvisoryRPMsSignedHandler(BaseHandler):
         for nvr in nvrs:
             if nvr.endswith(".rpm"):
                 srpm_name = self._find_build_srpm_name(nvr)
-                batches = lb.find_images_to_rebuild(srpm_name, content_sets)
+                batches = lb.find_images_to_rebuild(
+                    srpm_name, content_sets,
+                    filter_fnc=self._filter_out_not_allowed_builds)
                 builds = self._record_batches(batches, event, builds)
             else:
                 log.info("Skipping unsupported Errata build type: %s.", nvr)
diff --git a/freshmaker/lightblue.py b/freshmaker/lightblue.py
index a5045b8..61c95ca 100644
--- a/freshmaker/lightblue.py
+++ b/freshmaker/lightblue.py
@@ -636,7 +636,7 @@ class LightBlue(object):
 
     def find_images_to_rebuild(
             self, srpm_name, content_sets, published=True, deprecated=False,
-            release_category="Generally Available"):
+            release_category="Generally Available", filter_fnc=None):
         """
         Find images to rebuild through image build layers
 
@@ -649,10 +649,20 @@ class LightBlue(object):
         :param str srpm_name: srpm_name (source rpm name) to look for
         :param list content_sets: list of strings (content sets) to consider
             when looking for the packages
+        :param function filter_fnc: Function called as
+            filter_fnc(container_image) with container_image being
+            ContainerImage instance. If this function returns True, the image
+            will not be considered for a rebuild as well as its parent images.
+            This function is used to filter out images not allowed by
+            Freshmaker configuration.
         """
         images = self.find_images_with_package_from_content_set(
             srpm_name, content_sets, published, deprecated, release_category)
 
+        # Filter out images based on the filter_fnc.
+        if filter_fnc:
+            images = [image for image in images if not filter_fnc(image)]
+
         def _get_images_to_rebuild(image):
             """
             Find out parent images to rebuild, helper called from threadpool.
diff --git a/tests/test_errata_advisory_state_changed.py b/tests/test_errata_advisory_state_changed.py
index cb66873..9ea008c 100644
--- a/tests/test_errata_advisory_state_changed.py
+++ b/tests/test_errata_advisory_state_changed.py
@@ -141,7 +141,8 @@ class TestAllowBuild(unittest.TestCase):
                 "image": [{
                     "advisory_security_impact": [
                         "Normal", "Important"
-                    ]
+                    ],
+                    "image_name": "foo",
                 }]
             }
         })
@@ -184,6 +185,67 @@ class TestAllowBuild(unittest.TestCase):
 
         record_images.assert_not_called()
 
+    @patch(
+        "freshmaker.config.Config.handler_build_whitelist",
+        new_callable=PropertyMock,
+        return_value={
+            "ErrataAdvisoryRPMsSignedHandler": {
+                "image": [{
+                    "image_name": ["foo", "bar"]
+                }]
+            }
+        })
+    def test_filter_out_not_allowed_builds(
+            self, handler_build_whitelist):
+        """
+        Tests that allow_build does filter images based on image_name.
+        """
+
+        handler = ErrataAdvisoryRPMsSignedHandler()
+
+        image = {"brew": {"build": "foo-1-2.3"}}
+        ret = handler._filter_out_not_allowed_builds(image)
+        self.assertEqual(ret, False)
+
+        image = {"brew": {"build": "foo2-1-2.3"}}
+        ret = handler._filter_out_not_allowed_builds(image)
+        self.assertEqual(ret, False)
+
+        image = {"brew": {"build": "bar-1-2.3"}}
+        ret = handler._filter_out_not_allowed_builds(image)
+        self.assertEqual(ret, False)
+
+        image = {"brew": {"build": "unknown-1-2.3"}}
+        ret = handler._filter_out_not_allowed_builds(image)
+        self.assertEqual(ret, True)
+
+    @patch(
+        "freshmaker.config.Config.handler_build_whitelist",
+        new_callable=PropertyMock,
+        return_value={
+            "ErrataAdvisoryRPMsSignedHandler": {
+                "image": [{
+                    "image_name": ["foo", "bar"],
+                    "advisory_name": "RHSA-.*",
+                }]
+            }
+        })
+    def test_filter_out_image_name_and_advisory_name(
+            self, handler_build_whitelist):
+        """
+        Tests that allow_build does filter images based on image_name.
+        """
+
+        handler = ErrataAdvisoryRPMsSignedHandler()
+
+        image = {"brew": {"build": "foo-1-2.3"}}
+        ret = handler._filter_out_not_allowed_builds(image)
+        self.assertEqual(ret, False)
+
+        image = {"brew": {"build": "unknown-1-2.3"}}
+        ret = handler._filter_out_not_allowed_builds(image)
+        self.assertEqual(ret, True)
+
 
 class TestBatches(unittest.TestCase):
     """Test handling of batches"""
diff --git a/tests/test_lightblue.py b/tests/test_lightblue.py
index 207ec93..98146f7 100644
--- a/tests/test_lightblue.py
+++ b/tests/test_lightblue.py
@@ -166,7 +166,6 @@ class TestContainerImageObject(unittest.TestCase):
         self.assertEqual(image["target"], "target1")
         self.assertEqual(image["srpm_nevra"], "openssl-0:1.2.3-1.src")
 
-
     @patch('freshmaker.kojiservice.KojiService.get_build')
     @patch('freshmaker.kojiservice.KojiService.get_task_request')
     def test_resolve_commit_no_koji_build(self, get_task_request, get_build):
@@ -237,6 +236,7 @@ class TestContainerImageObject(unittest.TestCase):
             "Cannot find task_id or container_koji_task_id in the Koji build "
             "{'task_id': None}") != -1)
 
+
 class TestContainerRepository(unittest.TestCase):
 
     def test_create(self):
@@ -727,6 +727,9 @@ class TestQueryEntityFromLightBlue(unittest.TestCase):
         self.assertEqual(1, len(ret))
         self.assertEqual(ret[0]["brew"]["package"], "package-name-1")
 
+    def _filter_fnc(self, image):
+        return image["brew"]["build"].startswith("filtered_")
+
     @patch('freshmaker.lightblue.LightBlue.find_images_with_package_from_content_set')
     @patch('freshmaker.lightblue.LightBlue.find_parent_images_with_package')
     @patch('freshmaker.lightblue.LightBlue.find_unpublished_image_for_build')
@@ -740,8 +743,12 @@ class TestQueryEntityFromLightBlue(unittest.TestCase):
                                         "parsed_data": {"layers": None}})
         child2 = ContainerImage.create({'brew': {'package': 'child2', 'build': 'child2'},
                                         "parsed_data": {"layers": None}})
-        cont_images.return_value = [child1, child2]
-        unpublished_image.side_effect = [child1, child2]
+        # This "filtered_child" will be filtered by self._filter_fnc.
+        filtered_child = ContainerImage.create(
+            {'brew': {'package': 'filtered_child', 'build': 'filtered_child'},
+             "parsed_data": {"layers": None}})
+        cont_images.return_value = [child1, child2, filtered_child]
+        unpublished_image.side_effect = [child1, child2, filtered_child]
 
         child1_parent1 = ContainerImage.create(
             {'brew': {'package': 'child1_parent1', 'build': 'child1_parent1'}})
@@ -773,7 +780,8 @@ class TestQueryEntityFromLightBlue(unittest.TestCase):
         lb = LightBlue(server_url=self.fake_server_url,
                        cert=self.fake_cert_file,
                        private_key=self.fake_private_key)
-        ret = lb.find_images_to_rebuild("dummy", "dummy")
+        ret = lb.find_images_to_rebuild("dummy", "dummy",
+                                        filter_fnc=self._filter_fnc)
         self.assertEqual([len(x) for x in ret], [1, 2, 2, 1, 1, 1])
         self.assertEqual(set(ret[0]), set([child1_parent4]))
         self.assertEqual(set(ret[1]), set([child1_parent3, child2_parent2]))

