From 36bb02ddfa3ebfbc6f0761b88bf0a87e62c17d0b Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Sep 27 2017 11:22:49 +0000 Subject: Initiate rebuild of advisory related artifacts also when advisory state changes. --- diff --git a/freshmaker/errata.py b/freshmaker/errata.py index a40513c..97faef1 100644 --- a/freshmaker/errata.py +++ b/freshmaker/errata.py @@ -24,7 +24,7 @@ import requests from requests_kerberos import HTTPKerberosAuth -from freshmaker.events import BrewSignRPMEvent +from freshmaker.events import BrewSignRPMEvent, ErrataAdvisoryStateChangedEvent class ErrataAdvisory(object): @@ -103,6 +103,13 @@ class Errata(object): advisories.append(advisory) return advisories + elif isinstance(event, ErrataAdvisoryStateChangedEvent): + data = self._errata_http_get( + "advisory/%s.json" % str(event.errata_id)) + advisory = ErrataAdvisory( + data["id"], data["advisory_name"], data["status"], + data["security_impact"]) + return [advisory] else: raise ValueError("Unsupported event type") diff --git a/freshmaker/handlers/errata/errata_advisory_state_changed.py b/freshmaker/handlers/errata/errata_advisory_state_changed.py index 68d70d5..60f311a 100644 --- a/freshmaker/handlers/errata/errata_advisory_state_changed.py +++ b/freshmaker/handlers/errata/errata_advisory_state_changed.py @@ -19,12 +19,12 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from freshmaker import log -from freshmaker import db +from freshmaker import db, conf, log from freshmaker.events import ( ErrataAdvisoryStateChangedEvent, ErrataAdvisoryRPMsSignedEvent) from freshmaker.models import Event, EVENT_TYPES from freshmaker.handlers import BaseHandler +from freshmaker.errata import Errata class ErrataAdvisoryStateChangedHandler(BaseHandler): @@ -43,15 +43,11 @@ class ErrataAdvisoryStateChangedHandler(BaseHandler): def can_handle(self, event): return isinstance(event, ErrataAdvisoryStateChangedEvent) - def handle(self, event): - errata_id = event.errata_id - state = event.state - if state != "SHIPPED_LIVE": - log.debug("Skipping Errata advisory %d to be marked as released, " - "because its state is %s rather than SHIPPED_LIVE.", - errata_id, state) - return [] - + def mark_as_released(self, errata_id): + """ + Marks the Errata advisory with `errata_id` ID as "released", so it + is not included in further container images rebuilds. + """ # check db to see whether this advisory exists in db db_event = db.session.query(Event).filter_by( event_type_id=EVENT_TYPES[ErrataAdvisoryRPMsSignedEvent], @@ -64,3 +60,50 @@ class ErrataAdvisoryStateChangedHandler(BaseHandler): db_event.released = True db.session.commit() log.info("Errata advisory %d is now marked as released", errata_id) + + def rebuild_if_not_exists(self, event, errata_id): + """ + Initiates rebuild of artifacts based on Errata advisory with + `errata_id` id. + + :rtype: List of ErrataAdvisoryRPMsSignedEvent instances. + :return: List of extra events generated to initiate the rebuild. + """ + + db_event = db.session.query(Event).filter_by( + event_type_id=EVENT_TYPES[ErrataAdvisoryRPMsSignedEvent], + search_key=str(errata_id)).one_or_none() + if db_event: + log.debug("Ignoring Errata advisory %d - it already exists in " + "Freshmaker db.", errata_id) + return [] + + # Get additional info from Errata to fill in the needed data. + errata = Errata(conf.errata_tool_server_url) + advisories = errata.advisories_from_event(event) + if not advisories: + log.error("Unknown Errata advisory %d" % errata_id) + return [] + + log.info("Generating ErrataAdvisoryRPMsSignedEvent for Errata " + "advisory %d, because its state changed to %s.", errata_id, + event.state) + advisory = advisories[0] + db_event = ErrataAdvisoryRPMsSignedEvent( + event.msg_id + "." + str(advisory.name), advisory.name, + advisory.errata_id, advisory.security_impact) + return [db_event] + + def handle(self, event): + errata_id = event.errata_id + state = event.state + + extra_events = [] + + if state in ["REL_PREP", "PUSH_READY", "IN_PUSH", "SHIPPED_LIVE"]: + extra_events += self.rebuild_if_not_exists(event, errata_id) + + if state == "SHIPPED_LIVE": + self.mark_as_released(errata_id) + + return extra_events diff --git a/tests/test_errata.py b/tests/test_errata.py index 0f75b35..26b784f 100644 --- a/tests/test_errata.py +++ b/tests/test_errata.py @@ -25,7 +25,8 @@ import unittest from mock import patch from freshmaker.errata import Errata -from freshmaker.events import BrewSignRPMEvent, GitRPMSpecChangeEvent +from freshmaker.events import ( + BrewSignRPMEvent, GitRPMSpecChangeEvent, ErrataAdvisoryStateChangedEvent) class MockedErrataAPI(object): @@ -68,7 +69,11 @@ class MockedErrataAPI(object): "all_errata": [{"id": 28484, "name": "RHSA-2017:28484", "status": "QE"}], "rpms_signed": True} - self.advisory_json = {"security_impact": "Important"} + self.advisory_json = { + "id": 28484, + "advisory_name": "RHSA-2017:28484", + "status": "QE", + "security_impact": "Important"} def errata_rest_get(self, endpoint): if endpoint.find("build/") != -1: @@ -112,6 +117,16 @@ class TestErrata(unittest.TestCase): @patch.object(Errata, "_errata_rest_get") @patch.object(Errata, "_errata_http_get") + def test_advisories_from_event_errata_state_change_event( + self, errata_http_get, errata_rest_get): + MockedErrataAPI(errata_rest_get, errata_http_get) + event = ErrataAdvisoryStateChangedEvent("msgid", 28484, "SHIPPED_LIVE") + advisories = self.errata.advisories_from_event(event) + self.assertEqual(len(advisories), 1) + self.assertEqual(advisories[0].errata_id, 28484) + + @patch.object(Errata, "_errata_rest_get") + @patch.object(Errata, "_errata_http_get") def test_builds_signed_all_signed(self, errata_http_get, errata_rest_get): MockedErrataAPI(errata_rest_get, errata_http_get) self.assertTrue(self.errata.builds_signed(28484)) diff --git a/tests/test_errata_advisory_state_changed.py b/tests/test_errata_advisory_state_changed.py index 9a5d074..b9c1cea 100644 --- a/tests/test_errata_advisory_state_changed.py +++ b/tests/test_errata_advisory_state_changed.py @@ -27,7 +27,10 @@ import json from mock import patch, MagicMock, PropertyMock, Mock from freshmaker.handlers.errata import ErrataAdvisoryRPMsSignedHandler +from freshmaker.handlers.errata import ErrataAdvisoryStateChangedHandler from freshmaker.events import ErrataAdvisoryRPMsSignedEvent +from freshmaker.events import ErrataAdvisoryStateChangedEvent +from freshmaker.errata import ErrataAdvisory from freshmaker import db, events from freshmaker.models import Event, ArtifactBuild @@ -462,3 +465,110 @@ class TestFindEventsToInclude(unittest.TestCase): self.assertEqual(len(events), 1) self.assertEqual(events[0].search_key, "old_event_foo") + + +class TestErrataAdvisoryStateChangedHandler(unittest.TestCase): + + def setUp(self): + db.session.remove() + db.drop_all() + db.create_all() + db.session.commit() + + def tearDown(self): + db.session.remove() + db.drop_all() + db.session.commit() + + @patch('freshmaker.errata.Errata.advisories_from_event') + def test_rebuild_if_not_exists(self, advisories_from_event): + handler = ErrataAdvisoryStateChangedHandler() + + for state in ["REL_PREP", "PUSH_READY", "IN_PUSH", "SHIPPED_LIVE"]: + advisories_from_event.return_value = [ + ErrataAdvisory(123, "RHSA-2017", state, "Critical")] + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, state) + ret = handler.handle(ev) + + self.assertEqual(len(ret), 1) + self.assertEqual(ret[0].errata_id, 123) + self.assertEqual(ret[0].security_impact, "Critical") + self.assertEqual(ret[0].errata_name, "RHSA-2017") + + @patch('freshmaker.errata.Errata.advisories_from_event') + def test_rebuild_if_not_exists_unknown_states( + self, advisories_from_event): + handler = ErrataAdvisoryStateChangedHandler() + + for state in ["NEW_FILES", "QE", "UNKNOWN"]: + advisories_from_event.return_value = [ + ErrataAdvisory(123, "RHSA-2017", state, "Critical")] + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, state) + ret = handler.handle(ev) + + self.assertEqual(len(ret), 0) + + @patch('freshmaker.errata.Errata.advisories_from_event') + def test_rebuild_if_not_exists_already_exists( + self, advisories_from_event): + handler = ErrataAdvisoryStateChangedHandler() + + Event.create( + db.session, "msg124", "123", ErrataAdvisoryRPMsSignedEvent) + db.session.commit() + + for state in ["REL_PREP", "PUSH_READY", "IN_PUSH", "SHIPPED_LIVE"]: + advisories_from_event.return_value = [ + ErrataAdvisory(123, "RHSA-2017", state, "Critical")] + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, state) + ret = handler.handle(ev) + + self.assertEqual(len(ret), 0) + + @patch('freshmaker.errata.Errata.advisories_from_event') + def test_rebuild_if_not_exists_unknown_errata_id( + self, advisories_from_event): + advisories_from_event.return_value = [] + handler = ErrataAdvisoryStateChangedHandler() + + for state in ["REL_PREP", "PUSH_READY", "IN_PUSH", "SHIPPED_LIVE"]: + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, state) + ret = handler.handle(ev) + + self.assertEqual(len(ret), 0) + + def test_mark_as_released(self): + db_event = Event.create( + db.session, "msg124", "123", ErrataAdvisoryRPMsSignedEvent, False) + db.session.commit() + + self.assertEqual(db_event.released, False) + + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, "SHIPPED_LIVE") + + handler = ErrataAdvisoryStateChangedHandler() + handler.handle(ev) + + db.session.refresh(db_event) + self.assertEqual(db_event.released, True) + + def test_mark_as_released_wrong_advisory_status(self): + db_event = Event.create( + db.session, "msg124", "123", ErrataAdvisoryRPMsSignedEvent, False) + db.session.commit() + + for state in ["NEW_FILES", "QE", "REL_PREP", "PUSH_READY", "IN_PUSH"]: + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, state) + + handler = ErrataAdvisoryStateChangedHandler() + handler.handle(ev) + + db.session.refresh(db_event) + self.assertEqual(db_event.released, False) + + @patch('freshmaker.errata.Errata.advisories_from_event') + def test_mark_as_released_unknown_event(self, advisories_from_event): + ev = ErrataAdvisoryStateChangedEvent("msg123", 123, "SHIPPED_LIVE") + + handler = ErrataAdvisoryStateChangedHandler() + handler.handle(ev)