Adds disk_format and container_format to Image, and

removes the type column.

Needs migrate script, but having trouble getting sqlalchemy
migrate to work with any call to drop_column(). :(
This commit is contained in:
jaypipes@gmail.com 2011-02-23 17:16:32 -05:00
parent 2201bf2106
commit 1550ea4c20
11 changed files with 125 additions and 131 deletions

View File

@ -40,7 +40,8 @@ BASE = models.BASE
BASE_MODEL_ATTRS = set(['id', 'created_at', 'updated_at', 'deleted_at',
'deleted'])
IMAGE_ATTRS = BASE_MODEL_ATTRS | set(['name', 'type', 'status', 'size',
IMAGE_ATTRS = BASE_MODEL_ATTRS | set(['name', 'status', 'size',
'disk_format', 'container_format',
'is_public', 'location'])
@ -152,14 +153,7 @@ def validate_image(values):
:param values: Mapping of image metadata to check
"""
type = values.get('type', None)
if not type:
msg = "Image type is required."
raise exception.Invalid(msg)
if type not in ('machine', 'kernel', 'ramdisk', 'raw', 'vhd'):
msg = "Invalid image type '%s' for image." % type
raise exception.Invalid(msg)
status = values.get('status', None)
status = values.get('status')
if not status:
msg = "Image status is required."
raise exception.Invalid(msg)
@ -167,6 +161,16 @@ def validate_image(values):
msg = "Invalid image status '%s' for image." % status
raise exception.Invalid(msg)
disk_format = values.get('disk_format')
if not disk_format in ('vmdk', 'ami', 'raw', 'vhd'):
msg = "Invalid disk format '%s' for image." % disk_format
raise exception.Invalid(msg)
container_format = values.get('container_format')
if not container_format in ('ami', 'ovf'):
msg = "Invalid container format '%s' for image." % container_format
raise exception.Invalid(msg)
def _image_update(context, values, image_id):
"""Used internally by image_create and image_update

View File

@ -36,7 +36,8 @@ def define_images_table(meta):
Column('deleted_at', DateTime()),
Column('deleted', Boolean(), nullable=False, default=False,
index=True),
mysql_engine='InnoDB')
mysql_engine='InnoDB',
useexisting=True)
return images

View File

@ -41,7 +41,8 @@ def define_image_properties_table(meta):
Column('deleted', Boolean(), nullable=False, default=False,
index=True),
UniqueConstraint('image_id', 'key'),
mysql_engine='InnoDB')
mysql_engine='InnoDB',
useexisting=True)
Index('ix_image_properties_image_id_key', image_properties.c.image_id,
image_properties.c.key)

View File

@ -95,7 +95,8 @@ class Image(BASE, ModelBase):
id = Column(Integer, primary_key=True)
name = Column(String(255))
type = Column(String(30))
disk_format = Column(String(20))
container_format = Column(String(20))
size = Column(Integer)
status = Column(String(30), nullable=False)
is_public = Column(Boolean, nullable=False, default=False)

View File

@ -55,7 +55,6 @@ class Controller(wsgi.Controller):
images = db_api.image_get_all_public(None)
image_dicts = [dict(id=i['id'],
name=i['name'],
type=i['type'],
size=i['size']) for i in images]
return dict(images=image_dicts)

View File

