Merge "V2: Do not validate image schema when listing"

This commit is contained in:
Jenkins
2015-08-20 17:28:21 +00:00
committed by Gerrit Code Review
3 changed files with 381 additions and 14 deletions

View File

@@ -0,0 +1,307 @@
# Copyright (c) 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
UUID = "3fc2ba62-9a02-433e-b565-d493ffc69034"
image_list_fixture = {
"images": [
{
"checksum": "9cb02fe7fcac26f8a25d6db3109063ae",
"container_format": "bare",
"created_at": "2015-07-23T16:58:50.000000",
"deleted": "false",
"deleted_at": "null",
"disk_format": "raw",
"id": UUID,
"is_public": "false",
"min_disk": 0,
"min_ram": 0,
"name": "test",
"owner": "3447cea05d6947658d73791ed9e0ed9f",
"properties": {
"kernel_id": 1234,
"ramdisk_id": 5678
},
"protected": "false",
"size": 145,
"status": "active",
"updated_at": "2015-07-23T16:58:51.000000",
"virtual_size": "null"
}
]
}
image_show_fixture = {
"checksum": "9cb02fe7fcac26f8a25d6db3109063ae",
"container_format": "bare",
"created_at": "2015-07-24T12:18:13Z",
"disk_format": "raw",
"file": "/v2/images/%s/file" % UUID,
"id": UUID,
"kernel_id": "1234",
"min_disk": 0,
"min_ram": 0,
"name": "img1",
"owner": "411423405e10431fb9c47ac5b2446557",
"protected": "false",
"ramdisk_id": "5678",
"schema": "/v2/schemas/image",
"self": "/v2/images/%s" % UUID,
"size": 145,
"status": "active",
"tags": [],
"updated_at": "2015-07-24T12:18:13Z",
"virtual_size": "null",
"visibility": "private"
}
schema_fixture = {
"additionalProperties": {
"type": "string"
},
"links": [
{
"href": "{self}",
"rel": "self"
},
{
"href": "{file}",
"rel": "enclosure"
},
{
"href": "{schema}",
"rel": "describedby"
}
],
"name": "image",
"properties": {
"architecture": {
"description": "Operating system architecture as specified in "
"http://docs.openstack.org/trunk/openstack-compute"
"/admin/content/adding-images.html",
"is_base": "false",
"type": "string"
},
"checksum": {
"description": "md5 hash of image contents. (READ-ONLY)",
"maxLength": 32,
"type": [
"null",
"string"
]
},
"container_format": {
"description": "Format of the container",
"enum": [
"null",
"ami",
"ari",
"aki",
"bare",
"ovf",
"ova"
],
"type": [
"null",
"string"
]
},
"created_at": {
"description": "Date and time of image registration (READ-ONLY)",
"type": "string"
},
"direct_url": {
"description": "URL to access the image file kept in external "
"store (READ-ONLY)",
"type": "string"
},
"disk_format": {
"description": "Format of the disk",
"enum": [
"null",
"ami",
"ari",
"aki",
"vhd",
"vmdk",
"raw",
"qcow2",
"vdi",
"iso"
],
"type": [
"null",
"string"
]
},
"file": {
"description": "(READ-ONLY)",
"type": "string"
},
"id": {
"description": "An identifier for the image",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F])"
"{4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"type": "string"
},
"instance_uuid": {
"description": "ID of instance used to create this image.",
"is_base": "false",
"type": "string"
},
"kernel_id": {
"description": "ID of image stored in Glance that should be used "
"as the kernel when booting an AMI-style image.",
"is_base": "false",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F])"
"{4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"type": [
"null",
"string"
]
},
"locations": {
"description": "A set of URLs to access the image file kept "
"in external store",
"items": {
"properties": {
"metadata": {
"type": "object"
},
"url": {
"maxLength": 255,
"type": "string"
}
},
"required": [
"url",
"metadata"
],
"type": "object"
},
"type": "array"
},
"min_disk": {
"description": "Amount of disk space (in GB) required to "
"boot image.",
"type": "integer"
},
"min_ram": {
"description": "Amount of ram (in MB) required to boot image.",
"type": "integer"
},
"name": {
"description": "Descriptive name for the image",
"maxLength": 255,
"type": [
"null",
"string"
]
},
"os_distro": {
"description": "Common name of operating system distribution as "
"specified in http://docs.openstack.org/trunk/"
"openstack-compute/admin/content/"
"adding-images.html",
"is_base": "false",
"type": "string"
},
"os_version": {
"description": "Operating system version as specified "
"by the distributor",
"is_base": "false",
"type": "string"
},
"owner": {
"description": "Owner of the image",
"maxLength": 255,
"type": [
"null",
"string"
]
},
"protected": {
"description": "If true, image will not be deletable.",
"type": "boolean"
},
"ramdisk_id": {
"description": "ID of image stored in Glance that should be used "
"as the ramdisk when booting an AMI-style image.",
"is_base": "false",
"pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F])"
"{4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$",
"type": [
"null",
"string"
]
},
"schema": {
"description": "(READ-ONLY)",
"type": "string"
},
"self": {
"description": "(READ-ONLY)",
"type": "string"
},
"size": {
"description": "Size of image file in bytes (READ-ONLY)",
"type": [
"null",
"integer"
]
},
"status": {
"description": "Status of the image (READ-ONLY)",
"enum": [
"queued",
"saving",
"active",
"killed",
"deleted",
"pending_delete"
],
"type": "string"
},
"tags": {
"description": "List of strings related to the image",
"items": {
"maxLength": 255,
"type": "string"
},
"type": "array"
},
"updated_at": {
"description": "Date and time of the last image "
"modification (READ-ONLY)",
"type": "string"
},
"virtual_size": {
"description": "Virtual size of image in bytes (READ-ONLY)",
"type": [
"null",
"integer"
]
},
"visibility": {
"description": "Scope of image accessibility",
"enum": [
"public",
"private"
],
"type": "string"
}
}
}

