<VMWare> Allocate free bus for new SCSI controller
There are at most 16 virtual disks that can be attached onto a SCSI
controller, while if the limitation is reached, error occurs
with message "VMwareDriverException: Invalid configuration for
device '0'".
The reason is that when the controller's quota is used up, a new
controller will be created automatically, but the newly-created
one will try to use bus number 0, which is already used my existing
controller.
This change will allocate a new free bus number for the newly-created
controller.
Co-Authored-By: Qiaowei Ren <qiaowei.ren@intel.com>
Closes bug: #1522232
Change-Id: I2ced1358e682cda979d1d5bddb6359253699280b
(cherry picked from commit b36da5dd03
)
This commit is contained in:
parent
5c7741086b
commit
be033eef72
@ -366,8 +366,9 @@ class VirtualIDEController(DataObject):
|
||||
|
||||
class VirtualLsiLogicController(DataObject):
|
||||
"""VirtualLsiLogicController class."""
|
||||
def __init__(self, key=0, scsiCtlrUnitNumber=0):
|
||||
def __init__(self, key=0, scsiCtlrUnitNumber=0, busNumber=0):
|
||||
self.key = key
|
||||
self.busNumber = busNumber
|
||||
self.scsiCtlrUnitNumber = scsiCtlrUnitNumber
|
||||
self.device = []
|
||||
|
||||
|
@ -215,6 +215,13 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
|
||||
self.assertEqual("ns0:ParaVirtualSCSIController",
|
||||
config_spec.device.obj_name)
|
||||
|
||||
def test_create_controller_spec_with_specfic_bus_number(self):
|
||||
# Test controller spec with specifc bus number rather default 0
|
||||
config_spec = vm_util.create_controller_spec(fake.FakeFactory(), -101,
|
||||
adapter_type=constants.ADAPTER_TYPE_LSILOGICSAS,
|
||||
bus_number=1)
|
||||
self.assertEqual(1, config_spec.device.busNumber)
|
||||
|
||||
def _vmdk_path_and_adapter_type_devices(self, filename, parent=None):
|
||||
# Test the adapter_type returned for a lsiLogic sas controller
|
||||
controller_key = 1000
|
||||
@ -333,6 +340,27 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
|
||||
self.assertEqual([1], taken[201])
|
||||
self.assertEqual([7], taken[1000])
|
||||
|
||||
def test_get_bus_number_for_scsi_controller(self):
|
||||
devices = [fake.VirtualLsiLogicController(1000, scsiCtlrUnitNumber=7,
|
||||
busNumber=0),
|
||||
fake.VirtualLsiLogicController(1002, scsiCtlrUnitNumber=7,
|
||||
busNumber=2)]
|
||||
bus_number = vm_util._get_bus_number_for_scsi_controller(devices)
|
||||
self.assertEqual(1, bus_number)
|
||||
|
||||
def test_get_bus_number_for_scsi_controller_buses_used_up(self):
|
||||
devices = [fake.VirtualLsiLogicController(1000, scsiCtlrUnitNumber=7,
|
||||
busNumber=0),
|
||||
fake.VirtualLsiLogicController(1001, scsiCtlrUnitNumber=7,
|
||||
busNumber=1),
|
||||
fake.VirtualLsiLogicController(1002, scsiCtlrUnitNumber=7,
|
||||
busNumber=2),
|
||||
fake.VirtualLsiLogicController(1003, scsiCtlrUnitNumber=7,
|
||||
busNumber=3)]
|
||||
self.assertRaises(vexc.VMwareDriverException,
|
||||
vm_util._get_bus_number_for_scsi_controller,
|
||||
devices)
|
||||
|
||||
def test_allocate_controller_key_and_unit_number_ide_default(self):
|
||||
# Test that default IDE controllers are used when there is a free slot
|
||||
# on them
|
||||
@ -387,6 +415,23 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(8, unit_number)
|
||||
self.assertIsNone(controller_spec)
|
||||
|
||||
def test_allocate_controller_key_and_unit_number_scsi_new_controller(self):
|
||||
# Test that we allocate on existing SCSI controller if there is a free
|
||||
# slot on it
|
||||
devices = [fake.VirtualLsiLogicController(1000, scsiCtlrUnitNumber=15)]
|
||||
for unit_number in range(15):
|
||||
disk = fake.VirtualDisk(1000, unit_number)
|
||||
devices.append(disk)
|
||||
factory = fake.FakeFactory()
|
||||
(controller_key, unit_number,
|
||||
controller_spec) = vm_util.allocate_controller_key_and_unit_number(
|
||||
factory,
|
||||
devices,
|
||||
constants.DEFAULT_ADAPTER_TYPE)
|
||||
self.assertEqual(-101, controller_key)
|
||||
self.assertEqual(0, unit_number)
|
||||
self.assertEqual(1, controller_spec.device.busNumber)
|
||||
|
||||
def test_get_vnc_config_spec(self):
|
||||
fake_factory = fake.FakeFactory()
|
||||
result = vm_util.get_vnc_config_spec(fake_factory,
|
||||
|
@ -57,6 +57,9 @@ ADAPTER_TYPE_IDE = "ide"
|
||||
ADAPTER_TYPE_LSILOGICSAS = "lsiLogicsas"
|
||||
ADAPTER_TYPE_PARAVIRTUAL = "paraVirtual"
|
||||
|
||||
SCSI_ADAPTER_TYPES = [DEFAULT_ADAPTER_TYPE, ADAPTER_TYPE_LSILOGICSAS,
|
||||
ADAPTER_TYPE_BUSLOGIC, ADAPTER_TYPE_PARAVIRTUAL]
|
||||
|
||||
SUPPORTED_FLAT_VARIANTS = ["thin", "preallocated", "thick", "eagerZeroedThick"]
|
||||
|
||||
EXTENSION_KEY = 'org.openstack.compute'
|
||||
@ -66,6 +69,9 @@ EXTENSION_TYPE_INSTANCE = 'instance'
|
||||
# One adapter has 16 slots but one reserved for controller
|
||||
SCSI_MAX_CONNECT_NUMBER = 15
|
||||
|
||||
# The max number of SCSI adaptors that could be created on one instance.
|
||||
SCSI_MAX_CONTROLLER_NUMBER = 4
|
||||
|
||||
# This list was extracted from the installation iso image for ESX 6.0.
|
||||
# It is contained in s.v00, which is gzipped. The list was obtained by
|
||||
# searching for the string 'otherGuest' in the uncompressed contents of that
|
||||
|
@ -361,7 +361,8 @@ def get_vm_resize_spec(client_factory, vcpus, memory_mb, extra_specs,
|
||||
|
||||
|
||||
def create_controller_spec(client_factory, key,
|
||||
adapter_type=constants.DEFAULT_ADAPTER_TYPE):
|
||||
adapter_type=constants.DEFAULT_ADAPTER_TYPE,
|
||||
bus_number=0):
|
||||
"""Builds a Config Spec for the LSI or Bus Logic Controller's addition
|
||||
which acts as the controller for the virtual hard disk to be attached
|
||||
to the VM.
|
||||
@ -383,7 +384,7 @@ def create_controller_spec(client_factory, key,
|
||||
virtual_controller = client_factory.create(
|
||||
'ns0:VirtualLsiLogicController')
|
||||
virtual_controller.key = key
|
||||
virtual_controller.busNumber = 0
|
||||
virtual_controller.busNumber = bus_number
|
||||
virtual_controller.sharedBus = "noSharing"
|
||||
virtual_device_config.device = virtual_controller
|
||||
return virtual_device_config
|
||||
@ -739,6 +740,19 @@ def _find_allocated_slots(devices):
|
||||
return taken
|
||||
|
||||
|
||||
def _get_bus_number_for_scsi_controller(devices):
|
||||
"""Return usable bus number when create new SCSI controller."""
|
||||
# Every SCSI controller will take a unique bus number
|
||||
taken = [dev.busNumber for dev in devices if _is_scsi_controller(dev)]
|
||||
# The max bus number for SCSI controllers is 3
|
||||
for i in range(constants.SCSI_MAX_CONTROLLER_NUMBER):
|
||||
if i not in taken:
|
||||
return i
|
||||
msg = _('Only %d SCSI controllers are allowed to be '
|
||||
'created on this instance.') % constants.SCSI_MAX_CONTROLLER_NUMBER
|
||||
raise vexc.VMwareDriverException(msg)
|
||||
|
||||
|
||||
def allocate_controller_key_and_unit_number(client_factory, devices,
|
||||
adapter_type):
|
||||
"""This function inspects the current set of hardware devices and returns
|
||||
@ -754,10 +768,7 @@ def allocate_controller_key_and_unit_number(client_factory, devices,
|
||||
if adapter_type == constants.ADAPTER_TYPE_IDE:
|
||||
ide_keys = [dev.key for dev in devices if _is_ide_controller(dev)]
|
||||
ret = _find_controller_slot(ide_keys, taken, 2)
|
||||
elif adapter_type in [constants.DEFAULT_ADAPTER_TYPE,
|
||||
constants.ADAPTER_TYPE_LSILOGICSAS,
|
||||
constants.ADAPTER_TYPE_BUSLOGIC,
|
||||
constants.ADAPTER_TYPE_PARAVIRTUAL]:
|
||||
elif adapter_type in constants.SCSI_ADAPTER_TYPES:
|
||||
scsi_keys = [dev.key for dev in devices if _is_scsi_controller(dev)]
|
||||
ret = _find_controller_slot(scsi_keys, taken, 16)
|
||||
if ret:
|
||||
@ -765,8 +776,14 @@ def allocate_controller_key_and_unit_number(client_factory, devices,
|
||||
|
||||
# create new controller with the specified type and return its spec
|
||||
controller_key = -101
|
||||
|
||||
# Get free bus number for new SCSI controller.
|
||||
bus_number = 0
|
||||
if adapter_type in constants.SCSI_ADAPTER_TYPES:
|
||||
bus_number = _get_bus_number_for_scsi_controller(devices)
|
||||
|
||||
controller_spec = create_controller_spec(client_factory, controller_key,
|
||||
adapter_type)
|
||||
adapter_type, bus_number)
|
||||
return controller_key, 0, controller_spec
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user