Ironic: Add soft reboot support to ironic driver

This patch gets Ironic virt driver to support soft reboot.

Ironic API supports soft reboot since  API version 1.27. The API
version has already been bumped to 1.28.

Change-Id: I4e61ebf852f61e3c0a511b49f0304d3138ef022e
Implements: blueprint soft-reboot-poweroff
Co-Authored-By: Tang Chen <chen.tang@easystack.cn>
Co-Authored-By: xiexs <xiexs@cn.fujitsu.com>
This commit is contained in:
Hironori Shiina 2016-12-14 12:51:27 +00:00 committed by Matt Riedemann
parent 32e2654152
commit f3c774a96b
4 changed files with 64 additions and 10 deletions

View File

@ -1336,9 +1336,42 @@ class IronicDriverTestCase(test.NoDBTestCase):
mock_looping.return_value = fake_looping_call
instance = fake_instance.fake_instance_obj(self.ctx,
node=node.uuid)
self.driver.reboot(self.ctx, instance, None, None)
self.driver.reboot(self.ctx, instance, None, 'HARD')
mock_sp.assert_called_once_with(node.uuid, 'reboot')
@mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
@mock.patch.object(ironic_driver.IronicDriver,
'_validate_instance_and_node')
@mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
def test_reboot_soft(self, mock_sp, fake_validate, mock_looping):
node = ironic_utils.get_test_node()
fake_validate.side_effect = [node, node]
fake_looping_call = FakeLoopingCall()
mock_looping.return_value = fake_looping_call
instance = fake_instance.fake_instance_obj(self.ctx,
node=node.uuid)
self.driver.reboot(self.ctx, instance, None, 'SOFT')
mock_sp.assert_called_once_with(node.uuid, 'reboot', soft=True)
@mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
@mock.patch.object(ironic_driver.IronicDriver,
'_validate_instance_and_node')
@mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
def test_reboot_soft_not_supported(self, mock_sp, fake_validate,
mock_looping):
node = ironic_utils.get_test_node()
fake_validate.side_effect = [node, node]
mock_sp.side_effect = [ironic_exception.BadRequest(), None]
fake_looping_call = FakeLoopingCall()
mock_looping.return_value = fake_looping_call
instance = fake_instance.fake_instance_obj(self.ctx,
node=node.uuid)
self.driver.reboot(self.ctx, instance, None, 'SOFT')
mock_sp.assert_has_calls([mock.call(node.uuid, 'reboot', soft=True),
mock.call(node.uuid, 'reboot')])
@mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
@mock.patch.object(ironic_driver.IronicDriver,
'_validate_instance_and_node')

View File

@ -147,7 +147,7 @@ class FakeNodeClient(object):
def list_ports(self, node_uuid, detail=False):
pass
def set_power_state(self, node_uuid, target):
def set_power_state(self, node_uuid, target, soft=False):
pass
def set_provision_state(self, node_uuid, target):

View File

@ -993,8 +993,6 @@ class IronicDriver(virt_driver.ComputeDriver):
block_device_info=None, bad_volumes_callback=None):
"""Reboot the specified instance.
NOTE: Ironic does not support soft-off, so this method
always performs a hard-reboot.
NOTE: Unlike the libvirt driver, this method does not delete
and recreate the instance; it preserves local state.
@ -1002,23 +1000,40 @@ class IronicDriver(virt_driver.ComputeDriver):
:param instance: The instance object.
:param network_info: Instance network information. Ignored by
this driver.
:param reboot_type: Either a HARD or SOFT reboot. Ignored by
this driver.
:param reboot_type: Either a HARD or SOFT reboot.
:param block_device_info: Info pertaining to attached volumes.
Ignored by this driver.
:param bad_volumes_callback: Function to handle any bad volumes
encountered. Ignored by this driver.
"""
LOG.debug('Reboot called for instance', instance=instance)
LOG.debug('Reboot(type %s) called for instance',
reboot_type, instance=instance)
node = self._validate_instance_and_node(instance)
self.ironicclient.call("node.set_power_state", node.uuid, 'reboot')
hard = True
if reboot_type == 'SOFT':
try:
self.ironicclient.call("node.set_power_state", node.uuid,
'reboot', soft=True)
hard = False
except ironic.exc.BadRequest as exc:
LOG.info(_LI('Soft reboot is not supported by ironic hardware '
'driver. Falling back to hard reboot: %s'),
exc,
instance=instance)
if hard:
self.ironicclient.call("node.set_power_state", node.uuid, 'reboot')
timer = loopingcall.FixedIntervalLoopingCall(
self._wait_for_power_state, instance, 'reboot')
timer.start(interval=CONF.ironic.api_retry_interval).wait()
LOG.info(_LI('Successfully rebooted Ironic node %s'),
node.uuid, instance=instance)
LOG.info(_LI('Successfully rebooted(type %(type)s) Ironic node '
'%(node)s'),
{'type': ('HARD' if hard else 'SOFT'),
'node': node.uuid},
instance=instance)
def power_off(self, instance, timeout=0, retry_interval=0):
"""Power off the specified instance.

View File

@ -0,0 +1,6 @@
---
features:
- Adds soft reboot support to Ironic virt driver. If hardware driver in
Ironic doesn't support soft reboot, hard reboot is tried. This feature
requires the Ironic service to support API version 1.27 or later. It also
requires python-ironicclient >= 1.10.0.