Add minDisk and minRam to OSAPI image details

Change-Id: I4bf1920a245de85c88c38ec3ad82dc0e93cc671c
This commit is contained in:
Alex Meade
2011-09-15 14:46:19 -04:00
parent 37100f5653
commit 64736d1e12
10 changed files with 327 additions and 1 deletions

View File

@@ -187,6 +187,10 @@ class CreateInstanceHelper(object):
config_drive=config_drive,))
except quota.QuotaError as error:
self._handle_quota_error(error)
except exception.InstanceTypeMemoryTooSmall as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
except exception.InstanceTypeDiskTooSmall as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
except exception.ImageNotFound as error:
msg = _("Can not find requested image")
raise exc.HTTPBadRequest(explanation=msg)

View File

@@ -41,6 +41,8 @@ SUPPORTED_FILTERS = {
'changes-since': 'changes-since',
'server': 'property-instance_ref',
'type': 'property-image_type',
'minRam': 'min_ram',
'minDisk': 'min_disk',
}
@@ -239,6 +241,10 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer):
image_elem.set('status', str(image_dict['status']))
if 'progress' in image_dict:
image_elem.set('progress', str(image_dict['progress']))
if 'minRam' in image_dict:
image_elem.set('minRam', str(image_dict['minRam']))
if 'minDisk' in image_dict:
image_elem.set('minDisk', str(image_dict['minDisk']))
if 'server' in image_dict:
server_elem = self._create_server_node(image_dict['server'])
image_elem.append(server_elem)

View File

@@ -8,6 +8,12 @@
<optional>
<attribute name="progress"> <text/> </attribute>
</optional>
<optional>
<attribute name="minDisk"> <text/> </attribute>
</optional>
<optional>
<attribute name="minRam"> <text/> </attribute>
</optional>
<optional>
<element name="server">
<attribute name="id"> <text/> </attribute>

View File

@@ -161,6 +161,11 @@ class ViewBuilderV11(ViewBuilder):
if detail:
image["metadata"] = image_obj.get("properties", {})
if 'min_ram' in image_obj:
image["minRam"] = image_obj.get("min_ram") or 0
if 'min_disk' in image_obj:
image["minDisk"] = image_obj.get("min_disk") or 0
return image

View File

@@ -219,6 +219,11 @@ class API(base.Base):
image_href)
image = image_service.show(context, image_id)
if instance_type['memory_mb'] < int(image.get('min_ram', 0)):
raise exception.InstanceTypeMemoryTooSmall()
if instance_type['local_gb'] < int(image.get('min_disk', 0)):
raise exception.InstanceTypeDiskTooSmall()
config_drive_id = None
if config_drive and config_drive is not True:
# config_drive is volume id

View File

@@ -810,3 +810,11 @@ class ZoneRequestError(Error):
if message is None:
message = _("1 or more Zones could not complete the request")
super(ZoneRequestError, self).__init__(message=message)
class InstanceTypeMemoryTooSmall(NovaException):
message = _("Instance type's memory is too small for requested image.")
class InstanceTypeDiskTooSmall(NovaException):
message = _("Instance type's disk is too small for requested image.")

View File

@@ -404,7 +404,7 @@ def _limit_attributes(image_meta):
'container_format', 'checksum', 'id',
'name', 'created_at', 'updated_at',
'deleted_at', 'deleted', 'status',
'is_public']
'min_disk', 'min_ram', 'is_public']
output = {}
for attr in IMAGE_ATTRIBUTES:
output[attr] = image_meta.get(attr)

View File

