Merge "Add support for Docker image format"

This commit is contained in:
Jenkins 2015-06-01 20:09:33 +00:00 committed by Gerrit Code Review
commit 8f5aaead07
8 changed files with 92 additions and 52 deletions

View File

@ -566,6 +566,7 @@ Default::
('aki', _('AKI - Amazon Kernel Image')),
('ami', _('AMI - Amazon Machine Image')),
('ari', _('ARI - Amazon Ramdisk Image')),
('docker', _('Docker')),
('iso', _('ISO - Optical Disk Image')),
('qcow2', _('QCOW2 - QEMU Emulator')),
('raw', _('Raw')),

View File

@ -102,6 +102,10 @@ class IndexView(tables.DataTableView):
LOG.warning(invalid_msg)
except ValueError:
LOG.warning(invalid_msg)
elif (filter_field == 'disk_format' and
filter_string.lower() == 'docker'):
filters['disk_format'] = 'raw'
filters['container_format'] = 'docker'
else:
filters[filter_field] = filter_string
return filters

View File

@ -37,6 +37,49 @@ IMAGE_BACKEND_SETTINGS = getattr(settings, 'OPENSTACK_IMAGE_BACKEND', {})
IMAGE_FORMAT_CHOICES = IMAGE_BACKEND_SETTINGS.get('image_formats', [])
def create_image_metadata(data):
"""Use the given dict of image form data to generate the metadata used for
creating the image in glance.
"""
# Glance does not really do anything with container_format at the
# moment. It requires it is set to the same disk_format for the three
# Amazon image types, otherwise it just treats them as 'bare.' As such
# we will just set that to be that here instead of bothering the user
# with asking them for information we can already determine.
disk_format = data['disk_format']
if disk_format in ('ami', 'aki', 'ari',):
container_format = disk_format
elif disk_format == 'docker':
# To support docker containers we allow the user to specify
# 'docker' as the format. In that case we really want to use
# 'raw' as the disk format and 'docker' as the container format.
disk_format = 'raw'
container_format = 'docker'
else:
container_format = 'bare'
# The Create form uses 'is_public' but the Update form uses 'public'. Just
# being tolerant here so we don't break anything else.
meta = {'is_public': data.get('is_public', data.get('public', False)),
'protected': data['protected'],
'disk_format': disk_format,
'container_format': container_format,
'min_disk': (data['minimum_disk'] or 0),
'min_ram': (data['minimum_ram'] or 0),
'name': data['name'],
'properties': {}}
if data['description']:
meta['properties']['description'] = data['description']
if data.get('kernel'):
meta['properties']['kernel_id'] = data['kernel']
if data.get('ramdisk'):
meta['properties']['ramdisk_id'] = data['ramdisk']
if data.get('architecture'):
meta['properties']['architecture'] = data['architecture']
return meta
class CreateImageForm(forms.SelfHandlingForm):
name = forms.CharField(max_length=255, label=_("Name"))
description = forms.CharField(max_length=255, label=_("Description"),
@ -200,33 +243,9 @@ class CreateImageForm(forms.SelfHandlingForm):
return data
def handle(self, request, data):
# Glance does not really do anything with container_format at the
# moment. It requires it is set to the same disk_format for the three
# Amazon image types, otherwise it just treats them as 'bare.' As such
# we will just set that to be that here instead of bothering the user
# with asking them for information we can already determine.
if data['disk_format'] in ('ami', 'aki', 'ari',):
container_format = data['disk_format']
else:
container_format = 'bare'
meta = create_image_metadata(data)
meta = {'is_public': data['is_public'],
'protected': data['protected'],
'disk_format': data['disk_format'],
'container_format': container_format,
'min_disk': (data['minimum_disk'] or 0),
'min_ram': (data['minimum_ram'] or 0),
'name': data['name'],
'properties': {}}
if data['description']:
meta['properties']['description'] = data['description']
if data.get('kernel'):
meta['properties']['kernel_id'] = data['kernel']
if data.get('ramdisk'):
meta['properties']['ramdisk_id'] = data['ramdisk']
if data.get('architecture'):
meta['properties']['architecture'] = data['architecture']
# Add image source file or URL to metadata
if (settings.HORIZON_IMAGES_ALLOW_UPLOAD and
policy.check((("image", "upload_image"),), request) and
data.get('image_file', None)):
@ -240,7 +259,7 @@ class CreateImageForm(forms.SelfHandlingForm):
image = api.glance.image_create(request, **meta)
messages.success(request,
_('Your image %s has been queued for creation.') %
data['name'])
meta['name'])
return image
except Exception as e:
msg = _('Unable to create new image')
@ -248,7 +267,7 @@ class CreateImageForm(forms.SelfHandlingForm):
if hasattr(e, 'code') and e.code == 400:
if "Invalid disk format" in e.details:
msg = _('Unable to create new image: Invalid disk format '
'%s for image.') % data['disk_format']
'%s for image.') % meta['disk_format']
elif "Image name too long" in e.details:
msg = _('Unable to create new image: Image name too long.')
@ -313,26 +332,7 @@ class UpdateImageForm(forms.SelfHandlingForm):
def handle(self, request, data):
image_id = data['image_id']
error_updating = _('Unable to update image "%s".')
if data['disk_format'] in ['aki', 'ari', 'ami']:
container_format = data['disk_format']
else:
container_format = 'bare'
meta = {'is_public': data['public'],
'protected': data['protected'],
'disk_format': data['disk_format'],
'container_format': container_format,
'name': data['name'],
'min_ram': (data['minimum_ram'] or 0),
'min_disk': (data['minimum_disk'] or 0),
'properties': {'description': data['description']}}
if data.get('kernel'):
meta['properties']['kernel_id'] = data['kernel']
if data.get('ramdisk'):
meta['properties']['ramdisk_id'] = data['ramdisk']
if data.get('architecture'):
meta['properties']['architecture'] = data['architecture']
meta = create_image_metadata(data)
# Ensure we do not delete properties that have already been
# set on an image.
meta['purge_props'] = False

