Source code for ironic.drivers.modules.ucs.power

#    Copyright 2015, Cisco Systems.

#    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.

"""
Ironic Cisco UCSM interfaces.
Provides basic power control of servers managed by Cisco UCSM using PyUcs Sdk.
"""

from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import importutils

from ironic.common import exception
from ironic.common.i18n import _, _LE
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conf import CONF
from ironic.drivers import base
from ironic.drivers.modules.ucs import helper as ucs_helper

ucs_power = importutils.try_import('UcsSdk.utils.power')
ucs_error = importutils.try_import('UcsSdk.utils.exception')

LOG = logging.getLogger(__name__)

UCS_TO_IRONIC_POWER_STATE = {
    'up': states.POWER_ON,
    'down': states.POWER_OFF,
}

IRONIC_TO_UCS_POWER_STATE = {
    states.POWER_ON: 'up',
    states.POWER_OFF: 'down',
    states.REBOOT: 'hard-reset-immediate'
}


def _wait_for_state_change(target_state, ucs_power_handle):
    """Wait and check for the power state change."""
    state = [None]
    retries = [0]

    def _wait(state, retries):
        state[0] = ucs_power_handle.get_power_state()
        if ((retries[0] != 0) and (
           UCS_TO_IRONIC_POWER_STATE.get(state[0]) == target_state)):
            raise loopingcall.LoopingCallDone()

        if retries[0] > CONF.cisco_ucs.max_retry:
            state[0] = states.ERROR
            raise loopingcall.LoopingCallDone()

        retries[0] += 1

    timer = loopingcall.FixedIntervalLoopingCall(_wait, state, retries)
    timer.start(interval=CONF.cisco_ucs.action_interval).wait()
    return UCS_TO_IRONIC_POWER_STATE.get(state[0], states.ERROR)


[docs]class Power(base.PowerInterface): """Cisco Power Interface. This PowerInterface class provides a mechanism for controlling the power state of servers managed by Cisco UCS Manager. """
[docs] def get_properties(self): """Returns common properties of the driver.""" return ucs_helper.COMMON_PROPERTIES
[docs] def validate(self, task): """Check that node 'driver_info' is valid. Check that node 'driver_info' contains the required fields. :param task: instance of `ironic.manager.task_manager.TaskManager`. :raises: MissingParameterValue if required CiscoDriver parameters are missing. """ ucs_helper.parse_driver_info(task.node)
@ucs_helper.requires_ucs_client
[docs] def get_power_state(self, task, helper=None): """Get the current power state. Poll the host for the current power state of the node. :param task: instance of `ironic.manager.task_manager.TaskManager`. :param helper: ucs helper instance :raises: MissingParameterValue if required CiscoDriver parameters are missing. :raises: UcsOperationError on error from UCS Client. :returns: power state. One of :class:`ironic.common.states`. """ try: power_handle = ucs_power.UcsPower(helper) power_status = power_handle.get_power_state() except ucs_error.UcsOperationError as ucs_exception: LOG.error(_LE("%(driver)s: get_power_state operation failed for " "node %(uuid)s with error: %(msg)s."), {'driver': task.node.driver, 'uuid': task.node.uuid, 'msg': ucs_exception}) operation = _('getting power status') raise exception.UcsOperationError(operation=operation, error=ucs_exception, node=task.node.uuid) return UCS_TO_IRONIC_POWER_STATE.get(power_status, states.ERROR)
@task_manager.require_exclusive_lock @ucs_helper.requires_ucs_client
[docs] def set_power_state(self, task, pstate, helper=None): """Turn the power on or off. Set the power state of a node. :param task: instance of `ironic.manager.task_manager.TaskManager`. :param pstate: Either POWER_ON or POWER_OFF from :class: `ironic.common.states`. :param helper: ucs helper instance :raises: InvalidParameterValue if an invalid power state was specified. :raises: MissingParameterValue if required CiscoDriver parameters are missing. :raises: UcsOperationError on error from UCS Client. :raises: PowerStateFailure if the desired power state couldn't be set. """ if pstate not in (states.POWER_ON, states.POWER_OFF): msg = _("set_power_state called with invalid power state " "'%s'") % pstate raise exception.InvalidParameterValue(msg) try: ucs_power_handle = ucs_power.UcsPower(helper) power_status = ucs_power_handle.get_power_state() if UCS_TO_IRONIC_POWER_STATE.get(power_status) != pstate: ucs_power_handle.set_power_state( IRONIC_TO_UCS_POWER_STATE.get(pstate)) else: return except ucs_error.UcsOperationError as ucs_exception: LOG.error(_LE("%(driver)s: set_power_state operation failed for " "node %(uuid)s with error: %(msg)s."), {'driver': task.node.driver, 'uuid': task.node.uuid, 'msg': ucs_exception}) operation = _("setting power status") raise exception.UcsOperationError(operation=operation, error=ucs_exception, node=task.node.uuid) state = _wait_for_state_change(pstate, ucs_power_handle) if state != pstate: timeout = CONF.cisco_ucs.action_interval * CONF.cisco_ucs.max_retry LOG.error(_LE("%(driver)s: driver failed to change node %(uuid)s " "power state to %(state)s within %(timeout)s " "seconds."), {'driver': task.node.driver, 'uuid': task.node.uuid, 'state': pstate, 'timeout': timeout}) raise exception.PowerStateFailure(pstate=pstate)
@task_manager.require_exclusive_lock @ucs_helper.requires_ucs_client
[docs] def reboot(self, task, helper=None): """Cycles the power to a node. :param task: a TaskManager instance. :param helper: ucs helper instance. :raises: UcsOperationError on error from UCS Client. :raises: PowerStateFailure if the final state of the node is not POWER_ON. """ try: ucs_power_handle = ucs_power.UcsPower(helper) ucs_power_handle.reboot() except ucs_error.UcsOperationError as ucs_exception: LOG.error(_LE("%(driver)s: driver failed to reset node %(uuid)s " "power state."), {'driver': task.node.driver, 'uuid': task.node.uuid}) operation = _("rebooting") raise exception.UcsOperationError(operation=operation, error=ucs_exception, node=task.node.uuid) state = _wait_for_state_change(states.POWER_ON, ucs_power_handle) if state != states.POWER_ON: timeout = CONF.cisco_ucs.action_interval * CONF.cisco_ucs.max_retry LOG.error(_LE("%(driver)s: driver failed to reboot node %(uuid)s " "within %(timeout)s seconds."), {'driver': task.node.driver, 'uuid': task.node.uuid, 'timeout': timeout}) raise exception.PowerStateFailure(pstate=states.POWER_ON)