HPSSA: Add disk allocator
This commit adds the disk allocator which allocates physical disks to create requests (if physical_disks were not provided in the input). This commit modifies the size of disks in the test input data to facilitate writing easy test casese for disk allocator. Implements: blueprint hpssa-support Change-Id: I7b48aa68cb9305596ab772a410d2c497313935b6
This commit is contained in:
@@ -12,22 +12,23 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
INTERFACE_TYPE_SAS = 'SAS'
|
||||
INTERFACE_TYPE_SCSI = 'SCSI'
|
||||
INTERFACE_TYPE_SATA = 'SATA'
|
||||
INTERFACE_TYPE_SAS = 'sas'
|
||||
INTERFACE_TYPE_SCSI = 'scsi'
|
||||
INTERFACE_TYPE_SATA = 'sata'
|
||||
|
||||
DISK_TYPE_HDD = 'HDD'
|
||||
DISK_TYPE_SSD = 'SSD'
|
||||
DISK_TYPE_HDD = 'hdd'
|
||||
DISK_TYPE_SSD = 'ssd'
|
||||
|
||||
RAID_0 = '0'
|
||||
RAID_1 = '1'
|
||||
RAID_1_ADM = '1ADM'
|
||||
RAID_10 = '10'
|
||||
RAID_10_ADM = '10ADM'
|
||||
RAID_10 = '1+0'
|
||||
RAID_5 = '5'
|
||||
RAID_6 = '6'
|
||||
RAID_50 = '50'
|
||||
RAID_60 = '60'
|
||||
RAID_50 = '5+0'
|
||||
RAID_60 = '6+0'
|
||||
# Below are not supported in Ironic now.
|
||||
RAID_1_ADM = '1ADM'
|
||||
RAID_10_ADM = '10ADM'
|
||||
|
||||
|
||||
INTERFACE_TYPE_MAP = {'SCSI': INTERFACE_TYPE_SCSI,
|
||||
@@ -42,6 +43,14 @@ DISK_TYPE_MAP = {'SCSI': DISK_TYPE_HDD,
|
||||
'SATASSD': DISK_TYPE_SSD,
|
||||
'SASSSD': DISK_TYPE_SSD}
|
||||
|
||||
RAID_LEVEL_MIN_DISKS = {RAID_0: 2,
|
||||
RAID_1: 2,
|
||||
RAID_1_ADM: 3,
|
||||
RAID_5: 3,
|
||||
RAID_6: 4,
|
||||
RAID_10: 4,
|
||||
RAID_50: 6}
|
||||
|
||||
|
||||
def get_interface_type(ssa_interface):
|
||||
return INTERFACE_TYPE_MAP[ssa_interface]
|
||||
88
proliantutils/hpssa/disk_allocator.py
Normal file
88
proliantutils/hpssa/disk_allocator.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.hpssa import constants
|
||||
|
||||
FILTER_CRITERIA = ['disk_type', 'interface_type', 'model', 'firmware']
|
||||
|
||||
|
||||
def _get_criteria_matching_disks(logical_disk, physical_drives):
|
||||
"""Finds the physical drives matching the criteria of logical disk.
|
||||
|
||||
This method finds the physical drives matching the criteria
|
||||
of the logical disk passed.
|
||||
|
||||
:param logical_disk: The logical disk dictionary from raid config
|
||||
:param physical_drives: The physical drives to consider.
|
||||
:returns: A list of physical drives which match the criteria
|
||||
"""
|
||||
matching_physical_drives = []
|
||||
criteria_to_consider = [x for x in FILTER_CRITERIA
|
||||
if x in logical_disk]
|
||||
|
||||
for physical_drive in physical_drives:
|
||||
for criteria in criteria_to_consider:
|
||||
logical_drive_value = logical_disk.get(criteria)
|
||||
physical_drive_value = getattr(physical_drive, criteria)
|
||||
if logical_drive_value != physical_drive_value:
|
||||
break
|
||||
else:
|
||||
matching_physical_drives.append(physical_drive)
|
||||
|
||||
return matching_physical_drives
|
||||
|
||||
|
||||
def allocate_disks(logical_disk, server):
|
||||
"""Allocate physical disks to a logical disk.
|
||||
|
||||
This method allocated physical disks to a logical
|
||||
disk based on the current state of the server and
|
||||
criteria mentioned in the logical disk.
|
||||
|
||||
:param logical_disk: a dictionary of a logical disk
|
||||
from the RAID configuration input to the module.
|
||||
:param server: An objects.Server object
|
||||
:raises: PhysicalDisksNotFoundError, if cannot find
|
||||
physical disks for the request.
|
||||
"""
|
||||
size_gb = logical_disk['size_gb']
|
||||
raid_level = logical_disk['raid_level']
|
||||
number_of_physical_disks = logical_disk.get(
|
||||
'number_of_physical_disks', constants.RAID_LEVEL_MIN_DISKS[raid_level])
|
||||
share_physical_disks = logical_disk.get('share_physical_disks', False)
|
||||
|
||||
for controller in server.controllers:
|
||||
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 len(physical_drives) >= number_of_physical_disks:
|
||||
selected_drives = sorted(physical_drives, key=lambda x: x.size_gb)
|
||||
selected_drive_ids = [x.id for x in selected_drives]
|
||||
logical_disk['controller'] = controller.id
|
||||
physical_disks = selected_drive_ids[:number_of_physical_disks]
|
||||
logical_disk['physical_disks'] = physical_disks
|
||||
break
|
||||
|
||||
if not share_physical_disks:
|
||||
# TODO(rameshg87): When this logical drives can share disks
|
||||
# with other arrays, figure out free space in other arrays
|
||||
# and then consider which array to use.
|
||||
pass
|
||||
else:
|
||||
raise exception.PhysicalDisksNotFoundError(size_gb=size_gb,
|
||||
raid_level=raid_level)
|
||||
@@ -19,17 +19,14 @@ import jsonschema
|
||||
from jsonschema import exceptions as json_schema_exc
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.hpssa import constants
|
||||
from proliantutils.hpssa import disk_allocator
|
||||
from proliantutils.hpssa import objects
|
||||
|
||||
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
RAID_CONFIG_SCHEMA = os.path.join(CURRENT_DIR, "raid_config_schema.json")
|
||||
|
||||
|
||||
def _find_physical_disks(logical_disk, server):
|
||||
# To be implemented
|
||||
pass
|
||||
|
||||
|
||||
def validate(raid_config):
|
||||
"""Validates the RAID configuration provided.
|
||||
|
||||
@@ -46,6 +43,27 @@ def validate(raid_config):
|
||||
except json_schema_exc.ValidationError as e:
|
||||
raise exception.InvalidInputError(e.message)
|
||||
|
||||
for logical_disk in raid_config['logical_disks']:
|
||||
|
||||
# If user has provided 'number_of_physical_disks' or
|
||||
# 'physical_disks', validate that they have mentioned at least
|
||||
# minimum number of physical disks required for that RAID level.
|
||||
raid_level = logical_disk['raid_level']
|
||||
min_disks_reqd = constants.RAID_LEVEL_MIN_DISKS[raid_level]
|
||||
|
||||
no_of_disks_specified = None
|
||||
if 'number_of_physical_disks' in logical_disk:
|
||||
no_of_disks_specified = logical_disk['number_of_physical_disks']
|
||||
elif 'physical_disks' in logical_disk:
|
||||
no_of_disks_specified = len(logical_disk['physical_disks'])
|
||||
|
||||
if (no_of_disks_specified and
|
||||
no_of_disks_specified < min_disks_reqd):
|
||||
msg = ("RAID level %(raid_level)s requires at least %(number) "
|
||||
"disks." % {'raid_level': raid_level,
|
||||
'number': min_disks_reqd})
|
||||
raise exception.InvalidInputError(msg)
|
||||
|
||||
|
||||
def create_configuration(raid_config):
|
||||
"""Create a RAID configuration on this server.
|
||||
@@ -89,14 +107,7 @@ def create_configuration(raid_config):
|
||||
for logical_disk in logical_disks_sorted:
|
||||
|
||||
if 'physical_disks' not in logical_disk:
|
||||
# TODO(rameshg87): hpssa module should be capable of finding
|
||||
# the suitable controller and physical disks if it not provided
|
||||
# by using hints. This is a supported use-case, but not implemented
|
||||
# as of now. Will be implemented soon.
|
||||
# _find_physical_disks(logical_disk, server)
|
||||
msg = ("Mentioning logical_disks without 'controller' and "
|
||||
"'physical_disks' is not supported as of now.")
|
||||
raise exception.InvalidInputError(reason=msg)
|
||||
disk_allocator.allocate_disks(logical_disk, server)
|
||||
|
||||
controller_id = logical_disk['controller']
|
||||
|
||||
@@ -173,23 +184,7 @@ def get_configuration():
|
||||
raid_config['logical_disks'] = []
|
||||
|
||||
for logical_drive in logical_drives:
|
||||
logical_drive_info = {}
|
||||
logical_drive_info['size_gb'] = logical_drive.size_gb
|
||||
logical_drive_info['raid_level'] = logical_drive.raid_level
|
||||
|
||||
array = logical_drive.parent
|
||||
controller = array.parent
|
||||
logical_drive_info['controller'] = controller.id
|
||||
|
||||
physical_drive_ids = map(lambda x: x.id, array.physical_drives)
|
||||
logical_drive_info['physical_disks'] = physical_drive_ids
|
||||
|
||||
vol_name = logical_drive.get_property('Logical Drive Label')
|
||||
logical_drive_info['volume_name'] = vol_name
|
||||
|
||||
wwn = logical_drive.get_property('Unique Identifier')
|
||||
logical_drive_info['root_device_hint'] = {'wwn': wwn}
|
||||
|
||||
raid_config['logical_disks'].append(logical_drive_info)
|
||||
logical_drive_dict = logical_drive.get_logical_drive_dict()
|
||||
raid_config['logical_disks'].append(logical_drive_dict)
|
||||
|
||||
return raid_config
|
||||
|
||||
@@ -17,7 +17,7 @@ import time
|
||||
from oslo.concurrency import processutils
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.hpssa import types
|
||||
from proliantutils.hpssa import constants
|
||||
|
||||
|
||||
def _get_indentation(string):
|
||||
@@ -418,5 +418,7 @@ class PhysicalDrive:
|
||||
self.size_gb = int(float(self.properties['Size'].rstrip(' GB')))
|
||||
|
||||
ssa_interface = self.properties['Interface Type']
|
||||
self.interface_type = types.get_interface_type(ssa_interface)
|
||||
self.disk_type = types.get_disk_type(ssa_interface)
|
||||
self.interface_type = constants.get_interface_type(ssa_interface)
|
||||
self.disk_type = constants.get_disk_type(ssa_interface)
|
||||
self.model = self.properties.get('Model')
|
||||
self.firmware = self.properties.get('Firmware Revision')
|
||||
|
||||
@@ -55,7 +55,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -97,7 +97,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -118,7 +118,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -139,7 +139,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -285,7 +285,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -306,7 +306,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -330,7 +330,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -351,7 +351,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -372,7 +372,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -516,7 +516,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -537,7 +537,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -558,7 +558,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -582,7 +582,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -603,7 +603,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Unassigned Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -748,7 +748,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -769,7 +769,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -790,7 +790,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 400 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -844,7 +844,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
@@ -865,7 +865,7 @@ Smart Array P822 in Slot 2
|
||||
Status: OK
|
||||
Drive Type: Data Drive
|
||||
Interface Type: SAS
|
||||
Size: 600 GB
|
||||
Size: 500 GB
|
||||
Native Block Size: 512
|
||||
Rotational Speed: 15000
|
||||
Firmware Revision: HPD6
|
||||
|
||||
145
proliantutils/tests/hpssa/test_disk_allocator.py
Normal file
145
proliantutils/tests/hpssa/test_disk_allocator.py
Normal file
@@ -0,0 +1,145 @@
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.hpssa import disk_allocator
|
||||
from proliantutils.hpssa import objects
|
||||
from proliantutils.tests.hpssa import raid_constants
|
||||
|
||||
|
||||
@mock.patch.object(objects.Server, '_get_all_details')
|
||||
class DiskAllocatorTestCase(testtools.TestCase):
|
||||
|
||||
def test__get_criteria_matching_disks_all_criterias(self,
|
||||
get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
physical_drives = server.controllers[0].unassigned_physical_drives
|
||||
|
||||
logical_disk = {'size_gb': 100,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas',
|
||||
'model': 'HP EF0600FARNA',
|
||||
'firmware': 'HPD6'}
|
||||
|
||||
ret_physical_drives = disk_allocator._get_criteria_matching_disks(
|
||||
logical_disk, physical_drives)
|
||||
self.assertEqual(ret_physical_drives, physical_drives)
|
||||
|
||||
def test__get_criteria_matching_disks_not_all_criterias(
|
||||
self, get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
physical_drives = server.controllers[0].unassigned_physical_drives
|
||||
|
||||
logical_disk = {'size_gb': 100,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas',
|
||||
'firmware': 'HPD6'}
|
||||
|
||||
ret_physical_drives = disk_allocator._get_criteria_matching_disks(
|
||||
logical_disk, physical_drives)
|
||||
self.assertEqual(ret_physical_drives, physical_drives)
|
||||
|
||||
def test__get_criteria_matching_disks_some_disks_dont_match(
|
||||
self, get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
physical_drives = server.controllers[0].unassigned_physical_drives
|
||||
|
||||
logical_disk = {'size_gb': 100,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas',
|
||||
'firmware': 'HPD6'}
|
||||
|
||||
physical_drives[0].disk_type = 'ssd'
|
||||
physical_drives[1].firmware = 'HPD7'
|
||||
ret_physical_drives = disk_allocator._get_criteria_matching_disks(
|
||||
logical_disk, physical_drives)
|
||||
exp_physical_drives = physical_drives[2:]
|
||||
self.assertEqual(exp_physical_drives, ret_physical_drives)
|
||||
|
||||
def test__get_criteria_matching_disks_no_disks_match(
|
||||
self, get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
physical_drives = server.controllers[0].unassigned_physical_drives
|
||||
|
||||
logical_disk = {'size_gb': 100,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'ssdd',
|
||||
'interface_type': 'sas',
|
||||
'firmware': 'HPD6'}
|
||||
|
||||
ret_physical_drives = disk_allocator._get_criteria_matching_disks(
|
||||
logical_disk, physical_drives)
|
||||
self.assertFalse(ret_physical_drives)
|
||||
|
||||
def test_allocate_disks_okay(self, get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
|
||||
logical_disk = {'size_gb': 100,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas'}
|
||||
|
||||
# Decrease size of two disks so that they get 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')
|
||||
disk1.size_gb = 300
|
||||
disk2.size_gb = 300
|
||||
|
||||
disk_allocator.allocate_disks(logical_disk, server)
|
||||
self.assertEqual('Smart Array P822 in Slot 2',
|
||||
logical_disk['controller'])
|
||||
self.assertEqual(sorted(['5I:1:3', '6I:1:7']),
|
||||
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
|
||||
server = objects.Server()
|
||||
|
||||
logical_disk = {'size_gb': 700,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas'}
|
||||
exc = self.assertRaises(exception.PhysicalDisksNotFoundError,
|
||||
disk_allocator.allocate_disks,
|
||||
logical_disk, server)
|
||||
self.assertIn("of size 700 GB and raid level 1", str(exc))
|
||||
|
||||
def test_allocate_disks_disk_not_enough_disks(self,
|
||||
get_all_details_mock):
|
||||
get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE
|
||||
server = objects.Server()
|
||||
physical_drives = server.controllers[0].unassigned_physical_drives
|
||||
physical_drives = physical_drives[:2]
|
||||
server.controllers[0].unassigned_physical_drives = physical_drives
|
||||
|
||||
logical_disk = {'size_gb': 600,
|
||||
'raid_level': '5',
|
||||
'disk_type': 'hdd',
|
||||
'interface_type': 'sas'}
|
||||
exc = self.assertRaises(exception.PhysicalDisksNotFoundError,
|
||||
disk_allocator.allocate_disks,
|
||||
logical_disk, server)
|
||||
self.assertIn("of size 600 GB and raid level 5", str(exc))
|
||||
@@ -101,6 +101,57 @@ class ManagerTestCases(testtools.TestCase):
|
||||
manager.create_configuration,
|
||||
raid_info)
|
||||
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_create_configuration_without_disk_input_succeeds(
|
||||
self, controller_exec_cmd_mock, get_all_details_mock):
|
||||
no_drives = raid_constants.HPSSA_NO_DRIVES
|
||||
one_drive = raid_constants.HPSSA_ONE_DRIVE_100GB_RAID_5
|
||||
two_drives = raid_constants.HPSSA_TWO_DRIVES_100GB_RAID5_50GB_RAID1
|
||||
get_all_details_mock.side_effect = [no_drives, one_drive, two_drives]
|
||||
raid_info = {'logical_disks': [{'size_gb': 50,
|
||||
'raid_level': '1'},
|
||||
{'size_gb': 100,
|
||||
'raid_level': '5'}]}
|
||||
current_config = manager.create_configuration(raid_info)
|
||||
controller_exec_cmd_mock.assert_any_call("create",
|
||||
"type=logicaldrive",
|
||||
mock.ANY,
|
||||
"raid=5",
|
||||
"size=%d" % (100*1024))
|
||||
# Verify that we created the 50GB disk the last.
|
||||
controller_exec_cmd_mock.assert_called_with("create",
|
||||
"type=logicaldrive",
|
||||
mock.ANY,
|
||||
"raid=1",
|
||||
"size=%d" % (50*1024))
|
||||
|
||||
ld1_ret = [x for x in current_config['logical_disks']
|
||||
if x['raid_level'] == '1'][0]
|
||||
ld2_ret = [x for x in current_config['logical_disks']
|
||||
if x['raid_level'] == '5'][0]
|
||||
self.assertEqual('600508B1001CC42CDF101F06E5563967',
|
||||
ld2_ret['root_device_hint']['wwn'])
|
||||
self.assertEqual('600508B1001CE1E18302A8702C6AB008',
|
||||
ld1_ret['root_device_hint']['wwn'])
|
||||
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_create_configuration_without_disk_input_fails_on_disk_type(
|
||||
self, controller_exec_cmd_mock, get_all_details_mock):
|
||||
no_drives = raid_constants.HPSSA_NO_DRIVES
|
||||
one_drive = raid_constants.HPSSA_ONE_DRIVE_100GB_RAID_5
|
||||
two_drives = raid_constants.HPSSA_TWO_DRIVES_100GB_RAID5_50GB_RAID1
|
||||
get_all_details_mock.side_effect = [no_drives, one_drive, two_drives]
|
||||
raid_info = {'logical_disks': [{'size_gb': 50,
|
||||
'raid_level': '1',
|
||||
'disk_type': 'ssd'},
|
||||
{'size_gb': 100,
|
||||
'raid_level': '5',
|
||||
'disk_type': 'hdd'}]}
|
||||
exc = self.assertRaises(exception.PhysicalDisksNotFoundError,
|
||||
manager.create_configuration,
|
||||
raid_info)
|
||||
self.assertIn("of size 50 GB and raid level 1", str(exc))
|
||||
|
||||
@mock.patch.object(objects.Controller, 'execute_cmd')
|
||||
def test_delete_configuration(self, controller_exec_cmd_mock,
|
||||
get_all_details_mock):
|
||||
@@ -144,3 +195,18 @@ class ManagerTestCases(testtools.TestCase):
|
||||
ld1_returned['root_device_hint'])
|
||||
self.assertEqual(sorted(ld1_expected['physical_disks']),
|
||||
sorted(ld1_returned['physical_disks']))
|
||||
|
||||
|
||||
class RaidConfigValidationTestCases(testtools.TestCase):
|
||||
|
||||
def test_validate_fails_min_disks_number(self):
|
||||
raid_config = {'size_gb': 100, 'raid_level': 5,
|
||||
'number_of_physical_disks': 2}
|
||||
self.assertRaises(exception.InvalidInputError,
|
||||
manager.validate, raid_config)
|
||||
|
||||
def test_validate_fails_min_physical_disks(self):
|
||||
raid_config = {'size_gb': 100, 'raid_level': 5,
|
||||
'physical_disks': ['foo']}
|
||||
self.assertRaises(exception.InvalidInputError,
|
||||
manager.validate, raid_config)
|
||||
|
||||
@@ -17,8 +17,8 @@ from oslo.concurrency import processutils
|
||||
import testtools
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.hpssa import constants
|
||||
from proliantutils.hpssa import objects
|
||||
from proliantutils.hpssa import types
|
||||
from proliantutils.tests.hpssa import raid_constants
|
||||
|
||||
|
||||
@@ -53,10 +53,10 @@ class ServerTest(testtools.TestCase):
|
||||
physical_drive = filter(lambda x: x.id == '5I:1:1',
|
||||
controller.unassigned_physical_drives)[0]
|
||||
self.assertEqual(controller, physical_drive.parent)
|
||||
self.assertEqual(600, physical_drive.size_gb)
|
||||
self.assertEqual(types.INTERFACE_TYPE_SAS,
|
||||
self.assertEqual(500, physical_drive.size_gb)
|
||||
self.assertEqual(constants.INTERFACE_TYPE_SAS,
|
||||
physical_drive.interface_type)
|
||||
self.assertEqual(types.DISK_TYPE_HDD,
|
||||
self.assertEqual(constants.DISK_TYPE_HDD,
|
||||
physical_drive.disk_type)
|
||||
|
||||
def test_server_object_one_logical_drive(self, get_all_details_mock):
|
||||
@@ -82,20 +82,20 @@ class ServerTest(testtools.TestCase):
|
||||
self.assertEqual('1', logical_drive.id)
|
||||
self.assertEqual(logical_drive.parent, array)
|
||||
self.assertEqual(558, logical_drive.size_gb)
|
||||
self.assertEqual(types.RAID_1, logical_drive.raid_level)
|
||||
self.assertEqual(constants.RAID_1, logical_drive.raid_level)
|
||||
self.assertIsInstance(logical_drive.properties, dict)
|
||||
|
||||
# Assertion on physical drives of array
|
||||
physical_drive = filter(lambda x: x.id == '5I:1:1',
|
||||
array.physical_drives)[0]
|
||||
self.assertEqual(array, physical_drive.parent)
|
||||
self.assertEqual(600, physical_drive.size_gb)
|
||||
self.assertEqual(500, physical_drive.size_gb)
|
||||
|
||||
# Assertion on physical drives of controller
|
||||
physical_drive = filter(lambda x: x.id == '5I:1:3',
|
||||
controller.unassigned_physical_drives)[0]
|
||||
self.assertEqual(controller, physical_drive.parent)
|
||||
self.assertEqual(600, physical_drive.size_gb)
|
||||
self.assertEqual(400, physical_drive.size_gb)
|
||||
|
||||
def test_get_controller_by_id(self, get_all_details_mock):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user