Skip to content

Commit

Permalink
compute: Validate a BDMs disk_bus when provided
Browse files Browse the repository at this point in the history
Previously disk_bus values were never validated and could easily end up
being ignored by the underlying virt driver and hypervisor.

For example, a common mistake made by users is to request a virtio-scsi
disk_bus when using the libvirt virt driver. This however isn't a valid
bus and is ignored, defaulting back to the virtio (virtio-blk) bus.

This change adds a simple validation in the compute API using the
potential disk_bus values provided by the DiskBus field class as used
when validating the hw_*_bus image properties.

Closes-Bug: #1876301
Change-Id: I77b28b9cc8f99b159f628f4655d85ff305a71db8
(cherry picked from commit 5913bd8)
  • Loading branch information
lyarwood committed Aug 3, 2020
1 parent ac05bc3 commit fb31ae4
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 4 deletions.
7 changes: 4 additions & 3 deletions api-ref/source/parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2515,9 +2515,10 @@ disk_available_least_total:
disk_bus:
description: |
Disk bus type, some hypervisors (currently only libvirt) support
specify this parameter. Some example disk_bus values can be: `ide`,
`usb`, `virtio`, `scsi`. This is not an exhaustive list as it depends
on the virtualization driver, and may change as more support is added.
specify this parameter. Some example disk_bus values can be: ``fdc``,
``ide``, ``sata``, ``scsi``, ``usb``, ``virtio``, ``xen``, ``lxc``
and ``uml``. Support for each bus type depends on the virtualization driver
and underlying hypervisor.
in: body
required: false
type: string
Expand Down
1 change: 1 addition & 0 deletions nova/api/openstack/compute/servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,7 @@ def create(self, req, body):
exception.InvalidBDMEphemeralSize,
exception.InvalidBDMFormat,
exception.InvalidBDMSwapSize,
exception.InvalidBDMDiskBus,
exception.VolumeTypeNotFound,
exception.AutoDiskConfigDisabledByImage,
exception.InstanceGroupNotFound,
Expand Down
7 changes: 7 additions & 0 deletions nova/compute/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1741,6 +1741,13 @@ def _validate_bdm(self, context, instance, instance_type,
"(source: 'blank', dest: 'volume') need to have non-zero "
"size"))

# NOTE(lyarwood): Ensure the disk_bus is at least known to Nova.
# The virt driver may reject this later but for now just ensure
# it's listed as an acceptable value of the DiskBus field class.
disk_bus = bdm.disk_bus if 'disk_bus' in bdm else None
if disk_bus and disk_bus not in fields_obj.DiskBus.ALL:
raise exception.InvalidBDMDiskBus(disk_bus=disk_bus)

ephemeral_size = sum(bdm.volume_size or instance_type['ephemeral_gb']
for bdm in block_device_mappings
if block_device.new_format_is_ephemeral(bdm))
Expand Down
5 changes: 5 additions & 0 deletions nova/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ class TooManyDiskDevices(InvalidBDM):
code = 403


class InvalidBDMDiskBus(InvalidBDM):
msg_fmr = _("Block Device Mapping is invalid: The provided disk bus "
"%(disk_bus)s is not valid.")


class InvalidAttribute(Invalid):
msg_fmt = _("Attribute not supported: %(attr)s")

Expand Down
2 changes: 2 additions & 0 deletions nova/objects/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ class DiskBus(BaseNovaEnum):

# NOTE(aspiers): If you change this, don't forget to update the
# docs and metadata for hw_*_bus in glance.
# NOTE(lyarwood): Also update the possible values in the api-ref for the
# block_device_mapping_v2.disk_bus parameter.
FDC = "fdc"
IDE = "ide"
SATA = "sata"
Expand Down
3 changes: 2 additions & 1 deletion nova/tests/unit/api/openstack/compute/test_serversV21.py
Original file line number Diff line number Diff line change
Expand Up @@ -5059,7 +5059,8 @@ def test_create_instance_bdm_api_validation_fails(self, mock_get_volumes):
(exception.InvalidBDMVolume, {'id': 'fake'}),
(exception.InvalidBDMImage, {'id': 'fake'}),
(exception.InvalidBDMBootSequence, {}),
(exception.InvalidBDMLocalsLimit, {}))
(exception.InvalidBDMLocalsLimit, {}),
(exception.InvalidBDMDiskBus, {'disk_bus': 'foo'}))

ex_iter = iter(bdm_exceptions)

Expand Down
17 changes: 17 additions & 0 deletions nova/tests/unit/compute/test_compute_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4661,6 +4661,23 @@ def test_validate_bdm_missing_volume_size(self, mock_get_image):
bdms, image_cache, volumes)
mock_get_image.assert_called_once_with(self.context, image_id)

@mock.patch('nova.compute.api.API._get_image')
def test_validate_bdm_disk_bus(self, mock_get_image):
"""Tests that _validate_bdm fail if an invalid disk_bus is provided
"""
instance = self._create_instance_obj()
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(
boot_index=0, image_id=instance.image_ref,
source_type='image', destination_type='volume',
volume_type=None, snapshot_id=None, volume_id=None,
volume_size=1, disk_bus='virtio-scsi')])
image_cache = volumes = {}
self.assertRaises(exception.InvalidBDMDiskBus,
self.compute_api._validate_bdm,
self.context, instance, objects.Flavor(),
bdms, image_cache, volumes)

def test_the_specified_volume_type_id_assignment_to_name(self):
"""Test _check_requested_volume_type method is called, if the user
is using the volume type ID, assign volume_type to volume type name.
Expand Down

0 comments on commit fb31ae4

Please sign in to comment.