HPSSA: Support 'MAX' as size_gb for logical disks
This commit enables support for using 'MAX' as a possible value for size_gb for logical disks. When 'MAX' is used for a logical disk, that logical disk is created last. The remaining amount of space available is given to that logical disk. Multiple logical disks with 'MAX' may be specified, but might not be an actual use-case. Change-Id: I1af332285251667a2d40b8854a4f3c36753a3322
This commit is contained in:
@@ -56,6 +56,9 @@ RAID_LEVEL_MIN_DISKS = {RAID_0: 2,
|
||||
RAID_60: 8}
|
||||
|
||||
|
||||
MINIMUM_DISK_SIZE = 1
|
||||
|
||||
|
||||
def get_interface_type(ssa_interface):
|
||||
return INTERFACE_TYPE_MAP[ssa_interface]
|
||||
|
||||
|
||||
@@ -69,11 +69,22 @@ def allocate_disks(logical_disk, server, raid_config):
|
||||
physical_drives = controller.unassigned_physical_drives
|
||||
physical_drives = _get_criteria_matching_disks(logical_disk,
|
||||
physical_drives)
|
||||
physical_drives = [x for x in physical_drives
|
||||
if x.size_gb >= size_gb]
|
||||
|
||||
if size_gb != "MAX":
|
||||
# If we want to allocate for a logical disk for which size_gb is
|
||||
# mentioned, we take the smallest physical drives which is required
|
||||
# to match the criteria.
|
||||
reverse_sort = False
|
||||
physical_drives = [x for x in physical_drives
|
||||
if x.size_gb >= size_gb]
|
||||
else:
|
||||
# If we want to allocate for a logical disk for which size_gb is
|
||||
# MAX, we take the largest physical drives available.
|
||||
reverse_sort = True
|
||||
|
||||
if len(physical_drives) >= number_of_physical_disks:
|
||||
selected_drives = sorted(physical_drives, key=lambda x: x.size_gb)
|
||||
selected_drives = sorted(physical_drives, key=lambda x: x.size_gb,
|
||||
reverse=reverse_sort)
|
||||
selected_drive_ids = [x.id for x in selected_drives]
|
||||
logical_disk['controller'] = controller.id
|
||||
physical_disks = selected_drive_ids[:number_of_physical_disks]
|
||||
|
||||
@@ -103,9 +103,15 @@ def create_configuration(raid_config):
|
||||
# In this case, for RAID1 configuration, if we were to consider
|
||||
# LD1 first and allocate PD3 and PD4 for it, then allocation would
|
||||
# fail. So follow a particular order for allocation.
|
||||
logical_disks_sorted = sorted(raid_config['logical_disks'],
|
||||
key=lambda x: int(x['size_gb']),
|
||||
reverse=True)
|
||||
#
|
||||
# Also make sure we create the MAX logical_disks the last to make sure
|
||||
# we allot only the remaining space available.
|
||||
logical_disks_sorted = (
|
||||
sorted((x for x in raid_config['logical_disks']
|
||||
if x['size_gb'] != "MAX"),
|
||||
reverse=True,
|
||||
key=lambda x: x['size_gb']) +
|
||||
[x for x in raid_config['logical_disks'] if x['size_gb'] == "MAX"])
|
||||
|
||||
# We figure out the new disk created by recording the wwns
|
||||
# before and after the create, and then figuring out the
|
||||
|
||||
@@ -378,14 +378,19 @@ class Controller(object):
|
||||
phy_drive_ids = ','.join(logical_drive_info['physical_disks'])
|
||||
cmd_args.append("drives=%s" % phy_drive_ids)
|
||||
|
||||
size_mb = logical_drive_info['size_gb'] * 1024
|
||||
raid_level = logical_drive_info['raid_level']
|
||||
|
||||
# For RAID levels (like 5+0 and 6+0), HPSSA names them differently.
|
||||
# Check if we have mapping stored, otherwise use the same.
|
||||
raid_level = constants.RAID_LEVEL_INPUT_TO_HPSSA_MAPPING.get(
|
||||
raid_level, raid_level)
|
||||
cmd_args.extend(["raid=%s" % raid_level, "size=%s" % size_mb])
|
||||
cmd_args.append("raid=%s" % raid_level)
|
||||
|
||||
# If size_gb is MAX, then don't pass size argument. HPSSA will
|
||||
# automatically allocate the maximum # disks size possible to the
|
||||
# logical disk.
|
||||
if logical_drive_info['size_gb'] != "MAX":
|
||||
size_mb = logical_drive_info['size_gb'] * 1024
|
||||
cmd_args.append("size=%s" % size_mb)
|
||||
|
||||
self.execute_cmd(*cmd_args)
|
||||
|
||||
@@ -443,6 +448,11 @@ class RaidArray(object):
|
||||
args = ("array", self.id, "create", "type=logicaldrive",
|
||||
"raid=%s" % raid_level, "size=?")
|
||||
|
||||
if logical_disk['size_gb'] != "MAX":
|
||||
desired_disk_size = logical_disk['size_gb']
|
||||
else:
|
||||
desired_disk_size = constants.MINIMUM_DISK_SIZE
|
||||
|
||||
try:
|
||||
stdout, stderr = self.parent.execute_cmd(
|
||||
*args, dont_transform_to_hpssa_exception=True)
|
||||
@@ -467,7 +477,7 @@ class RaidArray(object):
|
||||
return False
|
||||
|
||||
max_size_gb = int(match.group(1)) / 1024
|
||||
return logical_disk['size_gb'] <= max_size_gb
|
||||
return desired_disk_size <= max_size_gb
|
||||
|
||||
|
||||
class LogicalDrive(object):
|
||||
|
||||
@@ -13,10 +13,16 @@
|
||||
"description": "RAID level for the logical disk. Required."
|
||||
},
|
||||
"size_gb": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"exclusiveMinimum": true,
|
||||
"description": "Size (Integer) for the logical disk. Required."
|
||||
"anyOf": [{
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"exclusiveMinimum": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [ "MAX" ]
|
||||
}],
|
||||
"description": "Size in GiB (Integer) for the logical disk. Use 'MAX' as size_gb if this logical disk is supposed to use the rest of the space available. Required."
|
||||
},
|
||||
"volume_name": {
|
||||
"type": "string",
|
||||
|
||||
@@ -1791,3 +1791,308 @@ Smart Array P822 in Slot 2
|
||||
Vendor ID: PMCSIERA
|
||||
Model: SRCv24x6G
|
||||
'''
|
||||
|
||||
|
||||
NO_DRIVES_HPSSA_7_DISKS = '''
|
||||
|
||||
Smart Array P822 in Slot 3
|
||||
Bus Interface: PCI
|
||||
Slot: 3
|
||||
Serial Number: PDVTF0BRH5T0KV
|
||||
|
||||
unassigned
|
||||
|
||||
physicaldrive 5I:1:1
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 1
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 199 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7G4QV0000B41803GZ
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:2
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 2
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 200 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7HK0Y0000N419008G
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:3
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 3
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7H1L50000B4180V5Y
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:4
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 4
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 599 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7H1K30000B41800TT
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 6I:1:5
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 5
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 598 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVUR97N
|
||||
Model: HP EF0600FATFF
|
||||
|
||||
physicaldrive 6I:1:6
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 6
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 500 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVVJR1N
|
||||
Model: HP EF0600FATFF
|
||||
|
||||
physicaldrive 6I:1:7
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 7
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 500 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVVENJN
|
||||
Model: HP EF0600FATFF
|
||||
'''
|
||||
|
||||
|
||||
ONE_DRIVE_RAID_1_50_GB = '''
|
||||
|
||||
Smart Array P822 in Slot 3
|
||||
Slot: 3
|
||||
Serial Number: PDVTF0BRH5T0KV
|
||||
|
||||
Array: A
|
||||
Interface Type: SAS
|
||||
Unused Space: 1042189 MB (91.1%)
|
||||
Used Space: 100.0 GB (8.9%)
|
||||
|
||||
Logical Drive: 1
|
||||
Size: 50.0 GB
|
||||
Fault Tolerance: 1
|
||||
Status: OK
|
||||
MultiDomain Status: OK
|
||||
Unique Identifier: 600508B1001C861A72C774A7394AE2AC
|
||||
Disk Name: /dev/sda
|
||||
Logical Drive Label: 013400ABPDVTF0BRH5T0KV22C5
|
||||
LD Acceleration Method: Controller Cache
|
||||
|
||||
physicaldrive 5I:1:1
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 1
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 199 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7G4QV0000B41803GZ
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:2
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 2
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 200 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7HK0Y0000N419008G
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
unassigned
|
||||
|
||||
physicaldrive 5I:1:3
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 3
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7H1L50000B4180V5Y
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:4
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 4
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 599 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7H1K30000B41800TT
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 6I:1:5
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 5
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 598 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVUR97N
|
||||
Model: HP EF0600FATFF
|
||||
|
||||
physicaldrive 6I:1:6
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 6
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 500 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVVJR1N
|
||||
Model: HP EF0600FATFF
|
||||
|
||||
physicaldrive 6I:1:7
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 7
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 500 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVVENJN
|
||||
Model: HP EF0600FATFF
|
||||
'''
|
||||
|
||||
|
||||
TWO_DRIVES_50GB_RAID1_MAXGB_RAID5 = '''
|
||||
|
||||
Smart Array P822 in Slot 3
|
||||
Slot: 3
|
||||
Serial Number: PDVTF0BRH5T0KV
|
||||
|
||||
Array: A
|
||||
Interface Type: SAS
|
||||
Unused Space: 1042189 MB (91.1%)
|
||||
Used Space: 100.0 GB (8.9%)
|
||||
Status: OK
|
||||
|
||||
Logical Drive: 1
|
||||
Size: 50.0 GB
|
||||
Fault Tolerance: 1
|
||||
Status: OK
|
||||
Unique Identifier: 600508B1001C861A72C774A7394AE2AC
|
||||
Disk Name: /dev/sda
|
||||
|
||||
physicaldrive 5I:1:1
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 1
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 199 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7G4QV0000B41803GZ
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:2
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 2
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 200 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7HK0Y0000N419008G
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
|
||||
Array: B
|
||||
Interface Type: SAS
|
||||
Unused Space: 0 MB (0.0%)
|
||||
Used Space: 1.6 TB (100.0%)
|
||||
Status: OK
|
||||
MultiDomain Status: OK
|
||||
Array Type: Data
|
||||
HP SSD Smart Path: disable
|
||||
|
||||
Logical Drive: 2
|
||||
Size: 1.1 TB
|
||||
Fault Tolerance: 5
|
||||
Status: OK
|
||||
Unique Identifier: 600508B1001CE9DE8551AEE29D5A72F7
|
||||
|
||||
physicaldrive 5I:1:3
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 3
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7H1L50000B4180V5Y
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 5I:1:4
|
||||
Port: 5I
|
||||
Box: 1
|
||||
Bay: 4
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 599 GB
|
||||
Firmware Revision: HPD6
|
||||
Serial Number: 6SL7H1K30000B41800TT
|
||||
Model: HP EF0600FARNA
|
||||
|
||||
physicaldrive 6I:1:5
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 5
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 598 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVUR97N
|
||||
Model: HP EF0600FATFF
|
||||
|
||||
unassigned
|
||||
|
||||
physicaldrive 6I:1:6
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 6
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 500 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVVJR1N
|
||||
|
||||
physicaldrive 6I:1:7
|
||||
Port: 6I
|
||||
Box: 1
|
||||
Bay: 7
|
||||
Status: OK
|
||||
Interface Type: SAS
|
||||
Size: 500 GB
|
||||
Firmware Revision: HPDB
|
||||
Serial Number: 2AVVENJN
|
||||
Model: HP EF0600FATFF
|
||||
'''
|
||||
|
||||
@@ -114,6 +114,31 @@ class DiskAllocatorTestCase(testtools.TestCase):
|
||||
self.assertEqual(sorted(['5I:1:3', '6I:1:7']),
|
||||
sorted(logical_disk['physical_disks']))
|
||||
|
||||
def test_allocate_disks_max_okay(self, get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
|
||||
logical_disk = {'size_gb': 'MAX',
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas'}
|
||||
|
||||
# Decrease size of three disks so that the remaining gets
|
||||
# selected.
|
||||
disk1 = server.controllers[0].get_physical_drive_by_id('5I:1:3')
|
||||
disk2 = server.controllers[0].get_physical_drive_by_id('6I:1:7')
|
||||
disk3 = server.controllers[0].get_physical_drive_by_id('5I:1:4')
|
||||
disk1.size_gb = 300
|
||||
disk2.size_gb = 300
|
||||
disk3.size_gb = 300
|
||||
|
||||
raid_config = {'logical_disks': [logical_disk]}
|
||||
disk_allocator.allocate_disks(logical_disk, server, raid_config)
|
||||
self.assertEqual('Smart Array P822 in Slot 2',
|
||||
logical_disk['controller'])
|
||||
self.assertEqual(sorted(['6I:1:5', '6I:1:6']),
|
||||
sorted(logical_disk['physical_disks']))
|
||||
|
||||
def test_allocate_disks_disk_size_not_matching(self,
|
||||
get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
|
||||
@@ -201,6 +201,35 @@ class ManagerTestCases(testtools.TestCase):
|
||||
'array', 'A', 'create', 'type=logicaldrive', 'raid=1',
|
||||
'size=51200')
|
||||
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_create_configuration_max_as_size_gb(
|
||||
self, controller_exec_cmd_mock, get_all_details_mock):
|
||||
no_drives = raid_constants.NO_DRIVES_HPSSA_7_DISKS
|
||||
one_drive = raid_constants.ONE_DRIVE_RAID_1_50_GB
|
||||
two_drives = raid_constants.TWO_DRIVES_50GB_RAID1_MAXGB_RAID5
|
||||
get_all_details_mock.side_effect = [no_drives, one_drive, two_drives]
|
||||
raid_info = {'logical_disks': [{'size_gb': 50,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd'},
|
||||
{'size_gb': 'MAX',
|
||||
'raid_level': '5',
|
||||
'disk_type': 'hdd'}]}
|
||||
raid_info = manager.create_configuration(raid_info)
|
||||
ld1 = raid_info['logical_disks'][0]
|
||||
ld2 = raid_info['logical_disks'][1]
|
||||
self.assertEqual('Smart Array P822 in Slot 3', ld1['controller'])
|
||||
self.assertEqual('Smart Array P822 in Slot 3', ld2['controller'])
|
||||
self.assertEqual(sorted(['5I:1:1', '5I:1:2']),
|
||||
sorted(ld1['physical_disks']))
|
||||
self.assertEqual(sorted(['5I:1:3', '5I:1:4', '6I:1:5']),
|
||||
sorted(ld2['physical_disks']))
|
||||
controller_exec_cmd_mock.assert_any_call(
|
||||
'create', 'type=logicaldrive', 'drives=5I:1:1,5I:1:2',
|
||||
'raid=1', 'size=51200')
|
||||
controller_exec_cmd_mock.assert_any_call(
|
||||
'create', 'type=logicaldrive', 'drives=5I:1:3,5I:1:4,6I:1:5',
|
||||
'raid=5')
|
||||
|
||||
@mock.patch.object(manager, 'get_configuration')
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_delete_configuration(self, controller_exec_cmd_mock,
|
||||
|
||||
@@ -232,6 +232,28 @@ class ControllerTest(testtools.TestCase):
|
||||
"raid=1",
|
||||
"size=51200")
|
||||
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_create_logical_drive_max_size_gb(self, execute_mock,
|
||||
get_all_details_mock):
|
||||
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_NO_DRIVES
|
||||
|
||||
server = objects.Server()
|
||||
controller = server.controllers[0]
|
||||
|
||||
logical_drive_info = {'size_gb': 'MAX',
|
||||
'raid_level': '1',
|
||||
'controller': 'Smart Array P822 in Slot 2',
|
||||
'physical_disks': ['5I:1:1',
|
||||
'5I:1:2',
|
||||
'5I:1:3']}
|
||||
|
||||
controller.create_logical_drive(logical_drive_info)
|
||||
execute_mock.assert_called_once_with("create",
|
||||
"type=logicaldrive",
|
||||
"drives=5I:1:1,5I:1:2,5I:1:3",
|
||||
"raid=1")
|
||||
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_create_logical_drive_with_raid_array(self, execute_mock,
|
||||
get_all_details_mock):
|
||||
@@ -363,6 +385,19 @@ class ArrayTest(testtools.TestCase):
|
||||
logical_disk)
|
||||
self.assertTrue(ret_val)
|
||||
|
||||
@mock.patch.object(processutils, 'execute')
|
||||
def test_can_accomodate_max_size_gb_okay(self, execute_mock,
|
||||
get_all_details_mock):
|
||||
current_config = raid_constants.HPSSA_TWO_DRIVES_100GB_RAID5_50GB_RAID1
|
||||
get_all_details_mock.return_value = current_config
|
||||
execute_mock.return_value = (
|
||||
raid_constants.ARRAY_ACCOMODATE_LOGICAL_DISK, None)
|
||||
logical_disk = {'size_gb': 'MAX', 'raid_level': '5'}
|
||||
server = objects.Server()
|
||||
ret_val = server.controllers[0].raid_arrays[0].can_accomodate(
|
||||
logical_disk)
|
||||
self.assertTrue(ret_val)
|
||||
|
||||
@mock.patch.object(processutils, 'execute')
|
||||
def test_can_accomodate_not_enough_space(self, execute_mock,
|
||||
get_all_details_mock):
|
||||
|
||||
Reference in New Issue
Block a user