Merge "HPSSA: Support 'MAX' as size_gb for logical disks"

This commit is contained in:
Jenkins
2015-11-24 17:11:52 +00:00
committed by Gerrit Code Review
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)
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": {
"anyOf": [{
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"description": "Size (Integer) for the logical disk. Required."
"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):