def _do_fire(self, event): """ Performs the actual act of firing an event to all appropriate listeners. This call will log but otherwise suppress any exception that comes out of a notifier. @param event: event object to fire @type event: pulp.server.event.data.Event """ # Determine which listeners should be notified listeners = list( EventListener.get_collection().find({"$or": ({"event_types": event.event_type}, {"event_types": "*"})}) ) # For each listener, retrieve the notifier and invoke it. Be sure that # an exception from a notifier is logged but does not interrupt the # remainder of the firing, nor bubble up. for l in listeners: notifier_type_id = l["notifier_type_id"] f = notifiers.get_notifier_function(notifier_type_id) try: f(l["notifier_config"], event) except Exception: _logger.exception("Exception from notifier of type [%s]" % notifier_type_id)
def test_post(self): # Setup params = { 'notifier_type_id' : http.TYPE_ID, 'notifier_config' : {'a' : 'a'}, 'event_types' : [event_data.TYPE_REPO_SYNC_STARTED], } # Test status, body = self.post('/v2/events/', params) # Verify self.assertEqual(status, 201) self.assertEqual(body['notifier_type_id'], params['notifier_type_id']) self.assertEqual(body['notifier_config'], params['notifier_config']) self.assertEqual(body['event_types'], params['event_types']) db_listener = EventListener.get_collection().find_one({'id' : body['id']}) self.assertTrue(db_listener is not None) self.assertEqual(db_listener['notifier_type_id'], params['notifier_type_id']) self.assertEqual(db_listener['notifier_config'], params['notifier_config']) self.assertEqual(db_listener['event_types'], params['event_types']) expected_href = '/v2/events/%s/' % body['id'] self.assertEqual(body['_href'], expected_href)
def get(self, event_listener_id): """ Retrieves the given event listener if it exists. If not, an exception is raised. @param event_listener_id: listener to retrieve @type event_listener_id: str @return: listener instance from the database @rtype: dict @raise MissingResource: if no listener exists at the given ID """ collection = EventListener.get_collection() try: id = ObjectId(event_listener_id) except InvalidId: raise MissingResource( event_listener=event_listener_id), None, sys.exc_info()[2] listener = collection.find_one({'_id': id}) if listener is None: raise MissingResource(event_listener=event_listener_id) else: return listener
def get(self, event_listener_id): """ Retrieves the given event listener if it exists. If not, an exception is raised. @param event_listener_id: listener to retrieve @type event_listener_id: str @return: listener instance from the database @rtype: dict @raise MissingResource: if no listener exists at the given ID """ collection = EventListener.get_collection() try: id = ObjectId(event_listener_id) except InvalidId: raise MissingResource(event_listener=event_listener_id), None, sys.exc_info()[2] listener = collection.find_one({'_id' : id}) if listener is None: raise MissingResource(event_listener=event_listener_id) else: return listener
def _do_fire(self, event): """ Performs the actual act of firing an event to all appropriate listeners. This call will log but otherwise suppress any exception that comes out of a notifier. @param event: event object to fire @type event: pulp.server.event.data.Event """ # Determine which listeners should be notified listeners = list(EventListener.get_collection().find( {'$or': ({ 'event_types': event.event_type }, { 'event_types': '*' })})) # For each listener, retrieve the notifier and invoke it. Be sure that # an exception from a notifier is logged but does not interrupt the # remainder of the firing, nor bubble up. for l in listeners: notifier_type_id = l['notifier_type_id'] f = notifiers.get_notifier_function(notifier_type_id) try: f(l['notifier_config'], event) except Exception: _LOG.exception('Exception from notifier of type [%s]' % notifier_type_id)
def create(self, notifier_type_id, notifier_config, event_types): """ Creates a new event listener in the server. The listener will listen for events of the given types and use the given notifier to react to them. The notifier will be passed the given configuration to drive how it behaves; values in the configuration vary based on the notifier being used. For instance, a message bus notifier will likely accept in its configuration the message bus and queue on which to broadcast the event. @param notifier_type_id: identifies the type of notification to produce @type notifier_type_id: str @param notifier_config: used to control how the notifier behaves @param event_types: list of event types to listen for; valid values can be found in pulp.server.event.notifiers @type event_types: list @return: created event listener instance from the database (i.e. _id will be populated) @raise InvalidValue: if the notifier or event type ID aren't found """ # Validation _validate_event_types(event_types) if not notifiers.is_valid_notifier_type_id(notifier_type_id): raise InvalidValue(['notifier_type_id']) # There's no need to check for a conflict; it's possible to use the # same notifier for the same event type but a different configuration # Make sure the configuration is at very least empty if notifier_config is None: notifier_config = {} # Create the database entry el = EventListener(notifier_type_id, notifier_config, event_types) collection = EventListener.get_collection() created_id = collection.save(el) created = collection.find_one(created_id) return created
def update(self, event_listener_id, notifier_config=None, event_types=None): """ Changes the configuration of an existing event listener. The notifier type cannot be changed; in such cases the event listener should be deleted and a new one created. If specified, the notifier_config follows the given conventions: - If a key is specified with a value of None, the effect is that the key is removed from the configuration - If an existing key is unspecified, its value is unaffected Event types must be the *complete* list of event types to listen for. This method does not support deltas on the event types. @param event_listener_id: listener being edited @type event_listener_id: str @param notifier_config: contains only configuration properties to change @type notifier_config: dict @param event_types: complete list of event types that should be fired on @type event_types: list @return: updated listener instance from the database """ collection = EventListener.get_collection() # Validation existing = self.get(event_listener_id) # will raise MissingResource # Munge the existing configuration if it was specified if notifier_config is not None: munged_config = dict(existing['notifier_config']) remove_us = [ k for k in notifier_config.keys() if notifier_config[k] is None ] for k in remove_us: munged_config.pop(k, None) notifier_config.pop(k) munged_config.update(notifier_config) existing['notifier_config'] = munged_config # Update the event list if event_types is not None: _validate_event_types(event_types) existing['event_types'] = event_types # Update the database collection.save(existing) # Reload to return existing = collection.find_one({'_id': ObjectId(event_listener_id)}) return existing
def migrate(*args, **kwargs): """ Change the type id from 'rest-api' to 'http' """ collection = EventListener.get_collection() collection.update({'notifier_type_id': 'rest-api'}, {'$set': { 'notifier_type_id': 'http' }})
def test_delete(self): # Setup created = self.manager.create(http.TYPE_ID, {}, [event_data.TYPE_REPO_SYNC_STARTED]) # Test self.manager.delete(created['_id']) # Verify all_event_listeners = list(EventListener.get_collection().find()) self.assertEqual(0, len(all_event_listeners))
def list(self): """ Returns all event listeners. @return: list of event listener SON documents from the database; empty list if there are none @rtype: list """ listeners = list(EventListener.get_collection().find()) return listeners
def test_create(self): # Test created = self.manager.create(http.TYPE_ID, None, [event_data.TYPE_REPO_SYNC_STARTED]) # Verify self.assertEqual(created['notifier_type_id'], http.TYPE_ID) self.assertEqual(created['notifier_config'], {}) self.assertEqual(created['event_types'], [event_data.TYPE_REPO_SYNC_STARTED]) all_event_listeners = list(EventListener.get_collection().find()) self.assertEqual(1, len(all_event_listeners))
def update(self, event_listener_id, notifier_config=None, event_types=None): """ Changes the configuration of an existing event listener. The notifier type cannot be changed; in such cases the event listener should be deleted and a new one created. If specified, the notifier_config follows the given conventions: - If a key is specified with a value of None, the effect is that the key is removed from the configuration - If an existing key is unspecified, its value is unaffected Event types must be the *complete* list of event types to listen for. This method does not support deltas on the event types. @param event_listener_id: listener being edited @type event_listener_id: str @param notifier_config: contains only configuration properties to change @type notifier_config: dict @param event_types: complete list of event types that should be fired on @type event_types: list @return: updated listener instance from the database """ collection = EventListener.get_collection() # Validation existing = self.get(event_listener_id) # will raise MissingResource # Munge the existing configuration if it was specified if notifier_config is not None: munged_config = dict(existing['notifier_config']) remove_us = [k for k in notifier_config.keys() if notifier_config[k] is None] for k in remove_us: munged_config.pop(k, None) notifier_config.pop(k) munged_config.update(notifier_config) existing['notifier_config'] = munged_config # Update the event list if event_types is not None: _validate_event_types(event_types) existing['event_types'] = event_types # Update the database collection.save(existing, safe=True) # Reload to return existing = collection.find_one({'_id' : ObjectId(event_listener_id)}) return existing
def test_delete(self): # Setup manager = manager_factory.event_listener_manager() created = manager.create(http.TYPE_ID, {'a' : 'a'}, [event_data.TYPE_REPO_SYNC_STARTED]) # Test status, body = self.delete('/v2/events/%s/' % created['id']) # Verify self.assertEqual(200, status) deleted = EventListener.get_collection().find_one({'_id' : ObjectId(created['_id'])}) self.assertTrue(deleted is None)
def delete(self, event_listener_id): """ Deletes the event listener with the given ID. No exception is raised if no event listener exists at the given ID. @param event_listener_id: database ID for the event listener @type event_listener_id: str @raise MissingResource: if no listener exists at the given ID """ collection = EventListener.get_collection() self.get(event_listener_id) # check for MissingResource collection.remove({'_id' : ObjectId(event_listener_id)})
def delete(self, event_listener_id): """ Deletes the event listener with the given ID. No exception is raised if no event listener exists at the given ID. @param event_listener_id: database ID for the event listener @type event_listener_id: str @raise MissingResource: if no listener exists at the given ID """ collection = EventListener.get_collection() self.get(event_listener_id) # check for MissingResource collection.remove({'_id': ObjectId(event_listener_id)})
def test_database_integration(self): # make sure the migration works on a live document in mongo collection = EventListener.get_collection() event_listener_id = str( collection.insert({"notifier_type_id": "rest-api", "event_types": ["*"], "notifier_config": {}}, safe=True) ) event_listener_factory = managers.factory.event_listener_manager() module = MigrationModule("pulp.server.db.migrations.0002_rename_http_notifier")._module module.migrate() event_listener = event_listener_factory.get(event_listener_id) self.assertEqual(event_listener["notifier_type_id"], "http") # cleanup collection.remove()
def create(self, notifier_type_id, notifier_config, event_types): """ Creates a new event listener in the server. The listener will listen for events of the given types and use the given notifier to react to them. The notifier will be passed the given configuration to drive how it behaves; values in the configuration vary based on the notifier being used. For instance, a message bus notifier will likely accept in its configuration the message bus and queue on which to broadcast the event. @param notifier_type_id: identifies the type of notification to produce @type notifier_type_id: str @param notifier_config: used to control how the notifier behaves @param event_types: list of event types to listen for; valid values can be found in pulp.server.event.notifiers @type event_types: list @return: created event listener instance from the database (i.e. _id will be populated) @raise InvalidValue: if the notifier or event type ID aren't found """ # Validation _validate_event_types(event_types) if not notifiers.is_valid_notifier_type_id(notifier_type_id): raise InvalidValue(['notifier_type_id']) # There's no need to check for a conflict; it's possible to use the # same notifier for the same event type but a different configuration # Make sure the configuration is at very least empty if notifier_config is None: notifier_config = {} # Create the database entry el = EventListener(notifier_type_id, notifier_config, event_types) collection = EventListener.get_collection() created_id = collection.save(el, safe=True) created = collection.find_one(created_id) return created
def test_update_only_event_types(self): # Setup manager = manager_factory.event_listener_manager() created = manager.create(http.TYPE_ID, {'a' : 'a', 'b' : 'b'}, [event_data.TYPE_REPO_SYNC_STARTED]) # Test new_event_types = [event_data.TYPE_REPO_SYNC_FINISHED] body = { 'event_types' : new_event_types, } status, body = self.put('/v2/events/%s/' % created['id'], body) # Verify self.assertEqual(200, status) updated = EventListener.get_collection().find_one({'_id' : ObjectId(created['_id'])}) self.assertEqual(updated['event_types'], new_event_types)
def test_database_integration(self): # make sure the migration works on a live document in mongo collection = EventListener.get_collection() event_listener_id = str(collection.insert({ 'notifier_type_id': 'rest-api', 'event_types': ['*'], 'notifier_config': {}, })) event_listener_factory = managers.factory.event_listener_manager() module = MigrationModule('pulp.server.db.migrations.0002_rename_http_notifier')._module module.migrate() event_listener = event_listener_factory.get(event_listener_id) self.assertEqual(event_listener['notifier_type_id'], 'http') # cleanup collection.remove()
def test_update_only_config(self): # Setup manager = manager_factory.event_listener_manager() created = manager.create(http.TYPE_ID, {'a' : 'a', 'b' : 'b'}, [event_data.TYPE_REPO_SYNC_STARTED]) # Test new_config = {'a' : 'x', 'c' : 'c'} body = { 'notifier_config' : new_config, } status, body = self.put('/v2/events/%s/' % created['id'], body) # Verify self.assertEqual(200, status) updated = EventListener.get_collection().find_one({'_id' : ObjectId(created['_id'])}) expected_config = {'a' : 'x', 'b' : 'b', 'c' : 'c'} self.assertEqual(updated['notifier_config'], expected_config)
def clean(self): super(EventResourceControllerTests, self).clean() EventListener.get_collection().remove()
def tearDown(self): super(EventFireManagerTests, self).tearDown() EventListener.get_collection().remove() notifiers.reset()
def migrate(*args, **kwargs): """ Change the type id from 'rest-api' to 'http' """ collection = EventListener.get_collection() collection.update({'notifier_type_id':'rest-api'}, {'$set': {'notifier_type_id':'http'}})
def clean(self): super(EventListenerManagerTests, self).clean() EventListener.get_collection().remove()
def _validate_event_listener(): objectdb = EventListener.get_collection() reference = EventListener('', {}, []) return _validate_model(EventListener.__name__, objectdb, reference)