276 lines
12 KiB
Python
276 lines
12 KiB
Python
# Copyright 2018 Hewlett Packard Enterprise Development LP
|
|
#
|
|
# 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.
|
|
|
|
"""
|
|
iLO5 RAID specific methods
|
|
"""
|
|
|
|
from ironic_lib import metrics_utils
|
|
from oslo_log import log as logging
|
|
from oslo_utils import importutils
|
|
|
|
from ironic.common import exception
|
|
from ironic.common.i18n import _
|
|
from ironic.common import raid
|
|
from ironic.common import states
|
|
from ironic.conductor import utils as manager_utils
|
|
from ironic import conf
|
|
from ironic.drivers import base
|
|
from ironic.drivers.modules import deploy_utils
|
|
from ironic.drivers.modules.ilo import common as ilo_common
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
CONF = conf.CONF
|
|
METRICS = metrics_utils.get_metrics_logger(__name__)
|
|
|
|
ilo_error = importutils.try_import('proliantutils.exception')
|
|
|
|
|
|
class Ilo5RAID(base.RAIDInterface):
|
|
"""Implementation of OOB RAIDInterface for iLO5."""
|
|
|
|
_RAID_APPLY_CONFIGURATION_ARGSINFO = {
|
|
"raid_config": {
|
|
"description": "The RAID configuration to apply.",
|
|
"required": True,
|
|
},
|
|
"create_root_volume": {
|
|
"description": (
|
|
"Setting this to 'False' indicates not to create root "
|
|
"volume that is specified in 'raid_config'. Default "
|
|
"value is 'True'."
|
|
),
|
|
"required": False,
|
|
},
|
|
"create_nonroot_volumes": {
|
|
"description": (
|
|
"Setting this to 'False' indicates not to create "
|
|
"non-root volumes (all except the root volume) in "
|
|
"'raid_config'. Default value is 'True'."
|
|
),
|
|
"required": False,
|
|
}
|
|
}
|
|
|
|
def get_properties(self):
|
|
"""Return the properties of the interface."""
|
|
return ilo_common.REQUIRED_PROPERTIES
|
|
|
|
def _set_step_failed(self, task, msg, exc):
|
|
LOG.error("RAID configuration job failed for node %(node)s. "
|
|
"Message: '%(message)s'.",
|
|
{'node': task.node.uuid, 'message': msg})
|
|
if task.node.provision_state == states.DEPLOYING:
|
|
manager_utils.deploying_error_handler(task, msg)
|
|
else:
|
|
manager_utils.cleaning_error_handler(task, msg)
|
|
|
|
def _set_driver_internal_true_value(self, task, *keys):
|
|
driver_internal_info = task.node.driver_internal_info
|
|
for key in keys:
|
|
driver_internal_info[key] = True
|
|
task.node.driver_internal_info = driver_internal_info
|
|
task.node.save()
|
|
|
|
def _set_driver_internal_false_value(self, task, *keys):
|
|
driver_internal_info = task.node.driver_internal_info
|
|
for key in keys:
|
|
driver_internal_info[key] = False
|
|
task.node.driver_internal_info = driver_internal_info
|
|
task.node.save()
|
|
|
|
def _pop_driver_internal_values(self, task, *keys):
|
|
driver_internal_info = task.node.driver_internal_info
|
|
for key in keys:
|
|
driver_internal_info.pop(key, None)
|
|
task.node.driver_internal_info = driver_internal_info
|
|
task.node.save()
|
|
|
|
def _prepare_for_read_raid(self, task, raid_step):
|
|
deploy_opts = deploy_utils.build_agent_options(task.node)
|
|
task.driver.boot.prepare_ramdisk(task, deploy_opts)
|
|
manager_utils.node_power_action(task, states.REBOOT)
|
|
if raid_step == 'create_raid':
|
|
self._set_driver_internal_true_value(
|
|
task, 'ilo_raid_create_in_progress')
|
|
else:
|
|
self._set_driver_internal_true_value(
|
|
task, 'ilo_raid_delete_in_progress')
|
|
deploy_utils.set_async_step_flags(task.node, reboot=True,
|
|
skip_current_step=False)
|
|
|
|
@base.deploy_step(priority=0,
|
|
argsinfo=_RAID_APPLY_CONFIGURATION_ARGSINFO)
|
|
def apply_configuration(self, task, raid_config, create_root_volume=True,
|
|
create_nonroot_volumes=False):
|
|
return super(Ilo5RAID, self).apply_configuration(
|
|
task, raid_config, create_root_volume=create_root_volume,
|
|
create_nonroot_volumes=create_nonroot_volumes)
|
|
|
|
@METRICS.timer('Ilo5RAID.create_configuration')
|
|
@base.clean_step(priority=0, abortable=False, argsinfo={
|
|
'create_root_volume': {
|
|
'description': (
|
|
'This specifies whether to create the root volume. '
|
|
'Defaults to `True`.'
|
|
),
|
|
'required': False
|
|
},
|
|
'create_nonroot_volumes': {
|
|
'description': (
|
|
'This specifies whether to create the non-root volumes. '
|
|
'Defaults to `True`.'
|
|
),
|
|
'required': False
|
|
}
|
|
})
|
|
def create_configuration(self, task, create_root_volume=True,
|
|
create_nonroot_volumes=True):
|
|
"""Create a RAID configuration on a bare metal using agent ramdisk.
|
|
|
|
This method creates a RAID configuration on the given node.
|
|
|
|
:param task: a TaskManager instance.
|
|
:param create_root_volume: If True, a root volume is created
|
|
during RAID configuration. Otherwise, no root volume is
|
|
created. Default is True.
|
|
:param create_nonroot_volumes: If True, non-root volumes are
|
|
created. If False, no non-root volumes are created. Default
|
|
is True.
|
|
:raises: MissingParameterValue, if node.target_raid_config is missing
|
|
or was found to be empty after skipping root volume and/or non-root
|
|
volumes.
|
|
:raises: NodeCleaningFailure, on failure to execute clean step.
|
|
:raises: InstanceDeployFailure, on failure to execute deploy step.
|
|
"""
|
|
node = task.node
|
|
target_raid_config = raid.filter_target_raid_config(
|
|
node, create_root_volume=create_root_volume,
|
|
create_nonroot_volumes=create_nonroot_volumes)
|
|
driver_internal_info = node.driver_internal_info
|
|
driver_internal_info['target_raid_config'] = target_raid_config
|
|
node.driver_internal_info = driver_internal_info
|
|
node.save()
|
|
LOG.debug("Calling OOB RAID create_configuration for node %(node)s "
|
|
"with the following target RAID configuration: %(target)s",
|
|
{'node': node.uuid, 'target': target_raid_config})
|
|
ilo_object = ilo_common.get_ilo_object(node)
|
|
|
|
try:
|
|
# Raid configuration in progress, checking status
|
|
if not driver_internal_info.get('ilo_raid_create_in_progress'):
|
|
ilo_object.create_raid_configuration(target_raid_config)
|
|
self._prepare_for_read_raid(task, 'create_raid')
|
|
return deploy_utils.get_async_step_return_state(node)
|
|
else:
|
|
# Raid configuration is done, updating raid_config
|
|
raid_conf = (
|
|
ilo_object.read_raid_configuration(
|
|
raid_config=target_raid_config))
|
|
fields = ['ilo_raid_create_in_progress']
|
|
if node.clean_step:
|
|
fields.append('skip_current_clean_step')
|
|
else:
|
|
fields.append('skip_current_deploy_step')
|
|
self._pop_driver_internal_values(task, *fields)
|
|
if len(raid_conf['logical_disks']):
|
|
raid.update_raid_info(node, raid_conf)
|
|
LOG.debug("Node %(uuid)s raid create clean step is done.",
|
|
{'uuid': node.uuid})
|
|
else:
|
|
# Raid configuration failed
|
|
msg = (_("Step create_configuration failed "
|
|
"on node %(node)s with error: "
|
|
"Unable to create raid")
|
|
% {'node': node.uuid})
|
|
if node.clean_step:
|
|
raise exception.NodeCleaningFailure(msg)
|
|
else:
|
|
raise exception.InstanceDeployFailure(reason=msg)
|
|
except ilo_error.IloError as ilo_exception:
|
|
operation = (_("Failed to create raid configuration on node %s")
|
|
% node.uuid)
|
|
fields = ['ilo_raid_create_in_progress']
|
|
if node.clean_step:
|
|
fields.append('skip_current_clean_step')
|
|
else:
|
|
fields.append('skip_current_deploy_step')
|
|
self._pop_driver_internal_values(task, *fields)
|
|
self._set_step_failed(task, operation, ilo_exception)
|
|
|
|
@METRICS.timer('Ilo5RAID.delete_configuration')
|
|
@base.clean_step(priority=0, abortable=False)
|
|
@base.deploy_step(priority=0)
|
|
def delete_configuration(self, task):
|
|
"""Delete the RAID configuration.
|
|
|
|
:param task: a TaskManager instance containing the node to act on.
|
|
:raises: NodeCleaningFailure, on failure to execute clean step.
|
|
:raises: InstanceDeployFailure, on failure to execute deploy step.
|
|
"""
|
|
node = task.node
|
|
LOG.debug("OOB RAID delete_configuration invoked for node %s.",
|
|
node.uuid)
|
|
driver_internal_info = node.driver_internal_info
|
|
ilo_object = ilo_common.get_ilo_object(node)
|
|
|
|
try:
|
|
# Raid configuration in progress, checking status
|
|
if not driver_internal_info.get('ilo_raid_delete_in_progress'):
|
|
ilo_object.delete_raid_configuration()
|
|
self._prepare_for_read_raid(task, 'delete_raid')
|
|
return deploy_utils.get_async_step_return_state(node)
|
|
else:
|
|
# Raid configuration is done, updating raid_config
|
|
raid_conf = ilo_object.read_raid_configuration()
|
|
fields = ['ilo_raid_delete_in_progress']
|
|
if node.clean_step:
|
|
fields.append('skip_current_clean_step')
|
|
else:
|
|
fields.append('skip_current_deploy_step')
|
|
self._pop_driver_internal_values(task, *fields)
|
|
if not len(raid_conf['logical_disks']):
|
|
node.raid_config = {}
|
|
LOG.debug("Node %(uuid)s raid delete clean step is done.",
|
|
{'uuid': node.uuid})
|
|
else:
|
|
# Raid configuration failed
|
|
err_msg = (_("Step delete_configuration failed "
|
|
"on node %(node)s with error: "
|
|
"Unable to delete these logical disks: "
|
|
"%(disks)s")
|
|
% {'node': node.uuid,
|
|
'disks': raid_conf['logical_disks']})
|
|
if node.clean_step:
|
|
raise exception.NodeCleaningFailure(err_msg)
|
|
else:
|
|
raise exception.InstanceDeployFailure(reason=err_msg)
|
|
except ilo_error.IloLogicalDriveNotFoundError:
|
|
LOG.info("No logical drive found to delete on node %(node)s",
|
|
{'node': node.uuid})
|
|
except ilo_error.IloError as ilo_exception:
|
|
operation = (_("Failed to delete raid configuration on node %s")
|
|
% node.uuid)
|
|
self._pop_driver_internal_values(task,
|
|
'ilo_raid_delete_in_progress',
|
|
'skip_current_clean_step')
|
|
fields = ['ilo_raid_delete_in_progress']
|
|
if node.clean_step:
|
|
fields.append('skip_current_clean_step')
|
|
else:
|
|
fields.append('skip_current_deploy_step')
|
|
self._pop_driver_internal_values(task, *fields)
|
|
self._set_step_failed(task, operation, ilo_exception)
|