diff options
-rw-r--r-- | nova/block_device.py | 15 | ||||
-rw-r--r-- | nova/compute/api.py | 10 | ||||
-rwxr-xr-x | nova/compute/manager.py | 10 | ||||
-rw-r--r-- | nova/tests/compute/test_compute.py | 50 |
4 files changed, 85 insertions, 0 deletions
diff --git a/nova/block_device.py b/nova/block_device.py index 1094ef3ae..746fd6bb4 100644 --- a/nova/block_device.py +++ b/nova/block_device.py @@ -166,6 +166,21 @@ def is_safe_for_update(block_device_dict): bdm_db_only_fields) +def create_image_bdm(image_ref, boot_index=0): + """Create a block device dict based on the image_ref. + + This is useful in the API layer to keep the compatibility + with having an image_ref as a field in the instance requests + """ + return BlockDeviceDict( + {'source_type': 'image', + 'image_id': image_ref, + 'delete_on_termination': True, + 'boot_index': boot_index, + 'device_type': 'disk', + 'destination_type': 'local'}) + + def legacy_mapping(block_device_mapping): """Transform a list of block devices of an instance back to the legacy data format.""" diff --git a/nova/compute/api.py b/nova/compute/api.py index 0674cff5f..65142aef0 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -898,6 +898,16 @@ class API(base.Base): continue self._update_block_device_mapping(context, instance_type, instance_uuid, mapping) + # NOTE(ndipanov): Create an image bdm - at the moment + # this is not used but is done for easier transition + # in the future. + if (instance['image_ref'] and not + self.is_volume_backed_instance(context, instance, None)): + image_bdm = block_device.create_image_bdm(instance['image_ref']) + image_bdm['instance_uuid'] = instance_uuid + self.db.block_device_mapping_update_or_create(context, + image_bdm, + legacy=False) def _populate_instance_shutdown_terminate(self, instance, image, block_device_mapping): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 998be6f76..42f8029a5 100755 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1376,6 +1376,7 @@ class ComputeManager(manager.SchedulerDependentManager): as necessary. """ instance_uuid = instance['uuid'] + image = instance['image_ref'] if context.is_admin and context.project_id != instance['project_id']: project_id = instance['project_id'] @@ -1429,6 +1430,15 @@ class ComputeManager(manager.SchedulerDependentManager): self._quota_commit(context, reservations, project_id=project_id) # ensure block device mappings are not leaked self.conductor_api.block_device_mapping_destroy(context, bdms) + # NOTE(ndipanov): Delete the dummy image BDM as well. This will not + # be needed once the manager code is using the image + if image: + # Do not convert to legacy here - we want them all + leftover_bdm = \ + self.conductor_api.block_device_mapping_get_all_by_instance( + context, instance) + self.conductor_api.block_device_mapping_destroy(context, + leftover_bdm) self._notify_about_instance_usage(context, instance, "delete.end", system_metadata=system_meta) diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 3e0fbe63e..4dea52dfb 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -7263,6 +7263,56 @@ class ComputeAPITestCase(BaseTestCase): instance = db.instance_get_by_uuid(self.context, instance['uuid']) self.compute.terminate_instance(self.context, instance) + def test_populate_instance_for_bdm(self): + # Test that the image bdm is created + instance_type = {'swap': 1} + instance = self._create_fake_instance( + {'root_device_name': 'vda'} + ) + image = {'uuid': FAKE_IMAGE_REF} + fake_bdms = [{'device_name': '/dev/vda', + 'snapshot_id': '33333333-aaaa-bbbb-cccc-333333333333', + 'delete_on_termination': False}] + + # Has an image but no bdms + self.compute_api._populate_instance_for_bdm(self.context, + instance, + instance_type, + image, []) + bdms = db.block_device_mapping_get_all_by_instance( + self.context, instance['uuid']) + self.assertEqual(len(bdms), 1) + self.assertEqual(bdms[0]['image_id'], FAKE_IMAGE_REF) + for bdm in bdms: + db.block_device_mapping_destroy(self.context, bdm['id']) + + # Has an image and is volume backed - legacy style + self.compute_api._populate_instance_for_bdm(self.context, + instance, + instance_type, + image, fake_bdms) + bdms = db.block_device_mapping_get_all_by_instance( + self.context, instance['uuid']) + self.assertEqual(len(bdms), 1) + self.assertEqual(bdms[0]['snapshot_id'], + '33333333-aaaa-bbbb-cccc-333333333333') + for bdm in bdms: + db.block_device_mapping_destroy(self.context, bdm['id']) + + # Is volume backed and has no image + instance['image_ref'] = '' + self.compute_api._populate_instance_for_bdm(self.context, + instance, + instance_type, + image, fake_bdms) + bdms = db.block_device_mapping_get_all_by_instance( + self.context, instance['uuid']) + self.assertEqual(len(bdms), 1) + self.assertEqual(bdms[0]['snapshot_id'], + '33333333-aaaa-bbbb-cccc-333333333333') + for bdm in bdms: + db.block_device_mapping_destroy(self.context, bdm['id']) + def test_volume_size(self): ephemeral_size = 2 swap_size = 3 |