Remove the remainder of the small container methods from session.
In the ongoing effort to remove nova.virt.lxd.session, I've removed more of the smaller container related methods from it, and replaced them with the modern api. `container_init` will require a little more effort to remove, and will need some full migration testing before we remove it. Change-Id: Ieafe916d1da1b0c1a8976d437b94ddd8dfd6bf63
This commit is contained in:
parent
cb0ab27c18
commit
8277d81d03
|
@ -1388,6 +1388,70 @@ class LXDDriverTest(test.NoDBTestCase):
|
|||
'container_format': 'bare'},
|
||||
data)
|
||||
|
||||
def test_finish_revert_migration(self):
|
||||
ctx = context.get_admin_context()
|
||||
instance = fake_instance.fake_instance_obj(ctx, name='test')
|
||||
network_info = []
|
||||
|
||||
container = mock.Mock()
|
||||
self.client.containers.get.return_value = container
|
||||
|
||||
lxd_driver = driver.LXDDriver(None)
|
||||
lxd_driver.init_host(None)
|
||||
|
||||
lxd_driver.finish_revert_migration(ctx, instance, network_info)
|
||||
|
||||
container.start.assert_called_once_with(wait=True)
|
||||
|
||||
def test_check_can_live_migrate_destination(self):
|
||||
ctx = context.get_admin_context()
|
||||
instance = fake_instance.fake_instance_obj(ctx, name='test')
|
||||
src_compute_info = mock.Mock()
|
||||
dst_compute_info = mock.Mock()
|
||||
|
||||
def container_get(*args, **kwargs):
|
||||
raise lxdcore_exceptions.LXDAPIException(MockResponse(404))
|
||||
self.client.containers.get.side_effect = container_get
|
||||
|
||||
lxd_driver = driver.LXDDriver(None)
|
||||
lxd_driver.init_host(None)
|
||||
|
||||
retval = lxd_driver.check_can_live_migrate_destination(
|
||||
ctx, instance, src_compute_info, dst_compute_info)
|
||||
|
||||
self.assertIsInstance(retval, driver.LXDLiveMigrateData)
|
||||
|
||||
def test_confirm_migration(self):
|
||||
migration = mock.Mock()
|
||||
instance = fake_instance.fake_instance_obj(
|
||||
context.get_admin_context, name='test')
|
||||
network_info = []
|
||||
profile = mock.Mock()
|
||||
container = mock.Mock()
|
||||
self.client.profiles.get.return_value = profile
|
||||
self.client.containers.get.return_value = container
|
||||
|
||||
lxd_driver = driver.LXDDriver(None)
|
||||
lxd_driver.init_host(None)
|
||||
|
||||
lxd_driver.confirm_migration(migration, instance, network_info)
|
||||
|
||||
profile.delete.assert_called_once_with()
|
||||
container.delete.assert_called_once_with(wait=True)
|
||||
|
||||
def test_post_live_migration(self):
|
||||
ctx = context.get_admin_context()
|
||||
instance = fake_instance.fake_instance_obj(ctx, name='test')
|
||||
container = mock.Mock()
|
||||
self.client.containers.get.return_value = container
|
||||
|
||||
lxd_driver = driver.LXDDriver(None)
|
||||
lxd_driver.init_host(None)
|
||||
|
||||
lxd_driver.post_live_migration(context, instance, None)
|
||||
|
||||
container.delete.assert_called_once_with(wait=True)
|
||||
|
||||
|
||||
class InstanceAttributesTest(test.NoDBTestCase):
|
||||
"""Tests for InstanceAttributes."""
|
||||
|
|
|
@ -19,47 +19,14 @@ import nova.conf
|
|||
from nova import exception
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit import fake_network
|
||||
import pylxd
|
||||
from pylxd.deprecated import exceptions as lxd_exceptions
|
||||
|
||||
from nova.virt.lxd import driver
|
||||
from nova.virt.lxd import session
|
||||
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
|
||||
class LXDTestContainerMigrate(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LXDTestContainerMigrate, self).setUp()
|
||||
|
||||
self.driver = driver.LXDDriver(None)
|
||||
self.context = 'fake_context'
|
||||
self.driver.session = mock.MagicMock()
|
||||
self.driver.config = mock.MagicMock()
|
||||
self.driver.unplug_vifs = mock.MagicMock()
|
||||
|
||||
@mock.patch.object(session.LXDAPISession, 'container_defined')
|
||||
def test_confirm_migration(self, mock_contaienr_defined):
|
||||
"""Verify that the correct migration container calls
|
||||
are made.
|
||||
"""
|
||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||
fake_network_info = fake_network.fake_get_instance_nw_info
|
||||
self.driver.confirm_migration(
|
||||
mock.sentinel.migration, mock_instance, fake_network_info)
|
||||
self.driver.session.profile_delete.assert_called_once_with(
|
||||
mock_instance
|
||||
)
|
||||
self.driver.session.container_destroy.assert_called_once_with(
|
||||
mock_instance.name, mock_instance
|
||||
)
|
||||
self.driver.unplug_vifs.assert_called_once_with(
|
||||
mock_instance, fake_network_info
|
||||
)
|
||||
|
||||
|
||||
class LXDTestLiveMigrate(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -128,17 +95,6 @@ class LXDTestLiveMigrate(test.NoDBTestCase):
|
|||
mock.sentinel.recover_method, mock.sentinel.block_migration,
|
||||
mock.sentinel.migrate_data)
|
||||
|
||||
def test_post_live_migration(self):
|
||||
"""Verify that the correct post_live_migration calls
|
||||
are made.
|
||||
"""
|
||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||
self.driver.post_live_migration(
|
||||
mock.sentinel.context, mock_instance,
|
||||
mock.sentinel.block_device_info, mock.sentinel.migrate_data)
|
||||
self.driver.session.container_destroy.assert_called_once_with(
|
||||
mock_instance.name, mock_instance)
|
||||
|
||||
def test_live_migration_not_allowed(self):
|
||||
"""Verify an exception is raised when live migration is not allowed."""
|
||||
self.flags(allow_live_migration=False,
|
||||
|
|
|
@ -47,93 +47,6 @@ class SessionContainerTest(test.NoDBTestCase):
|
|||
|
||||
self.session = session.LXDAPISession()
|
||||
|
||||
@stubs.annotated_data(
|
||||
('exists', True),
|
||||
('missing', False),
|
||||
)
|
||||
def test_container_defined(self, tag, side_effect):
|
||||
"""
|
||||
container_defined returns True if the container
|
||||
exists on an LXD host, False otherwise, verify
|
||||
the apporiate return value is returned.
|
||||
"""
|
||||
instance = stubs._fake_instance()
|
||||
self.ml.container_defined.return_value = side_effect
|
||||
if side_effect:
|
||||
self.assertTrue(self.session.container_defined(
|
||||
instance.name, instance))
|
||||
if not side_effect:
|
||||
self.assertFalse(self.session.container_defined(
|
||||
instance.name, instance))
|
||||
|
||||
@stubs.annotated_data(
|
||||
('1', True, (200, fake_api.fake_operation_info_ok()))
|
||||
)
|
||||
def test_container_start(self, tag, defined, side_effect=None):
|
||||
"""
|
||||
containser_start starts a container on a given LXD host.
|
||||
Verify that the correct pyLXD calls are made.
|
||||
"""
|
||||
instance = stubs._fake_instance()
|
||||
self.ml.container_start.return_value = side_effect
|
||||
self.assertEqual(None,
|
||||
self.session.container_start(instance.name,
|
||||
instance))
|
||||
calls = [mock.call.container_start(instance.name, -1),
|
||||
mock.call.wait_container_operation(
|
||||
'/1.0/operation/1234', 200, -1)]
|
||||
self.assertEqual(calls, self.ml.method_calls)
|
||||
|
||||
@stubs.annotated_data(
|
||||
('exists', (200, fake_api.fake_operation_info_ok())),
|
||||
)
|
||||
def test_container_destroy(self, tag, side_effect):
|
||||
"""
|
||||
container_destroy delete a container from the LXD Host. Check
|
||||
that the approiate pylxd calls are made.
|
||||
"""
|
||||
instance = stubs._fake_instance()
|
||||
self.ml.container_stop.return_value = side_effect
|
||||
self.ml.container_destroy.return_value = side_effect
|
||||
self.assertEqual(None,
|
||||
self.session.container_destroy(instance.name,
|
||||
instance))
|
||||
calls = [mock.call.container_stop(instance.name, -1),
|
||||
mock.call.wait_container_operation(
|
||||
'/1.0/operation/1234', 200, -1),
|
||||
mock.call.container_destroy(instance.name),
|
||||
mock.call.wait_container_operation(
|
||||
'/1.0/operation/1234', 200, -1)]
|
||||
self.assertEqual(calls, self.ml.method_calls)
|
||||
|
||||
@stubs.annotated_data(
|
||||
('fail_to_stop', True, 'fail_stop',
|
||||
lxd_exceptions.APIError('Fake', '500'), exception.NovaException),
|
||||
('fail_to_destroy', True, 'fail_destroy',
|
||||
lxd_exceptions.APIError('Fake', '500'), exception.NovaException)
|
||||
)
|
||||
def test_container_destroy_fail(self, tag, container_defined,
|
||||
test_type, side_effect, expected):
|
||||
"""
|
||||
container_destroy deletes a container on the LXD host.
|
||||
Check whether an exeption.NovaException is raised when
|
||||
there is an APIError or when the container fails to stop.
|
||||
"""
|
||||
instance = stubs._fake_instance()
|
||||
self.ml.cotnainer_defined.return_value = container_defined
|
||||
if test_type == 'fail_stop':
|
||||
self.ml.container_stop.side_effect = side_effect
|
||||
self.assertRaises(expected,
|
||||
self.session.container_destroy, instance.name,
|
||||
instance)
|
||||
if test_type == 'fail_destroy':
|
||||
self.ml.container_stop.return_value = \
|
||||
(200, fake_api.fake_operation_info_ok())
|
||||
self.ml.container_destroy.side_effect = side_effect
|
||||
self.assertRaises(expected,
|
||||
self.session.container_destroy, instance.name,
|
||||
instance)
|
||||
|
||||
@stubs.annotated_data(
|
||||
('1', (200, fake_api.fake_operation_info_ok()))
|
||||
)
|
||||
|
|
|
@ -980,9 +980,6 @@ class LXDDriver(driver.ComputeDriver):
|
|||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance,
|
||||
block_device_info=None, power_on=True):
|
||||
if self.session.container_defined(instance.name, instance):
|
||||
return
|
||||
|
||||
# Ensure that the instance directory exists
|
||||
instance_dir = InstanceAttributes(instance).instance_dir
|
||||
if not os.path.exists(instance_dir):
|
||||
|
@ -997,18 +994,17 @@ class LXDDriver(driver.ComputeDriver):
|
|||
|
||||
# Step 3 - Start the network and container
|
||||
self.plug_vifs(instance, network_info)
|
||||
self.session.container_start(instance.name, instance)
|
||||
self.client.container.get(instance.name).start(wait=True)
|
||||
|
||||
def confirm_migration(self, migration, instance, network_info):
|
||||
self.session.profile_delete(instance)
|
||||
self.session.container_destroy(instance.name,
|
||||
instance)
|
||||
self.unplug_vifs(instance, network_info)
|
||||
|
||||
self.client.profiles.get(instance.name).delete()
|
||||
self.client.containers.get(instance.name).delete(wait=True)
|
||||
|
||||
def finish_revert_migration(self, context, instance, network_info,
|
||||
block_device_info=None, power_on=True):
|
||||
if self.session.container_defined(instance.name, instance):
|
||||
self.session.container_start(instance.name, instance)
|
||||
self.client.containers.get(instance.name).start(wait=True)
|
||||
|
||||
def pre_live_migration(self, context, instance, block_device_info,
|
||||
network_info, disk_info, migrate_data=None):
|
||||
|
@ -1038,7 +1034,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||
|
||||
def post_live_migration(self, context, instance, block_device_info,
|
||||
migrate_data=None):
|
||||
self.session.container_destroy(instance.name, instance)
|
||||
self.client.containers.get(instance.name).delete(wait=True)
|
||||
|
||||
def post_live_migration_at_source(self, context, instance, network_info):
|
||||
self.session.profile_delete(instance)
|
||||
|
@ -1051,12 +1047,15 @@ class LXDDriver(driver.ComputeDriver):
|
|||
# XXX: rockstar (20 Jul 2016) - nova-lxd does not support
|
||||
# `check_instance_shared_storage_cleanup`
|
||||
|
||||
def check_can_live_migrate_destination(self, context, instance,
|
||||
src_compute_info, dst_compute_info,
|
||||
block_migration=False,
|
||||
disk_over_commit=False):
|
||||
if self.session.container_defined(instance.name, instance):
|
||||
def check_can_live_migrate_destination(
|
||||
self, context, instance, src_compute_info, dst_compute_info,
|
||||
block_migration=False, disk_over_commit=False):
|
||||
try:
|
||||
self.client.containers.get(instance.name)
|
||||
raise exception.InstanceExists(name=instance.name)
|
||||
except lxd_exceptions.LXDAPIException as e:
|
||||
if e.response.status_code != 404:
|
||||
raise
|
||||
return LXDLiveMigrateData()
|
||||
|
||||
def cleanup_live_migration_destination_check(
|
||||
|
|
|
@ -66,132 +66,6 @@ class LXDAPISession(object):
|
|||
#
|
||||
# Container related API methods
|
||||
#
|
||||
def container_defined(self, instance_name, instance):
|
||||
"""Determine if the container exists
|
||||
|
||||
:param instance_name: container anme
|
||||
:param instance: nova instance opbject
|
||||
:return: True if exists otherwise False
|
||||
|
||||
"""
|
||||
LOG.debug('container_defined for instance', instance=instance)
|
||||
try:
|
||||
client = self.get_session()
|
||||
return client.container_defined(instance_name)
|
||||
except lxd_exceptions.APIError as ex:
|
||||
if ex.status_code == 404:
|
||||
return False
|
||||
else:
|
||||
msg = _('Failed to get container status: %s') % ex
|
||||
raise exception.NovaException(msg)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Error from LXD during container_defined'
|
||||
'%(instance)s: %(reason)s'),
|
||||
{'instance': instance.name, 'reason': e},
|
||||
instance=instance)
|
||||
|
||||
def container_start(self, instance_name, instance):
|
||||
"""Start an LXD container
|
||||
|
||||
:param instance_name: name of container
|
||||
:param instance: nova instance object
|
||||
|
||||
"""
|
||||
LOG.debug('container_start called for instance', instance=instance)
|
||||
try:
|
||||
LOG.info(_LI('Starting instance %(instance)s with '
|
||||
'%(image)s'), {'instance': instance.name,
|
||||
'image': instance.image_ref})
|
||||
# Start the container
|
||||
client = self.get_session()
|
||||
|
||||
(state, data) = client.container_start(instance_name,
|
||||
CONF.lxd.timeout)
|
||||
self.operation_wait(data.get('operation'), instance)
|
||||
|
||||
LOG.info(_LI('Successfully started instance %(instance)s with'
|
||||
' %(image)s'), {'instance': instance.name,
|
||||
'image': instance.image_ref})
|
||||
except lxd_exceptions.APIError as ex:
|
||||
msg = _('Failed to communicate with LXD API %(instance)s:'
|
||||
' %(reason)s') % {'instance': instance.name,
|
||||
'reason': ex}
|
||||
raise exception.NovaException(msg)
|
||||
except Exception as ex:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(
|
||||
_LE('Failed to start container %(instance)s: %(reason)s'),
|
||||
{'instance': instance_name, 'reason': ex},
|
||||
instance=instance)
|
||||
|
||||
def container_stop(self, instance_name, instance):
|
||||
"""Stops an LXD container
|
||||
|
||||
:param instance_name: instance name
|
||||
:param instance: nova instance object
|
||||
|
||||
"""
|
||||
LOG.debug('container_stop called for instance', instance=instance)
|
||||
try:
|
||||
LOG.info(_LI('Stopping instance %(instance)s with'
|
||||
' %(image)s'), {'instance': instance.name,
|
||||
'image': instance.image_ref})
|
||||
# Stop the container
|
||||
client = self.get_session()
|
||||
(state, data) = client.container_stop(instance_name,
|
||||
CONF.lxd.timeout)
|
||||
self.operation_wait(data.get('operation'), instance)
|
||||
|
||||
LOG.info(_LI('Successfully stopped instance %(instance)s with'
|
||||
' %(image)s'), {'instance': instance.name,
|
||||
'image': instance.image_ref})
|
||||
except lxd_exceptions.APIError as ex:
|
||||
msg = _('Failed to communicate with LXD API %(instance)s:'
|
||||
' %(reason)s') % {'instance': instance.name,
|
||||
'reason': ex}
|
||||
raise exception.NovaException(msg)
|
||||
except Exception as ex:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(
|
||||
_LE('Failed to stop container %(instance)s: '
|
||||
'%(reason)s'), {'instance': instance_name,
|
||||
'reason': ex})
|
||||
|
||||
def container_destroy(self, instance_name, instance):
|
||||
"""Destroy a LXD container
|
||||
|
||||
:param instance_name: container name
|
||||
:param instance: nova instance object
|
||||
|
||||
"""
|
||||
LOG.debug('container_destroy for instance', instance=instance)
|
||||
try:
|
||||
LOG.info(_LI('Destroying instance %(instance)s with'
|
||||
' %(image)s'), {'instance': instance.name,
|
||||
'image': instance.image_ref})
|
||||
|
||||
# Destroying container
|
||||
self.container_stop(instance_name, instance)
|
||||
|
||||
client = self.get_session()
|
||||
(state, data) = client.container_destroy(instance_name)
|
||||
self.operation_wait(data.get('operation'), instance)
|
||||
|
||||
LOG.info(_LI('Successfully destroyed instance %(instance)s with'
|
||||
' %(image)s'), {'instance': instance.name,
|
||||
'image': instance.image_ref})
|
||||
except lxd_exceptions.APIError as ex:
|
||||
msg = _('Failed to communicate with LXD API %(instance)s:'
|
||||
' %(reason)s') % {'instance': instance.name,
|
||||
'reason': ex}
|
||||
raise exception.NovaException(msg)
|
||||
except Exception as ex:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to destroy container %(instance)s: '
|
||||
'%(reason)s'), {'instance': instance_name,
|
||||
'reason': ex})
|
||||
|
||||
def container_init(self, config, instance, host=None):
|
||||
"""Create a LXD container
|
||||
|
||||
|
|
Loading…
Reference in New Issue