diff --git a/nova/notifications.py b/nova/notifications.py index 998abee65..933af1f20 100644 --- a/nova/notifications.py +++ b/nova/notifications.py @@ -109,16 +109,6 @@ def _send_instance_update_notification(context, instance, old_vm_state, bw = bandwidth_usage(instance, audit_start) payload["bandwidth"] = bw - try: - system_metadata = db.instance_system_metadata_get( - context, instance.uuid) - except exception.NotFound: - system_metadata = {} - - # add image metadata - image_meta_props = image_meta(system_metadata) - payload["image_meta"] = image_meta_props - # if the service name (e.g. api/scheduler/compute) is not provided, default # to "compute" if not service: @@ -222,6 +212,19 @@ def usage_from_instance(context, instance_ref, network_info, instance_type_name = instance_ref.get('instance_type', {}).get('name', '') + if system_metadata is None: + try: + if instance_ref.get('deleted'): + with utils.temporary_mutation(context, read_deleted='yes'): + system_metadata = db.instance_system_metadata_get( + context, instance_ref['uuid']) + else: + system_metadata = db.instance_system_metadata_get( + context, instance_ref['uuid']) + + except exception.NotFound: + system_metadata = {} + usage_info = dict( # Owner properties tenant_id=instance_ref['project_id'], @@ -273,5 +276,9 @@ def usage_from_instance(context, instance_ref, network_info, if network_info is not None: usage_info['fixed_ips'] = network_info.fixed_ips() + # add image metadata + image_meta_props = image_meta(system_metadata) + usage_info["image_meta"] = image_meta_props + usage_info.update(kw) return usage_info diff --git a/nova/tests/test_compute_utils.py b/nova/tests/test_compute_utils.py index 4e00025bc..5081536ac 100644 --- a/nova/tests/test_compute_utils.py +++ b/nova/tests/test_compute_utils.py @@ -114,6 +114,41 @@ class UsageInfoTestCase(test.TestCase): self.assertEquals(payload['image_ref_url'], image_ref_url) self.compute.terminate_instance(self.context, instance['uuid']) + def test_notify_usage_exists_deleted_instance(self): + """Ensure 'exists' notification generates appropriate usage data.""" + instance_id = self._create_instance() + instance = db.instance_get(self.context, instance_id) + # Set some system metadata + sys_metadata = {'image_md_key1': 'val1', + 'image_md_key2': 'val2', + 'other_data': 'meow'} + db.instance_system_metadata_update(self.context, instance['uuid'], + sys_metadata, False) + self.compute.terminate_instance(self.context, instance['uuid']) + instance = db.instance_get(self.context.elevated(read_deleted='yes'), + instance_id) + compute_utils.notify_usage_exists(self.context, instance) + msg = test_notifier.NOTIFICATIONS[-1] + self.assertEquals(msg['priority'], 'INFO') + self.assertEquals(msg['event_type'], 'compute.instance.exists') + payload = msg['payload'] + self.assertEquals(payload['tenant_id'], self.project_id) + self.assertEquals(payload['user_id'], self.user_id) + self.assertEquals(payload['instance_id'], instance.uuid) + self.assertEquals(payload['instance_type'], 'm1.tiny') + type_id = instance_types.get_instance_type_by_name('m1.tiny')['id'] + self.assertEquals(str(payload['instance_type_id']), str(type_id)) + for attr in ('display_name', 'created_at', 'launched_at', + 'state', 'state_description', + 'bandwidth', 'audit_period_beginning', + 'audit_period_ending', 'image_meta'): + self.assertTrue(attr in payload, + msg="Key %s not in payload" % attr) + self.assertEquals(payload['image_meta'], + {'md_key1': 'val1', 'md_key2': 'val2'}) + image_ref_url = "%s/images/1" % utils.generate_glance_url() + self.assertEquals(payload['image_ref_url'], image_ref_url) + def test_notify_usage_exists_instance_not_found(self): """Ensure 'exists' notification generates appropriate usage data.""" instance_id = self._create_instance()