@ -82,7 +82,6 @@ class Controller(wsgi.Controller):
* id -- The opaque image identifier
* name -- The name of the image
* size -- Size of image data in bytes
* type -- One of 'kernel', 'ramdisk', 'raw', or 'machine'
:param request: The WSGI/Webob Request object
:retval The response body is a mapping of the following form::
@ -90,8 +89,7 @@ class Controller(wsgi.Controller):
{'images': [
{'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'type': <TYPE>}, ...
'size': <SIZE>}, ...
]}
"""
images = registry.get_images_list(self.options)
@ -108,7 +106,8 @@ class Controller(wsgi.Controller):
{'id': <ID>,
'name': <NAME>,
'size': <SIZE>,
'type': <TYPE>,
'disk_format': <DISK_FORMAT>,
'container_format': <CONTAINER_FORMAT>,
'store': <STORE>,
'status': <STATUS>,
'created_at': <TIMESTAMP>,

View File

@ -340,7 +340,8 @@ def stub_out_registry_db_image_api(stubs):
{'id': 1,
'name': 'fake image #1',
'status': 'active',
'type': 'kernel',
'disk_format': 'ami',
'container_format': 'ami',
'is_public': False,
'created_at': datetime.datetime.utcnow(),
'updated_at': datetime.datetime.utcnow(),
@ -348,11 +349,14 @@ def stub_out_registry_db_image_api(stubs):
'deleted': False,
'size': 13,
'location': "swift://user:passwd@acct/container/obj.tar.0",
'properties': []},
'properties': [{'key': 'type',
'value': 'kernel',
'deleted': False}]},
{'id': 2,
'name': 'fake image #2',
'status': 'active',
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'is_public': True,
'created_at': datetime.datetime.utcnow(),
'updated_at': datetime.datetime.utcnow(),
@ -362,8 +366,6 @@ def stub_out_registry_db_image_api(stubs):
'location': "file:///tmp/glance-tests/2",
'properties': []}]
VALID_STATUSES = ('active', 'killed', 'queued', 'saving')
def __init__(self):
self.images = FakeDatastore.FIXTURES
self.next_id = 3
@ -376,12 +378,7 @@ def stub_out_registry_db_image_api(stubs):
raise exception.Duplicate("Duplicate image id: %s" %
values['id'])
if 'status' not in values.keys():
values['status'] = 'active'
else:
if not values['status'] in self.VALID_STATUSES:
raise exception.Invalid("Invalid status '%s' for image" %
values['status'])
glance.registry.db.api.validate_image(values)
values['size'] = values.get('size', 0)
values['deleted'] = False
@ -393,7 +390,7 @@ def stub_out_registry_db_image_api(stubs):
props = []
if 'properties' in values.keys():
for k, v in values['properties'].iteritems():
for k, v in values['properties'].items():
p = {}
p['key'] = k
p['value'] = v
@ -414,7 +411,7 @@ def stub_out_registry_db_image_api(stubs):
props = []
if 'properties' in values.keys():
for k, v in values['properties'].iteritems():
for k, v in values['properties'].items():
p = {}
p['key'] = k
p['value'] = v
@ -439,9 +436,8 @@ def stub_out_registry_db_image_api(stubs):
images = [i for i in self.images if str(i['id']) == str(image_id)]
if len(images) != 1 or images[0]['deleted']:
new_exc = exception.NotFound("No model for id %s %s" %
raise exception.NotFound("No model for id %s %s" %
(image_id, str(self.images)))
raise new_exc.__class__, new_exc, sys.exc_info()[2]
else:
return images[0]

View File

@ -85,7 +85,8 @@ class TestRegistryAPI(unittest.TestCase):
fixture = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'active'}
req = webob.Request.blank('/images/detail')
@ -103,7 +104,8 @@ class TestRegistryAPI(unittest.TestCase):
"""Tests that the /images POST registry API creates the image"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel'}
'disk_format': 'vhd',
'container_format': 'ovf'}
req = webob.Request.blank('/images')
@ -130,7 +132,8 @@ class TestRegistryAPI(unittest.TestCase):
fixture = {'id': 3,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'bad status'}
req = webob.Request.blank('/images')
@ -144,7 +147,7 @@ class TestRegistryAPI(unittest.TestCase):
def test_update_image(self):
"""Tests that the /images PUT registry API updates the image"""
fixture = {'name': 'fake public image #2',
'type': 'ramdisk'}
'disk_format': 'raw'}
req = webob.Request.blank('/images/2')
@ -166,7 +169,8 @@ class TestRegistryAPI(unittest.TestCase):
fixture = {'id': 3,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'bad status'}
req = webob.Request.blank('/images/3')
@ -242,6 +246,8 @@ class TestGlanceAPI(unittest.TestCase):
def test_add_image_no_location_no_image_as_body(self):
"""Tests creates a queued image for no body and no loc header"""
fixture_headers = {'x-image-meta-store': 'file',
'x-image-meta-disk-format': 'vhd',
'x-image-meta-container-format': 'ovf',
'x-image-meta-name': 'fake image #3'}
req = webob.Request.blank("/images")
@ -270,8 +276,10 @@ class TestGlanceAPI(unittest.TestCase):
self.assertEquals(res.status_int, webob.exc.HTTPBadRequest.code)
def test_add_image_basic_file_store(self):
"""Tests raises BadRequest for invalid store header"""
"""Tests to add a basic image in the file store"""
fixture_headers = {'x-image-meta-store': 'file',
'x-image-meta-disk-format': 'vhd',
'x-image-meta-container-format': 'ovf',
'x-image-meta-name': 'fake image #3'}
req = webob.Request.blank("/images")

View File

