diff options
| author | vladimir.p <vladimir@zadarastorage.com> | 2011-08-23 15:18:50 -0700 |
|---|---|---|
| committer | vladimir.p <vladimir@zadarastorage.com> | 2011-08-23 15:18:50 -0700 |
| commit | ddc7d9470674a4d7300d15e5c6fa54b784b6a36f (patch) | |
| tree | 99d5ea16405985b5ed31f31d11b8663b06d89494 | |
| parent | 1d121a42f5072026a3ad19cb5fd1915d7cd2ff63 (diff) | |
added volume_types APIs
| -rw-r--r-- | nova/db/sqlalchemy/migrate_repo/versions/037_add_volume_types_and_extradata.py | 4 | ||||
| -rw-r--r-- | nova/tests/test_volume_types.py | 156 | ||||
| -rw-r--r-- | nova/volume/api.py | 9 | ||||
| -rw-r--r-- | nova/volume/volume_types.py | 14 |
4 files changed, 170 insertions, 13 deletions
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/037_add_volume_types_and_extradata.py b/nova/db/sqlalchemy/migrate_repo/versions/037_add_volume_types_and_extradata.py index fc365d2b2..27c8afcee 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/037_add_volume_types_and_extradata.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/037_add_volume_types_and_extradata.py @@ -2,7 +2,6 @@ # Copyright (c) 2011 Zadara Storage Inc. # Copyright (c) 2011 OpenStack LLC. -# 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 @@ -45,7 +44,8 @@ volume_types = Table('volume_types', meta, Column('id', Integer(), primary_key=True, nullable=False), Column('name', String(length=255, convert_unicode=False, assert_unicode=None, - unicode_error=None, _warn_on_bytestring=False))) + unicode_error=None, _warn_on_bytestring=False), + unique=True)) volume_type_extra_specs_table = Table('volume_type_extra_specs', meta, Column('created_at', DateTime(timezone=False)), diff --git a/nova/tests/test_volume_types.py b/nova/tests/test_volume_types.py new file mode 100644 index 000000000..3d906a5fd --- /dev/null +++ b/nova/tests/test_volume_types.py @@ -0,0 +1,156 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 Zadara Storage Inc. +# Copyright (c) 2011 OpenStack LLC. +# 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. +""" +Unit Tests for volume types code +""" +import time + +from nova import context +from nova import db +from nova import exception +from nova import flags +from nova import log as logging +from nova import test +from nova import utils +from nova.volume import volume_types +from nova.db.sqlalchemy.session import get_session +from nova.db.sqlalchemy import models + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.test_volume_types') + + +class VolumeTypeTestCase(test.TestCase): + """Test cases for volume type code""" + def setUp(self): + super(VolumeTypeTestCase, self).setUp() + + self.ctxt = context.get_admin_context() + self.vol_type1_name = str(int(time.time())) + self.vol_type1_specs = dict( + type="physical drive", + drive_type="SAS", + size="300", + rpm="7200", + visible="True") + self.vol_type1 = dict(name=self.vol_type1_name, + extra_specs=self.vol_type1_specs) + + def test_volume_type_create_then_destroy(self): + """Ensure volume types can be created and deleted""" + prev_all_vtypes = volume_types.get_all_types(self.ctxt) + + volume_types.create(self.ctxt, + self.vol_type1_name, + self.vol_type1_specs) + new = volume_types.get_volume_type_by_name(self.ctxt, + self.vol_type1_name) + + LOG.info(_("Given data: %s"), self.vol_type1_specs) + LOG.info(_("Result data: %s"), new) + + for k, v in self.vol_type1_specs.iteritems(): + self.assertEqual(v, new['extra_specs'][k], + 'one of fields doesnt match') + + new_all_vtypes = volume_types.get_all_types(self.ctxt) + self.assertEqual(len(prev_all_vtypes) + 1, + len(new_all_vtypes), + 'drive type was not created') + + volume_types.destroy(self.ctxt, self.vol_type1_name) + new_all_vtypes = volume_types.get_all_types(self.ctxt) + self.assertEqual(prev_all_vtypes, + new_all_vtypes, + 'drive type was not deleted') + + def test_volume_type_create_then_purge(self): + """Ensure volume types can be created and deleted""" + prev_all_vtypes = volume_types.get_all_types(self.ctxt, inactive=1) + + volume_types.create(self.ctxt, + self.vol_type1_name, + self.vol_type1_specs) + new = volume_types.get_volume_type_by_name(self.ctxt, + self.vol_type1_name) + + for k, v in self.vol_type1_specs.iteritems(): + self.assertEqual(v, new['extra_specs'][k], + 'one of fields doesnt match') + + new_all_vtypes = volume_types.get_all_types(self.ctxt, inactive=1) + self.assertEqual(len(prev_all_vtypes) + 1, + len(new_all_vtypes), + 'drive type was not created') + + volume_types.destroy(self.ctxt, self.vol_type1_name) + new_all_vtypes2 = volume_types.get_all_types(self.ctxt, inactive=1) + self.assertEqual(len(new_all_vtypes), + len(new_all_vtypes2), + 'drive type was incorrectly deleted') + + volume_types.purge(self.ctxt, self.vol_type1_name) + new_all_vtypes2 = volume_types.get_all_types(self.ctxt, inactive=1) + self.assertEqual(len(new_all_vtypes) - 1, + len(new_all_vtypes2), + 'drive type was not purged') + + def test_get_all_volume_types(self): + """Ensures that all volume types can be retrieved""" + session = get_session() + total_volume_types = session.query(models.VolumeTypes).\ + count() + vol_types = volume_types.get_all_types(self.ctxt) + self.assertEqual(total_volume_types, len(vol_types)) + + def test_non_existant_inst_type_shouldnt_delete(self): + """Ensures that volume type creation fails with invalid args""" + self.assertRaises(exception.ApiError, + volume_types.destroy, self.ctxt, "sfsfsdfdfs") + + def test_repeated_vol_types_should_raise_api_error(self): + """Ensures that volume duplicates raises ApiError""" + new_name = self.vol_type1_name + "dup" + volume_types.create(self.ctxt, new_name) + volume_types.destroy(self.ctxt, new_name) + self.assertRaises( + exception.ApiError, + volume_types.create, self.ctxt, new_name) + + def test_invalid_volume_types_params(self): + """Ensures that volume type creation fails with invalid args""" + self.assertRaises(exception.InvalidVolumeType, + volume_types.destroy, self.ctxt, None) + self.assertRaises(exception.InvalidVolumeType, + volume_types.purge, self.ctxt, None) + self.assertRaises(exception.InvalidVolumeType, + volume_types.get_volume_type, self.ctxt, None) + self.assertRaises(exception.InvalidVolumeType, + volume_types.get_volume_type_by_name, + self.ctxt, None) + + def test_volume_type_get_by_id_and_name(self): + """Ensure volume types get returns same entry""" + volume_types.create(self.ctxt, + self.vol_type1_name, + self.vol_type1_specs) + new = volume_types.get_volume_type_by_name(self.ctxt, + self.vol_type1_name) + + new2 = volume_types.get_volume_type(self.ctxt, new['id']) + self.assertEqual(new, new2) + + diff --git a/nova/volume/api.py b/nova/volume/api.py index 7a78e244f..80e8bd85f 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -42,7 +42,7 @@ class API(base.Base): """API for interacting with the volume manager.""" def create(self, context, size, snapshot_id, name, description, - volume_type=None, metadata=None): + volume_type=None, metadata=None, availability_zone=None): if snapshot_id != None: snapshot = self.get_snapshot(context, snapshot_id) if snapshot['status'] != "available": @@ -58,18 +58,21 @@ class API(base.Base): raise quota.QuotaError(_("Volume quota exceeded. You cannot " "create a volume of size %sG") % size) + if availability_zone is None: + availability_zone = FLAGS.storage_availability_zone + options = { 'size': size, 'user_id': context.user_id, 'project_id': context.project_id, 'snapshot_id': snapshot_id, - 'availability_zone': FLAGS.storage_availability_zone, + 'availability_zone': availability_zone, 'status': "creating", 'attach_status': "detached", 'display_name': name, 'display_description': description, 'volume_type_id': volume_type.get('id', None), - 'metadata' metadata, + 'metadata': metadata, } volume = self.db.volume_create(context, options) diff --git a/nova/volume/volume_types.py b/nova/volume/volume_types.py index c1fce1627..9df1e39f8 100644 --- a/nova/volume/volume_types.py +++ b/nova/volume/volume_types.py @@ -4,7 +4,6 @@ # Copyright (c) 2011 OpenStack LLC. # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. # Copyright (c) 2010 Citrix Systems, Inc. # Copyright 2011 Ken Pepple # @@ -29,16 +28,15 @@ from nova import flags from nova import log as logging FLAGS = flags.FLAGS -LOG = logging.getLogger('nova.volume_types') +LOG = logging.getLogger('nova.volume.volume_types') def create(context, name, extra_specs={}): """Creates volume types.""" try: - db.volume_type_create( - context, - dict(name=name, - extra_specs=extra_specs)) + db.volume_type_create(context, + dict(name=name, + extra_specs=extra_specs)) except exception.DBError, e: LOG.exception(_('DB error: %s') % e) raise exception.ApiError(_("Cannot create volume_type with " @@ -82,7 +80,7 @@ def get_all_types(context, inactive=0): def get_volume_type(context, id): """Retrieves single volume type by id.""" if id is None: - raise exception.ApiError(_("Invalid volume type: %s") % id) + raise exception.InvalidVolumeType(volume_type=id) try: return db.volume_type_get(context, id) @@ -93,7 +91,7 @@ def get_volume_type(context, id): def get_volume_type_by_name(context, name): """Retrieves single volume type by name.""" if name is None: - raise exception.ApiError(_("Invalid volume type name: %s") % name) + raise exception.InvalidVolumeType(volume_type=name) try: return db.volume_type_get_by_name(context, name) |
