summaryrefslogtreecommitdiff
path: root/nova/compute/api.py
diff options
context:
space:
mode:
Diffstat (limited to 'nova/compute/api.py')
-rw-r--r--nova/compute/api.py72
1 files changed, 20 insertions, 52 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 5c543887d1..7f68070885 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -1382,53 +1382,6 @@ class API(base.Base):
return certs_to_return
- def _get_bdm_image_metadata(self, context, block_device_mapping,
- legacy_bdm=True):
- """If we are booting from a volume, we need to get the
- volume details from Cinder and make sure we pass the
- metadata back accordingly.
- """
- if not block_device_mapping:
- return {}
-
- for bdm in block_device_mapping:
- if (legacy_bdm and
- block_device.get_device_letter(
- bdm.get('device_name', '')) != 'a'):
- continue
- elif not legacy_bdm and bdm.get('boot_index') != 0:
- continue
-
- volume_id = bdm.get('volume_id')
- snapshot_id = bdm.get('snapshot_id')
- if snapshot_id:
- # NOTE(alaski): A volume snapshot inherits metadata from the
- # originating volume, but the API does not expose metadata
- # on the snapshot itself. So we query the volume for it below.
- snapshot = self.volume_api.get_snapshot(context, snapshot_id)
- volume_id = snapshot['volume_id']
-
- if bdm.get('image_id'):
- try:
- image_id = bdm['image_id']
- image_meta = self.image_api.get(context, image_id)
- return image_meta
- except Exception:
- raise exception.InvalidBDMImage(id=image_id)
- elif volume_id:
- try:
- volume = self.volume_api.get(context, volume_id)
- except exception.CinderConnectionFailed:
- raise
- except Exception:
- raise exception.InvalidBDMVolume(id=volume_id)
-
- if not volume.get('bootable', True):
- raise exception.InvalidBDMVolumeNotBootable(id=volume_id)
-
- return utils.get_image_metadata_from_volume(volume)
- return {}
-
@staticmethod
def _get_requested_instance_group(context, filter_properties):
if (not filter_properties or
@@ -1481,8 +1434,9 @@ class API(base.Base):
"when booting from volume")
raise exception.CertificateValidationFailed(message=msg)
image_id = None
- boot_meta = self._get_bdm_image_metadata(
- context, block_device_mapping, legacy_bdm)
+ boot_meta = utils.get_bdm_image_metadata(
+ context, self.image_api, self.volume_api, block_device_mapping,
+ legacy_bdm)
self._check_auto_disk_config(image=boot_meta,
auto_disk_config=auto_disk_config)
@@ -2162,7 +2116,7 @@ class API(base.Base):
try:
self._update_queued_for_deletion(context, instance, True)
except exception.InstanceMappingNotFound:
- LOG.info("Instance Mapping does not exist while attempting"
+ LOG.info("Instance Mapping does not exist while attempting "
"local delete cleanup.",
instance=instance)
@@ -4247,7 +4201,8 @@ class API(base.Base):
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,
vm_states.ERROR])
def rescue(self, context, instance, rescue_password=None,
- rescue_image_ref=None, clean_shutdown=True):
+ rescue_image_ref=None, clean_shutdown=True,
+ allow_bfv_rescue=False):
"""Rescue the given instance."""
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
@@ -4256,7 +4211,20 @@ class API(base.Base):
if bdm.volume_id:
vol = self.volume_api.get(context, bdm.volume_id)
self.volume_api.check_attached(context, vol)
- if compute_utils.is_volume_backed_instance(context, instance, bdms):
+
+ volume_backed = compute_utils.is_volume_backed_instance(
+ context, instance, bdms)
+
+ if volume_backed and allow_bfv_rescue:
+ cn = objects.ComputeNode.get_by_host_and_nodename(
+ context, instance.host, instance.node)
+ traits = self.placementclient.get_provider_traits(
+ context, cn.uuid).traits
+ if os_traits.COMPUTE_RESCUE_BFV not in traits:
+ reason = _("Host unable to rescue a volume-backed instance")
+ raise exception.InstanceNotRescuable(instance_id=instance.uuid,
+ reason=reason)
+ elif volume_backed:
reason = _("Cannot rescue a volume-backed instance")
raise exception.InstanceNotRescuable(instance_id=instance.uuid,
reason=reason)