diff --git a/glance/notifier/__init__.py b/glance/notifier/__init__.py index e3a791a5d0..cb63117622 100644 --- a/glance/notifier/__init__.py +++ b/glance/notifier/__init__.py @@ -20,6 +20,7 @@ import socket import uuid from glance.common import exception +import glance.domain from glance.openstack.common import cfg from glance.openstack.common import importutils import glance.openstack.common.log as logging @@ -85,3 +86,54 @@ class Notifier(object): def error(self, event_type, payload): msg = self.generate_message(event_type, "ERROR", payload) self.strategy.error(msg) + + +def format_image_notification(image): + """ + Given a glance.domain.Image object, return a dictionary of relevant + notification information. + """ + return { + 'id': image.image_id, + 'name': image.name, + 'status': image.status, + 'created_at': timeutils.isotime(image.created_at), + 'updated_at': timeutils.isotime(image.updated_at), + 'min_disk': image.min_disk, + 'min_ram': image.min_ram, + 'protected': image.protected, + 'location': image.location, + 'checksum': image.checksum, + 'owner': image.owner, + 'disk_format': image.disk_format, + 'container_format': image.container_format, + 'size': image.size, + 'is_public': image.visibility == 'public', + 'properties': dict(image.extra_properties), + 'tags': list(image.tags), + 'deleted': False, + 'deleted_at': None, + } + + +class ImageRepoProxy(glance.domain.ImageRepoProxy): + + def __init__(self, image_repo, notifier): + self.image_repo = image_repo + self.notifier = notifier + super(ImageRepoProxy, self).__init__(image_repo) + + def save(self, image): + self.image_repo.save(image) + self.notifier.info('image.update', format_image_notification(image)) + + def add(self, image): + self.image_repo.add(image) + self.notifier.info('image.update', format_image_notification(image)) + + def remove(self, image): + self.image_repo.remove(image) + payload = format_image_notification(image) + payload['deleted'] = True + payload['deleted_at'] = timeutils.isotime() + self.notifier.info('image.delete', payload) diff --git a/glance/tests/unit/test_notifier.py b/glance/tests/unit/test_notifier.py index f92be805ef..d43515ed01 100644 --- a/glance/tests/unit/test_notifier.py +++ b/glance/tests/unit/test_notifier.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime import kombu.entity import mox try: @@ -30,6 +31,25 @@ import glance.notifier.notify_kombu from glance.openstack.common import importutils import glance.openstack.common.log as logging from glance.tests import utils +import glance.tests.unit.utils as unit_test_utils + + +DATETIME = datetime.datetime(2012, 5, 16, 15, 27, 36, 325355) + + +UUID1 = 'c80a1a6c-bd1f-41c5-90ee-81afedb1d58d' +TENANT1 = '6838eb7b-6ded-434a-882c-b344c77fe8df' + + +class ImageRepoStub(object): + def remove(self, *args, **kwargs): + return 'image_from_get' + + def save(self, *args, **kwargs): + return 'image_from_save' + + def add(self, *args, **kwargs): + return 'image_from_add' class TestNotifier(utils.BaseTestCase): @@ -406,3 +426,42 @@ class TestRabbitContentType(utils.BaseTestCase): def test_content_type_passed(self): self.notifier.warn("test_event", "test_message") self.assertEquals(self.called['content_type'], 'application/json') + + +class TestImageNotifications(utils.BaseTestCase): + """Test Image Notifications work""" + + def setUp(self): + self.image = glance.domain.Image( + image_id=UUID1, name='image-1', status='active', size=1024, + created_at=DATETIME, updated_at=DATETIME, owner=TENANT1, + visibility='public', container_format='ami', + tags=['one', 'two'], disk_format='ami', min_ram=128, + min_disk=10, checksum='ca425b88f047ce8ec45ee90e813ada91') + self.image_repo_stub = ImageRepoStub() + self.notifier = unit_test_utils.FakeNotifier() + self.image_repo_proxy = glance.notifier.ImageRepoProxy( + self.image_repo_stub, self.notifier) + super(TestImageNotifications, self).setUp() + + def test_image_save_notification(self): + self.image_repo_proxy.save(self.image) + output_log = self.notifier.get_log() + self.assertEqual(output_log['notification_type'], 'INFO') + self.assertEqual(output_log['event_type'], 'image.update') + self.assertEqual(output_log['payload']['id'], self.image.image_id) + + def test_image_add_notification(self): + self.image_repo_proxy.add(self.image) + output_log = self.notifier.get_log() + self.assertEqual(output_log['notification_type'], 'INFO') + self.assertEqual(output_log['event_type'], 'image.update') + self.assertEqual(output_log['payload']['id'], self.image.image_id) + + def test_image_delete_notification(self): + self.image_repo_proxy.remove(self.image) + output_log = self.notifier.get_log() + self.assertEqual(output_log['notification_type'], 'INFO') + self.assertEqual(output_log['event_type'], 'image.delete') + self.assertEqual(output_log['payload']['id'], self.image.image_id) + self.assertTrue(output_log['payload']['deleted'])