summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Shestakov <ashestakov@mirantis.com>2013-12-26 17:02:24 +0200
committerAndrey Shestakov <ashestakov@mirantis.com>2014-01-21 21:50:04 +0200
commit2296bdfceaf53b654102cb7bd66146276c871a61 (patch)
tree650f77dec47cb7cce472a54cbfc2282910eb94ce
parent68a5481911e4a310609fa8b7fe99987e61de5e9c (diff)
downloadtrove-2296bdfceaf53b654102cb7bd66146276c871a61.tar.gz
Datastores improvements
List of improvements: - added default_version field in datastore show output - admin can list deactivated versions too - admin can see extanded info about datastore version (image_id, packages) - add possibility to retrive version by uuid (without specified datastore) Implements: blueprint datastore-type-version-followon Change-Id: I9b0c3547fb6a881a01db9e6e3d8d72077bc5ee29
-rw-r--r--run_tests.py10
-rw-r--r--trove/common/api.py3
-rw-r--r--trove/common/exception.py6
-rw-r--r--trove/datastore/models.py49
-rw-r--r--trove/datastore/service.py16
-rw-r--r--trove/datastore/views.py12
-rw-r--r--trove/db/sqlalchemy/migrate_repo/versions/018_datastore_versions_fix.py33
-rw-r--r--trove/instance/models.py2
-rw-r--r--trove/tests/api/datastores.py18
-rw-r--r--trove/tests/api/instances_resize.py2
-rw-r--r--trove/tests/api/mgmt/instances_actions.py2
-rw-r--r--trove/tests/config.py3
-rw-r--r--trove/tests/unittests/instance/test_instance_status.py2
-rw-r--r--trove/tests/unittests/mgmt/test_models.py8
-rw-r--r--trove/tests/unittests/taskmanager/test_models.py4
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()