View File

@ -222,9 +222,12 @@ def get_format(image):
# which will raise an error if you call upper() on it.
if not format:
return format
# Most image formats are untranslated acronyms, but raw is a word
# and should be translated
if format == "raw":
if getattr(image, "container_format") == 'docker':
return pgettext_lazy("Image format for display in table",
u"Docker")
# Most image formats are untranslated acronyms, but raw is a word
# and should be translated
return pgettext_lazy("Image format for display in table", u"Raw")
return format.upper()

View File

@ -81,6 +81,31 @@ class CreateImageFormTests(test.TestCase):
source_type_dict = dict(form.fields['source_type'].choices)
self.assertNotIn('file', source_type_dict)
def test_create_image_metadata_docker(self):
form_data = {
'name': u'Docker image',
'description': u'Docker image test',
'source_type': u'url',
'image_url': u'/',
'disk_format': u'docker',
'architecture': u'x86-64',
'minimum_disk': 15,
'minimum_ram': 512,
'is_public': False,
'protected': False,
'is_copying': False
}
meta = forms.create_image_metadata(form_data)
self.assertEqual(meta['disk_format'], 'raw')
self.assertEqual(meta['container_format'], 'docker')
self.assertIn('properties', meta)
self.assertNotIn('description', meta)
self.assertNotIn('architecture', meta)
self.assertEqual(meta['properties']['description'],
form_data['description'])
self.assertEqual(meta['properties']['architecture'],
form_data['architecture'])
class UpdateImageFormTests(test.TestCase):
def test_is_format_field_editable(self):

View File

@ -79,17 +79,22 @@ class UpdateView(forms.ModalFormView):
def get_initial(self):
image = self.get_object()
properties = getattr(image, 'properties', {})
return {'image_id': self.kwargs['image_id'],
data = {'image_id': self.kwargs['image_id'],
'name': getattr(image, 'name', None) or image.id,
'description': properties.get('description', ''),
'kernel': properties.get('kernel_id', ''),
'ramdisk': properties.get('ramdisk_id', ''),
'architecture': properties.get('architecture', ''),
'disk_format': getattr(image, 'disk_format', None),
'minimum_ram': getattr(image, 'min_ram', None),
'minimum_disk': getattr(image, 'min_disk', None),
'public': getattr(image, 'is_public', None),
'protected': getattr(image, 'protected', None)}
disk_format = getattr(image, 'disk_format', None)
if (disk_format == 'raw' and
getattr(image, 'container_format') == 'docker'):
disk_format = 'docker'
data['disk_format'] = disk_format
return data
class DetailView(tabs.TabView):

View File

@ -265,6 +265,7 @@ OPENSTACK_NEUTRON_NETWORK = {
# ('aki', _('AKI - Amazon Kernel Image')),
# ('ami', _('AMI - Amazon Machine Image')),
# ('ari', _('ARI - Amazon Ramdisk Image')),
# ('docker', _('Docker')),
# ('iso', _('ISO - Optical Disk Image')),
# ('ova', _('OVA - Open Virtual Appliance')),
# ('qcow2', _('QCOW2 - QEMU Emulator')),

View File

@ -81,6 +81,7 @@ OPENSTACK_IMAGE_BACKEND = {
('aki', _('AKI - Amazon Kernel Image')),
('ami', _('AMI - Amazon Machine Image')),
('ari', _('ARI - Amazon Ramdisk Image')),
('docker', _('Docker')),
('iso', _('ISO - Optical Disk Image')),
('ova', _('OVA - Open Virtual Appliance')),
('qcow2', _('QCOW2 - QEMU Emulator')),