nova/nova/tests/unit/virt/libvirt/test_blockinfo.py

1548 lines
67 KiB
Python

# Copyright 2010 OpenStack Foundation
# Copyright 2012 University Of Minho
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import fixtures
import mock
from oslo_utils.fixture import uuidsentinel as uuids
from nova import block_device
from nova import context
from nova import exception
from nova import objects
from nova.objects import fields as obj_fields
from nova import test
from nova.tests import fixtures as nova_fixtures
from nova.tests.unit import fake_block_device
from nova.tests.unit.virt import fakelibosinfo
from nova.virt import block_device as driver_block_device
from nova.virt import driver
from nova.virt.libvirt import blockinfo
class LibvirtBlockInfoTest(test.NoDBTestCase):
def setUp(self):
super(LibvirtBlockInfoTest, self).setUp()
self.user_id = 'fake'
self.project_id = 'fake'
self.context = context.get_admin_context()
self.useFixture(nova_fixtures.GlanceFixture(self))
self.test_instance = {
'uuid': '32dfcb37-5af1-552b-357c-be8c3aa38310',
'memory_kb': '1024000',
'basepath': '/some/path',
'bridge_name': 'br100',
'vcpus': 2,
'project_id': 'fake',
'bridge': 'br101',
'image_ref': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
'root_gb': 10,
'ephemeral_gb': 20,
'instance_type_id': 2, # m1.tiny
'config_drive': None,
'launched_at': None,
'system_metadata': {},
}
self.test_image_meta = {
'disk_format': 'raw',
}
flavor = objects.Flavor(memory_mb=128,
root_gb=0,
name='m1.micro',
ephemeral_gb=0,
vcpus=1,
swap=0,
rxtx_factor=1.0,
flavorid='1',
vcpu_weight=None,
id=2)
self.test_instance['flavor'] = flavor
self.test_instance['old_flavor'] = None
self.test_instance['new_flavor'] = None
def _test_block_device_info(self, with_eph=True, with_swap=True,
with_bdms=True):
swap = {'device_name': '/dev/vdb', 'swap_size': 1}
ephemerals = [{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdc1', 'size': 10},
{'disk_bus': 'ide', 'guest_format': None,
'device_name': '/dev/vdd', 'size': 10}]
block_device_mapping = [{'mount_device': '/dev/sde',
'device_path': 'fake_device'},
{'mount_device': '/dev/sdf',
'device_path': 'fake_device'}]
return {'root_device_name': '/dev/vda',
'swap': swap if with_swap else {},
'ephemerals': ephemerals if with_eph else [],
'block_device_mapping':
block_device_mapping if with_bdms else []}
def test_volume_in_mapping(self):
block_device_info = self._test_block_device_info()
def _assert_volume_in_mapping(device_name, true_or_false):
self.assertEqual(
true_or_false,
block_device.volume_in_mapping(device_name,
block_device_info))
_assert_volume_in_mapping('vda', False)
_assert_volume_in_mapping('vdb', True)
_assert_volume_in_mapping('vdc1', True)
_assert_volume_in_mapping('vdd', True)
_assert_volume_in_mapping('sde', True)
_assert_volume_in_mapping('sdf', True)
_assert_volume_in_mapping('sdg', False)
_assert_volume_in_mapping('sdh1', False)
def test_find_disk_dev(self):
mapping = {
"disk.local": {
'dev': 'sda',
'bus': 'scsi',
'type': 'disk',
},
"disk.swap": {
'dev': 'sdc',
'bus': 'scsi',
'type': 'disk',
},
}
dev = blockinfo.find_disk_dev_for_disk_bus(mapping, 'scsi')
self.assertEqual('sdb', dev)
dev = blockinfo.find_disk_dev_for_disk_bus(mapping, 'virtio')
self.assertEqual('vda', dev)
dev = blockinfo.find_disk_dev_for_disk_bus(mapping, 'fdc')
self.assertEqual('fda', dev)
@mock.patch('nova.virt.libvirt.blockinfo.has_disk_dev', return_value=True)
def test_find_disk_dev_for_disk_bus_no_free_error(self, has_disk_dev_mock):
# Tests that an exception is raised when all devices for a given prefix
# are already reserved.
mapping = {
'disk': {
'bus': 'ide',
'dev': 'hda',
'type': 'cdrom',
'boot_index': '1',
}
}
self.assertRaises(exception.NovaException,
blockinfo.find_disk_dev_for_disk_bus,
mapping, 'ide')
def test_get_next_disk_dev(self):
mapping = {}
mapping['disk.local'] = blockinfo.get_next_disk_info(mapping,
'virtio')
self.assertEqual({'dev': 'vda', 'bus': 'virtio', 'type': 'disk'},
mapping['disk.local'])
mapping['disk.swap'] = blockinfo.get_next_disk_info(mapping,
'virtio')
self.assertEqual({'dev': 'vdb', 'bus': 'virtio', 'type': 'disk'},
mapping['disk.swap'])
mapping['disk.config'] = blockinfo.get_next_disk_info(mapping,
'ide',
'cdrom')
self.assertEqual({'dev': 'hda', 'bus': 'ide', 'type': 'cdrom'},
mapping['disk.config'])
def test_get_next_disk_dev_boot_index(self):
info = blockinfo.get_next_disk_info({}, 'virtio', boot_index=-1)
self.assertEqual({'dev': 'vda', 'bus': 'virtio', 'type': 'disk'}, info)
info = blockinfo.get_next_disk_info({}, 'virtio', boot_index=2)
self.assertEqual({'dev': 'vda', 'bus': 'virtio',
'type': 'disk', 'boot_index': '2'},
info)
def test_get_disk_mapping_simple(self):
# The simplest possible disk mapping setup, all defaults
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
with mock.patch.object(instance_ref, 'get_flavor',
return_value=instance_ref.flavor) as get_flavor:
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta)
# Since there was no block_device_info passed to get_disk_mapping we
# expect to get the swap info from the flavor in the instance.
get_flavor.assert_called_once_with()
expect = {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'}
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_simple_rootdev(self):
# A simple disk mapping setup, but with custom root device name
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'root_device_name': '/dev/sda'
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'disk': {'bus': 'virtio', 'dev': 'sda',
'type': 'disk', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'sda',
'type': 'disk', 'boot_index': '1'}
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_rescue(self):
# A simple disk mapping setup, but in rescue mode
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
rescue=True)
expect = {
'disk.rescue': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def _test_get_disk_mapping_rescue_with_config(
self, expect_disk_config_rescue,
):
# A simple disk mapping setup, but in rescue mode with a config drive
test_instance_with_config = self.test_instance
test_instance_with_config['config_drive'] = True
instance_ref = objects.Instance(**test_instance_with_config)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
rescue=True)
expect = {
'disk.rescue': {
'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1',
},
'disk': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.config.rescue': expect_disk_config_rescue,
'root': {
'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1',
},
}
self.assertEqual(expect, mapping)
@mock.patch('nova.virt.libvirt.utils.get_arch',
new=mock.Mock(return_value=obj_fields.Architecture.X86_64))
def test_get_disk_mapping_rescue_with_config__x86_64(self):
self._test_get_disk_mapping_rescue_with_config({
'bus': 'ide', 'dev': 'hda', 'type': 'cdrom',
})
@mock.patch('nova.virt.libvirt.utils.get_arch',
new=mock.Mock(return_value=obj_fields.Architecture.AARCH64))
def test_get_disk_mapping_rescue_with_config__aarch64(self):
self._test_get_disk_mapping_rescue_with_config({
'bus': 'scsi', 'dev': 'sda', 'type': 'cdrom',
})
def _test_get_disk_mapping_stable_rescue(
self, rescue_props, expected, block_device_info, with_local=False):
instance = objects.Instance(**self.test_instance)
# Make disk.local disks optional per test as found in
# nova.virt.libvirt.BlockInfo.get_default_ephemeral_info
instance.ephemeral_gb = '20' if with_local else None
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
rescue_image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
rescue_props = objects.ImageMetaProps.from_dict(rescue_props)
rescue_image_meta.properties = rescue_props
mapping = blockinfo.get_disk_mapping("kvm", instance, "virtio", "ide",
image_meta, rescue=True, block_device_info=block_device_info,
rescue_image_meta=rescue_image_meta)
# Assert that the expected mapping is returned from get_disk_mapping
self.assertEqual(expected, mapping)
def test_get_disk_mapping_stable_rescue_virtio_disk(self):
"""Assert the disk mapping when rescuing using a virtio disk"""
rescue_props = {'hw_rescue_bus': 'virtio'}
block_info = self._test_block_device_info(
with_eph=False, with_swap=False, with_bdms=False)
expected = {
'disk': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.rescue': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info)
def test_get_disk_mapping_stable_rescue_ide_disk(self):
"""Assert the disk mapping when rescuing using an IDE disk"""
rescue_props = {'hw_rescue_bus': 'ide'}
block_info = self._test_block_device_info(
with_eph=False, with_swap=False, with_bdms=False)
expected = {
'disk': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.rescue': {'bus': 'ide', 'dev': 'hda', 'type': 'disk'},
'root': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info)
def test_get_disk_mapping_stable_rescue_usb_disk(self):
"""Assert the disk mapping when rescuing using a USB disk"""
rescue_props = {'hw_rescue_bus': 'usb'}
block_info = self._test_block_device_info(
with_eph=False, with_swap=False, with_bdms=False)
expected = {
'disk': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.rescue': {'bus': 'usb', 'dev': 'sda', 'type': 'disk'},
'root': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info)
@mock.patch('nova.virt.libvirt.utils.get_arch',
new=mock.Mock(return_value=obj_fields.Architecture.X86_64))
def test_get_disk_mapping_stable_rescue_ide_cdrom(self):
"""Assert the disk mapping when rescuing using an IDE cd-rom"""
rescue_props = {'hw_rescue_device': 'cdrom'}
block_info = self._test_block_device_info(
with_eph=False, with_swap=False, with_bdms=False)
expected = {
'disk': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.rescue': {'bus': 'ide', 'dev': 'hda', 'type': 'cdrom'},
'root': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info)
def test_get_disk_mapping_stable_rescue_virtio_disk_with_local(self):
"""Assert the disk mapping when rescuing using a virtio disk with
default ephemeral (local) disks also attached to the instance.
"""
rescue_props = {'hw_rescue_bus': 'virtio'}
block_info = self._test_block_device_info(
with_eph=False, with_swap=False, with_bdms=False)
expected = {
'disk': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.rescue': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
'root': {'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info, with_local=True)
def test_get_disk_mapping_stable_rescue_virtio_disk_with_eph(self):
"""Assert the disk mapping when rescuing using a virtio disk with
ephemeral disks also attached to the instance.
"""
rescue_props = {'hw_rescue_bus': 'virtio'}
block_info = self._test_block_device_info(
with_swap=False, with_bdms=False)
expected = {
'disk': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.eph0': {
'bus': 'virtio', 'dev': 'vdc1', 'format': 'ext4',
'type': 'disk'},
'disk.eph1': {
'bus': 'ide', 'dev': 'vdd', 'type': 'disk'},
'disk.rescue': {
'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info, with_local=True)
def test_get_disk_mapping_stable_rescue_virtio_disk_with_swap(self):
"""Assert the disk mapping when rescuing using a virtio disk with
swap attached to the instance.
"""
rescue_props = {'hw_rescue_bus': 'virtio'}
block_info = self._test_block_device_info(
with_eph=False, with_bdms=False)
expected = {
'disk': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.rescue': {
'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
'disk.swap': {
'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info)
def test_get_disk_mapping_stable_rescue_virtio_disk_with_bdm(self):
"""Assert the disk mapping when rescuing using a virtio disk with
volumes also attached to the instance.
"""
rescue_props = {'hw_rescue_bus': 'virtio'}
block_info = self._test_block_device_info(
with_eph=False, with_swap=False)
expected = {
'/dev/sde': {
'bus': 'scsi', 'dev': 'sde', 'type': 'disk'},
'/dev/sdf': {
'bus': 'scsi', 'dev': 'sdf', 'type': 'disk'},
'disk': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.rescue': {
'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info)
def test_get_disk_mapping_stable_rescue_virtio_disk_with_everything(self):
"""Assert the disk mapping when rescuing using a virtio disk with
volumes, ephemerals and swap also attached to the instance.
"""
rescue_props = {'hw_rescue_bus': 'virtio'}
block_info = self._test_block_device_info()
expected = {
'/dev/sde': {
'bus': 'scsi', 'dev': 'sde', 'type': 'disk'},
'/dev/sdf': {
'bus': 'scsi', 'dev': 'sdf', 'type': 'disk'},
'disk': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'},
'disk.eph0': {
'bus': 'virtio', 'dev': 'vdc1', 'format': 'ext4',
'type': 'disk'},
'disk.eph1': {
'bus': 'ide', 'dev': 'vdd', 'type': 'disk'},
'disk.rescue': {
'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
'disk.swap': {
'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {
'boot_index': '1', 'bus': 'virtio', 'dev': 'vda',
'type': 'disk'}
}
self._test_get_disk_mapping_stable_rescue(
rescue_props, expected, block_info, with_local=True)
def test_get_disk_mapping_lxc(self):
# A simple disk mapping setup, but for lxc
self.test_instance['ephemeral_gb'] = 0
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("lxc", instance_ref,
"lxc", "lxc",
image_meta)
expect = {
'disk': {'bus': 'lxc', 'dev': None,
'type': 'disk', 'boot_index': '1'},
'root': {'bus': 'lxc', 'dev': None,
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_simple_iso(self):
# A simple disk mapping setup, but with a ISO for root device
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict({'disk_format': 'iso'})
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta)
expect = {
'disk': {'bus': 'ide', 'dev': 'hda',
'type': 'cdrom', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vda', 'type': 'disk'},
'root': {'bus': 'ide', 'dev': 'hda',
'type': 'cdrom', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_simple_swap(self):
# A simple disk mapping setup, but with a swap device added
instance_ref = objects.Instance(**self.test_instance)
instance_ref.flavor.swap = 5
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta)
expect = {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.swap': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_volumes_swap(self):
# A disk mapping setup with volumes attached, then a swap device added
instance_ref = objects.Instance(**self.test_instance)
instance_ref.root_device_name = '/dev/vda'
instance_ref.ephemeral_gb = 0
block_dev_info = {'swap': None, 'root_device_name': u'/dev/vda',
'ephemerals': [],
'block_device_mapping': [{'boot_index': None,
'mount_device': u'/dev/vdb',
'connection_info': {},
'disk_bus': None,
'device_type': None},
{'boot_index': 0,
'mount_device': u'/dev/vda',
'connection_info': {},
'disk_bus': u'virtio',
'device_type': u'disk'}]}
instance_ref.flavor.swap = 5
image_meta = {}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info=block_dev_info)
expect = {
'/dev/vda': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'/dev/vdb': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.swap': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def _test_get_disk_mapping_simple_configdrive(
self, expect_bus, expect_dev,
):
# A simple disk mapping setup, but with configdrive added
# It's necessary to check if the architecture is power, because
# power doesn't have support to ide, and so libvirt translate
# all ide calls to scsi
self.flags(force_config_drive=True)
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping(
"kvm", instance_ref, "virtio", "ide", image_meta)
# Pick the first drive letter on the bus that is available
# as the config drive. Delete the last device hardcode as
# the config drive here.
expect = {
'disk': {
'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1',
},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.config': {
'bus': expect_bus, 'dev': expect_dev, 'type': 'cdrom',
},
'root': {
'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1',
},
}
self.assertEqual(expect, mapping)
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.X86_64)
def test_get_disk_mapping_simple_configdrive__x86_64(self, mock_get_arch):
self._test_get_disk_mapping_simple_configdrive('ide', 'hda')
mock_get_arch.assert_called()
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.PPC64)
def test_get_disk_mapping_simple_configdrive__ppc64(self, mock_get_arch):
self._test_get_disk_mapping_simple_configdrive('scsi', 'sda')
mock_get_arch.assert_called()
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.AARCH64)
def test_get_disk_mapping_simple_configdrive__aarch64(self, mock_get_arch):
self._test_get_disk_mapping_simple_configdrive('scsi', 'sda')
mock_get_arch.assert_called()
def _test_get_disk_mapping_cdrom_configdrive(self, expect_bus, expect_dev):
# A simple disk mapping setup, with configdrive added as cdrom
# It's necessary to check if the architecture is power, because
# power doesn't have support to ide, and so libvirt translate
# all ide calls to scsi
self.flags(force_config_drive=True)
self.flags(config_drive_format='iso9660')
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping(
"kvm", instance_ref, "virtio", "ide", image_meta)
expect = {
'disk': {
'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1',
},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.config': {
'bus': expect_bus, 'dev': expect_dev, 'type': 'cdrom',
},
'root': {
'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1',
}
}
self.assertEqual(expect, mapping)
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.X86_64)
def test_get_disk_mapping_cdrom_configdrive__x86_64(self, mock_get_arch):
self._test_get_disk_mapping_cdrom_configdrive('ide', 'hda')
mock_get_arch.assert_called()
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.PPC64)
def test_get_disk_mapping_cdrom_configdrive__ppc64(self, mock_get_arch):
self._test_get_disk_mapping_cdrom_configdrive('scsi', 'sda')
mock_get_arch.assert_called()
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.AARCH64)
def test_get_disk_mapping_cdrom_configdrive__aarch64(self, mock_get_arch):
self._test_get_disk_mapping_cdrom_configdrive('scsi', 'sda')
mock_get_arch.assert_called()
def test_get_disk_mapping_disk_configdrive(self):
# A simple disk mapping setup, with configdrive added as disk
self.flags(force_config_drive=True)
self.flags(config_drive_format='vfat')
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta)
expect = {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'disk.config': {'bus': 'virtio', 'dev': 'vdc', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_ephemeral(self):
# A disk mapping with ephemeral devices
instance_ref = objects.Instance(**self.test_instance)
instance_ref.flavor.swap = 5
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'ephemerals': [
{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 10},
{'disk_bus': 'ide', 'guest_format': None,
'device_name': '/dev/vdc', 'size': 10},
{'device_type': 'floppy',
'device_name': '/dev/vdd', 'size': 10},
]
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.eph0': {'bus': 'virtio', 'dev': 'vdb',
'type': 'disk', 'format': 'ext4'},
'disk.eph1': {'bus': 'ide', 'dev': 'vdc', 'type': 'disk'},
'disk.eph2': {'bus': 'virtio', 'dev': 'vdd', 'type': 'floppy'},
'disk.swap': {'bus': 'virtio', 'dev': 'vde', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_custom_swap(self):
# A disk mapping with a swap device at position vdb. This
# should cause disk.local to be removed
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'swap': {'device_name': '/dev/vdb',
'swap_size': 10},
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.swap': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_blockdev_root(self):
# A disk mapping with a blockdev replacing the default root
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': "/dev/vda",
'boot_index': 0,
'device_type': 'disk',
'delete_on_termination': True},
]
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'/dev/vda': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_blockdev_root_on_spawn(self):
# A disk mapping with a blockdev initializing the default root
instance_ref = objects.Instance(**self.test_instance)
image_meta = {}
block_device_info = {
'block_device_mapping': [
{'connection_info': None,
'mount_device': None,
'boot_index': 0,
'device_type': None,
'delete_on_termination': True},
]
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'/dev/vda': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'disk.local': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_blockdev_eph(self):
# A disk mapping with a blockdev replacing the ephemeral device
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': "/dev/vdb",
'boot_index': -1,
'delete_on_termination': True},
]
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'/dev/vdb': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_blockdev_many(self):
# A disk mapping with a blockdev replacing all devices
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': "/dev/vda",
'boot_index': 0,
'disk_bus': 'scsi',
'delete_on_termination': True},
{'connection_info': "fake",
'mount_device': "/dev/vdb",
'boot_index': -1,
'delete_on_termination': True},
{'connection_info': "fake",
'mount_device': "/dev/vdc",
'boot_index': -1,
'device_type': 'cdrom',
'delete_on_termination': True},
]
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'/dev/vda': {'bus': 'scsi', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'/dev/vdb': {'bus': 'virtio', 'dev': 'vdb', 'type': 'disk'},
'/dev/vdc': {'bus': 'virtio', 'dev': 'vdc', 'type': 'cdrom'},
'root': {'bus': 'scsi', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_complex(self):
# The strangest possible disk mapping setup
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'root_device_name': '/dev/vdf',
'swap': {'device_name': '/dev/vdy',
'swap_size': 10},
'ephemerals': [
{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 10},
{'disk_bus': 'ide', 'guest_format': None,
'device_name': '/dev/vdc', 'size': 10},
],
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': "/dev/vda",
'boot_index': 1,
'delete_on_termination': True},
]
}
mapping = blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
expect = {
'disk': {'bus': 'virtio', 'dev': 'vdf',
'type': 'disk', 'boot_index': '1'},
'/dev/vda': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '2'},
'disk.eph0': {'bus': 'virtio', 'dev': 'vdb',
'type': 'disk', 'format': 'ext4'},
'disk.eph1': {'bus': 'ide', 'dev': 'vdc', 'type': 'disk'},
'disk.swap': {'bus': 'virtio', 'dev': 'vdy', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vdf',
'type': 'disk', 'boot_index': '1'},
}
self.assertEqual(expect, mapping)
def test_get_disk_mapping_updates_original(self):
instance_ref = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
block_device_info = {
'root_device_name': '/dev/vda',
'swap': {'device_name': '/dev/vdb',
'device_type': 'really_lame_type',
'swap_size': 10},
'ephemerals': [{'disk_bus': 'no_such_bus',
'device_type': 'yeah_right',
'device_name': '/dev/vdc', 'size': 10}],
'block_device_mapping': [
{'connection_info': "fake",
'mount_device': None,
'device_type': 'lawnmower',
'delete_on_termination': True}]
}
expected_swap = {'device_name': '/dev/vdb', 'disk_bus': 'virtio',
'device_type': 'disk', 'swap_size': 10}
expected_ephemeral = {'disk_bus': 'virtio',
'device_type': 'disk',
'device_name': '/dev/vdc', 'size': 10}
expected_bdm = {'connection_info': "fake",
'mount_device': '/dev/vdd',
'device_type': 'disk',
'disk_bus': 'virtio',
'delete_on_termination': True}
with mock.patch.object(instance_ref, 'get_flavor') as get_flavor_mock:
blockinfo.get_disk_mapping("kvm", instance_ref,
"virtio", "ide",
image_meta,
block_device_info)
# we should have gotten the swap info from block_device_info rather
# than the flavor information on the instance
self.assertFalse(get_flavor_mock.called)
self.assertEqual(expected_swap, block_device_info['swap'])
self.assertEqual(expected_ephemeral,
block_device_info['ephemerals'][0])
self.assertEqual(expected_bdm,
block_device_info['block_device_mapping'][0])
def test_get_disk_bus(self):
instance = objects.Instance(**self.test_instance)
expected = (
(obj_fields.Architecture.X86_64, 'disk', 'virtio'),
(obj_fields.Architecture.X86_64, 'cdrom', 'ide'),
(obj_fields.Architecture.X86_64, 'floppy', 'fdc'),
(obj_fields.Architecture.PPC, 'disk', 'virtio'),
(obj_fields.Architecture.PPC, 'cdrom', 'scsi'),
(obj_fields.Architecture.PPC64, 'disk', 'virtio'),
(obj_fields.Architecture.PPC64, 'cdrom', 'scsi'),
(obj_fields.Architecture.PPCLE, 'disk', 'virtio'),
(obj_fields.Architecture.PPCLE, 'cdrom', 'scsi'),
(obj_fields.Architecture.PPC64LE, 'disk', 'virtio'),
(obj_fields.Architecture.PPC64LE, 'cdrom', 'scsi'),
(obj_fields.Architecture.S390, 'disk', 'virtio'),
(obj_fields.Architecture.S390, 'cdrom', 'scsi'),
(obj_fields.Architecture.S390X, 'disk', 'virtio'),
(obj_fields.Architecture.S390X, 'cdrom', 'scsi'),
(obj_fields.Architecture.AARCH64, 'disk', 'virtio'),
(obj_fields.Architecture.AARCH64, 'cdrom', 'scsi')
)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
for guestarch, dev, res in expected:
with mock.patch.object(blockinfo.libvirt_utils,
'get_arch',
return_value=guestarch):
bus = blockinfo.get_disk_bus_for_device_type(
instance, 'kvm', image_meta, dev)
self.assertEqual(res, bus)
expected = (
('kvm', 'scsi', None, 'disk', 'scsi'),
('kvm', None, 'scsi', 'cdrom', 'scsi'),
('kvm', 'usb', None, 'disk', 'usb'),
('parallels', 'scsi', None, 'disk', 'scsi'),
('parallels', None, None, 'disk', 'scsi'),
('parallels', None, 'ide', 'cdrom', 'ide'),
('parallels', None, None, 'cdrom', 'ide')
)
for hv, dbus, cbus, dev, res in expected:
props = {}
if dbus is not None:
props['hw_disk_bus'] = dbus
if cbus is not None:
props['hw_cdrom_bus'] = cbus
image_meta = objects.ImageMeta.from_dict(
{'properties': props})
bus = blockinfo.get_disk_bus_for_device_type(
instance, hv, image_meta, device_type=dev)
self.assertEqual(res, bus)
image_meta = objects.ImageMeta.from_dict(
{'properties': {'hw_disk_bus': 'xen'}})
self.assertRaises(exception.UnsupportedHardware,
blockinfo.get_disk_bus_for_device_type,
instance, 'kvm', image_meta)
def test_get_disk_bus_with_osinfo(self):
self.useFixture(fixtures.MonkeyPatch(
'nova.virt.osinfo.libosinfo',
fakelibosinfo))
instance = objects.Instance(**self.test_instance)
image_meta = {'properties': {'os_name': 'fedora22'}}
image_meta = objects.ImageMeta.from_dict(image_meta)
bus = blockinfo.get_disk_bus_for_device_type(instance,
'kvm', image_meta)
self.assertEqual('virtio', bus)
def test_success_get_disk_bus_for_disk_dev(self):
expected = (
('ide', ("kvm", "hda")),
('scsi', ("kvm", "sdf")),
('virtio', ("kvm", "vds")),
('fdc', ("kvm", "fdc")),
)
for res, args in expected:
self.assertEqual(res, blockinfo.get_disk_bus_for_disk_dev(*args))
def test_fail_get_disk_bus_for_disk_dev_unsupported_virt_type(self):
instance = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
self.assertRaises(exception.UnsupportedVirtType,
blockinfo.get_disk_bus_for_device_type,
instance, 'kvm1', image_meta)
def test_fail_get_disk_bus_for_disk_dev(self):
self.assertRaises(exception.NovaException,
blockinfo.get_disk_bus_for_disk_dev, 'inv', 'val')
@mock.patch('nova.virt.libvirt.utils.get_machine_type')
@mock.patch('nova.virt.libvirt.utils.get_arch')
def test_get_disk_bus_for_device_type_cdrom_with_q35_get_arch(self,
mock_get_arch, mock_get_machine_type):
instance = objects.Instance(**self.test_instance)
mock_get_machine_type.return_value = 'pc-q35-rhel8.0.0'
mock_get_arch.return_value = obj_fields.Architecture.X86_64
image_meta = {'properties': {}}
image_meta = objects.ImageMeta.from_dict(image_meta)
bus = blockinfo.get_disk_bus_for_device_type(instance, 'kvm',
image_meta,
device_type='cdrom')
self.assertEqual('sata', bus)
def test_get_disk_bus_for_device_type_cdrom_with_q35_image_meta(self):
instance = objects.Instance(**self.test_instance)
image_meta = {'properties': {
'hw_machine_type': 'pc-q35-rhel8.0.0',
'hw_architecture': obj_fields.Architecture.X86_64}}
image_meta = objects.ImageMeta.from_dict(image_meta)
bus = blockinfo.get_disk_bus_for_device_type(instance, 'kvm',
image_meta,
device_type='cdrom')
self.assertEqual('sata', bus)
def test_get_config_drive_type_default(self):
config_drive_type = blockinfo.get_config_drive_type()
self.assertEqual('cdrom', config_drive_type)
def test_get_config_drive_type_cdrom(self):
self.flags(config_drive_format='iso9660')
config_drive_type = blockinfo.get_config_drive_type()
self.assertEqual('cdrom', config_drive_type)
def test_get_config_drive_type_disk(self):
self.flags(config_drive_format='vfat')
config_drive_type = blockinfo.get_config_drive_type()
self.assertEqual('disk', config_drive_type)
def test_get_info_from_bdm(self):
instance = objects.Instance(**self.test_instance)
bdms = [{'device_name': '/dev/vds', 'device_type': 'disk',
'disk_bus': 'usb', 'swap_size': 4},
{'device_type': 'disk', 'guest_format': 'ext4',
'device_name': '/dev/vdb', 'size': 2},
{'disk_bus': 'ide', 'guest_format': None,
'device_name': '/dev/vdc', 'size': 3},
{'connection_info': "fake",
'mount_device': "/dev/sdr",
'disk_bus': 'lame_bus',
'device_type': 'cdrom',
'boot_index': 0,
'delete_on_termination': True},
{'connection_info': "fake",
'mount_device': "/dev/vdo",
'disk_bus': 'scsi',
'boot_index': 1,
'device_type': 'lame_type',
'delete_on_termination': True},
{'disk_bus': 'sata', 'guest_format': None,
'device_name': '/dev/sda', 'size': 3}]
expected = [{'dev': 'vds', 'type': 'disk', 'bus': 'usb'},
{'dev': 'vdb', 'type': 'disk',
'bus': 'virtio', 'format': 'ext4'},
{'dev': 'vdc', 'type': 'disk', 'bus': 'ide'},
{'dev': 'sdr', 'type': 'cdrom',
'bus': 'scsi', 'boot_index': '1'},
{'dev': 'vdo', 'type': 'disk',
'bus': 'scsi', 'boot_index': '2'},
{'dev': 'sda', 'type': 'disk', 'bus': 'sata'}]
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
for bdm, expected in zip(bdms, expected):
self.assertEqual(expected,
blockinfo.get_info_from_bdm(instance,
'kvm',
image_meta,
bdm))
# Test that passed bus and type are considered
bdm = {'device_name': '/dev/vda'}
expected = {'dev': 'vda', 'type': 'disk', 'bus': 'ide'}
self.assertEqual(
expected, blockinfo.get_info_from_bdm(instance,
'kvm',
image_meta,
bdm,
disk_bus='ide',
dev_type='disk'))
# Test that lame bus values are defaulted properly
bdm = {'disk_bus': 'lame_bus', 'device_type': 'cdrom'}
with mock.patch.object(blockinfo,
'get_disk_bus_for_device_type',
return_value='ide') as get_bus:
blockinfo.get_info_from_bdm(instance,
'kvm',
image_meta,
bdm)
get_bus.assert_called_once_with(instance, 'kvm',
image_meta, 'cdrom')
# Test that missing device is defaulted as expected
bdm = {'disk_bus': 'ide', 'device_type': 'cdrom'}
expected = {'dev': 'vdd', 'type': 'cdrom', 'bus': 'ide'}
mapping = {'root': {'dev': 'vda'}}
with mock.patch.object(blockinfo,
'find_disk_dev_for_disk_bus',
return_value='vdd') as find_dev:
got = blockinfo.get_info_from_bdm(
instance,
'kvm',
image_meta,
bdm,
mapping,
assigned_devices=['vdb', 'vdc'])
find_dev.assert_called_once_with(
{'root': {'dev': 'vda'},
'vdb': {'dev': 'vdb'},
'vdc': {'dev': 'vdc'}}, 'ide')
self.assertEqual(expected, got)
def test_get_device_name(self):
bdm_obj = objects.BlockDeviceMapping(self.context,
**fake_block_device.FakeDbBlockDeviceDict(
{'id': 3, 'instance_uuid': uuids.instance,
'device_name': '/dev/vda',
'source_type': 'volume',
'destination_type': 'volume',
'volume_id': 'fake-volume-id-1',
'boot_index': 0}))
self.assertEqual('/dev/vda', blockinfo.get_device_name(bdm_obj))
driver_bdm = driver_block_device.DriverVolumeBlockDevice(bdm_obj)
self.assertEqual('/dev/vda', blockinfo.get_device_name(driver_bdm))
bdm_obj.device_name = None
self.assertIsNone(blockinfo.get_device_name(bdm_obj))
driver_bdm = driver_block_device.DriverVolumeBlockDevice(bdm_obj)
self.assertIsNone(blockinfo.get_device_name(driver_bdm))
@mock.patch('nova.virt.libvirt.blockinfo.find_disk_dev_for_disk_bus',
return_value='vda')
def test_get_root_info_no_bdm(self, mock_find_dev):
instance = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
info = blockinfo.get_root_info(instance, 'kvm', image_meta, None,
'virtio', 'ide')
mock_find_dev.assert_called_once_with({}, 'virtio')
self.assertEqual('virtio', info['bus'])
@mock.patch('nova.virt.libvirt.blockinfo.find_disk_dev_for_disk_bus',
return_value='vda')
def test_get_root_info_no_bdm_empty_image_meta(self, mock_find_dev):
# The evacuate operation passes image_ref=None to the compute node for
# rebuild which then defaults image_meta to {}, so we don't have any
# attributes in the ImageMeta object passed to get_root_info and we
# need to make sure we don't try lazy-loading anything.
instance = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict({})
info = blockinfo.get_root_info(instance, 'kvm', image_meta, None,
'virtio', 'ide')
mock_find_dev.assert_called_once_with({}, 'virtio')
self.assertEqual('virtio', info['bus'])
@mock.patch('nova.virt.libvirt.blockinfo.get_info_from_bdm')
def test_get_root_info_bdm(self, mock_get_info):
instance = objects.Instance(**self.test_instance)
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
root_bdm = {'mount_device': '/dev/vda',
'disk_bus': 'scsi',
'device_type': 'disk'}
# No root_device_name
blockinfo.get_root_info(instance, 'kvm', image_meta, root_bdm,
'virtio', 'ide')
mock_get_info.assert_called_once_with(instance, 'kvm', image_meta,
root_bdm, {}, 'virtio')
mock_get_info.reset_mock()
# Both device names
blockinfo.get_root_info(instance, 'kvm', image_meta, root_bdm,
'virtio', 'ide', root_device_name='sda')
mock_get_info.assert_called_once_with(instance, 'kvm', image_meta,
root_bdm, {}, 'virtio')
mock_get_info.reset_mock()
# Missing device names
del root_bdm['mount_device']
blockinfo.get_root_info(instance, 'kvm', image_meta, root_bdm,
'virtio', 'ide', root_device_name='sda')
mock_get_info.assert_called_once_with(instance, 'kvm',
image_meta,
{'device_name': 'sda',
'disk_bus': 'scsi',
'device_type': 'disk'},
{}, 'virtio')
mock_get_info.reset_mock()
def test_get_boot_order_simple(self):
disk_info = {
'disk_bus': 'virtio',
'cdrom_bus': 'ide',
'mapping': {
'disk': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'root': {'bus': 'virtio', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
}
expected_order = ['hd']
self.assertEqual(expected_order, blockinfo.get_boot_order(disk_info))
def test_get_boot_order_complex(self):
disk_info = {
'disk_bus': 'virtio',
'cdrom_bus': 'ide',
'mapping': {
'disk': {'bus': 'virtio', 'dev': 'vdf',
'type': 'disk', 'boot_index': '1'},
'/dev/hda': {'bus': 'ide', 'dev': 'hda',
'type': 'cdrom', 'boot_index': '3'},
'/dev/fda': {'bus': 'fdc', 'dev': 'fda',
'type': 'floppy', 'boot_index': '2'},
'disk.eph0': {'bus': 'virtio', 'dev': 'vdb',
'type': 'disk', 'format': 'ext4'},
'disk.eph1': {'bus': 'ide', 'dev': 'vdc', 'type': 'disk'},
'disk.swap': {'bus': 'virtio', 'dev': 'vdy', 'type': 'disk'},
'root': {'bus': 'virtio', 'dev': 'vdf',
'type': 'disk', 'boot_index': '1'},
}
}
expected_order = ['hd', 'fd', 'cdrom']
self.assertEqual(expected_order, blockinfo.get_boot_order(disk_info))
def test_get_boot_order_overlapping(self):
disk_info = {
'disk_bus': 'virtio',
'cdrom_bus': 'ide',
'mapping': {
'/dev/vda': {'bus': 'scsi', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
'/dev/vdb': {'bus': 'virtio', 'dev': 'vdb',
'type': 'disk', 'boot_index': '2'},
'/dev/vdc': {'bus': 'virtio', 'dev': 'vdc',
'type': 'cdrom', 'boot_index': '3'},
'root': {'bus': 'scsi', 'dev': 'vda',
'type': 'disk', 'boot_index': '1'},
}
}
expected_order = ['hd', 'cdrom']
self.assertEqual(expected_order, blockinfo.get_boot_order(disk_info))
def _get_rescue_image_meta(self, props_dict):
meta_dict = dict(self.test_image_meta)
meta_dict['properties'] = props_dict
return objects.ImageMeta.from_dict(meta_dict)
def test_get_rescue_device(self):
# Assert that all supported device types are returned correctly
for device in blockinfo.SUPPORTED_DEVICE_TYPES:
meta = self._get_rescue_image_meta({'hw_rescue_device': device})
self.assertEqual(device, blockinfo.get_rescue_device(meta))
# Assert that disk is returned if hw_rescue_device isn't set
meta = self._get_rescue_image_meta({'hw_rescue_bus': 'virtio'})
self.assertEqual('disk', blockinfo.get_rescue_device(meta))
# Assert that UnsupportedHardware is raised for unsupported devices
meta = self._get_rescue_image_meta({'hw_rescue_device': 'fs'})
self.assertRaises(exception.UnsupportedRescueDevice,
blockinfo.get_rescue_device, meta)
def test_get_rescue_bus(self):
# Assert that all supported device bus types are returned. Stable
# device rescue is not supported by lxc so ignore this.
for virt_type in ['qemu', 'kvm', 'parallels']:
for bus in blockinfo.SUPPORTED_DEVICE_BUSES[virt_type]:
meta = self._get_rescue_image_meta({'hw_rescue_bus': bus})
self.assertEqual(bus, blockinfo.get_rescue_bus(None, virt_type,
meta, None))
# Assert that UnsupportedHardware is raised for unsupported devices
meta = self._get_rescue_image_meta({'hw_rescue_bus': 'xen'})
self.assertRaises(exception.UnsupportedRescueBus,
blockinfo.get_rescue_bus, None, 'kvm', meta, 'disk')
class DefaultDeviceNamesTestCase(test.NoDBTestCase):
def setUp(self):
super(DefaultDeviceNamesTestCase, self).setUp()
self.context = context.get_admin_context()
self.instance = objects.Instance(
uuid='32dfcb37-5af1-552b-357c-be8c3aa38310',
memory_kb='1024000',
basepath='/some/path',
bridge_name='br100',
vcpus=2,
project_id='fake',
bridge='br101',
image_ref='155d900f-4e14-4e4c-a73d-069cbf4541e6',
root_gb=10,
ephemeral_gb=20,
instance_type_id=2,
config_drive=False,
root_device_name = '/dev/vda',
system_metadata={})
self.image_meta = objects.ImageMeta(
disk_format='raw',
properties=objects.ImageMetaProps())
self.virt_type = 'kvm'
self.flavor = objects.Flavor(swap=4)
self.patchers = []
self.patchers.append(mock.patch.object(self.instance, 'get_flavor',
return_value=self.flavor))
self.patchers.append(mock.patch(
'nova.objects.block_device.BlockDeviceMapping.save'))
for patcher in self.patchers:
patcher.start()
self.ephemerals = [objects.BlockDeviceMapping(
self.context, **fake_block_device.FakeDbBlockDeviceDict(
{'id': 1, 'instance_uuid': uuids.instance,
'device_name': '/dev/vdb',
'source_type': 'blank',
'destination_type': 'local',
'device_type': 'disk',
'disk_bus': 'virtio',
'delete_on_termination': True,
'guest_format': None,
'volume_size': 1,
'boot_index': -1}))]
self.swap = [objects.BlockDeviceMapping(
self.context, **fake_block_device.FakeDbBlockDeviceDict(
{'id': 2, 'instance_uuid': uuids.instance,
'device_name': '/dev/vdc',
'source_type': 'blank',
'destination_type': 'local',
'device_type': 'disk',
'disk_bus': 'virtio',
'delete_on_termination': True,
'guest_format': 'swap',
'volume_size': 1,
'boot_index': -1}))]
self.block_device_mapping = [
objects.BlockDeviceMapping(self.context,
**fake_block_device.FakeDbBlockDeviceDict(
{'id': 3, 'instance_uuid': uuids.instance,
'device_name': '/dev/vda',
'source_type': 'volume',
'destination_type': 'volume',
'device_type': 'disk',
'disk_bus': 'virtio',
'volume_id': 'fake-volume-id-1',
'boot_index': 0})),
objects.BlockDeviceMapping(self.context,
**fake_block_device.FakeDbBlockDeviceDict(
{'id': 4, 'instance_uuid': uuids.instance,
'device_name': '/dev/vdd',
'source_type': 'snapshot',
'device_type': 'disk',
'disk_bus': 'virtio',
'destination_type': 'volume',
'snapshot_id': 'fake-snapshot-id-1',
'boot_index': -1})),
objects.BlockDeviceMapping(self.context,
**fake_block_device.FakeDbBlockDeviceDict(
{'id': 5, 'instance_uuid': uuids.instance,
'device_name': '/dev/vde',
'source_type': 'blank',
'device_type': 'disk',
'disk_bus': 'virtio',
'destination_type': 'volume',
'boot_index': -1}))]
def tearDown(self):
super(DefaultDeviceNamesTestCase, self).tearDown()
for patcher in self.patchers:
patcher.stop()
@mock.patch(
'nova.virt.libvirt.utils.get_arch',
return_value=obj_fields.Architecture.X86_64)
def _test_default_device_names(self, eph, swap, bdm, mock_get_arch):
bdms = eph + swap + bdm
bdi = driver.get_block_device_info(self.instance, bdms)
blockinfo.default_device_names(self.virt_type,
self.context,
self.instance,
bdi,
self.image_meta)
mock_get_arch.assert_called()
def test_only_block_device_mapping(self):
# Test no-op
original_bdm = copy.deepcopy(self.block_device_mapping)
self._test_default_device_names([], [], self.block_device_mapping)
for original, defaulted in zip(
original_bdm, self.block_device_mapping):
self.assertEqual(original.device_name, defaulted.device_name)
# Assert it defaults the missing one as expected
self.block_device_mapping[1]['device_name'] = None
self.block_device_mapping[2]['device_name'] = None
self._test_default_device_names([], [], self.block_device_mapping)
self.assertEqual('/dev/vdd',
self.block_device_mapping[1]['device_name'])
self.assertEqual('/dev/vde',
self.block_device_mapping[2]['device_name'])
def test_with_ephemerals(self):
# Test ephemeral gets assigned
self.ephemerals[0]['device_name'] = None
self._test_default_device_names(self.ephemerals, [],
self.block_device_mapping)
self.assertEqual('/dev/vdb', self.ephemerals[0]['device_name'])
self.block_device_mapping[1]['device_name'] = None
self.block_device_mapping[2]['device_name'] = None
self._test_default_device_names(self.ephemerals, [],
self.block_device_mapping)
self.assertEqual('/dev/vdd',
self.block_device_mapping[1]['device_name'])
self.assertEqual('/dev/vde',
self.block_device_mapping[2]['device_name'])
def test_with_swap(self):
# Test swap only
self.swap[0]['device_name'] = None
self._test_default_device_names([], self.swap, [])
self.assertEqual('/dev/vdc', self.swap[0]['device_name'])
# Test swap and block_device_mapping
self.swap[0]['device_name'] = None
self.block_device_mapping[1]['device_name'] = None
self.block_device_mapping[2]['device_name'] = None
self._test_default_device_names([], self.swap,
self.block_device_mapping)
self.assertEqual('/dev/vdc', self.swap[0]['device_name'])
self.assertEqual('/dev/vdd',
self.block_device_mapping[1]['device_name'])
self.assertEqual('/dev/vde',
self.block_device_mapping[2]['device_name'])
def test_all_together(self):
# Test swap missing
self.swap[0]['device_name'] = None
self._test_default_device_names(self.ephemerals,
self.swap, self.block_device_mapping)
self.assertEqual('/dev/vdc', self.swap[0]['device_name'])
# Test swap and eph missing
self.swap[0]['device_name'] = None
self.ephemerals[0]['device_name'] = None
self._test_default_device_names(self.ephemerals,
self.swap, self.block_device_mapping)
self.assertEqual('/dev/vdb', self.ephemerals[0]['device_name'])
self.assertEqual('/dev/vdc', self.swap[0]['device_name'])
# Test all missing
self.swap[0]['device_name'] = None
self.ephemerals[0]['device_name'] = None
self.block_device_mapping[1]['device_name'] = None
self.block_device_mapping[2]['device_name'] = None
self._test_default_device_names(self.ephemerals,
self.swap, self.block_device_mapping)
self.assertEqual('/dev/vdb', self.ephemerals[0]['device_name'])
self.assertEqual('/dev/vdc', self.swap[0]['device_name'])
self.assertEqual('/dev/vdd',
self.block_device_mapping[1]['device_name'])
self.assertEqual('/dev/vde',
self.block_device_mapping[2]['device_name'])