Skip to content

Commit

Permalink
Consumers: replace Greenwave with ResultsDB and WaiverDB (#4224)
Browse files Browse the repository at this point in the history
This replaces the consumer that listens for Greenwave 'decision
change' messages with consumers that listen for ResultsDB and
WaiverDB "new result" / "new waiver" messages and update gating
decisions if the message may cause a change.

The goal here is to make it possible to remove the "decision
change" message code from Greenwave entirely, because in order
to publish those messages, Greenwave has to duplicate a lot of
Bodhi's knowledge about what kinds of decisions to ask for. This
being in Greenwave is really against the intended design of the
system, and means whenever anything changes about what kinds of
decision Bodhi might request, we need to change both Bodhi and
the Greenwave "decision change" publishing code.

Signed-off-by: Adam Williamson <awilliam@redhat.com>
  • Loading branch information
AdamWill authored and mergify[bot] committed Sep 17, 2021
1 parent 61aeb56 commit fc3bdcf
Show file tree
Hide file tree
Showing 10 changed files with 772 additions and 324 deletions.
8 changes: 5 additions & 3 deletions bodhi/server/consumers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
from bodhi.server.config import config
from bodhi.server.consumers.automatic_updates import AutomaticUpdateHandler
from bodhi.server.consumers.signed import SignedHandler
from bodhi.server.consumers.greenwave import GreenwaveHandler
from bodhi.server.consumers.ci import CIHandler
from bodhi.server.consumers.resultsdb import ResultsdbHandler
from bodhi.server.consumers.waiverdb import WaiverdbHandler


log = logging.getLogger('bodhi')
Expand All @@ -53,8 +54,9 @@ def __init__(self):
self.handler_infos = [
HandlerInfo('.buildsys.tag', "Signed", SignedHandler()),
HandlerInfo('.buildsys.tag', 'Automatic Update', AutomaticUpdateHandler()),
HandlerInfo('.greenwave.decision.update', 'Greenwave', GreenwaveHandler()),
HandlerInfo('.ci.koji-build.test.running', 'CI', CIHandler())
HandlerInfo('.ci.koji-build.test.running', 'CI', CIHandler()),
HandlerInfo('.waiverdb.waiver.new', 'WaiverDB', WaiverdbHandler()),
HandlerInfo('.resultsdb.result.new', 'ResultsDB', ResultsdbHandler()),
]

def __call__(self, msg: fedora_messaging.api.Message): # noqa: D401
Expand Down
101 changes: 0 additions & 101 deletions bodhi/server/consumers/greenwave.py

This file was deleted.

78 changes: 78 additions & 0 deletions bodhi/server/consumers/resultsdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright Red Hat and others.
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
The "resultsdb handler".
This module is responsible for listening for messages from ResultsDB.
If a message seems like it might be a result change for an update or
build from an update, we re-check the gating decision for that update.
"""

import logging

import fedora_messaging

from bodhi.server.consumers.util import update_from_db_message
from bodhi.server.models import TestGatingStatus
from bodhi.server.util import transactional_session_maker

log = logging.getLogger(__name__)


class ResultsdbHandler:
"""
The Bodhi ResultsDB Handler.
A fedora-messaging listener waiting for messages from resultsdb that may
affect gating status for an update.
"""

def __init__(self):
"""Initialize the handler."""
self.db_factory = transactional_session_maker()

def __call__(self, message: fedora_messaging.api.Message):
"""Handle messages arriving with the configured topic."""
msg = message.body
if not msg:
log.debug("Ignoring message without body.")
return

passed = msg.get("outcome") in ("PASSED", "INFO")

data = msg.get("data")
if not data:
log.error(f"Couldn't find data dict in ResultsDB message {message.id}")
return

with self.db_factory():
# find the update
update = update_from_db_message(message.id, msg["data"])
if not update:
# update_from_db_message will already have logged why
return
# update the gating status if there's a chance it changed
status = update.test_gating_status
if (
(passed and status == TestGatingStatus.passed)
or (not passed and status == TestGatingStatus.failed)
):
log.debug("Not updating test_gating_status as no chance of a change")
return
log.info(f"Updating the test_gating_status for: {update.alias}")
update.update_test_gating_status()
70 changes: 70 additions & 0 deletions bodhi/server/consumers/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright Red Hat and others.
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""Utility functions for message consumers."""

import logging

from bodhi.server.models import Build, Update

log = logging.getLogger(__name__)


def update_from_db_message(msgid: str, itemdict: dict):
"""
Find and return update for waiverdb or resultsdb message.
Used by the resultsdb and waiverdb consumers.
Args:
msgid: the message ID (for logging purposes)
itemdict: the relevant dict from the message. 'subject' dict
for a waiverdb message, 'item' dict for resultsdb.
Returns:
bodhi.server.models.Update or None: the relevant update, if
found.
"""
itemtype = itemdict.get("type")
if not itemtype:
log.error(f"Couldn't find item type in message {msgid}")
return None
if itemtype not in ("koji_build", "bodhi_update"):
log.debug(f"Irrelevant item type {itemtype}")
return None

# find the update
if itemtype == "bodhi_update":
updateid = itemdict.get("item")
if not updateid:
log.error(f"Couldn't find update ID in message {msgid}")
return None
update = Update.get(updateid)
if not update:
log.error(f"Couldn't find update {updateid} in DB")
return None
else:
nvr = itemdict.get("nvr", itemdict.get("item"))
if not nvr:
log.error(f"Couldn't find nvr in message {msgid}")
return None
build = Build.get(nvr)
if not build:
log.error(f"Couldn't find build {nvr} in DB")
return None
update = build.update

return update
67 changes: 67 additions & 0 deletions bodhi/server/consumers/waiverdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright Red Hat and others.
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
The "waiverdb handler".
This module is responsible for listening for 'new waiver' messages from
WaiverDB, and re-checking the gating decision for the relevant update.
"""

import logging

import fedora_messaging

from bodhi.server.consumers.util import update_from_db_message
from bodhi.server.models import TestGatingStatus
from bodhi.server.util import transactional_session_maker

log = logging.getLogger(__name__)


class WaiverdbHandler:
"""
The Bodhi WaiverDB Handler.
A fedora-messaging listener waiting for messages from WaiverDB and
updating gating status of the relevant update.
"""

def __init__(self):
"""Initialize the handler."""
self.db_factory = transactional_session_maker()

def __call__(self, message: fedora_messaging.api.Message):
"""Handle messages arriving with the configured topic."""
msg = message.body
if not msg:
log.debug("Ignoring message without body.")
return

subject = msg.get("subject")
if subject is None:
log.error(f"Couldn't find subject in WaiverDB message {message.id}")
return

with self.db_factory():
# find the update
update = update_from_db_message(message.id, subject)
# update the gating status unless it's already "passed", a
# waiver can't change it from passed to anything else
if update and update.test_gating_status != TestGatingStatus.passed:
log.info(f"Updating the test_gating_status for: {update.alias}")
update.update_test_gating_status()
17 changes: 14 additions & 3 deletions bodhi/tests/server/consumers/test_consumers.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,21 @@ def test_messaging_callback_signed_automatic_update(self,
signed_handler.assert_called_once_with(msg)
automatic_update_handler.assert_called_once_with(msg)

@mock.patch('bodhi.server.consumers.GreenwaveHandler')
def test_messaging_callback_greenwave(self, Handler):
@mock.patch('bodhi.server.consumers.ResultsdbHandler')
def test_messaging_callback_resultsdb(self, Handler):
msg = Message(
topic="org.fedoraproject.prod.greenwave.decision.update",
topic="org.fedoraproject.prod.resultsdb.result.new",
body={}
)
handler = mock.Mock()
Handler.side_effect = lambda: handler
Consumer()(msg)
handler.assert_called_once_with(msg)

@mock.patch('bodhi.server.consumers.WaiverdbHandler')
def test_messaging_callback_waiverdb(self, Handler):
msg = Message(
topic="org.fedoraproject.prod.waiverdb.waiver.new",
body={}
)
handler = mock.Mock()
Expand Down
Loading

0 comments on commit fc3bdcf

Please sign in to comment.