Merge "Allow block devices without device_name"
This commit is contained in:
commit
a433ff739e
@ -599,9 +599,12 @@ class API(base.Base):
|
||||
def _check_and_transform_bdm(self, base_options, min_count, max_count,
|
||||
block_device_mapping, legacy_bdm):
|
||||
if legacy_bdm:
|
||||
# NOTE (ndipanov): Assume root dev name is 'vda' if not supplied.
|
||||
# It's needed for legacy conversion to work.
|
||||
root_device_name = (base_options.get('root_device_name') or 'vda')
|
||||
block_device_mapping = block_device.from_legacy_mapping(
|
||||
block_device_mapping, base_options.get('image_ref', ''),
|
||||
base_options.get('root_device_name'))
|
||||
root_device_name)
|
||||
|
||||
if min_count > 1 or max_count > 1:
|
||||
if any(map(lambda bdm: bdm['source_type'] == 'volume',
|
||||
|
@ -40,6 +40,7 @@ import uuid
|
||||
from eventlet import greenthread
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova import block_device
|
||||
from nova.cells import rpcapi as cells_rpcapi
|
||||
from nova.cloudpipe import pipelib
|
||||
from nova import compute
|
||||
@ -1004,6 +1005,10 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
bdms = self.conductor_api.block_device_mapping_get_all_by_instance(
|
||||
context, instance, legacy=False)
|
||||
|
||||
# Verify that all the BDMs have a device_name set and assign a default
|
||||
# one to the ones missing it with the help of the driver.
|
||||
self._default_block_device_names(context, instance, image_meta, bdms)
|
||||
|
||||
# b64 decode the files to inject:
|
||||
injected_files_orig = injected_files
|
||||
injected_files = self._decode_files(injected_files)
|
||||
@ -1266,6 +1271,92 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
requested_networks, macs, security_groups, is_vpn,
|
||||
dhcp_options)
|
||||
|
||||
def _default_root_device_name(self, instance, image_meta, root_bdm):
|
||||
try:
|
||||
return self.driver.default_root_device_name(instance,
|
||||
image_meta,
|
||||
root_bdm)
|
||||
except NotImplementedError:
|
||||
return compute_utils.get_next_device_name(instance, [])
|
||||
|
||||
def _default_device_names_for_instance(self, instance,
|
||||
root_device_name,
|
||||
update_function,
|
||||
*block_device_lists):
|
||||
try:
|
||||
self.driver.default_device_names_for_instance(instance,
|
||||
root_device_name,
|
||||
*block_device_lists)
|
||||
except NotImplementedError:
|
||||
compute_utils.default_device_names_for_instance(
|
||||
instance, root_device_name,
|
||||
update_function, *block_device_lists)
|
||||
|
||||
def _default_block_device_names(self, context, instance,
|
||||
image_meta, block_devices):
|
||||
"""Verify that all the devices have the device_name set. If not,
|
||||
provide a default name.
|
||||
|
||||
It also ensures that there is a root_device_name and is set to the
|
||||
first block device in the boot sequence (boot_index=0).
|
||||
"""
|
||||
try:
|
||||
root_bdm = (bdm for bdm in block_devices
|
||||
if bdm['boot_index'] == 0).next()
|
||||
except StopIteration:
|
||||
return
|
||||
|
||||
# Get the root_device_name from the root BDM or the instance
|
||||
root_device_name = None
|
||||
update_instance = False
|
||||
update_root_bdm = False
|
||||
|
||||
if root_bdm['device_name']:
|
||||
root_device_name = root_bdm['device_name']
|
||||
instance['root_device_name'] = root_device_name
|
||||
update_instance = True
|
||||
elif instance['root_device_name']:
|
||||
root_device_name = instance['root_device_name']
|
||||
root_bdm['device_name'] = root_device_name
|
||||
update_root_bdm = True
|
||||
else:
|
||||
root_device_name = self._default_root_device_name(instance,
|
||||
image_meta,
|
||||
root_bdm)
|
||||
|
||||
instance['root_device_name'] = root_device_name
|
||||
root_bdm['device_name'] = root_device_name
|
||||
update_instance = update_root_bdm = True
|
||||
|
||||
if update_instance:
|
||||
self._instance_update(context, instance['uuid'],
|
||||
root_device_name=root_device_name)
|
||||
if update_root_bdm:
|
||||
self.conductor_api.block_device_mapping_update(
|
||||
context, root_bdm['id'], {'device_name': root_device_name})
|
||||
|
||||
def _is_mapping(bdm):
|
||||
return (bdm['source_type'] in ('image', 'volume', 'snapshot') and
|
||||
driver_block_device.is_implemented(bdm))
|
||||
|
||||
ephemerals = filter(block_device.new_format_is_ephemeral,
|
||||
block_devices)
|
||||
swap = filter(block_device.new_format_is_swap,
|
||||
block_devices)
|
||||
block_device_mapping = filter(_is_mapping, block_devices)
|
||||
|
||||
def _update_bdm(bdm_for_update):
|
||||
self.conductor_api.block_device_mapping_update(
|
||||
context, instance['uuid'], bdm_for_update['id'],
|
||||
bdm_for_update['device_name'])
|
||||
|
||||
self._default_device_names_for_instance(instance,
|
||||
root_device_name,
|
||||
_update_bdm,
|
||||
ephemerals,
|
||||
swap,
|
||||
block_device_mapping)
|
||||
|
||||
def _prep_block_device(self, context, instance, bdms):
|
||||
"""Set up the block device for an instance with error logging."""
|
||||
try:
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
"""Compute-related Utilities and helpers."""
|
||||
|
||||
import itertools
|
||||
import re
|
||||
import string
|
||||
import traceback
|
||||
@ -122,12 +123,78 @@ def pack_action_event_finish(context, instance_uuid, event_name, exc_val=None,
|
||||
def get_device_name_for_instance(context, instance, bdms, device):
|
||||
"""Validates (or generates) a device name for instance.
|
||||
|
||||
This method is a wrapper for get_next_device_name that gets the list
|
||||
of used devices and the root device from a block device mapping.
|
||||
"""
|
||||
mappings = block_device.instance_block_mapping(instance, bdms)
|
||||
return get_next_device_name(instance, mappings.values(),
|
||||
mappings['root'], device)
|
||||
|
||||
|
||||
def default_device_names_for_instance(instance, root_device_name,
|
||||
update_function, *block_device_lists):
|
||||
"""Generate missing device names for an instance."""
|
||||
|
||||
def _device_names(iterables):
|
||||
return [bdm['device_name']
|
||||
for bdm in itertools.chain(*iterables) if bdm['device_name']]
|
||||
|
||||
dev_list = _device_names(block_device_lists)
|
||||
if root_device_name not in dev_list:
|
||||
dev_list.append(root_device_name)
|
||||
inst_type = flavors.extract_flavor(instance)
|
||||
|
||||
is_libvirt = driver.compute_driver_matches('libvirt.LibvirtDriver')
|
||||
libvirt_default_ephemerals = []
|
||||
|
||||
bdm_named_lists = zip(('ephemerals', 'swap', 'block_device_mapping'),
|
||||
block_device_lists)
|
||||
|
||||
for name, bdm_list in bdm_named_lists:
|
||||
# Libvirt will create a default ephemeral if instance allows
|
||||
# and was not overridden.
|
||||
if (is_libvirt and name == 'ephemerals' and not bdm_list and
|
||||
instance['ephemeral_gb'] > 0):
|
||||
default_eph = get_next_device_name(instance,
|
||||
[root_device_name],
|
||||
root_device_name)
|
||||
if default_eph not in dev_list:
|
||||
dev_list.append(default_eph)
|
||||
libvirt_default_ephemerals.append(default_eph)
|
||||
|
||||
# Libvirt will create a default swap if it's in instance type
|
||||
# and it was not supplied or overridden
|
||||
if (is_libvirt and name == 'swap' and not bdm_list and
|
||||
inst_type['swap'] > 0):
|
||||
|
||||
ephemerals = (_device_names(bdm_named_lists[0][1]) or
|
||||
libvirt_default_ephemerals)
|
||||
default_swap = get_next_device_name(instance,
|
||||
[root_device_name] + ephemerals, root_device_name)
|
||||
if default_swap not in dev_list:
|
||||
dev_list.append(default_swap)
|
||||
|
||||
for bdm in bdm_list:
|
||||
dev = bdm.get('device_name')
|
||||
if not dev:
|
||||
dev = get_next_device_name(instance, dev_list,
|
||||
root_device_name)
|
||||
bdm['device_name'] = dev
|
||||
if update_function:
|
||||
update_function(bdm)
|
||||
dev_list.append(dev)
|
||||
|
||||
|
||||
def get_next_device_name(instance, device_name_list,
|
||||
root_device_name=None, device=None):
|
||||
"""Validates (or generates) a device name for instance.
|
||||
|
||||
If device is not set, it will generate a unique device appropriate
|
||||
for the instance. It uses the block device mapping table to find
|
||||
valid device names. If the device name is valid but applicable to
|
||||
a different backend (for example /dev/vdc is specified but the
|
||||
backend uses /dev/xvdc), the device name will be converted to the
|
||||
appropriate format.
|
||||
for the instance. It uses the root_device_name (if provided) and
|
||||
the list of used devices to find valid device names. If the device
|
||||
name is valid but applicable to a different backend (for example
|
||||
/dev/vdc is specified but the backend uses /dev/xvdc), the device
|
||||
name will be converted to the appropriate format.
|
||||
"""
|
||||
req_prefix = None
|
||||
req_letter = None
|
||||
@ -138,23 +205,29 @@ def get_device_name_for_instance(context, instance, bdms, device):
|
||||
except (TypeError, AttributeError, ValueError):
|
||||
raise exception.InvalidDevicePath(path=device)
|
||||
|
||||
mappings = block_device.instance_block_mapping(instance, bdms)
|
||||
if not root_device_name:
|
||||
root_device_name = block_device.DEFAULT_ROOT_DEV_NAME
|
||||
|
||||
try:
|
||||
prefix = block_device.match_device(mappings['root'])[0]
|
||||
prefix = block_device.match_device(root_device_name)[0]
|
||||
except (TypeError, AttributeError, ValueError):
|
||||
raise exception.InvalidDevicePath(path=mappings['root'])
|
||||
raise exception.InvalidDevicePath(path=root_device_name)
|
||||
|
||||
# NOTE(vish): remove this when xenapi is setting default_root_device
|
||||
if driver.compute_driver_matches('xenapi.XenAPIDriver'):
|
||||
prefix = '/dev/xvd'
|
||||
|
||||
# NOTE(xqueralt): This can be removed when we have libvirt
|
||||
# defaulting it's own device names.
|
||||
if driver.compute_driver_matches('libvirt.LibvirtDriver'):
|
||||
prefix = '/dev/vd'
|
||||
|
||||
if req_prefix != prefix:
|
||||
LOG.debug(_("Using %(prefix)s instead of %(req_prefix)s"),
|
||||
{'prefix': prefix, 'req_prefix': req_prefix})
|
||||
|
||||
used_letters = set()
|
||||
for device_path in mappings.itervalues():
|
||||
for device_path in device_name_list:
|
||||
letter = block_device.strip_prefix(device_path)
|
||||
# NOTE(vish): delete numbers in case we have something like
|
||||
# /dev/sda1
|
||||
@ -177,8 +250,7 @@ def get_device_name_for_instance(context, instance, bdms, device):
|
||||
if req_letter in used_letters:
|
||||
raise exception.DevicePathInUse(path=device)
|
||||
|
||||
device_name = prefix + req_letter
|
||||
return device_name
|
||||
return prefix + req_letter
|
||||
|
||||
|
||||
def _get_unused_letter(used_letters):
|
||||
|
@ -3451,32 +3451,35 @@ def block_device_mapping_update(context, bdm_id, values, legacy=True):
|
||||
|
||||
def block_device_mapping_update_or_create(context, values, legacy=True):
|
||||
_scrub_empty_str_values(values, ['volume_size'])
|
||||
values = _from_legacy_values(values, legacy, allow_updates=True)
|
||||
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
result = _block_device_mapping_get_query(context, session=session).\
|
||||
filter_by(instance_uuid=values['instance_uuid']).\
|
||||
filter_by(device_name=values['device_name']).\
|
||||
first()
|
||||
if not result:
|
||||
values = _from_legacy_values(values, legacy)
|
||||
bdm_ref = models.BlockDeviceMapping()
|
||||
bdm_ref.update(values)
|
||||
bdm_ref.save(session=session)
|
||||
result = bdm_ref
|
||||
else:
|
||||
values = _from_legacy_values(values, legacy, allow_updates=True)
|
||||
result.update(values)
|
||||
result = None
|
||||
# NOTE(xqueralt): Only update a BDM when device_name was provided. We
|
||||
# allow empty device names so they will be set later by the manager.
|
||||
if values['device_name']:
|
||||
query = _block_device_mapping_get_query(context, session=session)
|
||||
result = query.filter_by(instance_uuid=values['instance_uuid'],
|
||||
device_name=values['device_name']).first()
|
||||
|
||||
# NOTE(xqueralt): prevent from having multiple swap devices for the
|
||||
# same instance. So delete the existing ones.
|
||||
if result:
|
||||
result.update(values)
|
||||
else:
|
||||
# Either the device_name doesn't exist in the database yet, or no
|
||||
# device_name was provided. Both cases mean creating a new BDM.
|
||||
result = models.BlockDeviceMapping(**values)
|
||||
result.save(session=session)
|
||||
|
||||
# NOTE(xqueralt): Prevent from having multiple swap devices for the
|
||||
# same instance. This will delete all the existing ones.
|
||||
if block_device.new_format_is_swap(values):
|
||||
query = (_block_device_mapping_get_query(context, session=session).
|
||||
filter_by(instance_uuid=values['instance_uuid']).
|
||||
filter_by(source_type='blank').
|
||||
filter(models.BlockDeviceMapping.device_name !=
|
||||
values['device_name']).
|
||||
filter_by(guest_format='swap'))
|
||||
query = _block_device_mapping_get_query(context, session=session)
|
||||
query = query.filter_by(instance_uuid=values['instance_uuid'],
|
||||
source_type='blank', guest_format='swap')
|
||||
query = query.filter(models.BlockDeviceMapping.id != result.id)
|
||||
query.soft_delete()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
@ -5512,6 +5512,81 @@ class ComputeTestCase(BaseTestCase):
|
||||
instance.refresh()
|
||||
self.assertEqual(vm_states.ACTIVE, instance['vm_state'])
|
||||
|
||||
def _get_instance_and_bdm_for_dev_defaults_tests(self):
|
||||
instance = self._create_fake_instance(
|
||||
params={'root_device_name': '/dev/vda'})
|
||||
block_device_mapping = [
|
||||
{'id': 3, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/vda',
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'image_id': 'fake-image-id-1',
|
||||
'boot_index': 0}]
|
||||
|
||||
return instance, block_device_mapping
|
||||
|
||||
def test_default_block_device_names_empty_instance_root_dev(self):
|
||||
instance, bdms = self._get_instance_and_bdm_for_dev_defaults_tests()
|
||||
instance['root_device_name'] = None
|
||||
self.mox.StubOutWithMock(self.compute, '_instance_update')
|
||||
self.mox.StubOutWithMock(self.compute,
|
||||
'_default_device_names_for_instance')
|
||||
self.compute._instance_update(self.context, instance['uuid'],
|
||||
root_device_name='/dev/vda')
|
||||
self.compute._default_device_names_for_instance(instance,
|
||||
'/dev/vda',
|
||||
mox.IgnoreArg(),
|
||||
[], [], bdms)
|
||||
self.mox.ReplayAll()
|
||||
self.compute._default_block_device_names(self.context,
|
||||
instance,
|
||||
{}, bdms)
|
||||
|
||||
def test_default_block_device_names_empty_root_device(self):
|
||||
instance, bdms = self._get_instance_and_bdm_for_dev_defaults_tests()
|
||||
bdms[0]['device_name'] = None
|
||||
self.mox.StubOutWithMock(self.compute.conductor_api,
|
||||
'block_device_mapping_update')
|
||||
self.mox.StubOutWithMock(self.compute,
|
||||
'_default_device_names_for_instance')
|
||||
self.compute.conductor_api.block_device_mapping_update(
|
||||
self.context, bdms[0]['id'], {'device_name': '/dev/vda'})
|
||||
self.compute._default_device_names_for_instance(instance,
|
||||
'/dev/vda',
|
||||
mox.IgnoreArg(),
|
||||
[], [], bdms)
|
||||
self.mox.ReplayAll()
|
||||
self.compute._default_block_device_names(self.context,
|
||||
instance,
|
||||
{}, bdms)
|
||||
|
||||
def test_default_block_device_names_no_root_device(self):
|
||||
instance, bdms = self._get_instance_and_bdm_for_dev_defaults_tests()
|
||||
instance['root_device_name'] = None
|
||||
bdms[0]['device_name'] = None
|
||||
self.mox.StubOutWithMock(self.compute, '_instance_update')
|
||||
self.mox.StubOutWithMock(self.compute.conductor_api,
|
||||
'block_device_mapping_update')
|
||||
self.mox.StubOutWithMock(self.compute,
|
||||
'_default_root_device_name')
|
||||
self.mox.StubOutWithMock(self.compute,
|
||||
'_default_device_names_for_instance')
|
||||
|
||||
self.compute._default_root_device_name(instance, mox.IgnoreArg(),
|
||||
bdms[0]).AndReturn('/dev/vda')
|
||||
self.compute._instance_update(self.context, instance['uuid'],
|
||||
root_device_name='/dev/vda')
|
||||
self.compute.conductor_api.block_device_mapping_update(
|
||||
self.context, bdms[0]['id'], {'device_name': '/dev/vda'})
|
||||
self.compute._default_device_names_for_instance(instance,
|
||||
'/dev/vda',
|
||||
mox.IgnoreArg(),
|
||||
[], [], bdms)
|
||||
self.mox.ReplayAll()
|
||||
self.compute._default_block_device_names(self.context,
|
||||
instance,
|
||||
{}, bdms)
|
||||
|
||||
|
||||
class ComputeAPITestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
"""Tests For miscellaneous util methods used with compute."""
|
||||
|
||||
import copy
|
||||
import string
|
||||
|
||||
from oslo.config import cfg
|
||||
@ -37,6 +38,8 @@ from nova.tests import fake_instance_actions
|
||||
from nova.tests import fake_network
|
||||
from nova.tests import fake_notifier
|
||||
import nova.tests.image.fake
|
||||
from nova.tests import matchers
|
||||
from nova.virt import driver
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('compute_manager', 'nova.service')
|
||||
@ -226,6 +229,178 @@ class ComputeValidateDeviceTestCase(test.TestCase):
|
||||
self.assertEqual(device, '/dev/xvdd')
|
||||
|
||||
|
||||
class DefaultDeviceNamesForInstanceTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(DefaultDeviceNamesForInstanceTestCase, self).setUp()
|
||||
self.ephemerals = [
|
||||
{'id': 1, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/vdb',
|
||||
'source_type': 'blank',
|
||||
'destination_type': 'local',
|
||||
'delete_on_termination': True,
|
||||
'guest_format': None,
|
||||
'boot_index': -1}]
|
||||
|
||||
self.swap = [
|
||||
{'id': 2, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/vdc',
|
||||
'source_type': 'blank',
|
||||
'destination_type': 'local',
|
||||
'delete_on_termination': True,
|
||||
'guest_format': 'swap',
|
||||
'boot_index': -1}]
|
||||
|
||||
self.block_device_mapping = [
|
||||
{'id': 3, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/vda',
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'volume_id': 'fake-volume-id-1',
|
||||
'boot_index': 0},
|
||||
{'id': 4, 'instance_uuid': 'fake-instance',
|
||||
'device_name': '/dev/vdd',
|
||||
'source_type': 'snapshot',
|
||||
'destination_type': 'volume',
|
||||
'snapshot_id': 'fake-snapshot-id-1',
|
||||
'boot_index': -1}]
|
||||
self.instance_type = {'swap': 4}
|
||||
self.instance = {'uuid': 'fake_instance', 'ephemeral_gb': 2}
|
||||
self.is_libvirt = False
|
||||
self.root_device_name = '/dev/vda'
|
||||
self.update_called = False
|
||||
|
||||
def fake_extract_flavor(instance):
|
||||
return self.instance_type
|
||||
|
||||
def fake_driver_matches(driver_string):
|
||||
if driver_string == 'libvirt.LibvirtDriver':
|
||||
return self.is_libvirt
|
||||
return False
|
||||
|
||||
self.stubs.Set(flavors, 'extract_flavor', fake_extract_flavor)
|
||||
self.stubs.Set(driver, 'compute_driver_matches', fake_driver_matches)
|
||||
|
||||
def _test_default_device_names(self, update_function, *block_device_lists):
|
||||
compute_utils.default_device_names_for_instance(self.instance,
|
||||
self.root_device_name,
|
||||
update_function,
|
||||
*block_device_lists)
|
||||
|
||||
def test_only_block_device_mapping(self):
|
||||
# Test no-op
|
||||
original_bdm = copy.deepcopy(self.block_device_mapping)
|
||||
self._test_default_device_names(None, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertThat(original_bdm,
|
||||
matchers.DictListMatches(self.block_device_mapping))
|
||||
|
||||
# Asser it defaults the missing one as expected
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdb')
|
||||
|
||||
def test_with_ephemerals(self):
|
||||
# Test ephemeral gets assigned
|
||||
self.ephemerals[0]['device_name'] = None
|
||||
self._test_default_device_names(None, self.ephemerals, [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.ephemerals[0]['device_name'], '/dev/vdb')
|
||||
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, self.ephemerals, [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdc')
|
||||
|
||||
def test_with_swap(self):
|
||||
# Test swap only
|
||||
self.swap[0]['device_name'] = None
|
||||
self._test_default_device_names(None, [], self.swap, [])
|
||||
self.assertEquals(self.swap[0]['device_name'], '/dev/vdb')
|
||||
|
||||
# Test swap and block_device_mapping
|
||||
self.swap[0]['device_name'] = None
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, [], self.swap,
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.swap[0]['device_name'], '/dev/vdb')
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdc')
|
||||
|
||||
def test_all_together(self):
|
||||
# Test swap missing
|
||||
self.swap[0]['device_name'] = None
|
||||
self._test_default_device_names(None, self.ephemerals,
|
||||
self.swap, self.block_device_mapping)
|
||||
self.assertEquals(self.swap[0]['device_name'], '/dev/vdc')
|
||||
|
||||
# Test swap and eph missing
|
||||
self.swap[0]['device_name'] = None
|
||||
self.ephemerals[0]['device_name'] = None
|
||||
self._test_default_device_names(None, self.ephemerals,
|
||||
self.swap, self.block_device_mapping)
|
||||
self.assertEquals(self.ephemerals[0]['device_name'], '/dev/vdb')
|
||||
self.assertEquals(self.swap[0]['device_name'], '/dev/vdc')
|
||||
|
||||
# Test all missing
|
||||
self.swap[0]['device_name'] = None
|
||||
self.ephemerals[0]['device_name'] = None
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, self.ephemerals,
|
||||
self.swap, self.block_device_mapping)
|
||||
self.assertEquals(self.ephemerals[0]['device_name'], '/dev/vdb')
|
||||
self.assertEquals(self.swap[0]['device_name'], '/dev/vdc')
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdd')
|
||||
|
||||
def test_libvirt_default_eph(self):
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdb')
|
||||
|
||||
# Test that default eph will be taken into account on libvirt
|
||||
self.is_libvirt = True
|
||||
self.instance_type['swap'] = 0
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdc')
|
||||
|
||||
def test_libvirt_default_swap(self):
|
||||
# Test that default swap will be taken into account on libvirt
|
||||
self.is_libvirt = True
|
||||
self.instance['ephemeral_gb'] = 0
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdc')
|
||||
|
||||
def test_libvirt_default_swap_ephemeral(self):
|
||||
self.is_libvirt = True
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
self._test_default_device_names(None, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertEquals(self.block_device_mapping[1]['device_name'],
|
||||
'/dev/vdd')
|
||||
|
||||
def test_update_fn_gets_called(self):
|
||||
def _update(bdm):
|
||||
self.update_called = True
|
||||
|
||||
self.block_device_mapping[1]['device_name'] = None
|
||||
compute_utils.default_device_names_for_instance(
|
||||
self.instance, self.root_device_name, _update, [], [],
|
||||
self.block_device_mapping)
|
||||
self.assertTrue(self.update_called)
|
||||
|
||||
|
||||
class UsageInfoTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -4226,6 +4226,24 @@ class BlockDeviceMappingTestCase(test.TestCase):
|
||||
self.assertEqual(bdm_real['device_name'], 'fake_name')
|
||||
self.assertEqual(bdm_real['destination_type'], 'camelot')
|
||||
|
||||
# check create without device_name
|
||||
bdm1 = dict(values)
|
||||
bdm1['device_name'] = None
|
||||
db.block_device_mapping_update_or_create(self.ctxt, bdm1, legacy=False)
|
||||
bdm_real = db.block_device_mapping_get_all_by_instance(self.ctxt, uuid)
|
||||
self.assertEqual(len(bdm_real), 2)
|
||||
bdm_real = bdm_real[1]
|
||||
self.assertEqual(bdm_real['device_name'], None)
|
||||
|
||||
# check create multiple devices without device_name
|
||||
bdm2 = dict(values)
|
||||
bdm2['device_name'] = None
|
||||
db.block_device_mapping_update_or_create(self.ctxt, bdm2, legacy=False)
|
||||
bdm_real = db.block_device_mapping_get_all_by_instance(self.ctxt, uuid)
|
||||
self.assertEqual(len(bdm_real), 3)
|
||||
bdm_real = bdm_real[2]
|
||||
self.assertEqual(bdm_real['device_name'], None)
|
||||
|
||||
def test_block_device_mapping_update_or_create_multiple_ephemeral(self):
|
||||
uuid = self.instance['uuid']
|
||||
values = {
|
||||
|
@ -468,3 +468,11 @@ class TestDriverBlockDevice(test.TestCase):
|
||||
driver_block_device.get_swap(legacy_swap))
|
||||
self.assertEquals(no_swap, driver_block_device.get_swap(no_swap))
|
||||
self.assertEquals(None, driver_block_device.get_swap([]))
|
||||
|
||||
def test_is_implemented(self):
|
||||
for bdm in (self.image_bdm, self.volume_bdm, self.swap_bdm,
|
||||
self.ephemeral_bdm, self.snapshot_bdm):
|
||||
self.assertTrue(driver_block_device.is_implemented(bdm))
|
||||
local_image = self.image_bdm.copy()
|
||||
local_image['destination_type'] = 'local'
|
||||
self.assertFalse(driver_block_device.is_implemented(local_image))
|
||||
|
@ -327,3 +327,18 @@ def get_swap(transformed_list):
|
||||
return transformed_list.pop()
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
|
||||
_IMPLEMENTED_CLASSES = (DriverSwapBlockDevice, DriverEphemeralBlockDevice,
|
||||
DriverVolumeBlockDevice, DriverSnapshotBlockDevice,
|
||||
DriverImageBlockDevice)
|
||||
|
||||
|
||||
def is_implemented(bdm):
|
||||
for cls in _IMPLEMENTED_CLASSES:
|
||||
try:
|
||||
cls(bdm)
|
||||
return True
|
||||
except _NotTransformable:
|
||||
pass
|
||||
return False
|
||||
|
@ -1068,6 +1068,15 @@ class ComputeDriver(object):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def default_root_device_name(self, instance, image_meta, root_bdm):
|
||||
"""Provide a default root device name for the driver."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def default_device_names_for_instance(self, instance, root_device_name,
|
||||
*block_device_lists):
|
||||
"""Default the missing device names in the block device mapping."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def load_compute_driver(virtapi, compute_driver=None):
|
||||
"""Load a compute driver module.
|
||||
|
Loading…
Reference in New Issue
Block a user