Merge "Associate flavor types with datastore versions"
This commit is contained in:
commit
7cf297cd22
trove
cmd
common
datastore
db/sqlalchemy
instance
tests
@ -92,6 +92,30 @@ class Commands(object):
|
||||
config_models.load_datastore_configuration_parameters(
|
||||
datastore, datastore_version, config_file_location)
|
||||
|
||||
def datastore_version_flavor_add(self, datastore_name,
|
||||
datastore_version_name, flavor_ids):
|
||||
"""Adds flavors for a given datastore version id."""
|
||||
try:
|
||||
dsmetadata = datastore_models.DatastoreVersionMetadata
|
||||
dsmetadata.add_datastore_version_flavor_association(
|
||||
datastore_name, datastore_version_name, flavor_ids.split(","))
|
||||
print("Added flavors '%s' to the '%s' '%s'."
|
||||
% (flavor_ids, datastore_name, datastore_version_name))
|
||||
except exception.DatastoreVersionNotFound as e:
|
||||
print(e)
|
||||
|
||||
def datastore_version_flavor_delete(self, datastore_name,
|
||||
datastore_version_name, flavor_id):
|
||||
"""Deletes a flavor's association with a given datastore."""
|
||||
try:
|
||||
dsmetadata = datastore_models.DatastoreVersionMetadata
|
||||
dsmetadata.delete_datastore_version_flavor_association(
|
||||
datastore_name, datastore_version_name, flavor_id)
|
||||
print("Deleted flavor '%s' from '%s' '%s'."
|
||||
% (flavor_id, datastore_name, datastore_version_name))
|
||||
except exception.DatastoreVersionNotFound as e:
|
||||
print(e)
|
||||
|
||||
def params_of(self, command_name):
|
||||
if Commands.has(command_name):
|
||||
return utils.MethodInspector(getattr(self, command_name))
|
||||
@ -170,6 +194,23 @@ def main():
|
||||
help='Fully qualified file path to the configuration group '
|
||||
'parameter validation rules.')
|
||||
|
||||
parser = subparser.add_parser(
|
||||
'datastore_version_flavor_add', help='Adds flavor association to '
|
||||
'a given datastore and datastore version.')
|
||||
parser.add_argument('datastore_name', help='Name of the datastore.')
|
||||
parser.add_argument('datastore_version_name', help='Name of the '
|
||||
'datastore version.')
|
||||
parser.add_argument('flavor_ids', help='Comma separated list of '
|
||||
'flavor ids.')
|
||||
|
||||
parser = subparser.add_parser(
|
||||
'datastore_version_flavor_delete', help='Deletes a flavor '
|
||||
'associated with a given datastore and datastore version.')
|
||||
parser.add_argument('datastore_name', help='Name of the datastore.')
|
||||
parser.add_argument('datastore_version_name', help='Name of the '
|
||||
'datastore version.')
|
||||
parser.add_argument('flavor_id', help='The flavor to be deleted for '
|
||||
'a given datastore and datastore version.')
|
||||
cfg.custom_parser('action', actions)
|
||||
cfg.parse_args(sys.argv)
|
||||
|
||||
@ -179,7 +220,7 @@ def main():
|
||||
Commands().execute()
|
||||
sys.exit(0)
|
||||
except TypeError as e:
|
||||
print(_("Possible wrong number of arguments supplied %s") % e)
|
||||
print(_("Possible wrong number of arguments supplied %s.") % e)
|
||||
sys.exit(2)
|
||||
except Exception:
|
||||
print(_("Command failed, please check log for more info."))
|
||||
|
@ -57,6 +57,13 @@ class API(wsgi.Router):
|
||||
mapper.connect("/{tenant_id}/datastores/{datastore}/versions/{id}",
|
||||
controller=datastore_resource,
|
||||
action="version_show")
|
||||
mapper.connect(
|
||||
"/{tenant_id}/datastores/{datastore}/versions/"
|
||||
"{version_id}/flavors",
|
||||
controller=datastore_resource,
|
||||
action="list_associated_flavors",
|
||||
conditions={'method': ['GET']}
|
||||
)
|
||||
mapper.connect("/{tenant_id}/datastores/versions/{uuid}",
|
||||
controller=datastore_resource,
|
||||
action="version_show_by_uuid")
|
||||
|
@ -119,6 +119,18 @@ class DatastoresNotFound(NotFound):
|
||||
message = _("Datastores cannot be found.")
|
||||
|
||||
|
||||
class DatastoreFlavorAssociationNotFound(NotFound):
|
||||
|
||||
message = _("Datastore '%(datastore)s' version id %(version_id)s "
|
||||
"and flavor %(flavor_id)s mapping not found.")
|
||||
|
||||
|
||||
class DatastoreFlavorAssociationAlreadyExists(TroveError):
|
||||
|
||||
message = _("Datastore '%(datastore)s' version %(datastore_version)s "
|
||||
"and flavor %(flavor_id)s mapping already exists.")
|
||||
|
||||
|
||||
class DatastoreNoVersion(TroveError):
|
||||
|
||||
message = _("Datastore '%(datastore)s' has no version '%(version)s'.")
|
||||
|
@ -14,15 +14,16 @@
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common.remote import create_nova_client
|
||||
from trove.common import utils
|
||||
from trove.db import get_db_api
|
||||
from trove.db import models as dbmodels
|
||||
from trove.flavor.models import Flavor as flavor_model
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -36,6 +37,7 @@ def persisted_models():
|
||||
'capabilities': DBCapabilities,
|
||||
'datastore_version': DBDatastoreVersion,
|
||||
'capability_overrides': DBCapabilityOverrides,
|
||||
'datastore_version_metadata': DBDatastoreVersionMetadata
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +62,13 @@ class DBDatastoreVersion(dbmodels.DatabaseModelBase):
|
||||
'packages', 'active']
|
||||
|
||||
|
||||
class DBDatastoreVersionMetadata(dbmodels.DatabaseModelBase):
|
||||
|
||||
_data_fields = ['id', 'datastore_version_id', 'key', 'value',
|
||||
'created', 'deleted', 'deleted_at', 'updated_at']
|
||||
preserve_on_delete = True
|
||||
|
||||
|
||||
class Capabilities(object):
|
||||
|
||||
def __init__(self, datastore_version_id=None):
|
||||
@ -526,4 +535,126 @@ def update_datastore_version(datastore, name, manager, image_id, packages,
|
||||
version.image_id = image_id
|
||||
version.packages = packages
|
||||
version.active = active
|
||||
|
||||
db_api.save(version)
|
||||
|
||||
|
||||
class DatastoreVersionMetadata(object):
|
||||
@classmethod
|
||||
def _datastore_version_metadata_add(cls, datastore_version_id,
|
||||
key, value, exception_class):
|
||||
"""Create an entry in the Datastore Version Metadata table."""
|
||||
# Do we have a mapping in the db?
|
||||
# yes: and its deleted then modify the association
|
||||
# yes: and its not deleted then error on create
|
||||
# no: then just create the new association
|
||||
try:
|
||||
db_record = DBDatastoreVersionMetadata.find_by(
|
||||
datastore_version_id=datastore_version_id,
|
||||
key=key, value=value)
|
||||
if db_record.deleted == 1:
|
||||
db_record.deleted = 0
|
||||
db_record.updated_at = utils.utcnow()
|
||||
db_record.save()
|
||||
return
|
||||
else:
|
||||
raise exception_class(
|
||||
datastore_version_id=datastore_version_id,
|
||||
flavor_id=value)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
DBDatastoreVersionMetadata.create(
|
||||
datastore_version_id=datastore_version_id,
|
||||
key=key, value=value)
|
||||
|
||||
@classmethod
|
||||
def _datastore_version_metadata_delete(cls, datastore_version_id,
|
||||
key, value, exception_class):
|
||||
try:
|
||||
db_record = DBDatastoreVersionMetadata.find_by(
|
||||
datastore_version_id=datastore_version_id,
|
||||
key=key, value=value)
|
||||
if db_record.deleted == 0:
|
||||
db_record.delete()
|
||||
return
|
||||
else:
|
||||
raise exception_class(
|
||||
datastore_version_id=datastore_version_id,
|
||||
flavor_id=value)
|
||||
except exception.ModelNotFoundError:
|
||||
raise exception_class(datastore_version_id=datastore_version_id,
|
||||
flavor_id=value)
|
||||
|
||||
@classmethod
|
||||
def add_datastore_version_flavor_association(cls, datastore_name,
|
||||
datastore_version_name,
|
||||
flavor_ids):
|
||||
db_api.configure_db(CONF)
|
||||
db_ds_record = DBDatastore.find_by(
|
||||
name=datastore_name
|
||||
)
|
||||
db_datastore_id = db_ds_record.id
|
||||
db_dsv_record = DBDatastoreVersion.find_by(
|
||||
datastore_id=db_datastore_id,
|
||||
name=datastore_version_name
|
||||
)
|
||||
datastore_version_id = db_dsv_record.id
|
||||
for flavor_id in flavor_ids:
|
||||
cls._datastore_version_metadata_add(
|
||||
datastore_version_id, 'flavor', flavor_id,
|
||||
exception.DatastoreFlavorAssociationAlreadyExists)
|
||||
|
||||
@classmethod
|
||||
def delete_datastore_version_flavor_association(cls, datastore_name,
|
||||
datastore_version_name,
|
||||
flavor_id):
|
||||
db_api.configure_db(CONF)
|
||||
db_ds_record = DBDatastore.find_by(
|
||||
name=datastore_name
|
||||
)
|
||||
db_datastore_id = db_ds_record.id
|
||||
db_dsv_record = DBDatastoreVersion.find_by(
|
||||
datastore_id=db_datastore_id,
|
||||
name=datastore_version_name
|
||||
)
|
||||
datastore_version_id = db_dsv_record.id
|
||||
cls._datastore_version_metadata_delete(
|
||||
datastore_version_id, 'flavor', flavor_id,
|
||||
exception.DatastoreFlavorAssociationNotFound)
|
||||
|
||||
@classmethod
|
||||
def list_datastore_version_flavor_associations(cls, context,
|
||||
datastore_type,
|
||||
datastore_version_id):
|
||||
if datastore_type and datastore_version_id:
|
||||
"""
|
||||
All nova flavors are permitted for a datastore_version unless
|
||||
one or more entries are found in datastore_version_metadata,
|
||||
in which case only those are permitted.
|
||||
"""
|
||||
(datastore, datastore_version) = get_datastore_version(
|
||||
type=datastore_type, version=datastore_version_id)
|
||||
# If datastore_version_id and flavor key exists in the
|
||||
# metadata table return all the associated flavors for
|
||||
# that datastore version.
|
||||
nova_flavors = create_nova_client(context).flavors.list()
|
||||
bound_flavors = DBDatastoreVersionMetadata.find_all(
|
||||
datastore_version_id=datastore_version.id,
|
||||
key='flavor', deleted=False
|
||||
)
|
||||
if (bound_flavors.count() != 0):
|
||||
bound_flavors = tuple(f.value for f in bound_flavors)
|
||||
# Generate a filtered list of nova flavors
|
||||
ds_nova_flavors = (f for f in nova_flavors
|
||||
if f.id in bound_flavors)
|
||||
associated_flavors = tuple(flavor_model(flavor=item)
|
||||
for item in ds_nova_flavors)
|
||||
else:
|
||||
# Return all nova flavors if no flavor metadata found
|
||||
# for datastore_version.
|
||||
associated_flavors = tuple(flavor_model(flavor=item)
|
||||
for item in nova_flavors)
|
||||
return associated_flavors
|
||||
else:
|
||||
msg = _("Specify both the datastore and datastore_version_id.")
|
||||
raise exception.BadRequest(msg)
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
from trove.common import wsgi
|
||||
from trove.datastore import models, views
|
||||
from trove.flavor import views as flavor_views
|
||||
|
||||
|
||||
class DatastoreController(wsgi.Controller):
|
||||
@ -61,3 +62,16 @@ class DatastoreController(wsgi.Controller):
|
||||
return wsgi.Result(views.
|
||||
DatastoreVersionsView(datastore_versions,
|
||||
req).data(), 200)
|
||||
|
||||
def list_associated_flavors(self, req, tenant_id, datastore,
|
||||
version_id):
|
||||
"""
|
||||
All nova flavors are returned for a datastore-version unless
|
||||
one or more entries are found in datastore_version_metadata,
|
||||
in which case only those are returned.
|
||||
"""
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
flavors = (models.DatastoreVersionMetadata.
|
||||
list_datastore_version_flavor_associations(
|
||||
context, datastore, version_id))
|
||||
return wsgi.Result(flavor_views.FlavorsView(flavors, req).data(), 200)
|
||||
|
@ -32,6 +32,8 @@ def map(engine, models):
|
||||
Table('datastores', meta, autoload=True))
|
||||
orm.mapper(models['datastore_version'],
|
||||
Table('datastore_versions', meta, autoload=True))
|
||||
orm.mapper(models['datastore_version_metadata'],
|
||||
Table('datastore_version_metadata', meta, autoload=True))
|
||||
orm.mapper(models['capabilities'],
|
||||
Table('capabilities', meta, autoload=True))
|
||||
orm.mapper(models['capability_overrides'],
|
||||
|
@ -0,0 +1,61 @@
|
||||
# Copyright 2015 Rackspace
|
||||
# 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
|
||||
# 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 import ForeignKey
|
||||
from sqlalchemy.schema import Column
|
||||
from sqlalchemy.schema import MetaData
|
||||
from sqlalchemy.schema import UniqueConstraint
|
||||
|
||||
from trove.db.sqlalchemy.migrate_repo.schema import Boolean
|
||||
from trove.db.sqlalchemy.migrate_repo.schema import create_tables
|
||||
from trove.db.sqlalchemy.migrate_repo.schema import DateTime
|
||||
from trove.db.sqlalchemy.migrate_repo.schema import drop_tables
|
||||
from trove.db.sqlalchemy.migrate_repo.schema import String
|
||||
from trove.db.sqlalchemy.migrate_repo.schema import Table
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
datastore_version_metadata = Table(
|
||||
'datastore_version_metadata',
|
||||
meta,
|
||||
Column('id', String(36), primary_key=True, nullable=False),
|
||||
Column(
|
||||
'datastore_version_id',
|
||||
String(36),
|
||||
ForeignKey('datastore_versions.id', ondelete='CASCADE'),
|
||||
),
|
||||
Column('key', String(128), nullable=False),
|
||||
Column('value', String(128)),
|
||||
Column('created', DateTime(), nullable=False),
|
||||
Column('deleted', Boolean(), nullable=False, default=False),
|
||||
Column('deleted_at', DateTime()),
|
||||
Column('updated_at', DateTime()),
|
||||
UniqueConstraint(
|
||||
'datastore_version_id', 'key', 'value',
|
||||
name='UQ_datastore_version_metadata_datastore_version_id_key_value')
|
||||
)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
# Load the datastore_versions table into the session.
|
||||
# creates datastore_version_metadata table
|
||||
Table('datastore_versions', meta, autoload=True)
|
||||
create_tables([datastore_version_metadata])
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
drop_tables([datastore_version_metadata])
|
@ -37,6 +37,7 @@ from trove.common import template
|
||||
from trove.common import utils
|
||||
from trove.configuration.models import Configuration
|
||||
from trove.datastore import models as datastore_models
|
||||
from trove.datastore.models import DBDatastoreVersionMetadata
|
||||
from trove.db import get_db_api
|
||||
from trove.db import models as dbmodels
|
||||
from trove.extensions.security_group.models import SecurityGroup
|
||||
@ -670,6 +671,19 @@ class Instance(BuiltInstance):
|
||||
availability_zone=None, nics=None, configuration_id=None,
|
||||
slave_of_id=None, cluster_config=None, replica_count=None):
|
||||
|
||||
# All nova flavors are permitted for a datastore-version unless one
|
||||
# or more entries are found in datastore_version_metadata,
|
||||
# in which case only those are permitted.
|
||||
bound_flavors = DBDatastoreVersionMetadata.find_all(
|
||||
datastore_version_id=datastore_version.id,
|
||||
key='flavor', deleted=False
|
||||
)
|
||||
if bound_flavors.count() > 0:
|
||||
valid_flavors = tuple(f.value for f in bound_flavors)
|
||||
if flavor_id not in valid_flavors:
|
||||
raise exception.DatastoreFlavorAssociationNotFound(
|
||||
version_id=datastore_version.id, flavor_id=flavor_id)
|
||||
|
||||
datastore_cfg = CONF.get(datastore_version.manager)
|
||||
client = create_nova_client(context)
|
||||
try:
|
||||
|
@ -1,8 +1,8 @@
|
||||
# Copyright (c) 2011 OpenStack Foundation
|
||||
# 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
|
||||
# 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
|
||||
@ -20,19 +20,22 @@ from nose.tools import assert_false
|
||||
from nose.tools import assert_true
|
||||
from proboscis.asserts import assert_raises
|
||||
from proboscis import before_class
|
||||
from proboscis.decorators import time_out
|
||||
from proboscis import test
|
||||
from troveclient.compat import exceptions
|
||||
from troveclient.v1.flavors import Flavor
|
||||
|
||||
from trove.common.utils import poll_until
|
||||
from trove import tests
|
||||
from trove.tests.api.instances import TIMEOUT_INSTANCE_CREATE
|
||||
from trove.tests.util.check import AttrCheck
|
||||
from trove.tests.util import create_dbaas_client
|
||||
from trove.tests.util import create_nova_client
|
||||
from trove.tests.util import test_config
|
||||
from trove.tests.util.users import Requirements
|
||||
from troveclient.compat import exceptions
|
||||
from troveclient.v1.flavors import Flavor
|
||||
|
||||
GROUP = "dbaas.api.flavors"
|
||||
|
||||
GROUP_DS = "dbaas.api.datastores"
|
||||
FAKE_MODE = test_config.values['fake_mode']
|
||||
|
||||
servers_flavors = None
|
||||
dbaas_flavors = None
|
||||
@ -91,10 +94,9 @@ def assert_link_list_is_equal(flavor):
|
||||
assert_false(True, "Unexpected rel - %s" % link['rel'])
|
||||
|
||||
|
||||
@test(groups=[tests.DBAAS_API, GROUP, tests.PRE_INSTANCES],
|
||||
@test(groups=[tests.DBAAS_API, GROUP, GROUP_DS, tests.PRE_INSTANCES],
|
||||
depends_on_groups=["services.initialize"])
|
||||
class Flavors(object):
|
||||
|
||||
@before_class
|
||||
def setUp(self):
|
||||
rd_user = test_config.users.find_user(
|
||||
@ -171,3 +173,88 @@ class Flavors(object):
|
||||
def test_flavor_not_found(self):
|
||||
assert_raises(exceptions.NotFound,
|
||||
self.rd_client.flavors.get, "foo")
|
||||
|
||||
@test
|
||||
def test_flavor_list_datastore_version_associated_flavors(self):
|
||||
datastore = self.rd_client.datastores.get(
|
||||
test_config.dbaas_datastore)
|
||||
dbaas_flavors = (self.rd_client.flavors.
|
||||
list_datastore_version_associated_flavors(
|
||||
datastore=test_config.dbaas_datastore,
|
||||
version_id=datastore.default_version))
|
||||
os_flavors = self.get_expected_flavors()
|
||||
assert_equal(len(dbaas_flavors), len(os_flavors))
|
||||
# verify flavor lists are identical
|
||||
for os_flavor in os_flavors:
|
||||
found_index = None
|
||||
for index, dbaas_flavor in enumerate(dbaas_flavors):
|
||||
if os_flavor.name == dbaas_flavor.name:
|
||||
msg = ("Flavor ID '%s' appears in elements #%s and #%d." %
|
||||
(dbaas_flavor.id, str(found_index), index))
|
||||
assert_true(found_index is None, msg)
|
||||
assert_flavors_roughly_equivalent(os_flavor, dbaas_flavor)
|
||||
found_index = index
|
||||
msg = "Some flavors from OS list were missing in DBAAS list."
|
||||
assert_false(found_index is None, msg)
|
||||
for flavor in dbaas_flavors:
|
||||
assert_link_list_is_equal(flavor)
|
||||
|
||||
|
||||
@test(runs_after=[Flavors],
|
||||
groups=[tests.DBAAS_API, GROUP, GROUP_DS],
|
||||
depends_on_groups=["services.initialize"],
|
||||
enabled=FAKE_MODE)
|
||||
class DatastoreFlavorAssociation(object):
|
||||
@before_class
|
||||
def setUp(self):
|
||||
rd_user = test_config.users.find_user(
|
||||
Requirements(is_admin=False, services=["trove"]))
|
||||
self.rd_client = create_dbaas_client(rd_user)
|
||||
|
||||
self.datastore = self.rd_client.datastores.get(
|
||||
test_config.dbaas_datastore)
|
||||
self.name1 = "test_instance1"
|
||||
self.name2 = "test_instance2"
|
||||
self.volume = {'size': 2}
|
||||
self.instance_id = None
|
||||
|
||||
@test
|
||||
@time_out(TIMEOUT_INSTANCE_CREATE)
|
||||
def test_create_instance_with_valid_flavor_association(self):
|
||||
# all the nova flavors are associated with the default datastore
|
||||
result = self.rd_client.instances.create(
|
||||
name=self.name1, flavor_id='1', volume=self.volume,
|
||||
datastore=self.datastore.id)
|
||||
self.instance_id = result.id
|
||||
assert_equal(200, self.rd_client.last_http_code)
|
||||
|
||||
def result_is_active():
|
||||
instance = self.rd_client.instances.get(self.instance_id)
|
||||
if instance.status == "ACTIVE":
|
||||
return True
|
||||
else:
|
||||
# If its not ACTIVE, anything but BUILD must be
|
||||
# an error.
|
||||
assert_equal("BUILD", instance.status)
|
||||
return False
|
||||
|
||||
poll_until(result_is_active)
|
||||
self.rd_client.instances.delete(self.instance_id)
|
||||
|
||||
@test(runs_after=[test_create_instance_with_valid_flavor_association])
|
||||
def test_create_instance_with_invalid_flavor_association(self):
|
||||
dbaas_flavors = (self.rd_client.flavors.
|
||||
list_datastore_version_associated_flavors(
|
||||
datastore=test_config.dbaas_datastore,
|
||||
version_id=self.datastore.default_version))
|
||||
self.flavor_not_associated = None
|
||||
os_flavors = Flavors().get_expected_flavors()
|
||||
for os_flavor in os_flavors:
|
||||
if os_flavor not in dbaas_flavors:
|
||||
self.flavor_not_associated = os_flavor.id
|
||||
break
|
||||
if self.flavor_not_associated is not None:
|
||||
assert_raises(exceptions.BadRequest,
|
||||
self.rd_client.instances.create, self.name2,
|
||||
flavor_not_associated, self.volume,
|
||||
datastore=self.datastore.id)
|
||||
|
@ -17,6 +17,7 @@ from trove.datastore import models as datastore_models
|
||||
from trove.datastore.models import Capability
|
||||
from trove.datastore.models import Datastore
|
||||
from trove.datastore.models import DatastoreVersion
|
||||
from trove.datastore.models import DatastoreVersionMetadata
|
||||
from trove.datastore.models import DBCapabilityOverrides
|
||||
from trove.tests.unittests import trove_testtools
|
||||
from trove.tests.unittests.util import util
|
||||
@ -34,12 +35,16 @@ class TestDatastoreBase(trove_testtools.TestCase):
|
||||
self.capability_name = "root_on_create" + self.rand_id
|
||||
self.capability_desc = "Enables root on create"
|
||||
self.capability_enabled = True
|
||||
self.datastore_version_id = str(uuid.uuid4())
|
||||
self.flavor_id = 1
|
||||
|
||||
datastore_models.update_datastore(self.ds_name, False)
|
||||
self.datastore = Datastore.load(self.ds_name)
|
||||
|
||||
datastore_models.update_datastore_version(
|
||||
self.ds_name, self.ds_version, "mysql", "", "", True)
|
||||
DatastoreVersionMetadata.add_datastore_version_flavor_association(
|
||||
self.ds_name, self.ds_version, [self.flavor_id])
|
||||
|
||||
self.datastore_version = DatastoreVersion.load(self.datastore,
|
||||
self.ds_version)
|
||||
@ -63,6 +68,11 @@ class TestDatastoreBase(trove_testtools.TestCase):
|
||||
self.cap1.delete()
|
||||
self.cap2.delete()
|
||||
self.cap3.delete()
|
||||
datastore = datastore_models.Datastore.load(self.ds_name)
|
||||
ds_version = datastore_models.DatastoreVersion.load(datastore,
|
||||
self.ds_version)
|
||||
datastore_models.DBDatastoreVersionMetadata.find_by(
|
||||
datastore_version_id=ds_version.id).delete()
|
||||
Datastore.load(self.ds_name).delete()
|
||||
|
||||
def capability_name_filter(self, capabilities):
|
||||
|
@ -0,0 +1,76 @@
|
||||
# Copyright (c) 2015 Rackspace Hosting
|
||||
#
|
||||
# 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 trove.common import exception
|
||||
from trove.datastore import models as datastore_models
|
||||
from trove.tests.unittests.datastore.base import TestDatastoreBase
|
||||
|
||||
|
||||
class TestDatastoreVersionMetadata(TestDatastoreBase):
|
||||
def setUp(self):
|
||||
super(TestDatastoreVersionMetadata, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestDatastoreVersionMetadata, self).tearDown()
|
||||
|
||||
def test_map_flavors_to_datastore(self):
|
||||
datastore = datastore_models.Datastore.load(self.ds_name)
|
||||
ds_version = datastore_models.DatastoreVersion.load(datastore,
|
||||
self.ds_version)
|
||||
mapping = datastore_models.DBDatastoreVersionMetadata.find_by(
|
||||
datastore_version_id=ds_version.id,
|
||||
value=self.flavor_id, deleted=False, key='flavor')
|
||||
self.assertEqual(str(self.flavor_id), mapping.value)
|
||||
self.assertEqual(ds_version.id, mapping.datastore_version_id)
|
||||
self.assertEqual('flavor', str(mapping.key))
|
||||
|
||||
def test_add_existing_associations(self):
|
||||
dsmetadata = datastore_models.DatastoreVersionMetadata
|
||||
self.assertRaises(exception.DatastoreFlavorAssociationAlreadyExists,
|
||||
dsmetadata.add_datastore_version_flavor_association,
|
||||
self.ds_name, self.ds_version, [self.flavor_id])
|
||||
|
||||
def test_delete_nonexistent_mapping(self):
|
||||
dsmeta = datastore_models.DatastoreVersionMetadata
|
||||
self.assertRaises(exception.DatastoreFlavorAssociationNotFound,
|
||||
dsmeta.delete_datastore_version_flavor_association,
|
||||
self.ds_name, self.ds_version,
|
||||
flavor_id=2)
|
||||
|
||||
def test_delete_mapping(self):
|
||||
flavor_id = 2
|
||||
dsmetadata = datastore_models. DatastoreVersionMetadata
|
||||
dsmetadata.add_datastore_version_flavor_association(self.ds_name,
|
||||
self.ds_version,
|
||||
[flavor_id])
|
||||
dsmetadata.delete_datastore_version_flavor_association(self.ds_name,
|
||||
self.ds_version,
|
||||
flavor_id)
|
||||
datastore = datastore_models.Datastore.load(self.ds_name)
|
||||
ds_version = datastore_models.DatastoreVersion.load(datastore,
|
||||
self.ds_version)
|
||||
mapping = datastore_models.DBDatastoreVersionMetadata.find_by(
|
||||
datastore_version_id=ds_version.id, value=flavor_id, key='flavor')
|
||||
self.assertTrue(mapping.deleted)
|
||||
# check update
|
||||
dsmetadata.add_datastore_version_flavor_association(
|
||||
self.ds_name, self.ds_version, [flavor_id])
|
||||
mapping = datastore_models.DBDatastoreVersionMetadata.find_by(
|
||||
datastore_version_id=ds_version.id, value=flavor_id, key='flavor')
|
||||
self.assertFalse(mapping.deleted)
|
||||
# clear the mapping
|
||||
datastore_models.DatastoreVersionMetadata.\
|
||||
delete_datastore_version_flavor_association(self.ds_name,
|
||||
self.ds_version,
|
||||
flavor_id)
|
Loading…
x
Reference in New Issue
Block a user