utils: Move 'get_bdm_image_metadata' to nova.block_device
The 'nova.block_device' module is essentially a catchall utils-like module for all things BDM. The 'get_bdm_image_metadata' module, and closely related 'get_image_metadata_from_volume' both fall into the category of functions that belong here so move them. This allows us to clean up tests and, crucially, avoid a circular reference seen when we want to use proper type hints in the 'nova.virt.driver' module. nova.context imports... nova.utils, which imports... nova.block_device, which imports... nova.virt.driver, which tries to import... nova.context, causing a circular dependency Change-Id: I48177d6e93f2ff132d26b53cd682fd24a43a4b31 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -13,11 +13,12 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
import re
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import strutils
|
||||
|
||||
from oslo_utils import units
|
||||
|
||||
import nova.conf
|
||||
from nova import exception
|
||||
@@ -34,6 +35,12 @@ _DEFAULT_MAPPINGS = {'ami': 'sda1',
|
||||
'root': DEFAULT_ROOT_DEV_NAME,
|
||||
'swap': 'sda3'}
|
||||
|
||||
# Image attributes which Cinder stores in volume image metadata
|
||||
# as regular properties
|
||||
VIM_IMAGE_ATTRIBUTES = (
|
||||
'image_id', 'image_name', 'size', 'checksum',
|
||||
'container_format', 'disk_format', 'min_ram', 'min_disk',
|
||||
)
|
||||
|
||||
bdm_legacy_fields = set(['device_name', 'delete_on_termination',
|
||||
'virtual_name', 'snapshot_id',
|
||||
@@ -629,3 +636,86 @@ def get_bdm_swap_list(block_device_mappings):
|
||||
def get_bdm_local_disk_num(block_device_mappings):
|
||||
return len([bdm for bdm in block_device_mappings
|
||||
if bdm.get('destination_type') == 'local'])
|
||||
|
||||
|
||||
def get_bdm_image_metadata(context, image_api, volume_api,
|
||||
block_device_mapping, legacy_bdm=True):
|
||||
"""Attempt to retrive image metadata from a given block_device_mapping.
|
||||
|
||||
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.
|
||||
|
||||
:param context: request context
|
||||
:param image_api: Image API
|
||||
:param volume_api: Volume API
|
||||
:param block_device_mapping:
|
||||
:param legacy_bdm:
|
||||
"""
|
||||
if not block_device_mapping:
|
||||
return {}
|
||||
|
||||
for bdm in block_device_mapping:
|
||||
if (legacy_bdm and
|
||||
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 = 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 = image_api.get(context, image_id)
|
||||
return image_meta
|
||||
except Exception:
|
||||
raise exception.InvalidBDMImage(id=image_id)
|
||||
elif volume_id:
|
||||
try:
|
||||
volume = 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 get_image_metadata_from_volume(volume)
|
||||
return {}
|
||||
|
||||
|
||||
def get_image_metadata_from_volume(volume):
|
||||
properties = copy.copy(volume.get('volume_image_metadata', {}))
|
||||
image_meta = {'properties': properties}
|
||||
# Volume size is no longer related to the original image size,
|
||||
# so we take it from the volume directly. Cinder creates
|
||||
# volumes in Gb increments, and stores size in Gb, whereas
|
||||
# glance reports size in bytes. As we're returning glance
|
||||
# metadata here, we need to convert it.
|
||||
image_meta['size'] = volume.get('size', 0) * units.Gi
|
||||
# NOTE(yjiang5): restore the basic attributes
|
||||
# NOTE(mdbooth): These values come from volume_glance_metadata
|
||||
# in cinder. This is a simple key/value table, and all values
|
||||
# are strings. We need to convert them to ints to avoid
|
||||
# unexpected type errors.
|
||||
for attr in VIM_IMAGE_ATTRIBUTES:
|
||||
val = properties.pop(attr, None)
|
||||
if attr in ('min_ram', 'min_disk'):
|
||||
image_meta[attr] = int(val or 0)
|
||||
# NOTE(mriedem): Set the status to 'active' as a really old hack
|
||||
# from when this method was in the compute API class and is
|
||||
# needed for _validate_flavor_image which makes sure the image
|
||||
# is 'active'. For volume-backed servers, if the volume is not
|
||||
# available because the image backing the volume is not active,
|
||||
# then the compute API trying to reserve the volume should fail.
|
||||
image_meta['status'] = 'active'
|
||||
return image_meta
|
||||
|
||||
Reference in New Issue
Block a user