Add a test for destroying an instance when in rescue mode

A previous commit added some code to delete the rescued comtainer
when the instance was in rescue mode.  This means that there are two
containers for the instance (and thus using the profile).  However, no
test was added at that stage.  This patchset adds a test to verify that
the containers do get deleted and modifies the destroy code to also
ensure that the rescue container is also stopped before deletion.

Change-Id: I586261f25e8c8b9b8acdba6cafe67491bd55b46a
This commit is contained in:
Alex Kavanagh 2018-02-27 11:02:14 +00:00
parent 41f17f418c
commit 6b56b30e8b
2 changed files with 46 additions and 7 deletions

View File

@ -26,6 +26,7 @@ from nova import utils
from nova import test
from nova.compute import manager
from nova.compute import power_state
from nova.compute import vm_states
from nova.network import model as network_model
from nova.tests.unit import fake_instance
from pylxd import exceptions as lxdcore_exceptions
@ -544,6 +545,40 @@ class LXDDriverTest(test.NoDBTestCase):
mock_container.stop.assert_called_once_with(wait=True)
mock_container.delete.assert_called_once_with(wait=True)
def test_destroy_when_in_rescue(self):
mock_stopped_container = mock.Mock()
mock_stopped_container.status = 'Stopped'
mock_rescued_container = mock.Mock()
mock_rescued_container.status = 'Running'
ctx = context.get_admin_context()
instance = fake_instance.fake_instance_obj(
ctx, name='test', memory_mb=0)
network_info = [_VIF]
lxd_driver = driver.LXDDriver(None)
lxd_driver.init_host(None)
lxd_driver.cleanup = mock.Mock()
# set the vm_state on the fake instance to RESCUED
instance.vm_state = vm_states.RESCUED
# set up the containers.get to return the stopped container and then
# the rescued container
self.client.containers.get.side_effect = [
mock_stopped_container, mock_rescued_container]
lxd_driver.destroy(ctx, instance, network_info)
lxd_driver.cleanup.assert_called_once_with(
ctx, instance, network_info, None)
lxd_driver.client.containers.get.assert_has_calls([
mock.call(instance.name),
mock.call('{}-rescue'.format(instance.name))])
mock_stopped_container.stop.assert_not_called()
mock_stopped_container.delete.assert_called_once_with(wait=True)
mock_rescued_container.stop.assert_called_once_with(wait=True)
mock_rescued_container.delete.assert_called_once_with(wait=True)
def test_destroy_without_instance(self):
def side_effect(*args, **kwargs):
raise lxdcore_exceptions.LXDAPIException(MockResponse(404))

View File

@ -613,6 +613,8 @@ class LXDDriver(driver.ComputeDriver):
if (instance.vm_state == vm_states.RESCUED):
rescued_container = self.client.containers.get(
'%s-rescue' % instance.name)
if rescued_container.status != 'Stopped':
rescued_container.stop(wait=True)
rescued_container.delete(wait=True)
except lxd_exceptions.LXDAPIException as e:
if e.response.status_code == 404:
@ -890,13 +892,15 @@ class LXDDriver(driver.ComputeDriver):
rescue_password):
"""Rescue a LXD container.
Rescuing a instance requires a number of steps. First,
the failed container is stopped. Next, '-rescue', is
appended to the failed container's name, this is done
so the container can be unrescued. The container's
profile is updated with the rootfs of the
failed container. Finally, a new container
is created and started.
From the perspective of nova, rescuing a instance requires a number of
steps. First, the failed container is stopped, and then this method is
called.
So the original container is already stopped, and thus, next,
'-rescue', is appended to the failed container's name, this is done so
the container can be unrescued. The container's profile is updated with
the rootfs of the failed container. Finally, a new container is created
and started.
See 'nova.virt.driver.ComputeDriver.rescue` for more
information.