1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
# 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)
|