Merge "Ironic: Add soft reboot support to ironic driver"
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user