diff options
-rw-r--r-- | run_tests.py | 10 | ||||
-rw-r--r-- | trove/common/api.py | 3 | ||||
-rw-r--r-- | trove/common/exception.py | 6 | ||||
-rw-r--r-- | trove/datastore/models.py | 49 | ||||
-rw-r--r-- | trove/datastore/service.py | 16 | ||||
-rw-r--r-- | trove/datastore/views.py | 12 | ||||
-rw-r--r-- | trove/db/sqlalchemy/migrate_repo/versions/018_datastore_versions_fix.py | 33 | ||||
-rw-r--r-- | trove/instance/models.py | 2 | ||||
-rw-r--r-- | trove/tests/api/datastores.py | 18 | ||||
-rw-r--r-- | trove/tests/api/instances_resize.py | 2 | ||||
-rw-r--r-- | trove/tests/api/mgmt/instances_actions.py | 2 | ||||
-rw-r--r-- | trove/tests/config.py | 3 | ||||
-rw-r--r-- | trove/tests/unittests/instance/test_instance_status.py | 2 | ||||
-rw-r--r-- | trove/tests/unittests/mgmt/test_models.py | 8 | ||||
-rw-r--r-- | trove/tests/unittests/taskmanager/test_models.py | 4 |
15 files changed, 130 insertions, 40 deletions
diff --git a/run_tests.py b/run_tests.py index 91ed7456..100f0bf2 100644 --- a/run_tests.py +++ b/run_tests.py @@ -74,17 +74,17 @@ def datastore_init(): # Adds the datastore for mysql (needed to make most calls work). from trove.datastore import models - models.DBDatastore.create(id="a00000a0-00a0-0a00-00a0-000a000000aa", + models.DBDatastore.create(id=CONFIG.dbaas_datastore_id, name=CONFIG.dbaas_datastore, default_version_id= - "b00000b0-00b0-0b00-00b0-000b000000bb") + CONFIG.dbaas_datastore_version_id) models.DBDatastore.create(id="e00000e0-00e0-0e00-00e0-000e000000ee", name='Test_Datastore_1', default_version_id=None) - models.DBDatastoreVersion.create(id="b00000b0-00b0-0b00-00b0-000b000000bb", + models.DBDatastoreVersion.create(id=CONFIG.dbaas_datastore_version_id, datastore_id= - "a00000a0-00a0-0a00-00a0-000a000000aa", + CONFIG.dbaas_datastore_id, name=CONFIG.dbaas_datastore_version, manager="mysql", image_id= @@ -93,7 +93,7 @@ def datastore_init(): active=1) models.DBDatastoreVersion.create(id="d00000d0-00d0-0d00-00d0-000d000000dd", datastore_id= - "a00000a0-00a0-0a00-00a0-000a000000aa", + CONFIG.dbaas_datastore_id, name='mysql_inactive_version', manager="mysql", image_id= diff --git a/trove/common/api.py b/trove/common/api.py index 311bddd1..022221f5 100644 --- a/trove/common/api.py +++ b/trove/common/api.py @@ -49,6 +49,9 @@ class API(wsgi.Router): mapper.connect("/{tenant_id}/datastores/{datastore}/versions/{id}", controller=datastore_resource, action="version_show") + mapper.connect("/{tenant_id}/datastores/versions/{uuid}", + controller=datastore_resource, + action="version_show_by_uuid") def _instance_router(self, mapper): instance_resource = InstanceController().create_resource() diff --git a/trove/common/exception.py b/trove/common/exception.py index cf8927f6..1e9a374b 100644 --- a/trove/common/exception.py +++ b/trove/common/exception.py @@ -130,6 +130,12 @@ class DatastoreDefaultVersionNotFound(TroveError): message = _("Default version for datastore '%(datastore)s' not found.") +class NoUniqueMatch(TroveError): + + message = _("Multiple matches found for '%(name)s', i" + "use an UUID to be more specific.") + + class OverLimit(TroveError): internal_message = _("The server rejected the request due to its size or " diff --git a/trove/datastore/models.py b/trove/datastore/models.py index 22958340..24807b02 100644 --- a/trove/datastore/models.py +++ b/trove/datastore/models.py @@ -95,14 +95,25 @@ class DatastoreVersion(object): self.db_info = db_info @classmethod - def load(cls, id_or_name): + def load(cls, datastore, id_or_name): try: - return cls(DBDatastoreVersion.find_by(id=id_or_name)) + return cls(DBDatastoreVersion.find_by(datastore_id=datastore.id, + id=id_or_name)) except exception.ModelNotFoundError: - try: - return cls(DBDatastoreVersion.find_by(name=id_or_name)) - except exception.ModelNotFoundError: + versions = DBDatastoreVersion.find_all(datastore_id=datastore.id, + name=id_or_name) + if versions.count() == 0: raise exception.DatastoreVersionNotFound(version=id_or_name) + if versions.count() > 1: + raise exception.NoUniqueMatch(name=id_or_name) + return cls(versions.first()) + + @classmethod + def load_by_uuid(cls, uuid): + try: + return cls(DBDatastoreVersion.find_by(id=uuid)) + except exception.ModelNotFoundError: + raise exception.DatastoreVersionNotFound(version=uuid) @property def id(self): @@ -139,10 +150,14 @@ class DatastoreVersions(object): self.db_info = db_info @classmethod - def load(cls, id_or_name, active=True): + def load(cls, id_or_name, only_active=True): datastore = Datastore.load(id_or_name) - return cls(DBDatastoreVersion.find_all(datastore_id=datastore.id, - active=active)) + if only_active: + versions = DBDatastoreVersion.find_all(datastore_id=datastore.id, + active=True) + else: + versions = DBDatastoreVersion.find_all(datastore_id=datastore.id) + return cls(versions) def __iter__(self): for item in self.db_info: @@ -158,7 +173,7 @@ def get_datastore_version(type=None, version=None): if not version: raise exception.DatastoreDefaultVersionNotFound(datastore= datastore.name) - datastore_version = DatastoreVersion.load(version) + datastore_version = DatastoreVersion.load(datastore, version) if datastore_version.datastore_id != datastore.id: raise exception.DatastoreNoVersion(datastore=datastore.name, version=datastore_version.name) @@ -170,13 +185,14 @@ def get_datastore_version(type=None, version=None): def update_datastore(name, default_version): db_api.configure_db(CONF) - if default_version: - version = DatastoreVersion.load(default_version) - if not version.active: - raise exception.DatastoreVersionInactive(version= - version.name) try: datastore = DBDatastore.find_by(name=name) + if default_version: + version = DatastoreVersion.load(datastore, default_version) + if not version.active: + raise exception.DatastoreVersionInactive(version= + version.name) + datastore.default_version_id = version.id except exception.ModelNotFoundError: # Create a new one datastore = DBDatastore() @@ -192,13 +208,14 @@ def update_datastore_version(datastore, name, manager, image_id, packages, db_api.configure_db(CONF) datastore = Datastore.load(datastore) try: - version = DBDatastoreVersion.find_by(name=name) + version = DBDatastoreVersion.find_by(datastore_id=datastore.id, + name=name) except exception.ModelNotFoundError: # Create a new one version = DBDatastoreVersion() version.id = utils.generate_uuid() version.name = name - version.datastore_id = datastore.id + version.datastore_id = datastore.id version.manager = manager version.image_id = image_id version.packages = packages diff --git a/trove/datastore/service.py b/trove/datastore/service.py index e4682742..d2f0c0b3 100644 --- a/trove/datastore/service.py +++ b/trove/datastore/service.py @@ -34,13 +34,23 @@ class DatastoreController(wsgi.Controller): 200) def version_show(self, req, tenant_id, datastore, id): - datastore, datastore_version = models.get_datastore_version(datastore, - id) + datastore = models.Datastore.load(datastore) + datastore_version = models.DatastoreVersion.load(datastore, id) + return wsgi.Result(views.DatastoreVersionView(datastore_version, + req).data(), 200) + + def version_show_by_uuid(self, req, tenant_id, uuid): + datastore_version = models.DatastoreVersion.load_by_uuid(uuid) return wsgi.Result(views.DatastoreVersionView(datastore_version, req).data(), 200) def version_index(self, req, tenant_id, datastore): - datastore_versions = models.DatastoreVersions.load(datastore) + context = req.environ[wsgi.CONTEXT_KEY] + only_active = True + if context.is_admin: + only_active = False + datastore_versions = models.DatastoreVersions.load(datastore, + only_active) return wsgi.Result(views. DatastoreVersionsView(datastore_versions, req).data(), 200) diff --git a/trove/datastore/views.py b/trove/datastore/views.py index 91a345b3..0cf93e10 100644 --- a/trove/datastore/views.py +++ b/trove/datastore/views.py @@ -16,6 +16,7 @@ # under the License. # +from trove.common import wsgi from trove.common.views import create_links @@ -31,6 +32,9 @@ class DatastoreView(object): "name": self.datastore.name, "links": self._build_links(), } + default_version = self.datastore.default_version_id + if default_version: + datastore_dict["default_version"] = default_version return {"datastore": datastore_dict} @@ -61,14 +65,20 @@ class DatastoreVersionView(object): def __init__(self, datastore_version, req=None): self.datastore_version = datastore_version self.req = req + self.context = req.environ[wsgi.CONTEXT_KEY] def data(self): datastore_version_dict = { "id": self.datastore_version.id, "name": self.datastore_version.name, + "datastore": self.datastore_version.datastore_id, "links": self._build_links(), } - + if self.context.is_admin: + datastore_version_dict['active'] = self.datastore_version.active + datastore_version_dict['packages'] = (self.datastore_version. + packages) + datastore_version_dict['image'] = self.datastore_version.image_id return {"version": datastore_version_dict} def _build_links(self): diff --git a/trove/db/sqlalchemy/migrate_repo/versions/018_datastore_versions_fix.py b/trove/db/sqlalchemy/migrate_repo/versions/018_datastore_versions_fix.py new file mode 100644 index 00000000..3aebcf98 --- /dev/null +++ b/trove/db/sqlalchemy/migrate_repo/versions/018_datastore_versions_fix.py @@ -0,0 +1,33 @@ +# Copyright 2012 OpenStack Foundation +# +# 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 sqlalchemy.schema import MetaData + +from trove.db.sqlalchemy.migrate_repo.schema import Table + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + datastore_versions = Table('datastore_versions', meta, autoload=True) + #modify column + datastore_versions.c.name.alter(unique=False) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + # modify column: + datastore_versions = Table('datastore_versions', meta, autoload=True) + datastore_versions.c.name.alter(unique=True) diff --git a/trove/instance/models.py b/trove/instance/models.py index 05e4a930..48cc9312 100644 --- a/trove/instance/models.py +++ b/trove/instance/models.py @@ -122,7 +122,7 @@ class SimpleInstance(object): self.service_status = service_status self.root_pass = root_password self.ds_version = (datastore_models.DatastoreVersion. - load(self.db_info.datastore_version_id)) + load_by_uuid(self.db_info.datastore_version_id)) self.ds = (datastore_models.Datastore. load(self.ds_version.datastore_id)) diff --git a/trove/tests/api/datastores.py b/trove/tests/api/datastores.py index 5442f7cd..efcfe479 100644 --- a/trove/tests/api/datastores.py +++ b/trove/tests/api/datastores.py @@ -86,18 +86,20 @@ class Datastores(object): with TypeCheck('DatastoreVersion', version) as check: check.has_field("id", basestring) check.has_field("name", basestring) + check.has_field("datastore", basestring) check.has_field("links", list) assert_equal(version.name, test_config.dbaas_datastore_version) @test - def test_datastore_version_datastore_not_found(self): - try: - assert_raises(exceptions.NotFound, - self.rd_client.datastore_versions.get, - NAME, NAME) - except exceptions.BadRequest as e: - assert_equal(e.message, - "Datastore '%s' cannot be found." % NAME) + def test_datastore_version_get_by_uuid_attrs(self): + version = self.rd_client.datastore_versions.get_by_uuid( + test_config.dbaas_datastore_version_id) + with TypeCheck('DatastoreVersion', version) as check: + check.has_field("id", basestring) + check.has_field("name", basestring) + check.has_field("datastore", basestring) + check.has_field("links", list) + assert_equal(version.name, test_config.dbaas_datastore_version) @test def test_datastore_version_not_found(self): diff --git a/trove/tests/api/instances_resize.py b/trove/tests/api/instances_resize.py index fdea966a..94c6fa47 100644 --- a/trove/tests/api/instances_resize.py +++ b/trove/tests/api/instances_resize.py @@ -52,7 +52,7 @@ class ResizeTestBase(TestCase): flavor_id=OLD_FLAVOR_ID, tenant_id=999, volume_size=None, - datastore_version_id=test_config.dbaas_datastore_version, + datastore_version_id=test_config.dbaas_datastore_version_id, task_status=InstanceTasks.RESIZING) self.server = self.mock.CreateMock(Server) self.instance = models.BuiltInstanceTasks(context, diff --git a/trove/tests/api/mgmt/instances_actions.py b/trove/tests/api/mgmt/instances_actions.py index 4f6fcbf2..3ef933ca 100644 --- a/trove/tests/api/mgmt/instances_actions.py +++ b/trove/tests/api/mgmt/instances_actions.py @@ -52,7 +52,7 @@ class MgmtInstanceBase(object): self.db_info = DBInstance.create( name="instance", flavor_id=1, - datastore_version_id=test_config.dbaas_datastore_version, + datastore_version_id=test_config.dbaas_datastore_version_id, tenant_id=self.tenant_id, volume_size=None, task_status=InstanceTasks.NONE) diff --git a/trove/tests/config.py b/trove/tests/config.py index 1211f7fa..89d4699a 100644 --- a/trove/tests/config.py +++ b/trove/tests/config.py @@ -71,7 +71,10 @@ class TestConfig(object): 'version_url': "http://localhost:8775/", 'nova_url': "http://localhost:8774/v1.1", 'dbaas_datastore': "mysql", + 'dbaas_datastore_id': "a00000a0-00a0-0a00-00a0-000a000000aa", 'dbaas_datastore_version': "mysql-5.5", + 'dbaas_datastore_version_id': "b00000b0-00b0-0b00-00b0-" + "000b000000bb", 'instance_create_time': 16 * 60, 'mysql_connection_method': {"type": "direct"}, 'typical_nova_image_name': None, diff --git a/trove/tests/unittests/instance/test_instance_status.py b/trove/tests/unittests/instance/test_instance_status.py index b2a3ff2f..601c8d94 100644 --- a/trove/tests/unittests/instance/test_instance_status.py +++ b/trove/tests/unittests/instance/test_instance_status.py @@ -32,7 +32,7 @@ class FakeDBInstance(object): def __init__(self): self.id = None self.deleted = False - self.datastore_version_id = test_config.dbaas_datastore_version + self.datastore_version_id = test_config.dbaas_datastore_version_id self.server_status = "ACTIVE" self.task_status = FakeInstanceTask() diff --git a/trove/tests/unittests/mgmt/test_models.py b/trove/tests/unittests/mgmt/test_models.py index bda76d0e..6bd637e2 100644 --- a/trove/tests/unittests/mgmt/test_models.py +++ b/trove/tests/unittests/mgmt/test_models.py @@ -65,7 +65,7 @@ class MockMgmtInstanceTest(TestCase): id='1', flavor_id='flavor_1', datastore_version_id= - test_config.dbaas_datastore_version, + test_config.dbaas_datastore_version_id, compute_instance_id='compute_id_1', server_id='server_id_1', tenant_id='tenant_id_1', @@ -205,7 +205,11 @@ class TestNovaNotificationTransformer(MockMgmtInstanceTest): stub_datastore_version.id = "stub_datastore_version" stub_datastore_version.manager = "m0ng0" when(datastore_models. - DatastoreVersion).load(any()).thenReturn(stub_datastore_version) + DatastoreVersion).load(any(), any()).thenReturn( + stub_datastore_version) + when(datastore_models. + DatastoreVersion).load_by_uuid(any()).thenReturn( + stub_datastore_version) stub_datastore = mock() stub_datastore.default_datastore_version = "stub_datastore_version" diff --git a/trove/tests/unittests/taskmanager/test_models.py b/trove/tests/unittests/taskmanager/test_models.py index af2e3031..818fbdcc 100644 --- a/trove/tests/unittests/taskmanager/test_models.py +++ b/trove/tests/unittests/taskmanager/test_models.py @@ -140,7 +140,9 @@ class FreshInstanceTasksTest(testtools.TestCase): when(taskmanager_models.FreshInstanceTasks).name().thenReturn( 'name') when(datastore_models. - DatastoreVersion).load(any()).thenReturn(mock()) + DatastoreVersion).load(any(), any()).thenReturn(mock()) + when(datastore_models. + DatastoreVersion).load_by_uuid(any()).thenReturn(mock()) when(datastore_models. Datastore).load(any()).thenReturn(mock()) taskmanager_models.FreshInstanceTasks.nova_client = fake_nova_client() |