Correctly reset instance task state in rebooting hard
When a user ask for a reboot hard of a running instance while nova compute is unavailable (service stopped or host down) it might happens under certain conditions that the instance stays in rebooting_hard task_state after nova-compute start again. This patch aims to fix that. Closes-Bug: #1999674 Change-Id: I170e390fe4e467898a8dc7df6a446f62941d49ff
This commit is contained in:
parent
e5766446e5
commit
aa3e8fef7b
@ -1155,6 +1155,8 @@ class ComputeManager(manager.Manager):
|
||||
try_reboot, reboot_type = self._retry_reboot(
|
||||
instance, current_power_state)
|
||||
|
||||
# NOTE(amorin)
|
||||
# If the instance is in power_state_SHUTDOWN, we will try_reboot
|
||||
if try_reboot:
|
||||
LOG.debug("Instance in transitional state (%(task_state)s) at "
|
||||
"start-up and power state is (%(power_state)s), "
|
||||
@ -1177,9 +1179,14 @@ class ComputeManager(manager.Manager):
|
||||
reboot_type=reboot_type)
|
||||
return
|
||||
|
||||
# NOTE(plestang): an instance might be in power_state.RUNNING with a
|
||||
# transient state when a host is brutally shutdown or rebooted while a
|
||||
# reboot/pause/unpause is scheduled on client side
|
||||
elif (current_power_state == power_state.RUNNING and
|
||||
instance.task_state in [task_states.REBOOT_STARTED,
|
||||
task_states.REBOOT_STARTED_HARD,
|
||||
task_states.REBOOTING_HARD,
|
||||
task_states.REBOOTING,
|
||||
task_states.PAUSING,
|
||||
task_states.UNPAUSING]):
|
||||
LOG.warning("Instance in transitional state "
|
||||
@ -1339,7 +1346,9 @@ class ComputeManager(manager.Manager):
|
||||
current_task_state == task_states.REBOOT_PENDING_HARD and
|
||||
instance.vm_state in vm_states.ALLOW_HARD_REBOOT)
|
||||
started_not_running = (current_task_state in
|
||||
[task_states.REBOOT_STARTED,
|
||||
[task_states.REBOOTING,
|
||||
task_states.REBOOTING_HARD,
|
||||
task_states.REBOOT_STARTED,
|
||||
task_states.REBOOT_STARTED_HARD] and
|
||||
current_power_state != power_state.RUNNING)
|
||||
|
||||
|
@ -2185,18 +2185,30 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
instance.host = self.compute.host
|
||||
with test.nested(
|
||||
mock.patch.object(self.compute, '_get_power_state',
|
||||
return_value=power_state.RUNNING),
|
||||
return_value=instance.power_state),
|
||||
mock.patch.object(instance, 'save', autospec=True),
|
||||
mock.patch.object(objects.Instance, 'get_network_info')
|
||||
mock.patch.object(objects.Instance, 'get_network_info'),
|
||||
mock.patch.object(self.compute, 'reboot_instance'),
|
||||
) as (
|
||||
_get_power_state,
|
||||
instance_save,
|
||||
get_network_info
|
||||
get_network_info,
|
||||
reboot_instance,
|
||||
):
|
||||
self.compute._init_instance(self.context, instance)
|
||||
instance_save.assert_called_once_with()
|
||||
self.assertIsNone(instance.task_state)
|
||||
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
|
||||
# If instance was running, the instance should stay running,
|
||||
# and tasks are discarded
|
||||
if instance.power_state == power_state.RUNNING:
|
||||
instance_save.assert_called_once_with()
|
||||
self.assertIsNone(instance.task_state)
|
||||
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
|
||||
# If instance was not running, but we request to reboot it,
|
||||
# we should try a reboot
|
||||
else:
|
||||
call = mock.call(self.context, instance,
|
||||
block_device_info=None, reboot_type=mock.ANY)
|
||||
reboot_instance.assert_has_calls([call])
|
||||
self.assertEqual(vm_states.STOPPED, instance.vm_state)
|
||||
|
||||
def test_init_instance_cleans_image_state_reboot_started(self):
|
||||
instance = objects.Instance(self.context)
|
||||
@ -2214,37 +2226,13 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
instance.power_state = power_state.RUNNING
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def _test_init_instance_cleans_reboot_state_reproducer(self, instance,
|
||||
task_state):
|
||||
instance.host = self.compute.host
|
||||
with test.nested(
|
||||
mock.patch.object(self.compute, '_get_power_state',
|
||||
return_value=power_state.RUNNING),
|
||||
mock.patch.object(instance, 'save', autospec=True),
|
||||
mock.patch.object(objects.Instance, 'get_network_info')
|
||||
) as (
|
||||
_get_power_state,
|
||||
instance_save,
|
||||
get_network_info
|
||||
):
|
||||
self.compute._init_instance(self.context, instance)
|
||||
# By checking save method is not called we confirm that the init
|
||||
# instance does not take into account this use case
|
||||
instance_save.assert_not_called()
|
||||
# So the instance task_state is still task_state
|
||||
self.assertEqual(task_state, instance.task_state)
|
||||
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
|
||||
|
||||
def test_init_instance_cleans_image_state_rebooting(self):
|
||||
instance = objects.Instance(self.context)
|
||||
instance.uuid = uuids.instance
|
||||
instance.vm_state = vm_states.ACTIVE
|
||||
instance.task_state = task_states.REBOOTING
|
||||
instance.power_state = power_state.RUNNING
|
||||
# To uncomment once bug #1999674 is fixed and remove all the code below
|
||||
# self._test_init_instance_cleans_reboot_state(instance)
|
||||
self._test_init_instance_cleans_reboot_state_reproducer(instance,
|
||||
task_states.REBOOTING)
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def test_init_instance_cleans_image_state_rebooting_hard(self):
|
||||
instance = objects.Instance(self.context)
|
||||
@ -2252,10 +2240,39 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
instance.vm_state = vm_states.ACTIVE
|
||||
instance.task_state = task_states.REBOOTING_HARD
|
||||
instance.power_state = power_state.RUNNING
|
||||
# To uncomment once bug #1999674 is fixed and remove all the code below
|
||||
# self._test_init_instance_cleans_reboot_state(instance)
|
||||
self._test_init_instance_cleans_reboot_state_reproducer(instance,
|
||||
task_states.REBOOTING_HARD)
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def test_init_instance_cleans_shutdown_reboot_started(self):
|
||||
instance = objects.Instance(self.context)
|
||||
instance.uuid = uuids.instance
|
||||
instance.vm_state = vm_states.STOPPED
|
||||
instance.task_state = task_states.REBOOT_STARTED
|
||||
instance.power_state = power_state.SHUTDOWN
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def test_init_instance_cleans_shutdown_reboot_started_hard(self):
|
||||
instance = objects.Instance(self.context)
|
||||
instance.uuid = uuids.instance
|
||||
instance.vm_state = vm_states.STOPPED
|
||||
instance.task_state = task_states.REBOOT_STARTED_HARD
|
||||
instance.power_state = power_state.SHUTDOWN
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def test_init_instance_cleans_shutdown_rebooting(self):
|
||||
instance = objects.Instance(self.context)
|
||||
instance.uuid = uuids.instance
|
||||
instance.vm_state = vm_states.STOPPED
|
||||
instance.task_state = task_states.REBOOTING
|
||||
instance.power_state = power_state.SHUTDOWN
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def test_init_instance_cleans_shutdown_rebooting_hard(self):
|
||||
instance = objects.Instance(self.context)
|
||||
instance.uuid = uuids.instance
|
||||
instance.vm_state = vm_states.STOPPED
|
||||
instance.task_state = task_states.REBOOTING_HARD
|
||||
instance.power_state = power_state.SHUTDOWN
|
||||
self._test_init_instance_cleans_reboot_state(instance)
|
||||
|
||||
def test_init_instance_retries_power_off(self):
|
||||
instance = objects.Instance(self.context)
|
||||
|
Loading…
Reference in New Issue
Block a user