Fix image format error on vol-backed snapshot
Long ago, it was decided that we should create an empty image in glance for snapshots of volume-backed instances[1]. I'm not really sure why that is, since it doesn't seem to be a useful construct to do anything with (like a normal snapshot, which can be used to boot). It was so long ago that it was not documented well[2]. However, when glance v2 came along, that sort of nonsensical thing became harder because images would not be "active" until they had content, and nova decided to continue the status quo by uploading empty data[3] to force the state transition. Later, that stopped working for Xen because we were lying about the format in a way that didn't work for Xen, so we made that lie dynamic[4] to triple-down on the original decision. Now, with glance moving to image format safety, our lies have caught up with us. We can no longer upload an empty stream of data and claim that it is qcow2 because glance will call our bluff. Although it was originally suggested[5] as a fix that would be hypervisor-neutral (and not implemented that way for reasons that were not stated), we must start uploading that empty stream as the 'raw' format that it is in order for glance to accept it. Technically glance can be configured to not allow raw uploads, which means that we could again end up with the situation from the xen bug[5], but without synthesizing a fictitious image of a type that is supported, there's no good solutuon, other than a re-think. I think it would be worth revisiting whether or not we need an empty glance image for volume-backed server snapshots, and if we do, whether or not there's a better way to go about that (like adding a location which will indicate it lives elsewhere and will result in it becoming active). However, in the meantime we need to be truthful about the lie we're making, by correctly identifying the format of the zero- length data we're not uploading. Needed-By: https://review.opendev.org/c/openstack/glance-specs/+/925111 Change-Id: I6a6184da3b73506261c61005b6984c69cdc7fb98 1:c3476b5ca7
2: https://bugs.launchpad.net/nova/+bug/1034730 3:4a39b8b530
4:2fe5daeb5f
5: https://bugs.launchpad.net/nova/+bug/1616938/comments/1
This commit is contained in:
@@ -645,10 +645,17 @@ class GlanceImageServiceV2(object):
|
||||
# where we have to hardcode this parameters.
|
||||
if force_activate:
|
||||
data = ''
|
||||
# NOTE(danms): If we are using this terrible hack to upload
|
||||
# zero-length data to activate the image, we cannot claim it
|
||||
# is some format other than 'raw'. If the caller asked for
|
||||
# something specific, that's a bug. Otherwise, we must force
|
||||
# disk_format=raw.
|
||||
if 'disk_format' not in sent_service_image_meta:
|
||||
sent_service_image_meta['disk_format'] = (
|
||||
self._get_image_create_disk_format_default(context)
|
||||
)
|
||||
sent_service_image_meta['disk_format'] = 'raw'
|
||||
elif sent_service_image_meta['disk_format'] != 'raw':
|
||||
raise exception.ImageBadRequest(
|
||||
'Unable to force activate with disk_format=%s' % (
|
||||
sent_service_image_meta['disk_format']))
|
||||
if 'container_format' not in sent_service_image_meta:
|
||||
sent_service_image_meta['container_format'] = 'bare'
|
||||
|
||||
|
@@ -1721,18 +1721,27 @@ class TestCreate(test.NoDBTestCase):
|
||||
client.call.return_value = {'id': '123'}
|
||||
ctx = mock.sentinel.ctx
|
||||
service = glance.GlanceImageServiceV2(client)
|
||||
with mock.patch.object(service,
|
||||
'_get_image_create_disk_format_default',
|
||||
return_value='vdi'):
|
||||
image_meta = service.create(ctx, image_mock)
|
||||
image_meta = service.create(ctx, image_mock)
|
||||
trans_to_mock.assert_called_once_with(image_mock)
|
||||
# Verify that the disk_format and container_format kwargs are passed.
|
||||
create_call_kwargs = client.call.call_args_list[0][1]['kwargs']
|
||||
self.assertEqual('vdi', create_call_kwargs['disk_format'])
|
||||
self.assertEqual('raw', create_call_kwargs['disk_format'])
|
||||
self.assertEqual('bare', create_call_kwargs['container_format'])
|
||||
trans_from_mock.assert_called_once_with({'id': '123'})
|
||||
self.assertEqual(mock.sentinel.trans_from, image_meta)
|
||||
|
||||
def test_create_v2_rejects_incompatible_disk_format(self):
|
||||
client = mock.MagicMock()
|
||||
client.call.return_value = {'id': '123'}
|
||||
ctx = mock.sentinel.ctx
|
||||
service = glance.GlanceImageServiceV2(client)
|
||||
self.assertRaisesRegex(exception.ImageBadRequest,
|
||||
'Unable to force activate',
|
||||
service._create_v2,
|
||||
ctx,
|
||||
{'disk_format': 'qcow2'},
|
||||
force_activate=True)
|
||||
|
||||
@mock.patch('nova.image.glance._translate_from_glance')
|
||||
@mock.patch('nova.image.glance._translate_to_glance')
|
||||
def test_create_success_v2_with_location(
|
||||
|
Reference in New Issue
Block a user