@@ -113,6 +113,7 @@ class ImagesTest(test.TestCase):
self.assertDictMatch(expected_image, actual_image)
def test_get_image_v1_1(self):
self.maxDiff = None
request = webob.Request.blank('/v1.1/fake/images/124')
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
response = request.get_response(app)
@@ -133,6 +134,8 @@ class ImagesTest(test.TestCase):
"created": NOW_API_FORMAT,
"status": "SAVING",
"progress": 0,
"minDisk": 0,
"minRam": 0,
'server': {
'id': '42',
"links": [{
@@ -542,6 +545,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'ACTIVE',
'progress': 100,
'minDisk': 0,
'minRam': 0,
"links": [{
"rel": "self",
"href": "http://localhost/v1.1/fake/images/123",
@@ -567,6 +572,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'SAVING',
'progress': 0,
'minDisk': 0,
'minRam': 0,
'server': {
'id': '42',
"links": [{
@@ -603,6 +610,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'SAVING',
'progress': 0,
'minDisk': 0,
'minRam': 0,
'server': {
'id': '42',
"links": [{
@@ -639,6 +648,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'ACTIVE',
'progress': 100,
'minDisk': 0,
'minRam': 0,
'server': {
'id': '42',
"links": [{
@@ -675,6 +686,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'ERROR',
'progress': 0,
'minDisk': 0,
'minRam': 0,
'server': {
'id': '42',
"links": [{
@@ -711,6 +724,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'DELETED',
'progress': 0,
'minDisk': 0,
'minRam': 0,
'server': {
'id': '42',
"links": [{
@@ -747,6 +762,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'DELETED',
'progress': 0,
'minDisk': 0,
'minRam': 0,
'server': {
'id': '42',
"links": [{
@@ -780,6 +797,8 @@ class ImagesTest(test.TestCase):
'created': NOW_API_FORMAT,
'status': 'ACTIVE',
'progress': 100,
'minDisk': 0,
'minRam': 0,
"links": [{
"rel": "self",
"href": "http://localhost/v1.1/fake/images/130",
@@ -810,6 +829,30 @@ class ImagesTest(test.TestCase):
controller.index(request)
self.mox.VerifyAll()
def test_image_filter_with_min_ram(self):
image_service = self.mox.CreateMockAnything()
context = self._get_fake_context()
filters = {'min_ram': '0'}
image_service.index(context, filters=filters).AndReturn([])
self.mox.ReplayAll()
request = webob.Request.blank('/v1.1/images?minRam=0')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.index(request)
self.mox.VerifyAll()
def test_image_filter_with_min_disk(self):
image_service = self.mox.CreateMockAnything()
context = self._get_fake_context()
filters = {'min_disk': '7'}
image_service.index(context, filters=filters).AndReturn([])
self.mox.ReplayAll()
request = webob.Request.blank('/v1.1/images?minDisk=7')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.index(request)
self.mox.VerifyAll()
def test_image_filter_with_status(self):
image_service = self.mox.CreateMockAnything()
context = self._get_fake_context()
@@ -1369,6 +1412,152 @@ class ImageXMLSerializationTest(test.TestCase):
server_root = root.find('{0}server'.format(NS))
self.assertEqual(server_root, None)
def test_show_with_min_ram(self):
serializer = images.ImageXMLSerializer()
fixture = {
'image': {
'id': 1,
'name': 'Image1',
'created': self.TIMESTAMP,
'updated': self.TIMESTAMP,
'status': 'ACTIVE',
'progress': 80,
'minRam': 256,
'server': {
'id': '1',
'links': [
{
'href': self.SERVER_HREF,
'rel': 'self',
},
{
'href': self.SERVER_BOOKMARK,
'rel': 'bookmark',
},
],
},
'metadata': {
'key1': 'value1',
},
'links': [
{
'href': self.IMAGE_HREF % 1,
'rel': 'self',
},
{
'href': self.IMAGE_BOOKMARK % 1,
'rel': 'bookmark',
},
],
},
}
output = serializer.serialize(fixture, 'show')
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'image')
image_dict = fixture['image']
for key in ['name', 'id', 'updated', 'created', 'status', 'progress',
'minRam']:
self.assertEqual(root.get(key), str(image_dict[key]))
link_nodes = root.findall('{0}link'.format(ATOMNS))
self.assertEqual(len(link_nodes), 2)
for i, link in enumerate(image_dict['links']):
for key, value in link.items():
self.assertEqual(link_nodes[i].get(key), value)
metadata_root = root.find('{0}metadata'.format(NS))
metadata_elems = metadata_root.findall('{0}meta'.format(NS))
self.assertEqual(len(metadata_elems), 1)
for i, metadata_elem in enumerate(metadata_elems):
(meta_key, meta_value) = image_dict['metadata'].items()[i]
self.assertEqual(str(metadata_elem.get('key')), str(meta_key))
self.assertEqual(str(metadata_elem.text).strip(), str(meta_value))
server_root = root.find('{0}server'.format(NS))
self.assertEqual(server_root.get('id'), image_dict['server']['id'])
link_nodes = server_root.findall('{0}link'.format(ATOMNS))
self.assertEqual(len(link_nodes), 2)
for i, link in enumerate(image_dict['server']['links']):
for key, value in link.items():
self.assertEqual(link_nodes[i].get(key), value)
def test_show_with_min_disk(self):
serializer = images.ImageXMLSerializer()
fixture = {
'image': {
'id': 1,
'name': 'Image1',
'created': self.TIMESTAMP,
'updated': self.TIMESTAMP,
'status': 'ACTIVE',
'progress': 80,
'minDisk': 5,
'server': {
'id': '1',
'links': [
{
'href': self.SERVER_HREF,
'rel': 'self',
},
{
'href': self.SERVER_BOOKMARK,
'rel': 'bookmark',
},
],
},
'metadata': {
'key1': 'value1',
},
'links': [
{
'href': self.IMAGE_HREF % 1,
'rel': 'self',
},
{
'href': self.IMAGE_BOOKMARK % 1,
'rel': 'bookmark',
},
],
},
}
output = serializer.serialize(fixture, 'show')
print output
root = etree.XML(output)
xmlutil.validate_schema(root, 'image')
image_dict = fixture['image']
for key in ['name', 'id', 'updated', 'created', 'status', 'progress',
'minDisk']:
self.assertEqual(root.get(key), str(image_dict[key]))
link_nodes = root.findall('{0}link'.format(ATOMNS))
self.assertEqual(len(link_nodes), 2)
for i, link in enumerate(image_dict['links']):
for key, value in link.items():
self.assertEqual(link_nodes[i].get(key), value)
metadata_root = root.find('{0}metadata'.format(NS))
metadata_elems = metadata_root.findall('{0}meta'.format(NS))
self.assertEqual(len(metadata_elems), 1)
for i, metadata_elem in enumerate(metadata_elems):
(meta_key, meta_value) = image_dict['metadata'].items()[i]
self.assertEqual(str(metadata_elem.get('key')), str(meta_key))
self.assertEqual(str(metadata_elem.text).strip(), str(meta_value))
server_root = root.find('{0}server'.format(NS))
self.assertEqual(server_root.get('id'), image_dict['server']['id'])
link_nodes = server_root.findall('{0}link'.format(ATOMNS))
self.assertEqual(len(link_nodes), 2)
for i, link in enumerate(image_dict['server']['links']):
for key, value in link.items():
self.assertEqual(link_nodes[i].get(key), value)
def test_index(self):
serializer = images.ImageXMLSerializer()

View File

@@ -127,6 +127,8 @@ class TestGlanceImageService(test.TestCase):
'name': 'test image',
'is_public': False,
'size': None,
'min_disk': None,
'min_ram': None,
'location': None,
'disk_format': None,
'container_format': None,
@@ -157,6 +159,8 @@ class TestGlanceImageService(test.TestCase):
'name': 'test image',
'is_public': False,
'size': None,
'min_disk': None,
'min_ram': None,
'location': None,
'disk_format': None,
'container_format': None,
@@ -287,6 +291,8 @@ class TestGlanceImageService(test.TestCase):
'name': 'TestImage %d' % (i),
'properties': {},
'size': None,
'min_disk': None,
'min_ram': None,
'location': None,
'disk_format': None,
'container_format': None,
@@ -330,6 +336,8 @@ class TestGlanceImageService(test.TestCase):
'name': 'TestImage %d' % (i),
'properties': {},
'size': None,
'min_disk': None,
'min_ram': None,
'location': None,
'disk_format': None,
'container_format': None,
@@ -382,6 +390,8 @@ class TestGlanceImageService(test.TestCase):
'name': 'image1',
'is_public': True,
'size': None,
'min_disk': None,
'min_ram': None,
'location': None,
'disk_format': None,
'container_format': None,
@@ -416,6 +426,8 @@ class TestGlanceImageService(test.TestCase):
'name': 'image10',
'is_public': True,
'size': None,
'min_disk': None,
'min_ram': None,
'location': None,
'disk_format': None,
'container_format': None,

View File

@@ -20,6 +20,8 @@
Tests For Compute
"""
from copy import copy
from nova import compute
from nova import context
from nova import db
@@ -1394,3 +1396,92 @@ class ComputeTestCase(test.TestCase):
self.assertEqual(self.compute_api._volume_size(inst_type,
'swap'),
swap_size)
class ComputeTestMinRamMinDisk(test.TestCase):
def setUp(self):
super(ComputeTestMinRamMinDisk, self).setUp()
self.compute = utils.import_object(FLAGS.compute_manager)
self.compute_api = compute.API()
self.context = context.RequestContext('fake', 'fake')
self.fake_image = {
'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}}
def test_create_with_too_little_ram(self):
"""Test an instance type with too little memory"""
inst_type = instance_types.get_default_instance_type()
inst_type['memory_mb'] = 1
def fake_show(*args):
img = copy(self.fake_image)
img['min_ram'] = 2
return img
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
self.assertRaises(exception.InstanceTypeMemoryTooSmall,
self.compute_api.create, self.context, inst_type, None)
# Now increase the inst_type memory and make sure all is fine.
inst_type['memory_mb'] = 2
ref = self.compute_api.create(self.context, inst_type, None)
self.assertTrue(ref)
db.instance_destroy(self.context, ref[0]['id'])
def test_create_with_too_little_disk(self):
"""Test an instance type with too little disk space"""
inst_type = instance_types.get_default_instance_type()
inst_type['local_gb'] = 1
def fake_show(*args):
img = copy(self.fake_image)
img['min_disk'] = 2
return img
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
self.assertRaises(exception.InstanceTypeDiskTooSmall,
self.compute_api.create, self.context, inst_type, None)
# Now increase the inst_type disk space and make sure all is fine.
inst_type['local_gb'] = 2
ref = self.compute_api.create(self.context, inst_type, None)
self.assertTrue(ref)
db.instance_destroy(self.context, ref[0]['id'])
def test_create_just_enough_ram_and_disk(self):
"""Test an instance type with just enough ram and disk space"""
inst_type = instance_types.get_default_instance_type()
inst_type['local_gb'] = 2
inst_type['memory_mb'] = 2
def fake_show(*args):
img = copy(self.fake_image)
img['min_ram'] = 2
img['min_disk'] = 2
return img
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
ref = self.compute_api.create(self.context, inst_type, None)
self.assertTrue(ref)
db.instance_destroy(self.context, ref[0]['id'])
def test_create_with_no_ram_and_disk_reqs(self):
"""Test an instance type with no min_ram or min_disk"""
inst_type = instance_types.get_default_instance_type()
inst_type['local_gb'] = 1
inst_type['memory_mb'] = 1
def fake_show(*args):
return copy(self.fake_image)
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
ref = self.compute_api.create(self.context, inst_type, None)
self.assertTrue(ref)
db.instance_destroy(self.context, ref[0]['id'])