summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/block_device.py15
-rw-r--r--nova/compute/api.py10
-rwxr-xr-xnova/compute/manager.py10
-rw-r--r--nova/tests/compute/test_compute.py50
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