Merge "Update snapshot, fixing the hanging issues."

This commit is contained in:
Jenkins 2016-10-01 13:14:14 +00:00 committed by Gerrit Code Review
commit b4eaf92a94
2 changed files with 64 additions and 98 deletions

View File

@ -1229,3 +1229,41 @@ class LXDDriverTest(test.NoDBTestCase):
result = lxd_driver.get_available_nodes()
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)

View File

@ -582,6 +582,32 @@ class LXDDriver(driver.ComputeDriver):
container.stop(wait=True)
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):
"""Pause container.
@ -879,40 +905,6 @@ class LXDDriver(driver.ComputeDriver):
#
# 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,
network_info, image_meta, resize_instance,
block_device_info=None, power_on=True):
@ -1161,70 +1153,6 @@ class LXDDriver(driver.ComputeDriver):
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):
"""Download an image from glance and upload it to LXD