@ -66,7 +66,7 @@ class TestRegistryClient(unittest.TestCase):
images = self.client.get_images()
self.assertEquals(len(images), 1)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, images[0][k])
def test_get_image_details(self):
@ -74,16 +74,8 @@ class TestRegistryClient(unittest.TestCase):
fixture = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {}}
expected = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -92,33 +84,28 @@ class TestRegistryClient(unittest.TestCase):
images = self.client.get_images_detailed()
self.assertEquals(len(images), 1)
for k, v in expected.iteritems():
for k, v in fixture.items():
self.assertEquals(v, images[0][k])
def test_get_image(self):
"""Tests that the detailed info about an image returned"""
fixture = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
fixture = {'id': 1,
'name': 'fake image #1',
'is_public': False,
'disk_format': 'ami',
'container_format': 'ami',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {}}
'size': 13,
'location': "swift://user:passwd@acct/container/obj.tar.0",
'properties': {'type': 'kernel'}}
expected = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {}}
data = self.client.get_image(1)
data = self.client.get_image(2)
for k, v in expected.iteritems():
self.assertEquals(v, data[k])
for k, v in fixture.items():
el = data[k]
self.assertEquals(v, data[k],
"Failed v != data[k] where v = %(v)s and "
"k = %(k)s and data[k] = %(el)s" % locals())
def test_get_image_non_existing(self):
"""Tests that NotFound is raised when getting a non-existing image"""
@ -131,7 +118,8 @@ class TestRegistryClient(unittest.TestCase):
"""Tests that we can add image metadata and returns the new id"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vmdk',
'container_format': 'ovf',
'size': 19,
'location': "file:///tmp/glance-tests/acct/3.gz.0",
}
@ -144,7 +132,7 @@ class TestRegistryClient(unittest.TestCase):
# Test all other attributes set
data = self.client.get_image(3)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, data[k])
# Test status was updated properly
@ -155,13 +143,8 @@ class TestRegistryClient(unittest.TestCase):
"""Tests that we can add image metadata with properties"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {'distro': 'Ubuntu 10.04 LTS'}}
expected = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vmdk',
'container_format': 'ovf',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {'distro': 'Ubuntu 10.04 LTS'}}
@ -171,7 +154,7 @@ class TestRegistryClient(unittest.TestCase):
# Test ID auto-assigned properly
self.assertEquals(3, new_image['id'])
for k, v in expected.iteritems():
for k, v in fixture.items():
self.assertEquals(v, new_image[k])
# Test status was updated properly
@ -183,7 +166,8 @@ class TestRegistryClient(unittest.TestCase):
fixture = {'id': 2,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vmdk',
'container_format': 'ovf',
'status': 'bad status',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -198,7 +182,8 @@ class TestRegistryClient(unittest.TestCase):
fixture = {'id': 3,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vmdk',
'container_format': 'ovf',
'status': 'bad status',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -211,14 +196,14 @@ class TestRegistryClient(unittest.TestCase):
def test_update_image(self):
"""Tests that the /images PUT registry API updates the image"""
fixture = {'name': 'fake public image #2',
'type': 'ramdisk'}
'disk_format': 'vmdk'}
self.assertTrue(self.client.update_image(2, fixture))
# Test all other attributes set
data = self.client.get_image(2)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, data[k])
def test_update_image_not_existing(self):
@ -226,7 +211,8 @@ class TestRegistryClient(unittest.TestCase):
fixture = {'id': 3,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vmdk',
'container_format': 'ovf',
'status': 'bad status',
}
@ -283,7 +269,8 @@ class TestClient(unittest.TestCase):
expected_meta = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -295,7 +282,7 @@ class TestClient(unittest.TestCase):
image_data += image_chunk
self.assertEquals(expected_image, image_data)
for k, v in expected_meta.iteritems():
for k, v in expected_meta.items():
self.assertEquals(v, meta[k])
def test_get_image_not_existing(self):
@ -312,7 +299,7 @@ class TestClient(unittest.TestCase):
images = self.client.get_images()
self.assertEquals(len(images), 1)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, images[0][k])
def test_get_image_details(self):
@ -320,7 +307,8 @@ class TestClient(unittest.TestCase):
fixture = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -329,7 +317,8 @@ class TestClient(unittest.TestCase):
expected = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -338,7 +327,7 @@ class TestClient(unittest.TestCase):
images = self.client.get_images_detailed()
self.assertEquals(len(images), 1)
for k, v in expected.iteritems():
for k, v in expected.items():
self.assertEquals(v, images[0][k])
def test_get_image_meta(self):
@ -346,16 +335,8 @@ class TestClient(unittest.TestCase):
fixture = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {}}
expected = {'id': 2,
'name': 'fake image #2',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'active',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -363,7 +344,7 @@ class TestClient(unittest.TestCase):
data = self.client.get_image_meta(2)
for k, v in expected.iteritems():
for k, v in fixture.items():
self.assertEquals(v, data[k])
def test_get_image_non_existing(self):
@ -377,7 +358,8 @@ class TestClient(unittest.TestCase):
"""Tests client returns image as queued"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
}
image_meta = self.client.add_image(fixture)
self.assertEquals('queued', image_meta['status'])
@ -387,7 +369,8 @@ class TestClient(unittest.TestCase):
"""Tests that we can add image metadata and returns the new id"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'size': 19,
'location': "file:///tmp/glance-tests/2",
}
@ -400,7 +383,7 @@ class TestClient(unittest.TestCase):
# Test all other attributes set
data = self.client.get_image_meta(3)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, data[k])
# Test status was updated properly
@ -411,14 +394,8 @@ class TestClient(unittest.TestCase):
"""Tests that we can add image metadata with properties"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {'distro': 'Ubuntu 10.04 LTS'},
}
expected = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'size': 19,
'location': "file:///tmp/glance-tests/2",
'properties': {'distro': 'Ubuntu 10.04 LTS'},
@ -432,7 +409,7 @@ class TestClient(unittest.TestCase):
# Test all other attributes set
data = self.client.get_image_meta(3)
for k, v in expected.iteritems():
for k, v in fixture.items():
self.assertEquals(v, data[k])
# Test status was updated properly
@ -444,7 +421,8 @@ class TestClient(unittest.TestCase):
fixture = {'id': 2,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'bad status',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -458,7 +436,8 @@ class TestClient(unittest.TestCase):
"""Tests a bad status is set to a proper one by server"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'bad status',
'size': 19,
'location': "file:///tmp/glance-tests/2",
@ -471,7 +450,8 @@ class TestClient(unittest.TestCase):
"""Tests can add image by passing image data as string"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'size': 19,
'properties': {'distro': 'Ubuntu 10.04 LTS'},
}
@ -489,14 +469,15 @@ class TestClient(unittest.TestCase):
new_image_data += image_chunk
self.assertEquals(image_data_fixture, new_image_data)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, new_meta[k])
def test_add_image_with_image_data_as_file(self):
"""Tests can add image by passing image data as file"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'size': 19,
'properties': {'distro': 'Ubuntu 10.04 LTS'},
}
@ -526,14 +507,15 @@ class TestClient(unittest.TestCase):
new_image_data += image_chunk
self.assertEquals(image_data_fixture, new_image_data)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, new_meta[k])
def test_add_image_with_image_data_as_string_and_no_size(self):
"""Tests add image by passing image data as string w/ no size attr"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'properties': {'distro': 'Ubuntu 10.04 LTS'},
}
@ -550,7 +532,7 @@ class TestClient(unittest.TestCase):
new_image_data += image_chunk
self.assertEquals(image_data_fixture, new_image_data)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, new_meta[k])
self.assertEquals(19, new_meta['size'])
@ -559,7 +541,8 @@ class TestClient(unittest.TestCase):
"""Tests BadRequest raised when supplying bad store name in meta"""
fixture = {'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'size': 19,
'store': 'bad',
'properties': {'distro': 'Ubuntu 10.04 LTS'},
@ -575,15 +558,14 @@ class TestClient(unittest.TestCase):
def test_update_image(self):
"""Tests that the /images PUT registry API updates the image"""
fixture = {'name': 'fake public image #2',
'type': 'ramdisk',
}
'disk_format': 'vmdk'}
self.assertTrue(self.client.update_image(2, fixture))
# Test all other attributes set
data = self.client.get_image_meta(2)
for k, v in fixture.iteritems():
for k, v in fixture.items():
self.assertEquals(v, data[k])
def test_update_image_not_existing(self):
@ -591,7 +573,8 @@ class TestClient(unittest.TestCase):
fixture = {'id': 3,
'name': 'fake public image',
'is_public': True,
'type': 'kernel',
'disk_format': 'vhd',
'container_format': 'ovf',
'status': 'bad status',
}

View File

@ -27,6 +27,8 @@ class TestMigrations(unittest.TestCase):
def setUp(self):
self.db_path = "glance_test_migration.sqlite"
if os.path.exists(self.db_path):
os.unlink(self.db_path)
self.options = dict(sql_connection="sqlite:///%s" % self.db_path,
verbose=False)
config.setup_logging(self.options)

View File

@ -149,8 +149,8 @@ sql_idle_timeout = 3600
"-dinvalid http://0.0.0.0:%d/images" % api_port
ignored, out, err = execute(cmd)
self.assertTrue('Image type is required' in out,
"Could not find 'Image type is required' "
self.assertTrue('Invalid disk format' in out,
"Could not find 'Invalid disk format' "
"in output: %s" % out)
cmd = "./bin/glance-upload --port=%(api_port)d "\
@ -164,7 +164,7 @@ sql_idle_timeout = 3600
ignored, out, err = execute(cmd)
except RuntimeError, e:
hit_exception = True
self.assertTrue('Invalid image type' in str(e))
self.assertTrue('Invalid disk format' in str(e))
self.assertTrue(hit_exception)
# Spin down the API and default registry server