From edb3a2dc5c0d831f2c765683ffcc059a01f83b22 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Oct 03 2017 08:18:03 +0000 Subject: Add ERRATA_RHEL_RELEASE_PREFIX option to limit the builds we take from errata based on a base rhel version --- diff --git a/freshmaker/config.py b/freshmaker/config.py index 6dd1119..e9a9206 100644 --- a/freshmaker/config.py +++ b/freshmaker/config.py @@ -225,6 +225,11 @@ class Config(object): 'type': str, 'default': '', 'desc': 'Server URL of Errata Tool.'}, + 'errata_rhel_release_prefix': { + 'type': str, + 'default': 'RHEL-7', + 'desc': 'When set, only builds based on this RHEL release ' + 'will be included in rebuilds.'}, 'pulp_server_url': { 'type': str, 'default': '', diff --git a/freshmaker/errata.py b/freshmaker/errata.py index 3945e6c..492c62d 100644 --- a/freshmaker/errata.py +++ b/freshmaker/errata.py @@ -26,7 +26,7 @@ import dogpile.cache from requests_kerberos import HTTPKerberosAuth from freshmaker.events import BrewSignRPMEvent, ErrataAdvisoryStateChangedEvent -from freshmaker import conf +from freshmaker import conf, log class ErrataAdvisory(object): @@ -54,6 +54,13 @@ class Errata(object): region = dogpile.cache.make_region().configure( conf.dogpile_cache_backend, expiration_time=10) + # Change for _rhel_release_from_product_version. + # Big expiration_time is OK here, because once we start rebuilding + # something for particular product version, its rhel_release version + # should not change. + product_region = dogpile.cache.make_region().configure( + conf.dogpile_cache_backend, expiration_time=24*3600) + def __init__(self, server_url): """ Initializes the Errata instance. @@ -154,13 +161,80 @@ class Errata(object): return True - def get_builds(self, errata_id): + def _rhel_release_from_product_version(self, errata_id, product_version): + """ + Returns release name of RHEL release the product version is based on. + + :param number errata_id: Errata advisory ID. + :param string product_version: Version of product to check the RHEL + release for. + :rtype: string + :return: Name of the RHEL release. + """ + + # Get the product ID this advisory is about - for example "RHSCL". + data = self._errata_http_get("advisory/%s.json" % str(errata_id)) + product_id = data["product"]["id"] + + # Get all the product versions associated with this product ID. + data = self._errata_http_get("products/%s/product_versions.json" + % str(product_id)) + + # Find out the product version ID for the input `product_version` + # name. + pr_version_id = None + for pr_version in data: + if pr_version["product_version"]["name"] == product_version: + pr_version_id = pr_version["product_version"]["id"] + break + + if not pr_version_id: + raise ValueError( + "Cannot get RHEL release from Errata advisory %s, product " + "version %s" % (str(errata_id), product_version)) + + # Get the additional product version info to find out the RHEL release + # name. + data = self._errata_http_get("products/%s/product_versions/%s.json" + % (str(product_id), str(pr_version_id))) + + return data["rhel_release"]["name"] + + def get_builds(self, errata_id, rhel_release_prefix=None): + """ + Returns set of NVRs of builds added to the advisory. These are just + brew build NVRs, not the particular RPM NVRs. + + :param number errata_id: ID of advisory. + :param string rhel_release_prefix: When set to non-empty string, + it will be used to limit the set of builds returned by this + method to only builds based on the RHEL version starting with + `rhel_release_prefix`. For example to return only RHEL-7 builds, + this should be set to "RHEL-7". + Defaults to conf.errata_rhel_release_prefix. + :rtype: set of strings + :return: Set of NVR builds. + """ + if rhel_release_prefix is None: + rhel_release_prefix = conf.errata_rhel_release_prefix + builds_per_product = self._errata_http_get( "advisory/%s/builds.json" % str(errata_id)) # Store NVRs of all builds in advisory to nvrs set. nvrs = set() - for builds in builds_per_product.values(): + for product_version, builds in builds_per_product.items(): + rhel_release = Errata.product_region.get(product_version) + if not rhel_release: + rhel_release = self._rhel_release_from_product_version( + errata_id, product_version) + Errata.product_region.set(product_version, rhel_release) + + if (rhel_release_prefix and + not rhel_release.startswith(rhel_release_prefix)): + log.info("Skipping builds for %s - not based on RHEL %s", + product_version, rhel_release_prefix) + continue for build in builds: nvrs.update(set(build.keys())) return nvrs diff --git a/tests/test_errata.py b/tests/test_errata.py index 26b784f..cfd5242 100644 --- a/tests/test_errata.py +++ b/tests/test_errata.py @@ -73,7 +73,24 @@ class MockedErrataAPI(object): "id": 28484, "advisory_name": "RHSA-2017:28484", "status": "QE", - "security_impact": "Important"} + "security_impact": "Important", + "product" : { + "id": 89 + } + } + + self.product_versions_json = [ + {"product_version": {"name": "PRODUCT1-3.0-NFS", "id": 1}}, + {"product_version": {"name": "PRODUCT1-3.1-NFS", "id": 2}}, + {"product_version": {"name": "PRODUCT1-3.2-NFS", "id": 3}}, + {"product_version": {"name": "PRODUCT1", "id": 3}}, + {"product_version": {"name": "PRODUCT2-3.2-NFS", "id": 4}}, + {"product_version": {"name": "PRODUCT2", "id": 4}}, + ] + + self.product_versions = {} + self.product_versions[3] = {"rhel_release": {"name": "RHEL-6-foobar"}} + self.product_versions[4] = {"rhel_release": {"name": "RHEL-7-foobar"}} def errata_rest_get(self, endpoint): if endpoint.find("build/") != -1: @@ -85,7 +102,13 @@ class MockedErrataAPI(object): return self.builds_json elif endpoint.startswith("advisory/"): return self.advisory_json - + elif endpoint.startswith("products/"): + if endpoint.endswith("product_versions.json"): + return self.product_versions_json + elif endpoint.find("/product_versions/") != -1: + id = int(endpoint.split("/")[-1].replace(".json", "")) + return self.product_versions[id] + class TestErrata(unittest.TestCase): def setUp(self): @@ -165,3 +188,39 @@ class TestErrata(unittest.TestCase): 'rhel-6-server-eus-optional-debug-rpms__6_DOT_7__i386', 'rhel-6-server-eus-rpms__6_DOT_7__x86_64']), set(repo_ids)) + + @patch.object(Errata, "_errata_rest_get") + @patch.object(Errata, "_errata_http_get") + def test_rhel_release_from_product_version( + self, errata_http_get, errata_rest_get): + mocked_errata = MockedErrataAPI(errata_rest_get, errata_http_get) + ret = self.errata._rhel_release_from_product_version( + 28484, "PRODUCT1-3.2-NFS") + self.assertEqual(ret, "RHEL-6-foobar") + + @patch.object(Errata, "_errata_rest_get") + @patch.object(Errata, "_errata_http_get") + def test_rhel_release_from_product_version_unknown_product_ver( + self, errata_http_get, errata_rest_get): + mocked_errata = MockedErrataAPI(errata_rest_get, errata_http_get) + with self.assertRaises(ValueError): + ret = self.errata._rhel_release_from_product_version( + 28484, "PRODUCT1-2.9-NFS") + + @patch.object(Errata, "_errata_rest_get") + @patch.object(Errata, "_errata_http_get") + def test_get_builds( + self, errata_http_get, errata_rest_get): + mocked_errata = MockedErrataAPI(errata_rest_get, errata_http_get) + ret = self.errata.get_builds(28484, "") + self.assertEqual(ret, set(['libntirpc-1.4.3-4.el7rhgs', + 'libntirpc-1.4.3-4.el6rhs'])) + + @patch.object(Errata, "_errata_rest_get") + @patch.object(Errata, "_errata_http_get") + def test_get_builds_rhel_7( + self, errata_http_get, errata_rest_get): + mocked_errata = MockedErrataAPI(errata_rest_get, errata_http_get) + ret = self.errata.get_builds(28484, "RHEL-7") + self.assertEqual(ret, set(['libntirpc-1.4.3-4.el7rhgs'])) +