Files
deb-python-proliantutils/proliantutils/hpssa/disk_allocator.py
Ramakrishnan G 1f9cf46a37 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
2015-09-22 02:06:40 -07:00

128 lines
5.5 KiB
Python

# 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_object in physical_drives:
for criteria in criteria_to_consider:
logical_drive_value = logical_disk.get(criteria)
physical_drive_value = getattr(physical_drive_object, criteria)
if logical_drive_value != physical_drive_value:
break
else:
matching_physical_drives.append(physical_drive_object)
return matching_physical_drives
def allocate_disks(logical_disk, server, raid_config):
"""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
:param raid_config: The target RAID configuration requested.
: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)
# Try to create a new independent array for this request.
for controller in server.controllers:
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,
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]
logical_disk['physical_disks'] = physical_disks
return
# We didn't find physical disks to create an independent array.
# Check if we can get some shared arrays.
if share_physical_disks:
sharable_disk_wwns = []
for sharable_logical_disk in raid_config['logical_disks']:
if (sharable_logical_disk.get('share_physical_disks', False) and
'root_device_hint' in sharable_logical_disk):
wwn = sharable_logical_disk['root_device_hint']['wwn']
sharable_disk_wwns.append(wwn)
for controller in server.controllers:
sharable_arrays = [x for x in controller.raid_arrays if
x.logical_drives[0].wwn in sharable_disk_wwns]
for array in sharable_arrays:
# Check if criterias for the logical disk match the ones with
# physical disks in the raid array.
criteria_matched_disks = _get_criteria_matching_disks(
logical_disk, array.physical_drives)
# Check if all disks in the array don't match the criteria
if len(criteria_matched_disks) != len(array.physical_drives):
continue
# Check if raid array can accomodate the logical disk.
if array.can_accomodate(logical_disk):
logical_disk['controller'] = controller.id
logical_disk['array'] = array.id
return
# We check both options and couldn't get any physical disks.
raise exception.PhysicalDisksNotFoundError(size_gb=size_gb,
raid_level=raid_level)