Merge lp:~blamar/glance/notifier-strategy into lp:~johannes.erdfelt/glance/notifier

Proposed by Brian Lamar
Status: Merged
Merged at revision: 169
Proposed branch: lp:~blamar/glance/notifier-strategy
Merge into: lp:~johannes.erdfelt/glance/notifier
Diff against target: 707 lines (+256/-247)
13 files modified
Authors (+1/-0)
bin/glance-api (+0/-3)
bin/glance-registry (+0/-3)
glance/api/v1/images.py (+8/-7)
glance/common/client.py (+6/-0)
glance/common/exception.py (+4/-0)
glance/common/notifier.py (+115/-135)
tests/functional/test_scrubber.py (+20/-4)
tests/stubs.py (+0/-8)
tests/unit/test_api.py (+0/-1)
tests/unit/test_clients.py (+0/-1)
tests/unit/test_notifier.py (+101/-85)
tools/pip-requires (+1/-0)
To merge this branch: bzr merge lp:~blamar/glance/notifier-strategy
Reviewer Review Type Date Requested Status
Johannes Erdfelt Approve
Review via email: mp+69341@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Johannes Erdfelt (johannes.erdfelt) wrote :

I like the direction of your changes. The code was a port of the Tempo notification code, which in turn was a port of the nova notification code, but it was a mistake not to take the opportunity and consider if it could be simpler.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Authors'
--- Authors 2011-07-26 04:24:28 +0000
+++ Authors 2011-07-26 18:44:34 +0000
@@ -1,4 +1,5 @@
1Andrey Brindeyev <abrindeyev@griddynamics.com>1Andrey Brindeyev <abrindeyev@griddynamics.com>
2Brian Lamar <brian.lamar@rackspace.com>
2Brian Waldon <brian.waldon@rackspace.com>3Brian Waldon <brian.waldon@rackspace.com>
3Christopher MacGown <chris@slicehost.com>4Christopher MacGown <chris@slicehost.com>
4Cory Wright <corywright@gmail.com>5Cory Wright <corywright@gmail.com>
56
=== modified file 'bin/glance-api'
--- bin/glance-api 2011-07-22 17:59:11 +0000
+++ bin/glance-api 2011-07-26 18:44:34 +0000
@@ -36,7 +36,6 @@
3636
37from glance import version37from glance import version
38from glance.common import config38from glance.common import config
39from glance.common import notifier
40from glance.common import wsgi39from glance.common import wsgi
4140
4241
@@ -60,8 +59,6 @@
60 try:59 try:
61 conf, app = config.load_paste_app('glance-api', options, args)60 conf, app = config.load_paste_app('glance-api', options, args)
6261
63 notifier.configure_notifier(conf)
64
65 server = wsgi.Server()62 server = wsgi.Server()
66 server.start(app, int(conf['bind_port']), conf['bind_host'])63 server.start(app, int(conf['bind_port']), conf['bind_host'])
67 server.wait()64 server.wait()
6865
=== modified file 'bin/glance-registry'
--- bin/glance-registry 2011-07-22 17:59:11 +0000
+++ bin/glance-registry 2011-07-26 18:44:34 +0000
@@ -36,7 +36,6 @@
3636
37from glance import version37from glance import version
38from glance.common import config38from glance.common import config
39from glance.common import notifier
40from glance.common import wsgi39from glance.common import wsgi
4140
4241
@@ -60,8 +59,6 @@
60 try:59 try:
61 conf, app = config.load_paste_app('glance-registry', options, args)60 conf, app = config.load_paste_app('glance-registry', options, args)
6261
63 notifier.configure_notifier(conf)
64
65 server = wsgi.Server()62 server = wsgi.Server()
66 server.start(app, int(conf['bind_port']), conf['bind_host'])63 server.start(app, int(conf['bind_port']), conf['bind_host'])
67 server.wait()64 server.wait()
6865
=== modified file 'glance/api/v1/images.py'
--- glance/api/v1/images.py 2011-07-26 04:48:33 +0000
+++ glance/api/v1/images.py 2011-07-26 18:44:34 +0000
@@ -73,6 +73,7 @@
7373
74 def __init__(self, options):74 def __init__(self, options):
75 self.options = options75 self.options = options
76 self.notifier = notifier.Notifier(options)
7677
77 def index(self, req):78 def index(self, req):
78 """79 """
@@ -354,7 +355,7 @@
354 image_id,355 image_id,
355 {'checksum': checksum,356 {'checksum': checksum,
356 'size': size})357 'size': size})
357 notifier.notify('image.upload', 'INFO', image_meta)358 self.notifier.info('image.upload', image_meta)
358359
359 return location360 return location
360361
@@ -362,14 +363,14 @@
362 msg = ("Attempt to upload duplicate image: %s") % str(e)363 msg = ("Attempt to upload duplicate image: %s") % str(e)
363 logger.error(msg)364 logger.error(msg)
364 self._safe_kill(req, image_id)365 self._safe_kill(req, image_id)
365 notifier.notify('image.upload', 'ERROR', msg)366 self.notifier.error('image.upload', msg)
366 raise HTTPConflict(msg, request=req)367 raise HTTPConflict(msg, request=req)
367368
368 except exception.NotAuthorized, e:369 except exception.NotAuthorized, e:
369 msg = ("Unauthorized upload attempt: %s") % str(e)370 msg = ("Unauthorized upload attempt: %s") % str(e)
370 logger.error(msg)371 logger.error(msg)
371 self._safe_kill(req, image_id)372 self._safe_kill(req, image_id)
372 notifier.notify('image.upload', 'ERROR', msg)373 self.notifier.error('image.upload', msg)
373 raise HTTPForbidden(msg, request=req,374 raise HTTPForbidden(msg, request=req,
374 content_type='text/plain')375 content_type='text/plain')
375376
@@ -377,7 +378,7 @@
377 msg = ("Error uploading image: %s") % str(e)378 msg = ("Error uploading image: %s") % str(e)
378 logger.error(msg)379 logger.error(msg)
379 self._safe_kill(req, image_id)380 self._safe_kill(req, image_id)
380 notifier.notify('image.upload', 'ERROR', msg)381 self.notifier.error('image.upload', msg)
381 raise HTTPBadRequest(msg, request=req)382 raise HTTPBadRequest(msg, request=req)
382383
383 def _activate(self, req, image_id, location):384 def _activate(self, req, image_id, location):
@@ -524,10 +525,10 @@
524 % locals())525 % locals())
525 for line in msg.split('\n'):526 for line in msg.split('\n'):
526 logger.error(line)527 logger.error(line)
527 notifier.notify('image.update', 'ERROR', msg)528 self.notifier.error('image.update', msg)
528 raise HTTPBadRequest(msg, request=req, content_type="text/plain")529 raise HTTPBadRequest(msg, request=req, content_type="text/plain")
529 else:530 else:
530 notifier.notify('image.update', 'INFO', image_meta)531 self.notifier.info('image.update', image_meta)
531532
532 return {'image_meta': image_meta}533 return {'image_meta': image_meta}
533534
@@ -559,7 +560,7 @@
559 schedule_delete_from_backend(image['location'], self.options,560 schedule_delete_from_backend(image['location'], self.options,
560 req.context, id)561 req.context, id)
561 registry.delete_image_metadata(self.options, req.context, id)562 registry.delete_image_metadata(self.options, req.context, id)
562 notifier.notify('image.delete', 'INFO', id)563 self.notifier.info('image.delete', id)
563564
564 def get_store_or_400(self, request, store_name):565 def get_store_or_400(self, request, store_name):
565 """566 """
566567
=== modified file 'glance/common/client.py'
--- glance/common/client.py 2011-07-20 22:53:44 +0000
+++ glance/common/client.py 2011-07-26 18:44:34 +0000
@@ -56,6 +56,12 @@
56 self.auth_tok = auth_tok56 self.auth_tok = auth_tok
57 self.connection = None57 self.connection = None
5858
59 def set_auth_token(self, auth_tok):
60 """
61 Updates the authentication token for this client connection.
62 """
63 self.auth_tok = auth_tok
64
59 def get_connection_type(self):65 def get_connection_type(self):
60 """66 """
61 Returns the proper connection type67 Returns the proper connection type
6268
=== modified file 'glance/common/exception.py'
--- glance/common/exception.py 2011-07-13 20:15:46 +0000
+++ glance/common/exception.py 2011-07-26 18:44:34 +0000
@@ -145,3 +145,7 @@
145145
146class InvalidContentType(GlanceException):146class InvalidContentType(GlanceException):
147 message = "Invalid content type %(content_type)s"147 message = "Invalid content type %(content_type)s"
148
149
150class InvalidNotifierStrategy(GlanceException):
151 message = "'%(strategy)s' is not an available notifier strategy."
148152
=== modified file 'glance/common/notifier.py'
--- glance/common/notifier.py 2011-07-26 17:11:27 +0000
+++ glance/common/notifier.py 2011-07-26 18:44:34 +0000
@@ -20,148 +20,128 @@
20import socket20import socket
21import uuid21import uuid
2222
23from kombu.connection import BrokerConnection23import kombu.connection
2424
25from glance.common import config25from glance.common import config
2626from glance.common import exception
2727
28WARN = 'WARN'28
29INFO = 'INFO'29class NoopStrategy(object):
30ERROR = 'ERROR'30 """A notifier that does nothing when called."""
31CRITICAL = 'CRITICAL'31
32DEBUG = 'DEBUG'32 def __init__(self, options):
3333 pass
34log_levels = (DEBUG, WARN, INFO, ERROR, CRITICAL)34
3535 def warn(self, msg):
36_DRIVER = None36 pass
3737
3838 def info(self, msg):
39class BadPriorityException(Exception):39 pass
40 pass40
4141 def error(self, msg):
4242 pass
43def configure_notifier(options):43
44 global _DRIVER44
45 notification_driver = config.get_option(options, 'notification_driver',45class LoggingStrategy(object):
46 type='str', default='logging')46 """A notifier that calls logging when called."""
47 _DRIVER = _get_notifier_driver(notification_driver)(options)47
4848 def __init__(self, options):
49
50def notify(event_type, priority, payload):
51 """
52 Sends a notification using the specified driver
53
54 Notify parameters:
55
56 event_type - the literal type of event (ex. Instance Creation)
57 priority - patterned after the enumeration of Python logging levels in
58 the set (DEBUG, WARN, INFO, ERROR, CRITICAL)
59 payload - A python dictionary of attributes
60
61 Outgoing message format includes the above parameters, and appends the
62 following:
63
64 message_id - a UUID representing the id for this notification
65 timestamp - the GMT timestamp the notification was sent at
66
67 The composite message will be constructed as a dictionary of the above
68 attributes, which will then be sent via the transport mechanism defined
69 by the driver.
70
71 Message example:
72
73 {'message_id': str(uuid.uuid4()),
74 'publisher_id': 'compute.host1',
75 'timestamp': utils.utcnow(),
76 'priority': 'WARN',
77 'event_type': 'compute.create_instance',
78 'payload': {'instance_id': 12, ... }}
79
80 """
81 if priority not in log_levels:
82 raise BadPriorityException(
83 _('%s not in valid priorities' % priority))
84
85 msg = dict(message_id=str(uuid.uuid4()),
86 publisher_id=socket.gethostname(),
87 event_type=event_type,
88 priority=priority,
89 payload=payload,
90 timestamp=str(datetime.datetime.utcnow()))
91
92 _DRIVER.notify(msg)
93
94
95class Notifier(object):
96 def __init__(self, options):
97 self.level = config.get_option(options, 'default_notification_level',
98 type='str', default='INFO')
99
100 def notify(self, msg):
101 raise NotImplementedError()
102
103
104class NoopNotifier(Notifier):
105 def notify(self, msg):
106 pass
107
108
109class LoggingNotifier(Notifier):
110 def __init__(self, options):
111 super(LoggingNotifier, self).__init__(options)
112 self._setup_logger()
113
114 def _setup_logger(self):
115 str2log_level = {
116 'DEBUG': logging.DEBUG,
117 'INFO': logging.INFO,
118 'WARN': logging.WARN,
119 'ERROR': logging.ERROR,
120 'CRITICAL': logging.CRITICAL}
121 self.level = str2log_level[self.level]
122 self.logger = logging.getLogger('glance.notifier.logging_notifier')49 self.logger = logging.getLogger('glance.notifier.logging_notifier')
12350
124 def notify(self, msg):51 def warn(self, msg):
125 self.logger.log(self.level, msg)52 self.logger.warn(msg)
12653
12754 def info(self, msg):
128class RabbitNotifier(Notifier):55 self.logger.info(msg)
56
57 def error(self, msg):
58 self.logger.error(msg)
59
60
61class RabbitStrategy(object):
62 """A notifier that puts a message on a queue when called."""
63
129 def __init__(self, options):64 def __init__(self, options):
130 super(RabbitNotifier, self).__init__(options)65 """Initialize the rabbit notification strategy."""
131 host = config.get_option(options, 'rabbit_host',66 self._options = options
132 type='str', default='localhost')67 host = self._get_option('rabbit_host', 'str', 'localhost')
133 port = config.get_option(options, 'rabbit_port',68 port = self._get_option('rabbit_port', 'int', 5672)
134 type='int', default=5672)69 use_ssl = self._get_option('rabbit_use_ssl', 'bool', False)
135 use_ssl = config.get_option(options, 'rabbit_use_ssl',70 userid = self._get_option('rabbit_userid', 'str', 'guest')
136 type='bool', default=False)71 password = self._get_option('rabbit_password', 'str', 'guest')
137 userid = config.get_option(options, 'rabbit_userid',72 virtual_host = self._get_option('rabbit_virtual_host', 'str', '/')
138 type='str', default='guest')73
139 password = config.get_option(options, 'rabbit_password',74 self.connection = kombu.connection.BrokerConnection(
140 type='str', default='guest')75 hostname=host,
141 virtual_host = config.get_option(options, 'rabbit_virtual_host',76 userid=userid,
142 type='str', default='/')77 password=password,
14378 virtual_host=virtual_host,
144 self.connection = BrokerConnection(79 ssl=use_ssl)
145 hostname=host,80
146 userid=userid,81 self.topic = self._get_option('rabbit_notification_topic',
147 password=password,82 'str',
148 virtual_host=virtual_host,83 'glance_notifications')
149 ssl=use_ssl)84
150 self.topic = config.get_option(options, 'rabbit_notification_topic',85 def _get_option(self, name, datatype, default):
151 type='str', default='glance_notifications')86 """Retrieve a configuration option."""
15287 return config.get_option(self._options,
153 def notify(self, message):88 name,
154 priority = message.get('priority', self.level)89 type=datatype,
90 default=default)
91
92 def _send_message(self, message, priority):
155 topic = "%s.%s" % (self.topic, priority)93 topic = "%s.%s" % (self.topic, priority)
156 queue = self.connection.SimpleQueue(topic)94 queue = self.connection.SimpleQueue(topic)
157 queue.put(message, serializer="json")95 queue.put(message, serializer="json")
158 queue.close()96 queue.close()
15997
16098 def warn(self, msg):
161def _get_notifier_driver(driver):99 self._send_message(msg, "WARN")
162 if driver == "logging":100
163 return LoggingNotifier101 def info(self, msg):
164 elif driver == "rabbit":102 self._send_message(msg, "INFO")
165 return RabbitNotifier103
166 else:104 def error(self, msg):
167 return NoopNotifier105 self._send_message(msg, "ERROR")
106
107
108class Notifier(object):
109 """Uses a notification strategy to send out messages about events."""
110
111 STRATEGIES = {
112 "logging": LoggingStrategy,
113 "rabbit": RabbitStrategy,
114 "noop": NoopStrategy,
115 "default": NoopStrategy,
116 }
117
118 def __init__(self, options, strategy=None):
119 strategy = config.get_option(options, "notifier_strategy",
120 type="str", default="default")
121 try:
122 self.strategy = self.STRATEGIES[strategy](options)
123 except KeyError:
124 raise exception.InvalidNotifierStrategy(strategy=strategy)
125
126 @staticmethod
127 def generate_message(event_type, priority, payload):
128 return {
129 "message_id": str(uuid.uuid4()),
130 "publisher_id": socket.gethostname(),
131 "event_type": event_type,
132 "priority": priority,
133 "payload": payload,
134 "timestamp": str(datetime.datetime.utcnow()),
135 }
136
137 def warn(self, event_type, payload):
138 msg = self.generate_message(event_type, "WARN", payload)
139 self.strategy.warn(msg)
140
141 def info(self, event_type, payload):
142 msg = self.generate_message(event_type, "INFO", payload)
143 self.strategy.info(msg)
144
145 def error(self, event_type, payload):
146 msg = self.generate_message(event_type, "ERROR", payload)
147 self.strategy.error(msg)
168148
=== modified file 'tests/functional/test_scrubber.py'
--- tests/functional/test_scrubber.py 2011-07-22 23:08:43 +0000
+++ tests/functional/test_scrubber.py 2011-07-26 18:44:34 +0000
@@ -100,10 +100,26 @@
100 for rec in recs:100 for rec in recs:
101 self.assertEqual(rec['status'], 'pending_delete')101 self.assertEqual(rec['status'], 'pending_delete')
102102
103 # Wait 15 seconds for the scrubber to scrub103 # NOTE(jkoelker) The build servers sometimes take longer than
104 time.sleep(15)104 # 15 seconds to scrub. Give it up to 5 min, checking
105105 # checking every 15 seconds. When/if it flips to
106 recs = list(self.run_sql_cmd(sql))106 # deleted, bail immediatly.
107 deleted = set()
108 recs = []
109 for _ in xrange(20):
110 time.sleep(15)
111
112 recs = list(self.run_sql_cmd(sql))
113 self.assertTrue(recs)
114
115 # NOTE(jkoelker) Reset the deleted set for this loop
116 deleted = set()
117 for rec in recs:
118 deleted.add(rec['status'] == 'deleted')
119
120 if False not in deleted:
121 break
122
107 self.assertTrue(recs)123 self.assertTrue(recs)
108 for rec in recs:124 for rec in recs:
109 self.assertEqual(rec['status'], 'deleted')125 self.assertEqual(rec['status'], 'deleted')
110126
=== modified file 'tests/stubs.py'
--- tests/stubs.py 2011-07-26 04:25:03 +0000
+++ tests/stubs.py 2011-07-26 18:44:34 +0000
@@ -31,7 +31,6 @@
31import glance.common.client31import glance.common.client
32from glance.common import context32from glance.common import context
33from glance.common import exception33from glance.common import exception
34import glance.common.notifier
35from glance.registry import server as rserver34from glance.registry import server as rserver
36from glance.api import v1 as server35from glance.api import v1 as server
37import glance.store36import glance.store
@@ -476,10 +475,3 @@
476 fake_datastore.image_get_all_pending_delete)475 fake_datastore.image_get_all_pending_delete)
477 stubs.Set(glance.registry.db.api, 'image_get_all',476 stubs.Set(glance.registry.db.api, 'image_get_all',
478 fake_datastore.image_get_all)477 fake_datastore.image_get_all)
479
480
481def stub_out_notifier(stubs):
482 def notify(event_type, priority, payload):
483 pass
484
485 stubs.Set(glance.common.notifier, 'notify', notify)
486478
=== modified file 'tests/unit/test_api.py'
--- tests/unit/test_api.py 2011-07-26 04:25:03 +0000
+++ tests/unit/test_api.py 2011-07-26 18:44:34 +0000
@@ -1451,7 +1451,6 @@
1451 self.stubs = stubout.StubOutForTesting()1451 self.stubs = stubout.StubOutForTesting()
1452 stubs.stub_out_registry_and_store_server(self.stubs)1452 stubs.stub_out_registry_and_store_server(self.stubs)
1453 stubs.stub_out_registry_db_image_api(self.stubs)1453 stubs.stub_out_registry_db_image_api(self.stubs)
1454 stubs.stub_out_notifier(self.stubs)
1455 stubs.stub_out_filesystem_backend()1454 stubs.stub_out_filesystem_backend()
1456 sql_connection = os.environ.get('GLANCE_SQL_CONNECTION', "sqlite://")1455 sql_connection = os.environ.get('GLANCE_SQL_CONNECTION', "sqlite://")
1457 options = {'verbose': VERBOSE,1456 options = {'verbose': VERBOSE,
14581457
=== modified file 'tests/unit/test_clients.py'
--- tests/unit/test_clients.py 2011-07-26 04:25:03 +0000
+++ tests/unit/test_clients.py 2011-07-26 18:44:34 +0000
@@ -897,7 +897,6 @@
897 stubs.stub_out_registry_db_image_api(self.stubs)897 stubs.stub_out_registry_db_image_api(self.stubs)
898 stubs.stub_out_registry_and_store_server(self.stubs)898 stubs.stub_out_registry_and_store_server(self.stubs)
899 stubs.stub_out_filesystem_backend()899 stubs.stub_out_filesystem_backend()
900 stubs.stub_out_notifier(self.stubs)
901 self.client = client.Client("0.0.0.0", doc_root="")900 self.client = client.Client("0.0.0.0", doc_root="")
902901
903 def tearDown(self):902 def tearDown(self):
904903
=== modified file 'tests/unit/test_notifier.py'
--- tests/unit/test_notifier.py 2011-07-26 13:58:04 +0000
+++ tests/unit/test_notifier.py 2011-07-26 18:44:34 +0000
@@ -15,93 +15,109 @@
15# License for the specific language governing permissions and limitations15# License for the specific language governing permissions and limitations
16# under the License.16# under the License.
1717
18import os18import logging
19import stubout
20import unittest19import unittest
2120
22from glance import client
23from glance.common import exception21from glance.common import exception
24import glance.common.notifier22from glance.common import notifier
2523
26from tests import stubs24
2725class TestInvalidNotifier(unittest.TestCase):
28
29TEST_IMAGE_META = {'name': 'test_image',
30 'is_public': False,
31 'disk_format': 'raw',
32 'container_format': 'ovf'}
33
34
35class TestNotifier(unittest.TestCase):
36 """Test that notifications are generated appropriately"""26 """Test that notifications are generated appropriately"""
3727
38 def setUp(self):28 def test_cannot_create(self):
39 """Establish a clean test environment"""29 options = {"notifier_strategy": "invalid_notifier"}
40 self.stubs = stubout.StubOutForTesting()30 self.assertRaises(exception.InvalidNotifierStrategy,
41 stubs.stub_out_registry_db_image_api(self.stubs)31 notifier.Notifier,
42 stubs.stub_out_registry_and_store_server(self.stubs)32 options)
43 stubs.stub_out_filesystem_backend()33
44 self.client = client.Client("0.0.0.0", doc_root="")34
45 self.notification = (None, None)35class TestLoggingNotifier(unittest.TestCase):
4636 """Test the logging notifier is selected and works properly."""
47 def notify(event_type, priority, payload):37
48 self.notification = (event_type, priority)38 def setUp(self):
4939 options = {"notifier_strategy": "logging"}
50 self.stubs.Set(glance.common.notifier, 'notify', notify)40 self.called = False
5141 self.logger = logging.getLogger("glance.notifier.logging_notifier")
52 def tearDown(self):42 self.notifier = notifier.Notifier(options)
53 """Clear the test environment"""43
54 stubs.clean_out_fake_filesystem_backend()44 def _called(self, msg):
55 self.stubs.UnsetAll()45 self.called = msg
5646
57 def test_create_notify(self):47 def test_warn(self):
58 """Test image create notification."""48 self.logger.warn = self._called
5949 self.notifier.warn("test_event", "test_message")
60 self.client.add_image(TEST_IMAGE_META, 'foobar')50 if self.called is False:
6151 self.fail("Did not call logging library correctly.")
62 self.assertEquals(self.notification, ('image.upload', 'INFO'))52
6353 def test_info(self):
64 def test_update_notify(self):54 self.logger.info = self._called
65 """Test image update notification. """55 self.notifier.info("test_event", "test_message")
6656 if self.called is False:
67 image_meta = self.client.add_image(TEST_IMAGE_META, 'foobar')57 self.fail("Did not call logging library correctly.")
68 self.client.update_image(image_meta['id'])58
6959 def test_erorr(self):
70 self.assertEquals(self.notification, ('image.update', 'INFO'))60 self.logger.error = self._called
7161 self.notifier.error("test_event", "test_message")
72 def test_delete_notify(self):62 if self.called is False:
73 """Test image delete notification. """63 self.fail("Did not call logging library correctly.")
7464
75 image_meta = self.client.add_image(TEST_IMAGE_META, 'foobar')65
76 self.client.delete_image(image_meta['id'])66class TestNoopNotifier(unittest.TestCase):
7767 """Test that the noop notifier works...and does nothing?"""
78 self.assertEquals(self.notification, ('image.delete', 'INFO'))68
7969 def setUp(self):
80 def test_create_error_notify(self):70 options = {"notifier_strategy": "noop"}
81 """Test image create error notification."""71 self.notifier = notifier.Notifier(options)
8272
83 def boom(options, context, image_id, image_meta, purge_props=False):73 def test_warn(self):
84 if 'checksum' in image_meta:74 self.notifier.warn("test_event", "test_message")
85 raise Exception('boom')75
86 return image_meta76 def test_info(self):
8777 self.notifier.info("test_event", "test_message")
88 self.stubs.Set(glance.registry, 'update_image_metadata', boom)78
8979 def test_error(self):
90 try:80 self.notifier.error("test_event", "test_message")
91 self.client.add_image(TEST_IMAGE_META, 'foobar')81
92 except exception.Invalid:82
93 pass83class TestRabbitNotifier(unittest.TestCase):
9484 """Test AMQP/Rabbit notifier works."""
95 self.assertEquals(self.notification, ('image.upload', 'ERROR'))85
9686 def setUp(self):
97 def test_update_error_notify(self):87 notifier.RabbitStrategy._send_message = self._send_message
98 """Test image update error notification."""88 self.called = False
9989 options = {"notifier_strategy": "rabbit"}
100 image_meta = self.client.add_image(TEST_IMAGE_META, 'foobar')90 self.notifier = notifier.Notifier(options)
101 try:91
102 self.client.update_image(image_meta['id'],92 def _send_message(self, message, priority):
103 {'container_format': 'invalid'})93 self.called = {
104 except exception.Invalid:94 "message": message,
105 pass95 "priority": priority,
10696 }
107 self.assertEquals(self.notification, ('image.update', 'ERROR'))97
98 def test_warn(self):
99 self.notifier.warn("test_event", "test_message")
100
101 if self.called is False:
102 self.fail("Did not call _send_message properly.")
103
104 self.assertEquals("test_message", self.called["message"]["payload"])
105 self.assertEquals("WARN", self.called["message"]["priority"])
106
107 def test_info(self):
108 self.notifier.info("test_event", "test_message")
109
110 if self.called is False:
111 self.fail("Did not call _send_message properly.")
112
113 self.assertEquals("test_message", self.called["message"]["payload"])
114 self.assertEquals("INFO", self.called["message"]["priority"])
115
116 def test_error(self):
117 self.notifier.error("test_event", "test_message")
118
119 if self.called is False:
120 self.fail("Did not call _send_message properly.")
121
122 self.assertEquals("test_message", self.called["message"]["payload"])
123 self.assertEquals("ERROR", self.called["message"]["priority"])
108124
=== modified file 'tools/pip-requires'
--- tools/pip-requires 2011-07-12 09:09:36 +0000
+++ tools/pip-requires 2011-07-26 18:44:34 +0000
@@ -19,3 +19,4 @@
19httplib219httplib2
20hashlib20hashlib
21xattr21xattr
22kombu

Subscribers

People subscribed via source and target branches

to all changes: