Remove profile-related methods from nova.virt.lxd.session
Another red patch, a few less lines of code to maintain. Change-Id: Ie6d7fbea5ecf5184129dab4614fcfa94a44731ee
This commit is contained in:
parent
bc17707671
commit
42ed04c572
@ -1459,6 +1459,23 @@ class LXDDriverTest(test.NoDBTestCase):
|
|||||||
|
|
||||||
container.delete.assert_called_once_with(wait=True)
|
container.delete.assert_called_once_with(wait=True)
|
||||||
|
|
||||||
|
def test_post_live_migration_at_source(self):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
instance = fake_instance.fake_instance_obj(ctx, name='test')
|
||||||
|
network_info = []
|
||||||
|
profile = mock.Mock()
|
||||||
|
self.client.profiles.get.return_value = profile
|
||||||
|
|
||||||
|
lxd_driver = driver.LXDDriver(None)
|
||||||
|
lxd_driver.cleanup = mock.Mock()
|
||||||
|
lxd_driver.init_host(None)
|
||||||
|
|
||||||
|
lxd_driver.post_live_migration_at_source(
|
||||||
|
ctx, instance, network_info)
|
||||||
|
|
||||||
|
profile.delete.assert_called_once_with()
|
||||||
|
lxd_driver.cleanup.assert_called_once_with(ctx, instance, network_info)
|
||||||
|
|
||||||
|
|
||||||
class InstanceAttributesTest(test.NoDBTestCase):
|
class InstanceAttributesTest(test.NoDBTestCase):
|
||||||
"""Tests for InstanceAttributes."""
|
"""Tests for InstanceAttributes."""
|
||||||
|
@ -18,8 +18,6 @@ import mock
|
|||||||
import nova.conf
|
import nova.conf
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.tests.unit import fake_instance
|
|
||||||
import pylxd
|
|
||||||
from pylxd.deprecated import exceptions as lxd_exceptions
|
from pylxd.deprecated import exceptions as lxd_exceptions
|
||||||
|
|
||||||
from nova.virt.lxd import driver
|
from nova.virt.lxd import driver
|
||||||
@ -38,30 +36,6 @@ class LXDTestLiveMigrate(test.NoDBTestCase):
|
|||||||
self.driver.config = mock.MagicMock()
|
self.driver.config = mock.MagicMock()
|
||||||
self.driver.operations = mock.MagicMock()
|
self.driver.operations = mock.MagicMock()
|
||||||
|
|
||||||
def test_copy_container_profile(self):
|
|
||||||
"""Verify the correct calls are made
|
|
||||||
when a host needs to copy a container profile.
|
|
||||||
"""
|
|
||||||
self.driver.create_profile = mock.Mock()
|
|
||||||
self.driver.session = mock.Mock()
|
|
||||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
|
||||||
fake_network_info = []
|
|
||||||
|
|
||||||
self.driver._copy_container_profile(mock_instance, fake_network_info)
|
|
||||||
|
|
||||||
self.driver.create_profile.assert_called_once_with(
|
|
||||||
mock_instance, fake_network_info)
|
|
||||||
|
|
||||||
@mock.patch.object(driver.LXDDriver, '_copy_container_profile')
|
|
||||||
def test_pre_live_migration(self, mock_container_profile):
|
|
||||||
"""Verify that the copy profile methos is called."""
|
|
||||||
self.driver.pre_live_migration(
|
|
||||||
mock.sentinel.context, mock.sentinel.instance,
|
|
||||||
mock.sentinel.block_device_info,
|
|
||||||
[],
|
|
||||||
mock.sentinel.disk_info,
|
|
||||||
mock.sentinel.migrate_data)
|
|
||||||
|
|
||||||
@mock.patch.object(driver.LXDDriver, '_container_init')
|
@mock.patch.object(driver.LXDDriver, '_container_init')
|
||||||
def test_live_migration(self, mock_container_init):
|
def test_live_migration(self, mock_container_init):
|
||||||
"""Verify that the correct live migration calls
|
"""Verify that the correct live migration calls
|
||||||
@ -89,7 +63,7 @@ class LXDTestLiveMigrate(test.NoDBTestCase):
|
|||||||
mock_container_init.side_effect = \
|
mock_container_init.side_effect = \
|
||||||
lxd_exceptions.APIError(500, 'Fake')
|
lxd_exceptions.APIError(500, 'Fake')
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
pylxd.deprecated.exceptions.APIError,
|
lxd_exceptions.APIError,
|
||||||
self.driver.live_migration, mock.sentinel.context,
|
self.driver.live_migration, mock.sentinel.context,
|
||||||
mock.sentinel.instance, mock.sentinel.dest,
|
mock.sentinel.instance, mock.sentinel.dest,
|
||||||
mock.sentinel.recover_method, mock.sentinel.block_migration,
|
mock.sentinel.recover_method, mock.sentinel.block_migration,
|
||||||
|
@ -109,56 +109,3 @@ class SessionEventTest(test.NoDBTestCase):
|
|||||||
self.session.operation_wait(operation_id, instance))
|
self.session.operation_wait(operation_id, instance))
|
||||||
self.ml.wait_container_operation.assert_called_with(operation_id,
|
self.ml.wait_container_operation.assert_called_with(operation_id,
|
||||||
200, -1)
|
200, -1)
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class SessionProfileTest(test.NoDBTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(SessionProfileTest, self).setUp()
|
|
||||||
|
|
||||||
"""This is so we can mock out pylxd API calls."""
|
|
||||||
self.ml = stubs.lxd_mock()
|
|
||||||
lxd_patcher = mock.patch('pylxd.deprecated.api.API',
|
|
||||||
mock.Mock(return_value=self.ml))
|
|
||||||
lxd_patcher.start()
|
|
||||||
self.addCleanup(lxd_patcher.stop)
|
|
||||||
|
|
||||||
self.session = session.LXDAPISession()
|
|
||||||
|
|
||||||
@stubs.annotated_data(
|
|
||||||
('empty', [], []),
|
|
||||||
('valid', ['test'], ['test']),
|
|
||||||
)
|
|
||||||
def test_profile_list(self, tag, side_effect, expected):
|
|
||||||
self.ml.profile_list.return_value = side_effect
|
|
||||||
self.assertEqual(expected,
|
|
||||||
self.session.profile_list())
|
|
||||||
|
|
||||||
def test_profile_list_fail(self):
|
|
||||||
self.ml.profile_list.side_effect = (
|
|
||||||
lxd_exceptions.APIError('Fake', 500))
|
|
||||||
self.assertRaises(
|
|
||||||
exception.NovaException,
|
|
||||||
self.session.profile_list)
|
|
||||||
|
|
||||||
def test_profile_create(self):
|
|
||||||
instance = stubs._fake_instance()
|
|
||||||
config = mock.Mock()
|
|
||||||
self.ml.profile_defined.return_value = True
|
|
||||||
self.ml.profile_create.return_value = \
|
|
||||||
(200, fake_api.fake_standard_return())
|
|
||||||
self.assertEqual((200, fake_api.fake_standard_return()),
|
|
||||||
self.session.profile_create(config,
|
|
||||||
instance))
|
|
||||||
calls = [mock.call.profile_list(),
|
|
||||||
mock.call.profile_create(config)]
|
|
||||||
self.assertEqual(calls, self.ml.method_calls)
|
|
||||||
|
|
||||||
def test_profile_delete(self):
|
|
||||||
instance = stubs._fake_instance()
|
|
||||||
self.ml.profile_defined.return_value = True
|
|
||||||
self.ml.profile_delete.return_value = \
|
|
||||||
(200, fake_api.fake_standard_return())
|
|
||||||
self.assertEqual(None,
|
|
||||||
self.session.profile_delete(instance))
|
|
||||||
|
@ -986,7 +986,10 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
fileutils.ensure_tree(instance_dir)
|
fileutils.ensure_tree(instance_dir)
|
||||||
|
|
||||||
# Step 1 - Setup the profile on the dest host
|
# Step 1 - Setup the profile on the dest host
|
||||||
self._copy_container_profile(instance, network_info)
|
profile_data = self.create_profile(instance, network_info)
|
||||||
|
self.client.profiles.create(
|
||||||
|
profile_data['name'], profile_data['config'],
|
||||||
|
profile_data['devices'])
|
||||||
|
|
||||||
# Step 2 - Open a websocket on the srct and and
|
# Step 2 - Open a websocket on the srct and and
|
||||||
# generate the container config
|
# generate the container config
|
||||||
@ -1017,7 +1020,10 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
self.firewall_driver.apply_instance_filter(
|
self.firewall_driver.apply_instance_filter(
|
||||||
instance, network_info)
|
instance, network_info)
|
||||||
|
|
||||||
self._copy_container_profile(instance, network_info)
|
profile_data = self.create_profile(instance, network_info)
|
||||||
|
self.client.profiles.create(
|
||||||
|
profile_data['name'], profile_data['config'],
|
||||||
|
profile_data['devices'])
|
||||||
|
|
||||||
def live_migration(self, context, instance, dest,
|
def live_migration(self, context, instance, dest,
|
||||||
post_method, recover_method, block_migration=False,
|
post_method, recover_method, block_migration=False,
|
||||||
@ -1037,7 +1043,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
self.client.containers.get(instance.name).delete(wait=True)
|
self.client.containers.get(instance.name).delete(wait=True)
|
||||||
|
|
||||||
def post_live_migration_at_source(self, context, instance, network_info):
|
def post_live_migration_at_source(self, context, instance, network_info):
|
||||||
self.session.profile_delete(instance)
|
self.client.profiles.get(instance.name).delete()
|
||||||
self.cleanup(context, instance, network_info)
|
self.cleanup(context, instance, network_info)
|
||||||
|
|
||||||
# XXX: rockstar (20 Jul 2016) - nova-lxd does not support
|
# XXX: rockstar (20 Jul 2016) - nova-lxd does not support
|
||||||
@ -1510,7 +1516,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
instance=instance)
|
instance=instance)
|
||||||
try:
|
try:
|
||||||
config = {}
|
config = {}
|
||||||
lxd_config = self.session.get_host_config(instance)
|
lxd_config = self.client.host_info['environment']
|
||||||
config.setdefault('root', {'type': 'disk', 'path': '/'})
|
config.setdefault('root', {'type': 'disk', 'path': '/'})
|
||||||
if str(lxd_config['storage']) in ['btrfs', 'zfs']:
|
if str(lxd_config['storage']) in ['btrfs', 'zfs']:
|
||||||
config['root'].update({'size': '%sGB' % str(instance.root_gb)})
|
config['root'].update({'size': '%sGB' % str(instance.root_gb)})
|
||||||
@ -1684,7 +1690,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
container_url = 'https://%s:8443%s' \
|
container_url = 'https://%s:8443%s' \
|
||||||
% (CONF.my_ip, container_migrate.get('operation'))
|
% (CONF.my_ip, container_migrate.get('operation'))
|
||||||
|
|
||||||
lxd_config = self.session.get_host_config(instance)
|
lxd_config = self.client.host_info['environment']
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'base_image': '',
|
'base_image': '',
|
||||||
@ -1740,7 +1746,3 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
data, host, instance)
|
data, host, instance)
|
||||||
}
|
}
|
||||||
self.session.container_init(container_config, instance, host)
|
self.session.container_init(container_config, instance, host)
|
||||||
|
|
||||||
def _copy_container_profile(self, instance, network_info):
|
|
||||||
container_profile = self.create_profile(instance, network_info)
|
|
||||||
self.session.profile_create(container_profile, instance)
|
|
||||||
|
@ -185,116 +185,6 @@ class LXDAPISession(object):
|
|||||||
{'instance': instance.image_ref, 'reason': e},
|
{'instance': instance.image_ref, 'reason': e},
|
||||||
instance=instance)
|
instance=instance)
|
||||||
|
|
||||||
#
|
|
||||||
# Profile methods
|
|
||||||
#
|
|
||||||
def profile_list(self):
|
|
||||||
LOG.debug('profile_list called for instance')
|
|
||||||
try:
|
|
||||||
client = self.get_session()
|
|
||||||
return client.profile_list()
|
|
||||||
except lxd_exceptions.APIError as ex:
|
|
||||||
msg = _('Failed to communicate with LXD API: %(reason)s') \
|
|
||||||
% {'reason': ex}
|
|
||||||
LOG.error(msg)
|
|
||||||
raise exception.NovaException(msg)
|
|
||||||
except Exception as ex:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error(_LE('Error from LXD during profile_list: '
|
|
||||||
'%(reason)s') % {'reason': ex})
|
|
||||||
|
|
||||||
def profile_defined(self, instance_name, instance):
|
|
||||||
"""Validate if the profile is available on the LXD
|
|
||||||
host
|
|
||||||
|
|
||||||
:param instance: nova instance object
|
|
||||||
"""
|
|
||||||
LOG.debug('profile_defined called for instance',
|
|
||||||
instance=instance)
|
|
||||||
try:
|
|
||||||
found = False
|
|
||||||
if instance_name in self.profile_list():
|
|
||||||
found = True
|
|
||||||
return found
|
|
||||||
except lxd_exceptions.APIError as ex:
|
|
||||||
if ex.status_code == 404:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
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 determine profile %(instance)s:'
|
|
||||||
' %(reason)s'),
|
|
||||||
{'instance': instance.name, 'reason': ex})
|
|
||||||
|
|
||||||
def profile_create(self, config, instance):
|
|
||||||
"""Create an LXD container profile
|
|
||||||
|
|
||||||
:param config: profile dictionary
|
|
||||||
:param instance: nova instance object
|
|
||||||
"""
|
|
||||||
LOG.debug('profile_create called for instance',
|
|
||||||
instance=instance)
|
|
||||||
try:
|
|
||||||
if self.profile_defined(instance.name, instance):
|
|
||||||
msg = _('Profile already exists %(instance)s') % \
|
|
||||||
{'instance': instance.name}
|
|
||||||
raise exception.NovaException(msg)
|
|
||||||
|
|
||||||
client = self.get_session()
|
|
||||||
return client.profile_create(config)
|
|
||||||
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 create profile %(instance)s: %(reason)s'),
|
|
||||||
{'instance': instance.name, 'reason': ex})
|
|
||||||
|
|
||||||
def profile_delete(self, instance):
|
|
||||||
"""Delete a LXD container profile.
|
|
||||||
|
|
||||||
:param instance: nova instance object
|
|
||||||
"""
|
|
||||||
LOG.debug('profile_delete called for instance', instance=instance)
|
|
||||||
try:
|
|
||||||
if not self.profile_defined(instance.name, instance):
|
|
||||||
return
|
|
||||||
|
|
||||||
client = self.get_session()
|
|
||||||
return client.profile_delete(instance.name)
|
|
||||||
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 delete profile %(instance)s: %(reason)s'),
|
|
||||||
{'instance': instance.name, 'reason': ex})
|
|
||||||
|
|
||||||
#
|
|
||||||
# Host Methods
|
|
||||||
#
|
|
||||||
def get_host_config(self, instance):
|
|
||||||
LOG.debug('host_config called for instance', instance=instance)
|
|
||||||
try:
|
|
||||||
client = self.get_session()
|
|
||||||
return client.host_config()['environment']
|
|
||||||
except lxd_exceptions.APIError as ex:
|
|
||||||
msg = _('Failed to communicate with LXD %(instance)s:'
|
|
||||||
' %(reason)s') % {'instance': instance.name,
|
|
||||||
'ex': ex}
|
|
||||||
LOG.error(msg)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Migrate methods
|
# Migrate methods
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user