HPSSA: Add support for nested RAID levels

This commit adds support for nested RAID levels and
changes functional test case for testing them as well.
RAID 2 support is removed as it is useless and is now obsolete
(as per Wikipedia).

Implements: blueprint hpssa-support
Change-Id: I61e31825812b4e80f4fd09a2dbc7ea8ac3d061f9
This commit is contained in:
Ramakrishnan G 2014-10-28 22:27:48 +00:00
parent e923d7c750
commit 5e228cbac5
6 changed files with 362 additions and 48 deletions

View File

@ -18,6 +18,7 @@ import stat
from oslo.concurrency import processutils
import testtools
from proliantutils.hpssa import constants
from proliantutils.hpssa import manager
from proliantutils.hpssa import objects
@ -31,8 +32,6 @@ class HPSSATestCase(testtools.TestCase):
def _get_server(self):
server = objects.Server()
if not server.controllers:
self.fail("No controllers detected on the server.")
return server
def _get_physical_drives(self, server, no_of_physical_drives_required,
@ -50,7 +49,7 @@ class HPSSATestCase(testtools.TestCase):
return physical_drives[:no_of_physical_drives_required]
def test_create_configuration_single_logical_drive(self):
def _test_create_configuration_single_logical_drive(self, raid_level):
server = self._get_server()
size_gb = 100
@ -58,56 +57,74 @@ class HPSSATestCase(testtools.TestCase):
manager.delete_configuration()
devices_before_create = set(glob.glob('/dev/sd[a-z]'))
for raid_level in ['0', '1', '5', '6']:
self._get_physical_drives(server, 2, size_gb)
minimum_disks_required = constants.RAID_LEVEL_MIN_DISKS[raid_level]
self._get_physical_drives(server, minimum_disks_required, size_gb)
raid_config = {
'logical_disks':
[{'size_gb': size_gb,
'raid_level': raid_level}]
}
raid_config = {
'logical_disks': [{'size_gb': size_gb, 'raid_level': raid_level}]}
current_config = manager.create_configuration(raid_config)
current_config = manager.create_configuration(raid_config)
logical_disk = current_config['logical_disks'][0]
self.assertIsNotNone(logical_disk['root_device_hint'])
self.assertIsNotNone(logical_disk['volume_name'])
logical_disk = current_config['logical_disks'][0]
self.assertIsNotNone(logical_disk['root_device_hint'])
self.assertIsNotNone(logical_disk['volume_name'])
devices_after_create = set(glob.glob('/dev/sd[a-z]'))
new_device = devices_after_create - devices_before_create
devices_after_create = set(glob.glob('/dev/sd[a-z]'))
new_device = devices_after_create - devices_before_create
# Make sure only one new device appeared now.
if len(new_device) != 1:
self.fail("More than 1 block devices were found after "
"creating RAID volume")
# Make sure only one new device appeared now.
if len(new_device) != 1:
self.fail("More than 1 block devices were found after "
"creating RAID volume")
new_device_file = new_device.pop()
s = os.stat(new_device_file)
if not stat.S_ISBLK(s.st_mode):
self.fail("Newly created disk %s is not a block device"
% new_device_file)
new_device_file = new_device.pop()
s = os.stat(new_device_file)
if not stat.S_ISBLK(s.st_mode):
self.fail("Newly created disk %s is not a block device"
% new_device_file)
# SCSI disk devices have major number 8
# https://www.kernel.org/doc/Documentation/devices.txt
# TODO(rameshg87: Need to check if any more assetions need to be
# done on the newly created disk device.
self.assertEqual(8, os.major(s.st_rdev))
# SCSI disk devices have major number 8
# https://www.kernel.org/doc/Documentation/devices.txt
# TODO(rameshg87: Need to check if any more assetions need to be
# done on the newly created disk device.
self.assertEqual(8, os.major(s.st_rdev))
stdout, stderr = processutils.execute("lsblk", "-Pio", "SIZE",
new_device_file)
# Output is like (two times printed):
# SIZE="8G"
# SIZE="8G"
created_disk_size = stdout.split("\n")[0].split('"')[1][:-1]
self.assertEqual(size_gb, int(created_disk_size))
stdout, stderr = processutils.execute("lsblk", "-Pio", "SIZE",
new_device_file)
# Output is like (two times printed):
# SIZE="8G"
# SIZE="8G"
created_disk_size = stdout.split("\n")[0].split('"')[1][:-1]
self.assertEqual(size_gb, int(created_disk_size))
stdout, stderr = processutils.execute("lsblk", "-Pio", "WWN",
new_device_file)
# Output is like:
# WWN="0x600508b1001cca7f"
# TODO(rameshg87: Check with hpssa team whether this can be
# assumed.
wwn = stdout.split("\n")[0].split('"')[1]
self.assertEqual(logical_disk['root_device_hint']['wwn'], wwn)
stdout, stderr = processutils.execute("lsblk", "-Pio", "WWN",
new_device_file)
# Output is like:
# WWN="0x600508b1001cca7f"
# TODO(rameshg87: Check with hpssa team whether this can be
# assumed.
wwn = stdout.split("\n")[0].split('"')[1]
self.assertEqual(logical_disk['root_device_hint']['wwn'], wwn)
manager.delete_configuration()
manager.delete_configuration()
def test_raid_0_single_drive(self):
self._test_create_configuration_single_logical_drive('0')
def test_raid_1_single_drive(self):
self._test_create_configuration_single_logical_drive('1')
def test_raid_5_single_drive(self):
self._test_create_configuration_single_logical_drive('5')
def test_raid_6_single_drive(self):
self._test_create_configuration_single_logical_drive('6')
def test_raid_10_single_drive(self):
self._test_create_configuration_single_logical_drive('1+0')
def test_raid_50_single_drive(self):
self._test_create_configuration_single_logical_drive('5+0')
def test_raid_60_single_drive(self):
self._test_create_configuration_single_logical_drive('6+0')

View File

@ -30,6 +30,9 @@ RAID_60 = '6+0'
RAID_1_ADM = '1ADM'
RAID_10_ADM = '10ADM'
RAID_LEVEL_INPUT_TO_HPSSA_MAPPING = {RAID_50: '50', RAID_60: '60'}
RAID_LEVEL_HPSSA_TO_INPUT_MAPPING = {
v: k for k, v in RAID_LEVEL_INPUT_TO_HPSSA_MAPPING.iteritems()}
INTERFACE_TYPE_MAP = {'SCSI': INTERFACE_TYPE_SCSI,
'SAS': INTERFACE_TYPE_SAS,
@ -49,7 +52,8 @@ RAID_LEVEL_MIN_DISKS = {RAID_0: 2,
RAID_5: 3,
RAID_6: 4,
RAID_10: 4,
RAID_50: 6}
RAID_50: 6,
RAID_60: 8}
def get_interface_type(ssa_interface):

View File

@ -326,6 +326,11 @@ class Controller(object):
phy_drive_ids = ','.join(physical_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)
self.execute_cmd("create", "type=logicaldrive",
"drives=%s" % phy_drive_ids,
"raid=%s" % raid_level,
@ -382,7 +387,14 @@ class LogicalDrive(object):
# TODO(rameshg87): Check if size is always reported in GB
self.size_gb = int(float(self.properties['Size'].rstrip(' GB')))
self.raid_level = self.properties.get('Fault Tolerance')
# 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_mapping = constants.RAID_LEVEL_HPSSA_TO_INPUT_MAPPING
self.raid_level = raid_level_mapping.get(self.raid_level,
self.raid_level)
self.volume_name = self.properties.get('Logical Drive Label')
# Trim down the WWN to 16 digits (8 bytes) so that it matches

View File

@ -9,7 +9,7 @@
"properties": {
"raid_level": {
"type": "string",
"enum": [ "0", "1", "2", "5", "6", "1+0" ],
"enum": [ "0", "1", "5", "6", "1+0", "5+0", "6+0" ],
"description": "RAID level for the logical disk. Required."
},
"size_gb": {

View File

@ -437,6 +437,248 @@ Smart Array P822 in Slot 2
Model: SRCv24x6G
'''
HPSSA_ONE_DRIVE_RAID_50 = '''
Smart Array P822 in Slot 2
Bus Interface: PCI
Slot: 2
Serial Number: PDVTF0BRH5T0MO
Cache Serial Number: PBKUD0BRH5T3I6
RAID 6 (ADG) Status: Enabled
Controller Status: OK
Hardware Revision: B
Firmware Version: 4.68
Rebuild Priority: Medium
Expand Priority: Medium
Surface Scan Delay: 3 secs
Surface Scan Mode: Idle
Queue Depth: Automatic
Monitor and Performance Delay: 60 min
Elevator Sort: Enabled
Degraded Performance Optimization: Disabled
Inconsistency Repair Policy: Disabled
Wait for Cache Room: Disabled
Surface Analysis Inconsistency Notification: Disabled
Post Prompt Timeout: 15 secs
Cache Board Present: True
Cache Status: OK
Cache Ratio: 10% Read / 90% Write
Drive Write Cache: Disabled
Total Cache Size: 2.0 GB
Total Cache Memory Available: 1.8 GB
No-Battery Write Cache: Disabled
Cache Backup Power Source: Capacitors
Battery/Capacitor Count: 1
Battery/Capacitor Status: OK
SATA NCQ Supported: True
Spare Activation Mode: Activate on physical drive failure (default)
Controller Temperature (C): 88
Cache Module Temperature (C): 38
Capacitor Temperature (C): 23
Number of Ports: 6 (2 Internal / 4 External )
Driver Name: hpsa
Driver Version: 3.4.4
Driver Supports HP SSD Smart Path: True
Array: A
Interface Type: SAS
Unused Space: 3280165 MB
Status: OK
MultiDomain Status: OK
Array Type: Data
HP SSD Smart Path: disable
Logical Drive: 1
Size: 100.0 GB
Fault Tolerance: 50
Number of Parity Groups: 2
Heads: 255
Sectors Per Track: 32
Cylinders: 25700
Strip Size: 256 KB
Full Stripe Size: 512 KB
Status: OK
MultiDomain Status: OK
Caching: Enabled
Parity Initialization Status: Queued
Unique Identifier: 600508B1001C0FC2145AA6F3A0AF2A57
Disk Name: /dev/sda
Mount Points: None
Logical Drive Label: 02795E8FPDVTF0BRH5T0MOF6B8
Parity Group 0:
physicaldrive 5I:1:1 (port 5I:box 1:bay 1, SAS, 600 GB, OK)
physicaldrive 5I:1:3 (port 5I:box 1:bay 3, SAS, 600 GB, OK)
physicaldrive 6I:1:5 (port 6I:box 1:bay 5, SAS, 600 GB, OK)
Parity Group 1:
physicaldrive 5I:1:2 (port 5I:box 1:bay 2, SAS, 600 GB, OK)
physicaldrive 5I:1:4 (port 5I:box 1:bay 4, SAS, 600 GB, OK)
physicaldrive 6I:1:6 (port 6I:box 1:bay 6, SAS, 600 GB, OK)
Drive Type: Data
LD Acceleration Method: Controller Cache
physicaldrive 5I:1:1
Port: 5I
Box: 1
Bay: 1
Status: OK
Drive Type: Data Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7G55D0000N4173JLT
Model: HP EF0600FARNA
Current Temperature (C): 36
Maximum Temperature (C): 43
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
physicaldrive 5I:1:2
Port: 5I
Box: 1
Bay: 2
Status: OK
Drive Type: Data Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7H2DM0000B41800Y0
Model: HP EF0600FARNA
Current Temperature (C): 37
Maximum Temperature (C): 44
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
physicaldrive 5I:1:3
Port: 5I
Box: 1
Bay: 3
Status: OK
Drive Type: Data Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7G4ZN0000B41707PD
Model: HP EF0600FARNA
Current Temperature (C): 35
Maximum Temperature (C): 42
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
physicaldrive 5I:1:4
Port: 5I
Box: 1
Bay: 4
Status: OK
Drive Type: Data Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7H27F0000B41800S0
Model: HP EF0600FARNA
Current Temperature (C): 38
Maximum Temperature (C): 45
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
physicaldrive 6I:1:5
Port: 6I
Box: 1
Bay: 5
Status: OK
Drive Type: Data Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7H2BR0000B41800V8
Model: HP EF0600FARNA
Current Temperature (C): 33
Maximum Temperature (C): 41
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
physicaldrive 6I:1:6
Port: 6I
Box: 1
Bay: 6
Status: OK
Drive Type: Data Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7G4WD0000N4180GEJ
Model: HP EF0600FARNA
Current Temperature (C): 36
Maximum Temperature (C): 44
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
unassigned
physicaldrive 6I:1:7
Port: 6I
Box: 1
Bay: 7
Status: OK
Drive Type: Unassigned Drive
Interface Type: SAS
Size: 600 GB
Native Block Size: 512
Rotational Speed: 15000
Firmware Revision: HPD6
Serial Number: 6SL7G54Q0000N4180W34
Model: HP EF0600FARNA
Current Temperature (C): 33
Maximum Temperature (C): 39
PHY Count: 2
PHY Transfer Rate: 6.0Gbps, Unknown
Drive Authentication Status: OK
Carrier Application Version: 11
Carrier Bootloader Version: 6
SEP (Vendor ID PMCSIERA, Model SRCv24x6G) 380
Device Number: 380
Firmware Version: RevB
WWID: 5001438028842E1F
Vendor ID: PMCSIERA
Model: SRCv24x6G
'''
HPSSA_ONE_DRIVE_100GB_RAID_5 = '''
Smart Array P822 in Slot 2

View File

@ -97,6 +97,16 @@ class ServerTest(testtools.TestCase):
self.assertEqual(controller, physical_drive.parent)
self.assertEqual(400, physical_drive.size_gb)
def test_server_object_one_logical_drive_raid_level_mappping(
self, get_all_details_mock):
stdout = raid_constants.HPSSA_ONE_DRIVE_RAID_50
get_all_details_mock.return_value = stdout
server = objects.Server()
logical_drive = server.controllers[0].raid_arrays[0].logical_drives[0]
self.assertEqual(constants.RAID_50, logical_drive.raid_level)
def test_get_controller_by_id(self, get_all_details_mock):
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
@ -212,6 +222,35 @@ class ControllerTest(testtools.TestCase):
"raid=1",
"size=51200")
@mock.patch.object(objects.Controller, 'execute_cmd')
def test_create_logical_drive_raid_level_mapping(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': 50,
'raid_level': '5+0',
'volume_name': 'boot_volume',
'is_boot_volume': 'true',
'controller': 'Smart Array P822 in Slot 2',
'physical_disks': ['5I:1:1',
'5I:1:2',
'5I:1:3',
'5I:1:4',
'5I:1:5',
'6I:1:6']}
controller.create_logical_drive(logical_drive_info,
['5I:1:1', '5I:1:2', '5I:1:3',
'5I:1:4', '5I:1:5', '6I:1:6'])
execute_mock.assert_called_once_with(
"create", "type=logicaldrive",
"drives=5I:1:1,5I:1:2,5I:1:3,5I:1:4,5I:1:5,6I:1:6",
"raid=50", "size=51200")
@mock.patch.object(objects.Controller, 'execute_cmd')
def test_delete_all_logical_drives(self, execute_mock,
get_all_details_mock):