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:
Ramakrishnan G
2015-05-25 23:32:23 +00:00
parent afbe98dd09
commit 1f9cf46a37
9 changed files with 444 additions and 14 deletions

View File

@@ -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]

View File

@@ -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]

View File

@@ -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

View File

@@ -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):

View File

@@ -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",

View File

@@ -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
'''

View File

@@ -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

View File

@@ -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,

View File

@@ -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):