diff --git a/nova/notifications.py b/nova/notifications.py index 776bf60cc1..456b5a9632 100644 --- a/nova/notifications.py +++ b/nova/notifications.py @@ -25,7 +25,6 @@ from oslo.utils import excutils from oslo.utils import timeutils import six -from nova.compute import flavors import nova.context from nova import db from nova.i18n import _ @@ -336,11 +335,12 @@ def image_meta(system_metadata): return image_meta -def info_from_instance(context, instance_ref, network_info, +def info_from_instance(context, instance, network_info, system_metadata, **kw): """Get detailed instance information for an instance which is common to all notifications. + :param:instance: nova.objects.Instance :param:network_info: network_info provided if not None :param:system_metadata: system_metadata DB entries for the instance, if not None @@ -364,71 +364,68 @@ def info_from_instance(context, instance_ref, network_info, else: return str(s) if s else '' - image_ref_url = glance.generate_image_url(instance_ref['image_ref']) + image_ref_url = glance.generate_image_url(instance.image_ref) - instance_type = flavors.extract_flavor(instance_ref) + instance_type = instance.get_flavor() instance_type_name = instance_type.get('name', '') instance_flavorid = instance_type.get('flavorid', '') - if system_metadata is None: - system_metadata = utils.instance_sys_meta(instance_ref) - instance_info = dict( # Owner properties - tenant_id=instance_ref['project_id'], - user_id=instance_ref['user_id'], + tenant_id=instance.project_id, + user_id=instance.user_id, # Identity properties - instance_id=instance_ref['uuid'], - display_name=instance_ref['display_name'], - reservation_id=instance_ref['reservation_id'], - hostname=instance_ref['hostname'], + instance_id=instance.uuid, + display_name=instance.display_name, + reservation_id=instance.reservation_id, + hostname=instance.hostname, # Type properties instance_type=instance_type_name, - instance_type_id=instance_ref['instance_type_id'], + instance_type_id=instance.instance_type_id, instance_flavor_id=instance_flavorid, - architecture=instance_ref['architecture'], + architecture=instance.architecture, # Capacity properties - memory_mb=instance_ref['memory_mb'], - disk_gb=instance_ref['root_gb'] + instance_ref['ephemeral_gb'], - vcpus=instance_ref['vcpus'], + memory_mb=instance.memory_mb, + disk_gb=instance.root_gb + instance.ephemeral_gb, + vcpus=instance.vcpus, # Note(dhellmann): This makes the disk_gb value redundant, but # we are keeping it for backwards-compatibility with existing # users of notifications. - root_gb=instance_ref['root_gb'], - ephemeral_gb=instance_ref['ephemeral_gb'], + root_gb=instance.root_gb, + ephemeral_gb=instance.ephemeral_gb, # Location properties - host=instance_ref['host'], - node=instance_ref['node'], - availability_zone=instance_ref['availability_zone'], - cell_name=null_safe_str(instance_ref['cell_name']), + host=instance.host, + node=instance.node, + availability_zone=instance.availability_zone, + cell_name=null_safe_str(instance.cell_name), # Date properties - created_at=str(instance_ref['created_at']), + created_at=str(instance.created_at), # Terminated and Deleted are slightly different (although being # terminated and not deleted is a transient state), so include # both and let the recipient decide which they want to use. - terminated_at=null_safe_isotime(instance_ref.get('terminated_at')), - deleted_at=null_safe_isotime(instance_ref.get('deleted_at')), - launched_at=null_safe_isotime(instance_ref.get('launched_at')), + terminated_at=null_safe_isotime(instance.get('terminated_at', None)), + deleted_at=null_safe_isotime(instance.get('deleted_at', None)), + launched_at=null_safe_isotime(instance.get('launched_at', None)), # Image properties image_ref_url=image_ref_url, - os_type=instance_ref['os_type'], - kernel_id=instance_ref['kernel_id'], - ramdisk_id=instance_ref['ramdisk_id'], + os_type=instance.os_type, + kernel_id=instance.kernel_id, + ramdisk_id=instance.ramdisk_id, # Status properties - state=instance_ref['vm_state'], - state_description=null_safe_str(instance_ref.get('task_state')), - progress=null_safe_int(instance_ref['progress']), + state=instance.vm_state, + state_description=null_safe_str(instance.task_state), + progress=null_safe_int(instance.progress), # accessIPs - access_ip_v4=instance_ref['access_ip_v4'], - access_ip_v6=instance_ref['access_ip_v6'], + access_ip_v4=instance.access_ip_v4, + access_ip_v6=instance.access_ip_v6, ) if network_info is not None: @@ -441,11 +438,11 @@ def info_from_instance(context, instance_ref, network_info, instance_info['fixed_ips'] = fixed_ips # add image metadata - image_meta_props = image_meta(system_metadata) + image_meta_props = image_meta(instance.system_metadata) instance_info["image_meta"] = image_meta_props # add instance metadata - instance_info['metadata'] = utils.instance_meta(instance_ref) + instance_info['metadata'] = instance.metadata instance_info.update(kw) return instance_info diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 3ac84c8f44..2829e48a11 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -540,7 +540,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject): self._from_db_object(context, self, inst_ref, expected_attrs=expected_attrs) - notifications.send_update(context, old_ref, inst_ref) + notifications.send_update(context, old_ref, self) self.obj_reset_changes() @base.remotable @@ -667,8 +667,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject): md_was_changed = 'metadata' in self.obj_what_changed() del self.metadata[key] self._orig_metadata.pop(key, None) - instance_dict = base.obj_to_primitive(self) - notifications.send_update(context, instance_dict, instance_dict) + notifications.send_update(context, self, self) if not md_was_changed: self.obj_reset_changes(['metadata']) diff --git a/nova/tests/unit/test_notifications.py b/nova/tests/unit/test_notifications.py index bce03da1c3..66eae77ef2 100644 --- a/nova/tests/unit/test_notifications.py +++ b/nova/tests/unit/test_notifications.py @@ -24,9 +24,10 @@ from nova.compute import flavors from nova.compute import task_states from nova.compute import vm_states from nova import context -from nova import db from nova.network import api as network_api from nova import notifications +from nova import objects +from nova.objects import base as obj_base from nova import test from nova.tests.unit import fake_network from nova.tests.unit import fake_notifier @@ -68,22 +69,23 @@ class NotificationsTestCase(test.TestCase): def _wrapped_create(self, params=None): instance_type = flavors.get_flavor_by_name('m1.tiny') sys_meta = flavors.save_flavor_info({}, instance_type) - inst = {} - inst['image_ref'] = 1 - inst['user_id'] = self.user_id - inst['project_id'] = self.project_id - inst['instance_type_id'] = instance_type['id'] - inst['root_gb'] = 0 - inst['ephemeral_gb'] = 0 - inst['access_ip_v4'] = '1.2.3.4' - inst['access_ip_v6'] = 'feed:5eed' - inst['display_name'] = 'test_instance' - inst['hostname'] = 'test_instance_hostname' - inst['node'] = 'test_instance_node' - inst['system_metadata'] = sys_meta + inst = objects.Instance(image_ref=1, + user_id=self.user_id, + project_id=self.project_id, + instance_type_id=instance_type['id'], + root_gb=0, + ephemeral_gb=0, + access_ip_v4='1.2.3.4', + access_ip_v6='feed::5eed', + display_name='test_instance', + hostname='test_instance_hostname', + node='test_instance_node', + system_metadata=sys_meta) + inst._context = self.context if params: inst.update(params) - return db.instance_create(self.context, inst) + inst.create() + return inst def test_send_api_fault_disabled(self): self.flags(notify_api_faults=False) @@ -115,12 +117,12 @@ class NotificationsTestCase(test.TestCase): self.flags(notify_on_state_change=None) old = copy.copy(self.instance) - self.instance["vm_state"] = vm_states.ACTIVE + self.instance.vm_state = vm_states.ACTIVE old_vm_state = old['vm_state'] - new_vm_state = self.instance["vm_state"] + new_vm_state = self.instance.vm_state old_task_state = old['task_state'] - new_task_state = self.instance["task_state"] + new_task_state = self.instance.task_state notifications.send_update_with_states(self.context, self.instance, old_vm_state, new_vm_state, old_task_state, new_task_state, @@ -136,12 +138,12 @@ class NotificationsTestCase(test.TestCase): # we should not get a notification on task stgate chagne now old = copy.copy(self.instance) - self.instance["task_state"] = task_states.SPAWNING + self.instance.task_state = task_states.SPAWNING old_vm_state = old['vm_state'] - new_vm_state = self.instance["vm_state"] + new_vm_state = self.instance.vm_state old_task_state = old['task_state'] - new_task_state = self.instance["task_state"] + new_task_state = self.instance.task_state notifications.send_update_with_states(self.context, self.instance, old_vm_state, new_vm_state, old_task_state, new_task_state, @@ -158,10 +160,10 @@ class NotificationsTestCase(test.TestCase): def test_send_no_notif(self): # test notification on send no initial vm state: - old_vm_state = self.instance['vm_state'] - new_vm_state = self.instance['vm_state'] - old_task_state = self.instance['task_state'] - new_task_state = self.instance['task_state'] + old_vm_state = self.instance.vm_state + new_vm_state = self.instance.vm_state + old_task_state = self.instance.task_state + new_task_state = self.instance.task_state notifications.send_update_with_states(self.context, self.instance, old_vm_state, new_vm_state, old_task_state, new_task_state, @@ -170,22 +172,21 @@ class NotificationsTestCase(test.TestCase): self.assertEqual(0, len(fake_notifier.NOTIFICATIONS)) def test_send_on_vm_change(self): - + old = obj_base.obj_to_primitive(self.instance) + old['task_state'] = None # pretend we just transitioned to ACTIVE: - params = {"vm_state": vm_states.ACTIVE} - (old_ref, new_ref) = db.instance_update_and_get_original(self.context, - self.instance['uuid'], params) - notifications.send_update(self.context, old_ref, new_ref) + self.instance.task_state = task_states.SPAWNING + notifications.send_update(self.context, old, self.instance) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) def test_send_on_task_change(self): + old = obj_base.obj_to_primitive(self.instance) + old['task_state'] = None # pretend we just transitioned to task SPAWNING: - params = {"task_state": task_states.SPAWNING} - (old_ref, new_ref) = db.instance_update_and_get_original(self.context, - self.instance['uuid'], params) - notifications.send_update(self.context, old_ref, new_ref) + self.instance.task_state = task_states.SPAWNING + notifications.send_update(self.context, old, self.instance) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) @@ -204,11 +205,11 @@ class NotificationsTestCase(test.TestCase): self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) notif = fake_notifier.NOTIFICATIONS[0] payload = notif.payload - access_ip_v4 = self.instance["access_ip_v4"] - access_ip_v6 = self.instance["access_ip_v6"] - display_name = self.instance["display_name"] - hostname = self.instance["hostname"] - node = self.instance["node"] + access_ip_v4 = str(self.instance.access_ip_v4) + access_ip_v6 = str(self.instance.access_ip_v6) + display_name = self.instance.display_name + hostname = self.instance.hostname + node = self.instance.node self.assertEqual(vm_states.BUILDING, payload["old_state"]) self.assertEqual(vm_states.ACTIVE, payload["state"]) @@ -229,10 +230,10 @@ class NotificationsTestCase(test.TestCase): self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) notif = fake_notifier.NOTIFICATIONS[0] payload = notif.payload - access_ip_v4 = self.instance["access_ip_v4"] - access_ip_v6 = self.instance["access_ip_v6"] - display_name = self.instance["display_name"] - hostname = self.instance["hostname"] + access_ip_v4 = str(self.instance.access_ip_v4) + access_ip_v6 = str(self.instance.access_ip_v6) + display_name = self.instance.display_name + hostname = self.instance.hostname self.assertEqual(vm_states.BUILDING, payload["old_state"]) self.assertEqual(vm_states.BUILDING, payload["state"]) @@ -290,11 +291,11 @@ class NotificationsTestCase(test.TestCase): info = notifications.info_from_instance(self.context, self.instance, self.net_info, None) self.assertIn("cell_name", info) - self.assertIsNone(self.instance['cell_name']) + self.assertIsNone(self.instance.cell_name) self.assertEqual("", info["cell_name"]) def test_payload_has_cell_name(self): - self.instance['cell_name'] = "cell1" + self.instance.cell_name = "cell1" info = notifications.info_from_instance(self.context, self.instance, self.net_info, None) self.assertIn("cell_name", info) @@ -304,11 +305,11 @@ class NotificationsTestCase(test.TestCase): info = notifications.info_from_instance(self.context, self.instance, self.net_info, None) self.assertIn("progress", info) - self.assertIsNone(self.instance['progress']) + self.assertIsNone(self.instance.progress) self.assertEqual("", info["progress"]) def test_payload_has_progress(self): - self.instance['progress'] = 50 + self.instance.progress = 50 info = notifications.info_from_instance(self.context, self.instance, self.net_info, None) self.assertIn("progress", info) @@ -319,8 +320,8 @@ class NotificationsTestCase(test.TestCase): self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) notif = fake_notifier.NOTIFICATIONS[0] payload = notif.payload - access_ip_v4 = self.instance["access_ip_v4"] - access_ip_v6 = self.instance["access_ip_v6"] + access_ip_v4 = str(self.instance.access_ip_v4) + access_ip_v6 = str(self.instance.access_ip_v6) self.assertEqual(payload["access_ip_v4"], access_ip_v4) self.assertEqual(payload["access_ip_v6"], access_ip_v6) @@ -332,8 +333,8 @@ class NotificationsTestCase(test.TestCase): self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) notif = fake_notifier.NOTIFICATIONS[0] payload = notif.payload - old_display_name = self.instance["display_name"] - new_display_name = new_name_inst["display_name"] + old_display_name = self.instance.display_name + new_display_name = new_name_inst.display_name self.assertEqual(payload["old_display_name"], old_display_name) self.assertEqual(payload["display_name"], new_display_name)