Merge "Update snapshot, fixing the hanging issues."
This commit is contained in:
commit
b4eaf92a94
@ -1229,3 +1229,41 @@ class LXDDriverTest(test.NoDBTestCase):
|
|||||||
result = lxd_driver.get_available_nodes()
|
result = lxd_driver.get_available_nodes()
|
||||||
|
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
@mock.patch('nova.virt.lxd.driver.IMAGE_API')
|
||||||
|
@mock.patch('nova.virt.lxd.driver.lockutils.lock')
|
||||||
|
def test_snapshot(self, lock, IMAGE_API):
|
||||||
|
update_task_state_expected = [
|
||||||
|
mock.call(task_state='image_pending_upload'),
|
||||||
|
mock.call(
|
||||||
|
expected_state='image_pending_upload',
|
||||||
|
task_state='image_uploading'),
|
||||||
|
]
|
||||||
|
|
||||||
|
container = mock.Mock()
|
||||||
|
self.client.containers.get.return_value = container
|
||||||
|
image = mock.Mock()
|
||||||
|
container.publish.return_value = image
|
||||||
|
data = mock.Mock()
|
||||||
|
image.export.return_value = data
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
instance = fake_instance.fake_instance_obj(ctx, name='test')
|
||||||
|
image_id = mock.Mock()
|
||||||
|
update_task_state = mock.Mock()
|
||||||
|
snapshot = {'name': mock.Mock()}
|
||||||
|
IMAGE_API.get.return_value = snapshot
|
||||||
|
|
||||||
|
lxd_driver = driver.LXDDriver(None)
|
||||||
|
lxd_driver.init_host(None)
|
||||||
|
|
||||||
|
lxd_driver.snapshot(ctx, instance, image_id, update_task_state)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
update_task_state_expected, update_task_state.call_args_list)
|
||||||
|
IMAGE_API.get.assert_called_once_with(ctx, image_id)
|
||||||
|
IMAGE_API.update.assert_called_once_with(
|
||||||
|
ctx, image_id, {
|
||||||
|
'name': snapshot['name'],
|
||||||
|
'disk_format': 'raw',
|
||||||
|
'container_format': 'bare'},
|
||||||
|
data)
|
||||||
|
@ -582,6 +582,32 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
container.stop(wait=True)
|
container.stop(wait=True)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def snapshot(self, context, instance, image_id, update_task_state):
|
||||||
|
lock_path = str(os.path.join(CONF.instances_path, 'locks'))
|
||||||
|
|
||||||
|
with lockutils.lock(
|
||||||
|
lock_path, external=True,
|
||||||
|
lock_file_prefix=('lxd-snapshot-%s' % instance.name)):
|
||||||
|
|
||||||
|
update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD)
|
||||||
|
|
||||||
|
container = self.client.containers.get(instance.name)
|
||||||
|
if container.status != 'Stopped':
|
||||||
|
container.stop(wait=True)
|
||||||
|
image = container.publish(wait=True)
|
||||||
|
container.start(wait=True)
|
||||||
|
|
||||||
|
update_task_state(
|
||||||
|
task_state=task_states.IMAGE_UPLOADING,
|
||||||
|
expected_state=task_states.IMAGE_PENDING_UPLOAD)
|
||||||
|
|
||||||
|
snapshot = IMAGE_API.get(context, image_id)
|
||||||
|
data = image.export()
|
||||||
|
image_meta = {'name': snapshot['name'],
|
||||||
|
'disk_format': 'raw',
|
||||||
|
'container_format': 'bare'}
|
||||||
|
IMAGE_API.update(context, image_id, image_meta, data)
|
||||||
|
|
||||||
def pause(self, instance):
|
def pause(self, instance):
|
||||||
"""Pause container.
|
"""Pause container.
|
||||||
|
|
||||||
@ -879,40 +905,6 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
#
|
#
|
||||||
# ComputeDriver implementation methods
|
# ComputeDriver implementation methods
|
||||||
#
|
#
|
||||||
def snapshot(self, context, instance, image_id, update_task_state):
|
|
||||||
lock_path = str(os.path.join(CONF.instances_path, 'locks'))
|
|
||||||
try:
|
|
||||||
if not self.session.container_defined(instance.name, instance):
|
|
||||||
raise exception.InstanceNotFound(instance_id=instance.name)
|
|
||||||
|
|
||||||
with lockutils.lock(lock_path,
|
|
||||||
lock_file_prefix=('lxd-snapshot-%s' %
|
|
||||||
instance.name),
|
|
||||||
external=True):
|
|
||||||
|
|
||||||
update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD)
|
|
||||||
|
|
||||||
# We have to stop the container before we can publish the
|
|
||||||
# image to the local store
|
|
||||||
self.session.container_stop(instance.name,
|
|
||||||
instance)
|
|
||||||
fingerprint = self._save_lxd_image(instance,
|
|
||||||
image_id)
|
|
||||||
self.session.container_start(instance.name, instance)
|
|
||||||
|
|
||||||
update_task_state(task_state=task_states.IMAGE_UPLOADING,
|
|
||||||
expected_state=task_states.IMAGE_PENDING_UPLOAD) # noqa
|
|
||||||
self._save_glance_image(context, instance, image_id,
|
|
||||||
fingerprint)
|
|
||||||
except Exception as ex:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error(_LE('Failed to create snapshot for %(instance)s: '
|
|
||||||
'%(ex)s'), {'instance': instance.name, 'ex': ex},
|
|
||||||
instance=instance)
|
|
||||||
|
|
||||||
def post_interrupted_snapshot_cleanup(self, context, instance):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def finish_migration(self, context, migration, instance, disk_info,
|
def finish_migration(self, context, migration, instance, disk_info,
|
||||||
network_info, image_meta, resize_instance,
|
network_info, image_meta, resize_instance,
|
||||||
block_device_info=None, power_on=True):
|
block_device_info=None, power_on=True):
|
||||||
@ -1161,70 +1153,6 @@ class LXDDriver(driver.ComputeDriver):
|
|||||||
|
|
||||||
return configdrive_dir
|
return configdrive_dir
|
||||||
|
|
||||||
def _save_lxd_image(self, instance, image_id):
|
|
||||||
"""Creates an LXD image from the LXD continaer
|
|
||||||
|
|
||||||
"""
|
|
||||||
LOG.debug('_save_lxd_image called for instance', instance=instance)
|
|
||||||
|
|
||||||
fingerprint = None
|
|
||||||
try:
|
|
||||||
# Publish the snapshot to the local LXD image store
|
|
||||||
container_snapshot = {
|
|
||||||
"properties": {},
|
|
||||||
"public": False,
|
|
||||||
"source": {
|
|
||||||
"name": instance.name,
|
|
||||||
"type": "container"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(state, data) = self.session.container_publish(container_snapshot,
|
|
||||||
instance)
|
|
||||||
event_id = data.get('operation')
|
|
||||||
self.session.wait_for_snapshot(event_id, instance)
|
|
||||||
|
|
||||||
# Image has been create but the fingerprint is buried deep
|
|
||||||
# in the metadata when the snapshot is complete
|
|
||||||
(state, data) = self.session.operation_info(event_id, instance)
|
|
||||||
fingerprint = data['metadata']['metadata']['fingerprint']
|
|
||||||
except Exception as ex:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error(_LE('Failed to publish snapshot for %(instance)s: '
|
|
||||||
'%(ex)s'), {'instance': instance.name,
|
|
||||||
'ex': ex}, instance=instance)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Set the alias for the LXD image
|
|
||||||
alias_config = {
|
|
||||||
'name': image_id,
|
|
||||||
'target': fingerprint
|
|
||||||
}
|
|
||||||
self.session.create_alias(alias_config, instance)
|
|
||||||
except Exception as ex:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error(_LE('Failed to create alias for %(instance)s: '
|
|
||||||
'%(ex)s'), {'instance': instance.name,
|
|
||||||
'ex': ex}, instance=instance)
|
|
||||||
|
|
||||||
return fingerprint
|
|
||||||
|
|
||||||
def _save_glance_image(self, context, instance, image_id, fingerprint):
|
|
||||||
LOG.debug('_save_glance_image called for instance', instance=instance)
|
|
||||||
|
|
||||||
try:
|
|
||||||
snapshot = IMAGE_API.get(context, image_id)
|
|
||||||
data = self.session.container_export(fingerprint, instance)
|
|
||||||
image_meta = {'name': snapshot['name'],
|
|
||||||
'disk_format': 'raw',
|
|
||||||
'container_format': 'bare'}
|
|
||||||
IMAGE_API.update(context, image_id, image_meta, data)
|
|
||||||
except Exception as ex:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error(_LE('Failed to upload image to glance for '
|
|
||||||
'%(instance)s: %(ex)s'),
|
|
||||||
{'instance': instance.name, 'ex': ex},
|
|
||||||
instance=instance)
|
|
||||||
|
|
||||||
def setup_image(self, context, instance, image_meta):
|
def setup_image(self, context, instance, image_meta):
|
||||||
"""Download an image from glance and upload it to LXD
|
"""Download an image from glance and upload it to LXD
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user