Drop deprecated Glance V1 API support
Glance V1 API was deprecated in Stein release in Horizon and deprecated in Glance since Newton release. Change-Id: I18f6fd03dd3e07fa4f2ccfdccfdc3ca766c91c16
This commit is contained in:
parent
cf904d1194
commit
6037a58c6e
@ -30,7 +30,7 @@ from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.core.files.uploadedfile import TemporaryUploadedFile
|
||||
|
||||
import glanceclient as glance_client
|
||||
from glanceclient.v2 import client
|
||||
import six
|
||||
from six.moves import _thread as thread
|
||||
|
||||
@ -52,20 +52,8 @@ else:
|
||||
LOG = logging.getLogger(__name__)
|
||||
VERSIONS = base.APIVersionManager("image", preferred_version=2)
|
||||
|
||||
try:
|
||||
# pylint: disable=ungrouped-imports
|
||||
from glanceclient.v2 import client as glance_client_v2
|
||||
VERSIONS.load_supported_version(2, {"client": glance_client_v2,
|
||||
"version": 2})
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
# pylint: disable=ungrouped-imports
|
||||
from glanceclient.v1 import client as glance_client_v1
|
||||
VERSIONS.load_supported_version(1, {"client": glance_client_v1,
|
||||
"version": 1})
|
||||
except ImportError:
|
||||
pass
|
||||
VERSIONS.load_supported_version(2, {"client": client,
|
||||
"version": 2})
|
||||
|
||||
# TODO(e0ne): remove this workaround once glanceclient will raise
|
||||
# RequestURITooLong exception
|
||||
@ -91,9 +79,8 @@ class Image(base.APIResourceWrapper):
|
||||
def __getattribute__(self, attr):
|
||||
# Because Glance v2 treats custom properties as normal
|
||||
# attributes, we need to be more flexible than the resource
|
||||
# wrappers usually allow. In v1 they were defined under a
|
||||
# "properties" attribute.
|
||||
if VERSIONS.active >= 2 and attr == "properties":
|
||||
# wrappers usually allow.
|
||||
if attr == "properties":
|
||||
return {k: v for (k, v) in self._apiresource.items()
|
||||
if self.property_visible(k)}
|
||||
try:
|
||||
@ -130,10 +117,6 @@ class Image(base.APIResourceWrapper):
|
||||
return prop_name not in (self._attrs | self._ext_attrs)
|
||||
|
||||
def to_dict(self, show_ext_attrs=False):
|
||||
# When using v1 Image objects (including when running unit tests
|
||||
# for v2), self._apiresource is not iterable. In that case,
|
||||
# the properties are included in the apiresource dict, so
|
||||
# just return that dict.
|
||||
if not isinstance(self._apiresource, Iterable):
|
||||
return self._apiresource.to_dict()
|
||||
image_dict = super(Image, self).to_dict()
|
||||
@ -151,22 +134,15 @@ class Image(base.APIResourceWrapper):
|
||||
|
||||
|
||||
@memoized
|
||||
def glanceclient(request, version=None):
|
||||
def glanceclient(request):
|
||||
api_version = VERSIONS.get_active_version()
|
||||
|
||||
url = base.url_for(request, 'image')
|
||||
insecure = settings.OPENSTACK_SSL_NO_VERIFY
|
||||
cacert = settings.OPENSTACK_SSL_CACERT
|
||||
|
||||
# TODO(jpichon): Temporarily keep both till we update the API calls
|
||||
# to stop hardcoding a version in this file. Once that's done we
|
||||
# can get rid of the deprecated 'version' parameter.
|
||||
if version is None:
|
||||
return api_version['client'].Client(url, token=request.user.token.id,
|
||||
insecure=insecure, cacert=cacert)
|
||||
else:
|
||||
return glance_client.Client(version, url, token=request.user.token.id,
|
||||
insecure=insecure, cacert=cacert)
|
||||
return api_version['client'].Client(url, token=request.user.token.id,
|
||||
insecure=insecure, cacert=cacert)
|
||||
|
||||
|
||||
# Note: Glance is adding more than just public and private in Newton or later
|
||||
@ -193,75 +169,30 @@ def _normalize_is_public_filter(filters):
|
||||
if not filters:
|
||||
return
|
||||
|
||||
# Glance v1 uses filter 'is_public' (True, False).
|
||||
# Glance v2 uses filter 'visibility' ('public', 'private', ...).
|
||||
if VERSIONS.active >= 2:
|
||||
if 'is_public' in filters:
|
||||
# Glance v2: Replace 'is_public' with 'visibility'.
|
||||
visibility = PUBLIC_TO_VISIBILITY_MAP[filters['is_public']]
|
||||
del filters['is_public']
|
||||
if visibility is not None:
|
||||
filters['visibility'] = visibility
|
||||
elif 'visibility' in filters:
|
||||
# Glance v1: Replace 'visibility' with 'is_public'.
|
||||
filters['is_public'] = filters['visibility'] == "public"
|
||||
del filters['visibility']
|
||||
if 'is_public' in filters:
|
||||
# Glance v2: Replace 'is_public' with 'visibility'.
|
||||
visibility = PUBLIC_TO_VISIBILITY_MAP[filters['is_public']]
|
||||
del filters['is_public']
|
||||
if visibility is not None:
|
||||
filters['visibility'] = visibility
|
||||
|
||||
|
||||
def _normalize_owner_id_filter(filters):
|
||||
if not filters:
|
||||
return
|
||||
|
||||
# Glance v1 uses filter 'property-owner_id' (Project ID).
|
||||
# Glance v2 uses filter 'owner' (Project ID).
|
||||
if VERSIONS.active >= 2:
|
||||
if 'property-owner_id' in filters:
|
||||
# Glance v2: Replace 'property-owner_id' with 'owner'.
|
||||
filters['owner'] = filters['property-owner_id']
|
||||
del filters['property-owner_id']
|
||||
elif 'owner' in filters:
|
||||
# Glance v1: Replace 'owner' with 'property-owner_id'.
|
||||
filters['property-owner_id'] = filters['owner']
|
||||
del filters['owner']
|
||||
if 'property-owner_id' in filters:
|
||||
# Glance v2: Replace 'property-owner_id' with 'owner'.
|
||||
filters['owner'] = filters['property-owner_id']
|
||||
del filters['property-owner_id']
|
||||
|
||||
|
||||
def _normalize_list_input(filters, **kwargs):
|
||||
_normalize_is_public_filter(filters)
|
||||
_normalize_owner_id_filter(filters)
|
||||
|
||||
if VERSIONS.active < 2:
|
||||
# Glance v1 client processes some keywords specifically.
|
||||
# Others, it just takes as a nested dict called filters.
|
||||
# This results in the following being passed into the glance client:
|
||||
# {
|
||||
# 'is_public': u'true',
|
||||
# 'sort_key': u'name',
|
||||
# 'sort_dir': u'asc',
|
||||
# 'filters': {
|
||||
# u'min_disk': u'0',
|
||||
# u'name': u'mysql',
|
||||
# 'properties': {
|
||||
# u'os_shutdown_timeout': u'1'
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
v1_keywords = ['page_size', 'limit', 'sort_dir', 'sort_key', 'marker',
|
||||
'is_public', 'return_req_id', 'paginate']
|
||||
|
||||
filters = {}
|
||||
properties = {}
|
||||
for key, value in iter(kwargs.items()):
|
||||
if key in v1_keywords:
|
||||
continue
|
||||
else:
|
||||
filters[key] = value
|
||||
del kwargs[key]
|
||||
|
||||
if properties:
|
||||
filters['properties'] = properties
|
||||
if filters:
|
||||
kwargs['filters'] = filters
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def image_delete(request, image_id):
|
||||
@ -399,12 +330,6 @@ def image_list_detailed(request, marker=None, sort_dir='desc',
|
||||
def image_update(request, image_id, **kwargs):
|
||||
image_data = kwargs.get('data', None)
|
||||
try:
|
||||
# Horizon doesn't support purging image properties. Make sure we don't
|
||||
# unintentionally remove properties when using v1. We don't need a
|
||||
# similar setting for v2 because you have to specify which properties
|
||||
# to remove, and the default is nothing gets removed.
|
||||
if VERSIONS.active < 2:
|
||||
kwargs['purge_props'] = False
|
||||
return Image(glanceclient(request).images.update(
|
||||
image_id, **kwargs))
|
||||
finally:
|
||||
@ -433,10 +358,7 @@ class ExternallyUploadedImage(Image):
|
||||
def __init__(self, apiresource, request):
|
||||
super(ExternallyUploadedImage, self).__init__(apiresource)
|
||||
image_endpoint = base.url_for(request, 'image', 'publicURL')
|
||||
if VERSIONS.active >= 2:
|
||||
upload_template = "%s/v2/images/%s/file"
|
||||
else:
|
||||
upload_template = "%s/v1/images/%s"
|
||||
upload_template = "%s/v2/images/%s/file"
|
||||
self._url = upload_template % (image_endpoint, self.id)
|
||||
self._token_id = request.user.token.id
|
||||
|
||||
@ -509,12 +431,8 @@ def create_image_metadata(data):
|
||||
raise KeyError('invalid visibility option: %s' % data['visibility'])
|
||||
_normalize_is_public_filter(data)
|
||||
|
||||
if VERSIONS.active < 2:
|
||||
meta['properties'] = properties
|
||||
meta['is_public'] = data.get('is_public', False)
|
||||
else:
|
||||
meta['visibility'] = data.get('visibility', 'private')
|
||||
meta.update(properties)
|
||||
meta['visibility'] = data.get('visibility', 'private')
|
||||
meta.update(properties)
|
||||
|
||||
return meta
|
||||
|
||||
@ -548,9 +466,7 @@ def image_create(request, **kwargs):
|
||||
some time and is handed off to a separate thread.
|
||||
"""
|
||||
data = kwargs.pop('data', None)
|
||||
location = None
|
||||
if VERSIONS.active >= 2:
|
||||
location = kwargs.pop('location', None)
|
||||
location = kwargs.pop('location', None)
|
||||
|
||||
image = glanceclient(request).images.create(**kwargs)
|
||||
if location is not None:
|
||||
@ -573,23 +489,19 @@ def image_create(request, **kwargs):
|
||||
data = SimpleUploadedFile(data.name,
|
||||
data.read(),
|
||||
data.content_type)
|
||||
if VERSIONS.active < 2:
|
||||
thread.start_new_thread(image_update,
|
||||
(request, image.id),
|
||||
{'data': data})
|
||||
else:
|
||||
def upload():
|
||||
|
||||
def upload():
|
||||
try:
|
||||
return glanceclient(request).images.upload(image.id, data)
|
||||
finally:
|
||||
filename = str(data.file.name)
|
||||
try:
|
||||
return glanceclient(request).images.upload(image.id, data)
|
||||
finally:
|
||||
filename = str(data.file.name)
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError as e:
|
||||
LOG.warning('Failed to remove temporary image file '
|
||||
'%(file)s (%(e)s)',
|
||||
{'file': filename, 'e': e})
|
||||
thread.start_new_thread(upload, ())
|
||||
os.remove(filename)
|
||||
except OSError as e:
|
||||
LOG.warning('Failed to remove temporary image file '
|
||||
'%(file)s (%(e)s)',
|
||||
{'file': filename, 'e': e})
|
||||
thread.start_new_thread(upload, ())
|
||||
|
||||
return Image(image)
|
||||
|
||||
@ -597,9 +509,9 @@ def image_create(request, **kwargs):
|
||||
@profiler.trace
|
||||
def image_update_properties(request, image_id, remove_props=None, **kwargs):
|
||||
"""Add or update a custom property of an image."""
|
||||
return glanceclient(request, '2').images.update(image_id,
|
||||
remove_props,
|
||||
**kwargs)
|
||||
return glanceclient(request).images.update(image_id,
|
||||
remove_props,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
@ -666,7 +578,7 @@ def filter_properties_target(namespaces_iter,
|
||||
|
||||
@memoized
|
||||
def metadefs_namespace_get(request, namespace, resource_type=None, wrap=False):
|
||||
namespace = glanceclient(request, '2').\
|
||||
namespace = glanceclient(request).\
|
||||
metadefs_namespace.get(namespace, resource_type=resource_type)
|
||||
# There were problems with using the wrapper class in
|
||||
# nested json serialization. So sometimes, it is not desirable
|
||||
@ -709,9 +621,6 @@ def metadefs_namespace_list(request,
|
||||
"""
|
||||
# Listing namespaces requires the v2 API. If not supported we return an
|
||||
# empty array so callers don't need to worry about version checking.
|
||||
if get_version() < 2:
|
||||
return [], False, False
|
||||
|
||||
if filters is None:
|
||||
filters = {}
|
||||
limit = settings.API_RESULT_LIMIT
|
||||
@ -728,7 +637,7 @@ def metadefs_namespace_list(request,
|
||||
kwargs['sort_dir'] = sort_dir
|
||||
kwargs['sort_key'] = sort_key
|
||||
|
||||
namespaces_iter = glanceclient(request, '2').metadefs_namespace.list(
|
||||
namespaces_iter = glanceclient(request).metadefs_namespace.list(
|
||||
page_size=request_size, limit=limit, **kwargs)
|
||||
|
||||
# Filter the namespaces based on the provided properties_target since this
|
||||
@ -780,34 +689,31 @@ def metadefs_namespace_full_list(request, resource_type, filters=None,
|
||||
|
||||
@profiler.trace
|
||||
def metadefs_namespace_create(request, namespace):
|
||||
return glanceclient(request, '2').metadefs_namespace.create(**namespace)
|
||||
return glanceclient(request).metadefs_namespace.create(**namespace)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def metadefs_namespace_update(request, namespace_name, **properties):
|
||||
return glanceclient(request, '2').metadefs_namespace.update(
|
||||
return glanceclient(request).metadefs_namespace.update(
|
||||
namespace_name,
|
||||
**properties)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def metadefs_namespace_delete(request, namespace_name):
|
||||
return glanceclient(request, '2').metadefs_namespace.delete(namespace_name)
|
||||
return glanceclient(request).metadefs_namespace.delete(namespace_name)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def metadefs_resource_types_list(request):
|
||||
# Listing Resource Types requires the v2 API. If not supported we return
|
||||
# an empty array so callers don't need to worry about version checking.
|
||||
if get_version() < 2:
|
||||
return []
|
||||
else:
|
||||
return glanceclient(request, '2').metadefs_resource_type.list()
|
||||
return glanceclient(request).metadefs_resource_type.list()
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def metadefs_namespace_resource_types(request, namespace_name):
|
||||
resource_types = glanceclient(request, '2').metadefs_resource_type.get(
|
||||
resource_types = glanceclient(request).metadefs_resource_type.get(
|
||||
namespace_name)
|
||||
|
||||
# metadefs_resource_type.get() returns generator, converting it to list
|
||||
@ -818,7 +724,7 @@ def metadefs_namespace_resource_types(request, namespace_name):
|
||||
def metadefs_namespace_add_resource_type(request,
|
||||
namespace_name,
|
||||
resource_type):
|
||||
return glanceclient(request, '2').metadefs_resource_type.associate(
|
||||
return glanceclient(request).metadefs_resource_type.associate(
|
||||
namespace_name, **resource_type)
|
||||
|
||||
|
||||
@ -826,7 +732,7 @@ def metadefs_namespace_add_resource_type(request,
|
||||
def metadefs_namespace_remove_resource_type(request,
|
||||
namespace_name,
|
||||
resource_type_name):
|
||||
glanceclient(request, '2').metadefs_resource_type.deassociate(
|
||||
glanceclient(request).metadefs_resource_type.deassociate(
|
||||
namespace_name, resource_type_name)
|
||||
|
||||
|
||||
|
@ -87,52 +87,6 @@ class UpdateImageFormTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
mock_image_get.assert_called_once_with(test.IsHttpRequest(),
|
||||
image.id)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
@mock.patch.object(api.glance, 'image_get')
|
||||
@mock.patch.object(api.glance, 'image_update')
|
||||
def test_image_update_post_v1(self, mock_image_update, mock_image_get):
|
||||
image = self.images.first()
|
||||
data = {
|
||||
'name': u'Ubuntu 11.10',
|
||||
'image_id': str(image.id),
|
||||
'description': u'Login with admin/admin',
|
||||
'source_type': u'url',
|
||||
'image_url': u'http://cloud-images.ubuntu.com/releases/'
|
||||
u'oneiric/release/ubuntu-11.10-server-cloudimg'
|
||||
u'-amd64-disk1.img',
|
||||
'disk_format': u'qcow2',
|
||||
'architecture': u'x86-64',
|
||||
'min_disk': 15,
|
||||
'min_ram': 512,
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'method': 'UpdateImageForm'}
|
||||
|
||||
mock_image_get.return_value = image
|
||||
mock_image_update.return_value = image
|
||||
|
||||
url = reverse('horizon:project:images:images:update',
|
||||
args=[image.id])
|
||||
res = self.client.post(url, data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertEqual(res.status_code, 302)
|
||||
mock_image_get.assert_called_once_with(test.IsHttpRequest(),
|
||||
str(image.id))
|
||||
mock_image_update.assert_called_once_with(
|
||||
test.IsHttpRequest(),
|
||||
image.id,
|
||||
is_public=data['is_public'],
|
||||
protected=data['protected'],
|
||||
disk_format=data['disk_format'],
|
||||
container_format="bare",
|
||||
name=data['name'],
|
||||
min_ram=data['min_ram'],
|
||||
min_disk=data['min_disk'],
|
||||
properties={
|
||||
'description': data['description'],
|
||||
'architecture': data['architecture']})
|
||||
|
||||
@mock.patch.object(api.glance, 'image_get')
|
||||
@mock.patch.object(api.glance, 'image_update')
|
||||
def test_image_update_post_v2(self, mock_image_update, mock_image_get):
|
||||
@ -196,30 +150,6 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
self.assertTemplateUsed(res, 'project/images/images/create.html')
|
||||
mock_image_list.assert_has_calls(image_calls)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_image_create_post_copy_from_v1(self):
|
||||
data = {
|
||||
'source_type': u'url',
|
||||
'image_url': u'http://cloud-images.ubuntu.com/releases/'
|
||||
u'oneiric/release/ubuntu-11.10-server-cloudimg'
|
||||
u'-amd64-disk1.img',
|
||||
'is_copying': True}
|
||||
|
||||
api_data = {'copy_from': data['image_url']}
|
||||
self._test_image_create(data, api_data)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_image_create_post_location_v1(self):
|
||||
data = {
|
||||
'source_type': u'url',
|
||||
'image_url': u'http://cloud-images.ubuntu.com/releases/'
|
||||
u'oneiric/release/ubuntu-11.10-server-cloudimg'
|
||||
u'-amd64-disk1.img',
|
||||
'is_copying': False}
|
||||
|
||||
api_data = {'location': data['image_url']}
|
||||
self._test_image_create(data, api_data)
|
||||
|
||||
@override_settings(IMAGES_ALLOW_LOCATION=True)
|
||||
def test_image_create_post_location_v2(self):
|
||||
data = {
|
||||
@ -231,19 +161,6 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
api_data = {'location': data['image_url']}
|
||||
self._test_image_create(data, api_data)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_image_create_post_upload_v1(self):
|
||||
temp_file = tempfile.NamedTemporaryFile()
|
||||
temp_file.write(b'123')
|
||||
temp_file.flush()
|
||||
temp_file.seek(0)
|
||||
|
||||
data = {'source_type': u'file',
|
||||
'image_file': temp_file}
|
||||
|
||||
api_data = {'data': test.IsA(InMemoryUploadedFile)}
|
||||
self._test_image_create(data, api_data)
|
||||
|
||||
def test_image_create_post_upload_v2(self):
|
||||
temp_file = tempfile.NamedTemporaryFile()
|
||||
temp_file.write(b'123')
|
||||
@ -256,23 +173,6 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
api_data = {'data': test.IsA(InMemoryUploadedFile)}
|
||||
self._test_image_create(data, api_data)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_image_create_post_with_kernel_ramdisk_v1(self):
|
||||
temp_file = tempfile.NamedTemporaryFile()
|
||||
temp_file.write(b'123')
|
||||
temp_file.flush()
|
||||
temp_file.seek(0)
|
||||
|
||||
data = {
|
||||
'source_type': u'file',
|
||||
'image_file': temp_file,
|
||||
'kernel_id': '007e7d55-fe1e-4c5c-bf08-44b4a496482e',
|
||||
'ramdisk_id': '007e7d55-fe1e-4c5c-bf08-44b4a496482a'
|
||||
}
|
||||
|
||||
api_data = {'data': test.IsA(InMemoryUploadedFile)}
|
||||
self._test_image_create(data, api_data)
|
||||
|
||||
def test_image_create_post_with_kernel_ramdisk_v2(self):
|
||||
temp_file = tempfile.NamedTemporaryFile()
|
||||
temp_file.write(b'123')
|
||||
@ -360,12 +260,6 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
mock_image_get.assert_called_once_with(test.IsHttpRequest(),
|
||||
six.text_type(image.id))
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_image_detail_get_v1(self):
|
||||
image = self.images.first()
|
||||
|
||||
self._test_image_detail_get(image)
|
||||
|
||||
def test_image_detail_get_v2(self):
|
||||
image = self.imagesV2.first()
|
||||
|
||||
@ -397,12 +291,6 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
mock_image_get.assert_called_once_with(test.IsHttpRequest(),
|
||||
six.text_type(image.id))
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_image_detail_custom_props_get_v1(self):
|
||||
image = self.images.list()[9]
|
||||
|
||||
self._test_image_detail_custom_props_get(image)
|
||||
|
||||
def test_image_detail_custom_props_get_v2(self):
|
||||
image = self.imagesV2.list()[2]
|
||||
|
||||
@ -422,12 +310,6 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
mock_image_get.assert_called_once_with(test.IsHttpRequest(),
|
||||
six.text_type(image.id))
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_protected_image_detail_get_v1(self):
|
||||
image = self.images.list()[2]
|
||||
|
||||
self._test_protected_image_detail_get(image)
|
||||
|
||||
def test_protected_image_detail_get_v2(self):
|
||||
image = self.imagesV2.list()[1]
|
||||
|
||||
|
@ -885,13 +885,6 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
image.min_disk = 30
|
||||
self._test_create_volume_from_image_under_image_min_disk_size(image)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_create_volume_from_image_under_image_prop_min_disk_size_v1(self):
|
||||
image = self.images.get(name="protected_images")
|
||||
image.min_disk = 0
|
||||
image.properties['min_disk'] = 30
|
||||
self._test_create_volume_from_image_under_image_min_disk_size(image)
|
||||
|
||||
def test_create_volume_from_image_under_image_prop_min_disk_size_v2(self):
|
||||
image = self.imagesV2.get(name="protected_images")
|
||||
self._test_create_volume_from_image_under_image_min_disk_size(image)
|
||||
|
@ -12,8 +12,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from glanceclient.v1 import images
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.test.test_data import utils
|
||||
|
||||
@ -47,6 +45,9 @@ class APIResourceV2(dict):
|
||||
|
||||
|
||||
def data(TEST):
|
||||
# TODO(e0ne): merge images with imagesV2 and snapshots with snapshotsV2
|
||||
# test data.
|
||||
|
||||
TEST.images = utils.TestDataContainer()
|
||||
TEST.images_api = utils.TestDataContainer()
|
||||
TEST.snapshots = utils.TestDataContainer()
|
||||
@ -90,14 +91,13 @@ def data(TEST):
|
||||
'is_public': False,
|
||||
'protected': False}
|
||||
|
||||
snapshot = images.Image(images.ImageManager(None), snapshot_dict)
|
||||
snapshot = APIResourceV2(snapshot_dict)
|
||||
TEST.snapshots.add(api.glance.Image(snapshot))
|
||||
snapshot = images.Image(images.ImageManager(None), snapshot_dict_no_owner)
|
||||
snapshot = APIResourceV2(snapshot_dict_no_owner)
|
||||
TEST.snapshots.add(api.glance.Image(snapshot))
|
||||
snapshot = images.Image(images.ImageManager(None), snapshot_dict_queued)
|
||||
snapshot = APIResourceV2(snapshot_dict_queued)
|
||||
TEST.snapshots.add(api.glance.Image(snapshot))
|
||||
snapshot = images.Image(images.ImageManager(None),
|
||||
snapshot_dict_with_volume)
|
||||
snapshot = APIResourceV2(snapshot_dict_with_volume)
|
||||
TEST.snapshots.add(api.glance.Image(snapshot))
|
||||
|
||||
# Images
|
||||
@ -115,7 +115,7 @@ def data(TEST):
|
||||
'protected': False,
|
||||
'min_ram': 0,
|
||||
'created_at': '2014-02-14T20:56:53'}
|
||||
public_image = images.Image(images.ImageManager(None), image_dict)
|
||||
public_image = APIResourceV2(image_dict)
|
||||
|
||||
image_dict = {'id': 'a001c047-22f8-47d0-80a1-8ec94a9524fe',
|
||||
'name': 'private_image',
|
||||
@ -129,7 +129,7 @@ def data(TEST):
|
||||
'protected': False,
|
||||
'min_ram': 0,
|
||||
'created_at': '2014-03-14T12:56:53'}
|
||||
private_image = images.Image(images.ImageManager(None), image_dict)
|
||||
private_image = APIResourceV2(image_dict)
|
||||
|
||||
image_dict = {'id': 'd6936c86-7fec-474a-85c5-5e467b371c3c',
|
||||
'name': 'protected_images',
|
||||
@ -144,7 +144,7 @@ def data(TEST):
|
||||
'protected': True,
|
||||
'min_ram': 0,
|
||||
'created_at': '2014-03-16T06:22:14'}
|
||||
protected_image = images.Image(images.ImageManager(None), image_dict)
|
||||
protected_image = APIResourceV2(image_dict)
|
||||
|
||||
image_dict = {'id': '278905a6-4b52-4d1e-98f9-8c57bb25ba32',
|
||||
'name': None,
|
||||
@ -158,7 +158,7 @@ def data(TEST):
|
||||
'is_public': True,
|
||||
'protected': False,
|
||||
'min_ram': 0}
|
||||
public_image2 = images.Image(images.ImageManager(None), image_dict)
|
||||
public_image2 = APIResourceV2(image_dict)
|
||||
|
||||
image_dict = {'id': '710a1acf-a3e3-41dd-a32d-5d6b6c86ea10',
|
||||
'name': 'private_image 2',
|
||||
@ -171,7 +171,7 @@ def data(TEST):
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'min_ram': 0}
|
||||
private_image2 = images.Image(images.ImageManager(None), image_dict)
|
||||
private_image2 = APIResourceV2(image_dict)
|
||||
|
||||
image_dict = {'id': '7cd892fd-5652-40f3-a450-547615680132',
|
||||
'name': 'private_image 3',
|
||||
@ -184,7 +184,7 @@ def data(TEST):
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'min_ram': 0}
|
||||
private_image3 = images.Image(images.ImageManager(None), image_dict)
|
||||
private_image3 = APIResourceV2(image_dict)
|
||||
|
||||
# A community image. Not public and not local tenant, but visibility
|
||||
# is set as 'community'
|
||||
@ -200,7 +200,7 @@ def data(TEST):
|
||||
'protected': False,
|
||||
'min_ram': 0,
|
||||
'visibility': 'community'}
|
||||
community_image = images.Image(images.ImageManager(None), image_dict)
|
||||
community_image = APIResourceV2(image_dict)
|
||||
|
||||
# A shared image. Not public and not local tenant.
|
||||
image_dict = {'id': 'c8756975-7a3b-4e43-b7f7-433576112849',
|
||||
@ -214,7 +214,7 @@ def data(TEST):
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'min_ram': 0}
|
||||
shared_image1 = images.Image(images.ImageManager(None), image_dict)
|
||||
shared_image1 = APIResourceV2(image_dict)
|
||||
|
||||
# "Official" image. Public and tenant matches an entry
|
||||
# in IMAGES_LIST_FILTER_TENANTS.
|
||||
@ -229,7 +229,7 @@ def data(TEST):
|
||||
'is_public': True,
|
||||
'protected': False,
|
||||
'min_ram': 0}
|
||||
official_image1 = images.Image(images.ImageManager(None), image_dict)
|
||||
official_image1 = APIResourceV2(image_dict)
|
||||
|
||||
image_dict = {'id': 'a67e7d45-fe1e-4c5c-bf08-44b4a4964822',
|
||||
'name': 'multi_prop_image',
|
||||
@ -244,7 +244,7 @@ def data(TEST):
|
||||
'bar': u'bar val'},
|
||||
'is_public': True,
|
||||
'protected': False}
|
||||
multi_prop_image = images.Image(images.ImageManager(None), image_dict)
|
||||
multi_prop_image = APIResourceV2(image_dict)
|
||||
|
||||
# An image without name being returned based on current api
|
||||
image_dict = {'id': 'c8756975-7a3b-4e43-b7f7-433576112849',
|
||||
@ -256,7 +256,7 @@ def data(TEST):
|
||||
'container_format': 'aki',
|
||||
'is_public': False,
|
||||
'protected': False}
|
||||
no_name_image = images.Image(images.ImageManager(None), image_dict)
|
||||
no_name_image = APIResourceV2(image_dict)
|
||||
|
||||
TEST.images_api.add(public_image, private_image, protected_image,
|
||||
public_image2, private_image2, private_image3,
|
||||
|
@ -77,38 +77,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
glance.Image().delete(request, "1")
|
||||
self.mock_image_delete.assert_called_once_with(request, "1")
|
||||
|
||||
@test.create_mocks({api.glance: ['image_update', 'VERSIONS']})
|
||||
def test_image_edit_v1(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "aki", "container_format": "aki",
|
||||
"visibility": "public", "protected": false,
|
||||
"image_url": "test.com",
|
||||
"source_type": "url", "architecture": "testArch",
|
||||
"description": "description", "kernel": "kernel",
|
||||
"min_disk": 10, "min_ram": 5, "ramdisk": 10 }
|
||||
''')
|
||||
self.mock_VERSIONS.active = 1
|
||||
self.mock_image_update.return_value = self.images.first()
|
||||
|
||||
metadata = {'name': 'Test',
|
||||
'disk_format': 'aki',
|
||||
'container_format': 'aki',
|
||||
'is_public': True,
|
||||
'protected': False,
|
||||
'min_disk': 10,
|
||||
'min_ram': 5,
|
||||
'properties': {'description': 'description',
|
||||
'architecture': 'testArch',
|
||||
'ramdisk_id': 10,
|
||||
'kernel_id': 'kernel'}
|
||||
}
|
||||
|
||||
response = glance.Image().patch(request, "1")
|
||||
self.assertStatusCode(response, 204)
|
||||
self.assertEqual(response.content.decode('utf-8'), '')
|
||||
self.mock_image_update.assert_called_once_with(request, '1',
|
||||
**metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_update', 'VERSIONS']})
|
||||
def test_image_edit_v2(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
@ -166,43 +134,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
filters=filters,
|
||||
**kwargs)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v1_basic(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "aki", "import_data": false,
|
||||
"visibility": "public", "container_format": "aki",
|
||||
"protected": false, "image_url": "test.com",
|
||||
"source_type": "url", "architecture": "testArch",
|
||||
"description": "description", "kernel": "kernel",
|
||||
"min_disk": 10, "min_ram": 5, "ramdisk": 10 }
|
||||
''')
|
||||
new = self.mock_image_create.return_value
|
||||
self.mock_VERSIONS.active = 1
|
||||
new.to_dict.return_value = {'name': 'testimage'}
|
||||
new.name = 'testimage'
|
||||
|
||||
metadata = {'name': 'Test',
|
||||
'disk_format': 'aki',
|
||||
'container_format': 'aki',
|
||||
'is_public': True,
|
||||
'protected': False,
|
||||
'min_disk': 10,
|
||||
'min_ram': 5,
|
||||
'location': 'test.com',
|
||||
'properties': {
|
||||
'description': 'description',
|
||||
'architecture': 'testArch',
|
||||
'ramdisk_id': 10,
|
||||
'kernel_id': 'kernel',
|
||||
}}
|
||||
|
||||
response = glance.Images().put(request)
|
||||
self.assertStatusCode(response, 201)
|
||||
self.assertEqual(response.content.decode('utf-8'),
|
||||
'{"name": "testimage"}')
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v2_basic(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
@ -239,43 +170,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v1_shared(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "aki", "import_data": false,
|
||||
"visibility": "shared", "container_format": "aki",
|
||||
"protected": false, "image_url": "test.com",
|
||||
"source_type": "url", "architecture": "testArch",
|
||||
"description": "description", "kernel": "kernel",
|
||||
"min_disk": 10, "min_ram": 5, "ramdisk": 10 }
|
||||
''')
|
||||
self.mock_VERSIONS.active = 1
|
||||
new = self.mock_image_create.return_value
|
||||
new.to_dict.return_value = {'name': 'testimage'}
|
||||
new.name = 'testimage'
|
||||
|
||||
metadata = {'name': 'Test',
|
||||
'disk_format': 'aki',
|
||||
'container_format': 'aki',
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'min_disk': 10,
|
||||
'min_ram': 5,
|
||||
'location': 'test.com',
|
||||
'properties': {
|
||||
'description': 'description',
|
||||
'architecture': 'testArch',
|
||||
'ramdisk_id': 10,
|
||||
'kernel_id': 'kernel',
|
||||
}}
|
||||
|
||||
response = glance.Images().put(request)
|
||||
self.assertStatusCode(response, 201)
|
||||
self.assertEqual(response.content.decode('utf-8'),
|
||||
'{"name": "testimage"}')
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v2_shared(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
@ -312,43 +206,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v1_private(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "aki", "import_data": false,
|
||||
"visibility": "private", "container_format": "aki",
|
||||
"protected": false, "image_url": "test.com",
|
||||
"source_type": "url", "architecture": "testArch",
|
||||
"description": "description", "kernel": "kernel",
|
||||
"min_disk": 10, "min_ram": 5, "ramdisk": 10 }
|
||||
''')
|
||||
self.mock_VERSIONS.active = 1
|
||||
new = self.mock_image_create.return_value
|
||||
new.to_dict.return_value = {'name': 'testimage'}
|
||||
new.name = 'testimage'
|
||||
|
||||
metadata = {'name': 'Test',
|
||||
'disk_format': 'aki',
|
||||
'container_format': 'aki',
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'min_disk': 10,
|
||||
'min_ram': 5,
|
||||
'location': 'test.com',
|
||||
'properties': {
|
||||
'description': 'description',
|
||||
'architecture': 'testArch',
|
||||
'ramdisk_id': 10,
|
||||
'kernel_id': 'kernel',
|
||||
}}
|
||||
|
||||
response = glance.Images().put(request)
|
||||
self.assertStatusCode(response, 201)
|
||||
self.assertEqual(response.content.decode('utf-8'),
|
||||
'{"name": "testimage"}')
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v2_private(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
@ -385,23 +242,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['VERSIONS']})
|
||||
def test_image_create_v1_bad_visibility(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "aki", "import_data": false,
|
||||
"visibility": "verybad", "container_format": "aki",
|
||||
"protected": false, "image_url": "test.com",
|
||||
"source_type": "url", "architecture": "testArch",
|
||||
"description": "description", "kernel": "kernel",
|
||||
"min_disk": 10, "min_ram": 5, "ramdisk": 10 }
|
||||
''')
|
||||
self.mock_VERSIONS.active = 1
|
||||
|
||||
response = glance.Images().put(request)
|
||||
self.assertStatusCode(response, 400)
|
||||
self.assertEqual(response.content.decode('utf-8'),
|
||||
'"invalid visibility option: verybad"')
|
||||
|
||||
@test.create_mocks({api.glance: ['VERSIONS']})
|
||||
def test_image_create_v2_bad_visibility(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
@ -419,33 +259,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
self.assertEqual(response.content.decode('utf-8'),
|
||||
'"invalid visibility option: verybad"')
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v1_required(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "raw", "import_data": true,
|
||||
"container_format": "docker",
|
||||
"visibility": "public", "protected": false,
|
||||
"source_type": "url", "image_url": "test.com" }''')
|
||||
self.mock_VERSIONS.active = 1
|
||||
new = self.mock_image_create.return_value
|
||||
new.to_dict.return_value = {'name': 'testimage'}
|
||||
new.name = 'testimage'
|
||||
|
||||
metadata = {'name': 'Test',
|
||||
'disk_format': 'raw',
|
||||
'container_format': 'docker',
|
||||
'copy_from': 'test.com',
|
||||
'is_public': True,
|
||||
'protected': False,
|
||||
'min_disk': 0,
|
||||
'min_ram': 0,
|
||||
'properties': {}
|
||||
}
|
||||
response = glance.Images().put(request)
|
||||
self.assertStatusCode(response, 201)
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v2_required(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
@ -472,34 +285,6 @@ class ImagesRestTestCase(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v1_additional_props(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
"disk_format": "raw", "import_data": true,
|
||||
"container_format": "docker",
|
||||
"visibility": "public", "protected": false,
|
||||
"arbitrary": "property", "another": "prop",
|
||||
"source_type": "url", "image_url": "test.com" }''')
|
||||
self.mock_VERSIONS.active = 1
|
||||
new = self.mock_image_create.return_value
|
||||
new.to_dict.return_value = {'name': 'testimage'}
|
||||
new.name = 'testimage'
|
||||
|
||||
metadata = {'name': 'Test',
|
||||
'disk_format': 'raw',
|
||||
'container_format': 'docker',
|
||||
'copy_from': 'test.com',
|
||||
'is_public': True,
|
||||
'protected': False,
|
||||
'min_disk': 0,
|
||||
'min_ram': 0,
|
||||
'properties': {'arbitrary': 'property', 'another': 'prop'}
|
||||
}
|
||||
response = glance.Images().put(request)
|
||||
self.assertStatusCode(response, 201)
|
||||
self.assertEqual(response['location'], '/api/glance/images/testimage')
|
||||
self.mock_image_create.assert_called_once_with(request, **metadata)
|
||||
|
||||
@test.create_mocks({api.glance: ['image_create', 'VERSIONS']})
|
||||
def test_image_create_v2_additional_props(self):
|
||||
request = self.mock_rest_request(body='''{"name": "Test",
|
||||
|
@ -359,18 +359,6 @@ class GlanceApiTests(test.APIMockTestCase):
|
||||
self.assertEqual(1, len(defs))
|
||||
self.assertEqual('namespace_4', defs[0].namespace)
|
||||
|
||||
@mock.patch.object(api.glance, 'get_version', return_value=1)
|
||||
def test_metadefs_namespace_list_v1(self, mock_version):
|
||||
defs, more, prev = api.glance.metadefs_namespace_list(self.request)
|
||||
self.assertItemsEqual(defs, [])
|
||||
self.assertFalse(more)
|
||||
self.assertFalse(prev)
|
||||
|
||||
@mock.patch.object(api.glance, 'get_version', return_value=1)
|
||||
def test_metadefs_resource_types_list_v1(self, mock_version):
|
||||
res_types = api.glance.metadefs_resource_types_list(self.request)
|
||||
self.assertItemsEqual(res_types, [])
|
||||
|
||||
@mock.patch.object(api.glance, 'glanceclient')
|
||||
def _test_image_create_external_upload(self, mock_glanceclient,
|
||||
api_version=2):
|
||||
@ -393,39 +381,9 @@ class GlanceApiTests(test.APIMockTestCase):
|
||||
self.assertEqual(upload_url, actual_image.upload_url)
|
||||
self.assertEqual(self.request.user.token.id, actual_image.token_id)
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={"image": 1})
|
||||
def test_image_create_v1_external_upload(self):
|
||||
self._test_image_create_external_upload(api_version=1)
|
||||
|
||||
def test_image_create_v2_external_upload(self):
|
||||
self._test_image_create_external_upload()
|
||||
|
||||
@override_settings(OPENSTACK_API_VERSIONS={'image': 1})
|
||||
def test_create_image_metadata_docker_v1(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',
|
||||
'min_disk': 15,
|
||||
'min_ram': 512,
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
'is_copying': False
|
||||
}
|
||||
meta = api.glance.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'])
|
||||
|
||||
def test_create_image_metadata_docker_v2(self):
|
||||
form_data = {
|
||||
'name': u'Docker image',
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Glance API V1 support has been dropped in Ussuri release. Glance V1 API
|
||||
support was deprecated in Stein release.
|
Loading…
Reference in New Issue
Block a user