From f84587e4720af12374dd1a92dbf97e9f076ad144 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Apr 10 2017 09:34:54 +0000 Subject: Rename Trigger to Event. --- diff --git a/freshmaker/consumer.py b/freshmaker/consumer.py index d16def8..a7d454c 100644 --- a/freshmaker/consumer.py +++ b/freshmaker/consumer.py @@ -31,7 +31,7 @@ import freshmaker.handlers import freshmaker.parsers.mbsmodule import freshmaker.parsers.gitreceive -from freshmaker import log, conf, messaging, triggers +from freshmaker import log, conf, messaging, events class FreshmakerConsumer(fedmsg.consumers.FedmsgConsumer): @@ -61,11 +61,11 @@ class FreshmakerConsumer(fedmsg.consumers.FedmsgConsumer): self.incoming.put(msg) def register_parsers(self): - triggers.BaseTrigger.register_parser(freshmaker.parsers.mbsmodule.MBSModuleParser) - triggers.BaseTrigger.register_parser(freshmaker.parsers.gitreceive.GitReceiveParser) - log.debug("Parser classes: %r", triggers.BaseTrigger._parsers) + events.BaseEvent.register_parser(freshmaker.parsers.mbsmodule.MBSModuleParser) + events.BaseEvent.register_parser(freshmaker.parsers.gitreceive.GitReceiveParser) + log.debug("Parser classes: %r", events.BaseEvent._parsers) - self.topic = triggers.BaseTrigger.get_parsing_topics() + self.topic = events.BaseEvent.get_parsed_topics() log.debug('Setting topics: {}'.format(', '.join(self.topic))) def shutdown(self): @@ -77,7 +77,7 @@ class FreshmakerConsumer(fedmsg.consumers.FedmsgConsumer): def validate(self, message): if conf.messaging == 'fedmsg': # If this is a faked internal message, don't bother. - if isinstance(message, triggers.BaseTrigger): + if isinstance(message, events.BaseEvent): log.info("Skipping crypto validation for %r" % message) return # Otherwise, if it is a real message from the network, pass it @@ -92,14 +92,14 @@ class FreshmakerConsumer(fedmsg.consumers.FedmsgConsumer): # messages, then just use them as-is. If they are not already # instances of our message abstraction base class, then first transform # them before proceeding. - if isinstance(message, triggers.BaseTrigger): + if isinstance(message, events.BaseEvent): msg = message else: msg = self.get_abstracted_msg(message['body']) # Primary work is done here. try: - self.process_trigger(msg) + self.process_event(msg) except Exception: log.exception('Failed while handling {0!r}'.format(msg)) @@ -109,14 +109,14 @@ class FreshmakerConsumer(fedmsg.consumers.FedmsgConsumer): def get_abstracted_msg(self, message): # Convert the message to an abstracted message if conf.messaging == 'fedmsg' or conf.messaging == 'in_memory': - msg = triggers.BaseTrigger.from_fedmsg( + msg = events.BaseEvent.from_fedmsg( message['topic'], message) else: raise ValueError('The messaging format "{0}" is not supported' .format(conf.messaging)) return msg - def process_trigger(self, msg): + def process_event(self, msg): log.debug('Received a message with an ID of "{0}" and of type "{1}"' .format(getattr(msg, 'msg_id', None), type(msg).__name__)) diff --git a/freshmaker/events.py b/freshmaker/events.py new file mode 100644 index 0000000..09afb84 --- /dev/null +++ b/freshmaker/events.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 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. +# +# Written by Jan Kaluza + +import itertools + +from freshmaker import conf + +try: + from inspect import signature +except ImportError: + from funcsigs import signature + + +class BaseEvent(object): + + _parsers = {} + + def __init__(self, msg_id): + """ + A base class to abstract events from different fedmsg messages. + :param msg_id: the id of the msg (e.g. 2016-SomeGUID) + """ + self.msg_id = msg_id + + # Moksha calls `consumer.validate` on messages that it receives, and + # even though we have validation turned off in the config there's still + # a step that tries to access `msg['body']`, `msg['topic']` and + # `msg.get('topic')`. + # These are here just so that the `validate` method won't raise an + # exception when we push our fake messages through. + # Note that, our fake message pushing has worked for a while... but the + # *latest* version of fedmsg has some code that exercises the bug. I + # didn't hit this until I went to test in jenkins. + self.body = {} + self.topic = None + + @classmethod + def register_parser(cls, parser_class): + """ + Registers a parser for BaseEvent which is used to parse + fedmsg in `from_fedmsg(...)` method. + """ + BaseEvent._parsers[parser_class.name] = parser_class() + + @classmethod + def get_parsed_topics(cls): + """ + Returns the list of topics this class is parsing using the + registered parsers. + """ + topic_suffixes = [] + for parser in BaseEvent._parsers.values(): + topic_suffixes.extend(parser.topic_suffixes) + return ['{}.{}.'.format(pref.rstrip('.'), cat) + for pref, cat + in itertools.product( + conf.messaging_topic_prefix, + topic_suffixes)] + + def __repr__(self): + init_sig = signature(self.__init__) + + args_strs = ( + "{}={!r}".format(name, getattr(self, name)) + if param.default != param.empty + else repr(getattr(self, name)) + for name, param in init_sig.parameters.items()) + + return "{}({})".format(type(self).__name__, ', '.join(args_strs)) + + def __getitem__(self, key): + """ Used to trick moksha into thinking we are a dict. """ + return getattr(self, key) + + def __setitem__(self, key, value): + """ Used to trick moksha into thinking we are a dict. """ + return setattr(self, key, value) + + def get(self, key, value=None): + """ Used to trick moksha into thinking we are a dict. """ + return getattr(self, key, value) + + def __json__(self): + return dict(msg_id=self.msg_id, topic=self.topic, body=self.body) + + @staticmethod + def from_fedmsg(topic, msg): + """ + Takes a fedmsg topic and message and converts it to a BaseEvent + object. + :param topic: the topic of the fedmsg message + :param msg: the message contents from the fedmsg message + :return: an object of BaseEvent descent if the message is a type + that the app looks for, otherwise None is returned + """ + for parser in BaseEvent._parsers.values(): + if not parser.can_parse(topic, msg): + continue + + return parser.parse(topic, msg) + + return None + + +class ModuleBuilt(BaseEvent): + """ A class that inherits from BaseEvent to provide an event + object for a module event generated by module-build-service + :param msg_id: the id of the msg (e.g. 2016-SomeGUID) + :param module_build_id: the id of the module build + :param module_build_state: the state of the module build + """ + def __init__(self, msg_id, module_build_id, module_build_state): + super(ModuleBuilt, self).__init__(msg_id) + self.module_build_id = module_build_id + self.module_build_state = module_build_state + + +class ModuleMetadataUpdated(BaseEvent): + """ + Provides an event object for "Module metadata in dist-git updated". + :param scm_url: SCM URL of a updated module. + :param branch: Branch of updated module. + """ + def __init__(self, msg_id, scm_url, branch): + super(ModuleMetadataUpdated, self).__init__(msg_id) + self.scm_url = scm_url + self.branch = branch + + +class TestingEvent(BaseEvent): + """ + Event useds in unit-tests. + """ + def __init__(self, msg_id): + super(TestingEvent, self).__init__(msg_id) diff --git a/freshmaker/handlers/__init__.py b/freshmaker/handlers/__init__.py index 0d53af0..8654218 100644 --- a/freshmaker/handlers/__init__.py +++ b/freshmaker/handlers/__init__.py @@ -37,21 +37,21 @@ def load_handlers(): class BaseHandler(object): """ - Abstract base class for trigger handlers. + Abstract base class for event handlers. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod - def can_handle(self, trigger): + def can_handle(self, event): """ - Returns true if this class can handle this type of trigger. + Returns true if this class can handle this type of event. """ raise NotImplementedError() @abc.abstractmethod - def handle(self, trigger): + def handle(self, event): """ - Handles the trigger. Can return another BaseTrigger instances to - generate another triggers to be used by other local handlers. + Handles the event. Can return another BaseEvent instances to + generate another events to be used by other local handlers. """ raise NotImplementedError() diff --git a/freshmaker/handlers/mbs.py b/freshmaker/handlers/mbs.py index 937b2ed..85ecac0 100644 --- a/freshmaker/handlers/mbs.py +++ b/freshmaker/handlers/mbs.py @@ -25,21 +25,21 @@ import requests from freshmaker import log, conf from freshmaker.handlers import BaseHandler -from freshmaker.triggers import ModuleBuilt, TestingTrigger, ModuleMetadataUpdated +from freshmaker.events import ModuleBuilt, TestingEvent, ModuleMetadataUpdated class MBS(BaseHandler): name = "MBS" - def can_handle(self, trigger): + def can_handle(self, event): # Handle only "ready" state of ModuleBuilt. # TODO: Handle only when something depends on # this module. - if (isinstance(trigger, ModuleBuilt) and - trigger.module_build_state == 5): + if (isinstance(event, ModuleBuilt) and + event.module_build_state == 5): return True - if isinstance(trigger, ModuleMetadataUpdated): + if isinstance(event, ModuleMetadataUpdated): return True return False @@ -64,23 +64,23 @@ class MBS(BaseHandler): log.error("Error when triggering rebuild of %s: %s", scm_url, data) return None - def handle_metadata_update(self, trigger): - log.info("Triggering rebuild of %s, metadata updated", trigger.scm_url) - self.rebuild_module(trigger.scm_url, trigger.branch) + def handle_metadata_update(self, event): + log.info("Triggering rebuild of %s, metadata updated", event.scm_url) + self.rebuild_module(event.scm_url, event.branch) return [] - def handle_module_built(self, trigger): + def handle_module_built(self, event): log.info("Triggering rebuild of modules depending on %r " - "in MBS" % trigger) + "in MBS" % event) # TODO: Just for initial testing of consumer - return [TestingTrigger("ModuleBuilt handled")] + return [TestingEvent("ModuleBuilt handled")] - def handle(self, trigger): - if isinstance(trigger, ModuleMetadataUpdated): - return self.handle_metadata_update(trigger) - elif isinstance(trigger, ModuleBuilt): - return self.handle_module_built(trigger) + def handle(self, event): + if isinstance(event, ModuleMetadataUpdated): + return self.handle_metadata_update(event) + elif isinstance(event, ModuleBuilt): + return self.handle_module_built(event) return [] diff --git a/freshmaker/messaging.py b/freshmaker/messaging.py index eb89e1c..1550294 100644 --- a/freshmaker/messaging.py +++ b/freshmaker/messaging.py @@ -26,7 +26,7 @@ """Generic messaging functions.""" from freshmaker import log -from freshmaker.triggers import BaseTrigger +from freshmaker.events import BaseEvent def publish(topic, msg, conf, service): @@ -63,9 +63,9 @@ def _in_memory_publish(topic, msg, conf, service): _in_memory_msg_id += 1 # Create fake fedmsg from the message so we can reuse - # the BaseTrigger.from_fedmsg code to get the particular BaseTrigger + # the BaseEvent.from_fedmsg code to get the particular BaseEvent # class instance. - wrapped_msg = BaseTrigger.from_fedmsg( + wrapped_msg = BaseEvent.from_fedmsg( service + "." + topic, {"msg_id": str(_in_memory_msg_id), "msg": msg}, ) diff --git a/freshmaker/parsers/__init__.py b/freshmaker/parsers/__init__.py index fe4cbd7..2cd7b00 100644 --- a/freshmaker/parsers/__init__.py +++ b/freshmaker/parsers/__init__.py @@ -26,7 +26,7 @@ import abc class BaseParser(object): """ - Abstract parser class parsing fedmsg messages and generating triggers. + Abstract parser class parsing fedmsg messages and generating events. """ __metaclass__ = abc.ABCMeta name = "abstract_parser" @@ -42,6 +42,6 @@ class BaseParser(object): @abc.abstractmethod def parse(self, topic, msg): """ - Parses the message and returns BaseTrigger object. + Parses the message and returns BaseEvent object. """ raise NotImplementedError() diff --git a/freshmaker/parsers/gitreceive.py b/freshmaker/parsers/gitreceive.py index c5f0acc..1e4a5c7 100644 --- a/freshmaker/parsers/gitreceive.py +++ b/freshmaker/parsers/gitreceive.py @@ -23,7 +23,7 @@ from freshmaker import log, conf from freshmaker.parsers import BaseParser -from freshmaker.triggers import ModuleMetadataUpdated +from freshmaker.events import ModuleMetadataUpdated class GitReceiveParser(BaseParser): diff --git a/freshmaker/parsers/mbsmodule.py b/freshmaker/parsers/mbsmodule.py index 00c3459..d16a59f 100644 --- a/freshmaker/parsers/mbsmodule.py +++ b/freshmaker/parsers/mbsmodule.py @@ -23,13 +23,13 @@ from freshmaker import log from freshmaker.parsers import BaseParser -from freshmaker.triggers import ModuleBuilt +from freshmaker.events import ModuleBuilt class MBSModuleParser(BaseParser): """ Parser parsing message from module-build-service, generating - ModuleBuilt trigger. + ModuleBuilt event. """ name = "MBSModuleParser" topic_suffixes = ["mbs.module.state.change"] diff --git a/freshmaker/triggers.py b/freshmaker/triggers.py deleted file mode 100644 index 8be95c2..0000000 --- a/freshmaker/triggers.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2016 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. -# -# Written by Jan Kaluza - -import itertools - -from freshmaker import conf - -try: - from inspect import signature -except ImportError: - from funcsigs import signature - - -class BaseTrigger(object): - - _parsers = {} - - def __init__(self, msg_id): - """ - A base class to abstract triggers from different fedmsg messages. - :param msg_id: the id of the msg (e.g. 2016-SomeGUID) - """ - self.msg_id = msg_id - - # Moksha calls `consumer.validate` on messages that it receives, and - # even though we have validation turned off in the config there's still - # a step that tries to access `msg['body']`, `msg['topic']` and - # `msg.get('topic')`. - # These are here just so that the `validate` method won't raise an - # exception when we push our fake messages through. - # Note that, our fake message pushing has worked for a while... but the - # *latest* version of fedmsg has some code that exercises the bug. I - # didn't hit this until I went to test in jenkins. - self.body = {} - self.topic = None - - @classmethod - def register_parser(cls, parser_class): - """ - Registers a parser for BaseTrigger which is used to parse - fedmsg in `from_fedmsg(...)` method. - """ - BaseTrigger._parsers[parser_class.name] = parser_class() - - @classmethod - def get_parsing_topics(cls): - """ - Returns the list of topics this class is parsing using the - registered parsers. - """ - topic_suffixes = [] - for parser in BaseTrigger._parsers.values(): - topic_suffixes.extend(parser.topic_suffixes) - return ['{}.{}.'.format(pref.rstrip('.'), cat) - for pref, cat - in itertools.product( - conf.messaging_topic_prefix, - topic_suffixes)] - - def __repr__(self): - init_sig = signature(self.__init__) - - args_strs = ( - "{}={!r}".format(name, getattr(self, name)) - if param.default != param.empty - else repr(getattr(self, name)) - for name, param in init_sig.parameters.items()) - - return "{}({})".format(type(self).__name__, ', '.join(args_strs)) - - def __getitem__(self, key): - """ Used to trick moksha into thinking we are a dict. """ - return getattr(self, key) - - def __setitem__(self, key, value): - """ Used to trick moksha into thinking we are a dict. """ - return setattr(self, key, value) - - def get(self, key, value=None): - """ Used to trick moksha into thinking we are a dict. """ - return getattr(self, key, value) - - def __json__(self): - return dict(msg_id=self.msg_id, topic=self.topic, body=self.body) - - @staticmethod - def from_fedmsg(topic, msg): - """ - Takes a fedmsg topic and message and converts it to a BaseTrigger - object. - :param topic: the topic of the fedmsg message - :param msg: the message contents from the fedmsg message - :return: an object of BaseTrigger descent if the message is a type - that the app looks for, otherwise None is returned - """ - for parser in BaseTrigger._parsers.values(): - if not parser.can_parse(topic, msg): - continue - - return parser.parse(topic, msg) - - return None - - -class ModuleBuilt(BaseTrigger): - """ A class that inherits from BaseTrigger to provide a trigger - object for a module event generated by module-build-service - :param msg_id: the id of the msg (e.g. 2016-SomeGUID) - :param module_build_id: the id of the module build - :param module_build_state: the state of the module build - """ - def __init__(self, msg_id, module_build_id, module_build_state): - super(ModuleBuilt, self).__init__(msg_id) - self.module_build_id = module_build_id - self.module_build_state = module_build_state - - -class ModuleMetadataUpdated(BaseTrigger): - """ - Provides a trigger object for "Module metadata in dist-git updated". - :param scm_url: SCM URL of a updated module. - :param branch: Branch of updated module. - """ - def __init__(self, msg_id, scm_url, branch): - super(ModuleMetadataUpdated, self).__init__(msg_id) - self.scm_url = scm_url - self.branch = branch - - -class TestingTrigger(BaseTrigger): - """ - Trigger useds in unit-tests. - """ - def __init__(self, msg_id): - super(TestingTrigger, self).__init__(msg_id) diff --git a/tests/test_consumer.py b/tests/test_consumer.py index fb4fea6..fe5ce5a 100644 --- a/tests/test_consumer.py +++ b/tests/test_consumer.py @@ -37,7 +37,7 @@ class TestPoller(unittest.TestCase): def test_consumer_processing_message(self, global_consumer): """ - Tests that consumer parses the message, forwards the trigger + Tests that consumer parses the message, forwards the event to proper handler and is able to get the further work from the handler. """ @@ -59,5 +59,5 @@ class TestPoller(unittest.TestCase): consumer.consume(msg) - trigger = consumer.incoming.get() - self.assertEqual(trigger.msg_id, "ModuleBuilt handled") + event = consumer.incoming.get() + self.assertEqual(event.msg_id, "ModuleBuilt handled")