129 lines
5.1 KiB
Python
129 lines
5.1 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.
|
|
|
|
import datetime
|
|
|
|
import jsonschema
|
|
from jsonschema import exceptions as json_schema_exc
|
|
|
|
from ironic.common import exception
|
|
from ironic.common.i18n import _
|
|
from ironic.common import utils
|
|
|
|
|
|
def _check_and_return_root_volumes(raid_config):
|
|
"""Returns root logical disks after validating RAID config.
|
|
|
|
This method checks if multiple logical disks had 'is_root_volume'
|
|
set to True and raises an exception if it is True. Otherwise,
|
|
returns the root logical disk mentioned in the RAID config.
|
|
|
|
:param raid_config: target RAID configuration or current RAID
|
|
configuration.
|
|
:returns: the dictionary for the root logical disk if it is
|
|
present, otherwise None.
|
|
:raises: InvalidParameterValue, if there were more than one
|
|
root volume specified in the RAID configuration.
|
|
"""
|
|
logical_disks = raid_config['logical_disks']
|
|
root_logical_disks = [x for x in logical_disks if x.get('is_root_volume')]
|
|
if len(root_logical_disks) > 1:
|
|
msg = _("Raid config cannot have more than one root volume. "
|
|
"%d root volumes were specified") % len(root_logical_disks)
|
|
raise exception.InvalidParameterValue(msg)
|
|
|
|
if root_logical_disks:
|
|
return root_logical_disks[0]
|
|
|
|
|
|
def validate_configuration(raid_config, raid_config_schema):
|
|
"""Validates the RAID configuration passed using JSON schema.
|
|
|
|
This method validates a RAID configuration against a RAID configuration
|
|
schema.
|
|
|
|
:param raid_config: A dictionary containing RAID configuration information
|
|
:param raid_config_schema: A dictionary which is the schema to be used for
|
|
validation.
|
|
:raises: InvalidParameterValue, if validation of the RAID configuration
|
|
fails.
|
|
"""
|
|
try:
|
|
jsonschema.validate(raid_config, raid_config_schema)
|
|
except json_schema_exc.ValidationError as e:
|
|
# NOTE: Even though e.message is deprecated in general, it is said
|
|
# in jsonschema documentation to use this still.
|
|
msg = _("RAID config validation error: %s") % e.message
|
|
raise exception.InvalidParameterValue(msg)
|
|
|
|
# Check if there are multiple root volumes specified.
|
|
_check_and_return_root_volumes(raid_config)
|
|
|
|
|
|
def get_logical_disk_properties(raid_config_schema):
|
|
"""Get logical disk properties from RAID configuration schema.
|
|
|
|
This method reads the logical properties and their textual description
|
|
from the schema that is passed.
|
|
|
|
:param raid_config_schema: A dictionary which is the schema to be used for
|
|
getting properties that may be specified for the logical disk.
|
|
:returns: A dictionary containing the logical disk properties as keys
|
|
and a textual description for them as values.
|
|
"""
|
|
logical_disk_schema = raid_config_schema['properties']['logical_disks']
|
|
properties = logical_disk_schema['items']['properties']
|
|
return {prop: prop_dict['description']
|
|
for prop, prop_dict in properties.items()}
|
|
|
|
|
|
def update_raid_info(node, raid_config):
|
|
"""Update the node's information based on the RAID config.
|
|
|
|
This method updates the node's information to make use of the configured
|
|
RAID for scheduling purposes (through properties['capabilities'] and
|
|
properties['local_gb']) and deploying purposes (using
|
|
properties['root_device']).
|
|
|
|
:param node: a node object
|
|
:param raid_config: The dictionary containing the current RAID
|
|
configuration.
|
|
:raises: InvalidParameterValue, if 'raid_config' has more than
|
|
one root volume or if node.properties['capabilities'] is malformed.
|
|
"""
|
|
current = raid_config.copy()
|
|
current['last_updated'] = str(datetime.datetime.utcnow())
|
|
node.raid_config = current
|
|
|
|
# Current RAID configuration can have 0 or 1 root volumes. If there
|
|
# are > 1 root volumes, then it's invalid. We check for this condition
|
|
# while accepting target RAID configuration, but this check is just in
|
|
# place, if some drivers pass > 1 root volumes to this method.
|
|
root_logical_disk = _check_and_return_root_volumes(raid_config)
|
|
if root_logical_disk:
|
|
# Update local_gb and root_device_hint
|
|
properties = node.properties
|
|
properties['local_gb'] = root_logical_disk['size_gb']
|
|
try:
|
|
properties['root_device'] = (
|
|
root_logical_disk['root_device_hint'])
|
|
except KeyError:
|
|
pass
|
|
properties['capabilities'] = utils.get_updated_capabilities(
|
|
properties.get('capabilities', ''),
|
|
{'raid_level': root_logical_disk['raid_level']})
|
|
node.properties = properties
|
|
|
|
node.save()
|