View File

@@ -0,0 +1,58 @@
# Copyright (c) 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from requests_mock.contrib import fixture as rm_fixture
from glanceclient import client
from glanceclient.tests.unit.v2.fixtures import image_list_fixture
from glanceclient.tests.unit.v2.fixtures import image_show_fixture
from glanceclient.tests.unit.v2.fixtures import schema_fixture
from glanceclient.tests import utils as testutils
class ClientTestRequests(testutils.TestCase):
"""Client tests using the requests mock library."""
def test_list_bad_image_schema(self):
# if kernel_id or ramdisk_id are not uuids, verify we can
# still perform an image listing. Regression test for bug
# 1477910
self.requests = self.useFixture(rm_fixture.Fixture())
self.requests.get('http://example.com/v2/schemas/image',
json=schema_fixture)
self.requests.get('http://example.com/v2/images?limit=20',
json=image_list_fixture)
gc = client.Client(2.2, "http://example.com/v2.1")
images = gc.images.list()
for image in images:
pass
def test_show_bad_image_schema(self):
# if kernel_id or ramdisk_id are not uuids, verify we
# fail schema validation on 'show'
self.requests = self.useFixture(rm_fixture.Fixture())
self.requests.get('http://example.com/v2/schemas/image',
json=schema_fixture)
self.requests.get('http://example.com/v2/images/%s'
% image_show_fixture['id'],
json=image_show_fixture)
gc = client.Client(2.2, "http://example.com/v2.1")
try:
gc.images.get(image_show_fixture['id'])
self.fail('Expected exception was not raised.')
except ValueError as e:
if 'ramdisk_id' not in str(e) and 'kernel_id' not in str(e):
self.fail('Expected exception message was not returned.')

View File

@@ -39,7 +39,18 @@ class Controller(object):
@utils.memoized_property
def model(self):
schema = self.schema_client.get('image')
return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
warlock_model = warlock.model_factory(schema.raw(),
schemas.SchemaBasedModel)
return warlock_model
@utils.memoized_property
def unvalidated_model(self):
"""A model which does not validate the image against the v2 schema."""
schema = self.schema_client.get('image')
warlock_model = warlock.model_factory(schema.raw(),
schemas.SchemaBasedModel)
warlock_model.validate = lambda *args, **kwargs: None
return warlock_model
@staticmethod
def _wrap(value):
@@ -78,9 +89,6 @@ class Controller(object):
:returns: generator over list of Images.
"""
ori_validate_fun = self.model.validate
empty_fun = lambda *args, **kwargs: None
limit = kwargs.get('limit')
# NOTE(flaper87): Don't use `get('page_size', DEFAULT_SIZE)` otherwise,
# it could be possible to send invalid data to the server by passing
@@ -103,21 +111,15 @@ class Controller(object):
# an elegant way to pass it into the model constructor
# without conflict.
image.pop('self', None)
yield self.model(**image)
# NOTE(zhiyan): In order to resolve the performance issue
# of JSON schema validation for image listing case, we
# don't validate each image entry but do it only on first
# image entry for each page.
self.model.validate = empty_fun
# We do not validate the model when listing.
# This prevents side-effects of injecting invalid
# schema values via v1.
yield self.unvalidated_model(**image)
if limit:
limit -= 1
if limit <= 0:
raise StopIteration
# NOTE(zhiyan); Reset validation function.
self.model.validate = ori_validate_fun
try:
next_url = body['next']
except KeyError: