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
This commit is contained in:
Andrey Shestakov 2013-12-26 17:02:24 +02:00
parent 68a5481911
commit 2296bdfcea
15 changed files with 130 additions and 40 deletions

View File

@ -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=

View File

@ -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()

View File

@ -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 "

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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))

View File

@ -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):

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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()

View File

@ -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"

View File

@ -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()