Merge "Support datastore version number for creating instance"

This commit is contained in:
Zuul 2020-11-19 02:31:06 +00:00 committed by Gerrit Code Review
commit c19c564694
12 changed files with 311 additions and 248 deletions

View File

@ -73,7 +73,7 @@ class Commands(object):
packages, active,
version=version)
print("Datastore version '%s(%s)' updated." %
(version_name, version))
(version_name, version or version_name))
except exception.DatastoreNotFound as e:
print(e)
@ -99,63 +99,96 @@ class Commands(object):
datastore, datastore_version_name)
def datastore_version_flavor_add(self, datastore_name,
datastore_version_name, flavor_ids):
datastore_version_name, flavor_ids,
version=None):
"""Adds flavors for a given datastore version id."""
dsmetadata = datastore_models.DatastoreVersionMetadata
try:
dsmetadata = datastore_models.DatastoreVersionMetadata
datastore_version_id = dsmetadata.datastore_version_find(
datastore_name,
datastore_version_name,
version_number=version)
dsmetadata.add_datastore_version_flavor_association(
datastore_name, datastore_version_name, flavor_ids.split(","))
datastore_version_id, flavor_ids.split(","))
print("Added flavors '%s' to the '%s' '%s'."
% (flavor_ids, datastore_name, datastore_version_name))
except exception.DatastoreVersionNotFound as e:
except Exception as e:
print(e)
def datastore_version_flavor_delete(self, datastore_name,
datastore_version_name, flavor_id):
datastore_version_name, flavor_id,
version=None):
"""Deletes a flavor's association with a given datastore."""
try:
dsmetadata = datastore_models.DatastoreVersionMetadata
datastore_version_id = dsmetadata.datastore_version_find(
datastore_name,
datastore_version_name,
version_number=version)
dsmetadata.delete_datastore_version_flavor_association(
datastore_name, datastore_version_name, flavor_id)
datastore_version_id, flavor_id)
print("Deleted flavor '%s' from '%s' '%s'."
% (flavor_id, datastore_name, datastore_version_name))
except exception.DatastoreVersionNotFound as e:
except Exception as e:
print(e)
def datastore_version_volume_type_add(self, datastore_name,
datastore_version_name,
volume_type_ids):
volume_type_ids, version=None):
"""Adds volume type assiciation for a given datastore version id."""
try:
dsmetadata = datastore_models.DatastoreVersionMetadata
datastore_version_id = dsmetadata.datastore_version_find(
datastore_name,
datastore_version_name,
version_number=version)
dsmetadata.add_datastore_version_volume_type_association(
datastore_name, datastore_version_name,
datastore_version_id,
volume_type_ids.split(","))
print("Added volume type '%s' to the '%s' '%s'."
% (volume_type_ids, datastore_name, datastore_version_name))
except exception.DatastoreVersionNotFound as e:
except Exception as e:
print(e)
def datastore_version_volume_type_delete(self, datastore_name,
datastore_version_name,
volume_type_id):
volume_type_id, version=None):
"""Deletes a volume type association with a given datastore."""
try:
dsmetadata = datastore_models.DatastoreVersionMetadata
datastore_version_id = dsmetadata.datastore_version_find(
datastore_name,
datastore_version_name,
version_number=version)
dsmetadata.delete_datastore_version_volume_type_association(
datastore_name, datastore_version_name, volume_type_id)
datastore_version_id, volume_type_id)
print("Deleted volume type '%s' from '%s' '%s'."
% (volume_type_id, datastore_name, datastore_version_name))
except exception.DatastoreVersionNotFound as e:
except Exception as e:
print(e)
def datastore_version_volume_type_list(self, datastore_name,
datastore_version_name):
datastore_version_name,
version=None):
"""Lists volume type association with a given datastore."""
try:
dsmetadata = datastore_models.DatastoreVersionMetadata
vtlist = dsmetadata.list_datastore_volume_type_associations(
datastore_name, datastore_version_name)
datastore_version_id = dsmetadata.datastore_version_find(
datastore_name,
datastore_version_name,
version_number=version)
vtlist = dsmetadata. \
list_datastore_version_volume_type_associations(
datastore_version_id)
if vtlist.count() > 0:
for volume_type in vtlist:
print("Datastore: %s, Version: %s, Volume Type: %s" %
@ -165,7 +198,7 @@ class Commands(object):
print("No Volume Type Associations found for Datastore: %s, "
"Version: %s." %
(datastore_name, datastore_version_name))
except exception.DatastoreVersionNotFound as e:
except Exception as e:
print(e)
def params_of(self, command_name):
@ -262,49 +295,79 @@ def main():
help='Name of the datastore version.')
parser = subparser.add_parser(
'datastore_version_flavor_add', help='Adds flavor association to '
'a given datastore and datastore version.')
'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.add_argument(
'--version',
help='The version number of the datastore version, e.g. 5.7.30. '
'If not specified, use <datastore_version_name> as default '
'value.')
parser = subparser.add_parser(
'datastore_version_flavor_delete', help='Deletes a flavor '
'associated with a given datastore and datastore version.')
'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.')
parser.add_argument(
'--version',
help='The version number of the datastore version, e.g. 5.7.30. '
'If not specified, use <datastore_version_name> as default '
'value.')
parser = subparser.add_parser(
'datastore_version_volume_type_add', help='Adds volume_type '
'association to a given datastore and datastore version.')
'datastore_version_volume_type_add',
help='Adds volume_type 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('volume_type_ids', help='Comma separated list of '
'volume_type ids.')
parser.add_argument(
'--version',
help='The version number of the datastore version, e.g. 5.7.30. '
'If not specified, use <datastore_version_name> as default '
'value.')
parser = subparser.add_parser(
'datastore_version_volume_type_delete',
help='Deletes a volume_type '
'associated with a given datastore and datastore version.')
'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('volume_type_id', help='The volume_type to be '
'deleted for a given datastore and datastore '
'version.')
parser.add_argument(
'--version',
help='The version number of the datastore version, e.g. 5.7.30. '
'If not specified, use <datastore_version_name> as default '
'value.')
parser = subparser.add_parser(
'datastore_version_volume_type_list',
help='Lists the volume_types '
'associated with a given datastore and datastore version.')
'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(
'--version',
help='The version number of the datastore version, e.g. 5.7.30. '
'If not specified, use <datastore_version_name> as default '
'value.')
cfg.custom_parser('action', actions)
cfg.parse_args(sys.argv)

View File

@ -410,7 +410,8 @@ instance = {
"additionalProperties": True,
"properties": {
"type": non_empty_string,
"version": non_empty_string
"version": non_empty_string,
"version_number": non_empty_string
}
},
"nics": nics,

View File

@ -134,38 +134,38 @@ class DatastoresNotFound(NotFound):
class DatastoreFlavorAssociationNotFound(NotFound):
message = _("Flavor %(id)s is not supported for datastore "
"%(datastore)s version %(datastore_version)s")
"version %(datastore_version_id)s")
class DatastoreFlavorAssociationAlreadyExists(TroveError):
message = _("Flavor %(id)s is already associated with "
"datastore %(datastore)s version %(datastore_version)s")
"datastore version %(datastore_version_id)s")
class DatastoreVolumeTypeAssociationNotFound(NotFound):
message = _("The volume type %(id)s is not valid for datastore "
"%(datastore)s and version %(version_id)s.")
"version %(datastore_version_id)s.")
class DatastoreVolumeTypeAssociationAlreadyExists(TroveError):
message = _("Datastore '%(datastore)s' version %(datastore_version)s "
message = _("Datastore version %(datastore_version_id)s "
"and volume-type %(id)s mapping already exists.")
class DataStoreVersionVolumeTypeRequired(TroveError):
message = _("Only specific volume types are allowed for a "
"datastore %(datastore)s version %(datastore_version)s. "
"datastore version %(datastore_version_id)s. "
"You must specify a valid volume type.")
class DatastoreVersionNoVolumeTypes(TroveError):
message = _("No valid volume types could be found for datastore "
"%(datastore)s and version %(datastore_version)s.")
"version %(datastore_version_id)s.")
class DatastoreNoVersion(TroveError):
@ -194,6 +194,13 @@ class DatastoreVersionsInUse(BadRequest):
message = _("Datastore version is in use by %(resource)s.")
class DatastoreVersionsNoUniqueMatch(TroveError):
message = _("Multiple datastore versions found for '%(name)s', "
"use an UUID or specify both the name and version number to "
"be more specific.")
class DatastoreDefaultDatastoreNotFound(TroveError):
message = _("Please specify datastore. Default datastore "
@ -222,12 +229,6 @@ class DatastoreOperationNotSupported(TroveError):
"the '%(datastore)s' datastore.")
class NoUniqueMatch(TroveError):
message = _("Multiple matches found for '%(name)s', "
"use an UUID to be more specific.")
class OverLimit(TroveError):
# internal_message is used for log, stop translating.

View File

@ -405,15 +405,25 @@ class DatastoreVersion(object):
return cls(DBDatastoreVersion.find_by(datastore_id=datastore.id,
id=id_or_name))
version = version or id_or_name
versions = DBDatastoreVersion.find_all(datastore_id=datastore.id,
name=id_or_name,
version=version)
if versions.count() == 0:
raise exception.DatastoreVersionNotFound(version=version)
if versions.count() > 1:
raise exception.NoUniqueMatch(name=id_or_name)
return cls(versions.first())
if not version:
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.DatastoreVersionsNoUniqueMatch(name=id_or_name)
db_version = versions.first()
else:
try:
db_version = DBDatastoreVersion.find_by(
datastore_id=datastore.id,
name=id_or_name,
version=version)
except exception.ModelNotFoundError:
raise exception.DatastoreVersionNotFound(version=version)
return cls(db_version)
@classmethod
def load_by_uuid(cls, uuid):
@ -508,7 +518,8 @@ class DatastoreVersions(object):
yield item
def get_datastore_version(type=None, version=None, return_inactive=False):
def get_datastore_version(type=None, version=None, return_inactive=False,
version_number=None):
datastore = type or CONF.default_datastore
if not datastore:
raise exception.DatastoreDefaultDatastoreNotDefined()
@ -520,11 +531,12 @@ def get_datastore_version(type=None, version=None, return_inactive=False):
datastore=datastore)
raise
version = version or datastore.default_version_id
if not version:
version_id = version or datastore.default_version_id
if not version_id:
raise exception.DatastoreDefaultVersionNotFound(
datastore=datastore.name)
datastore_version = DatastoreVersion.load(datastore, version)
datastore_version = DatastoreVersion.load(datastore, version_id,
version=version_number)
if datastore_version.datastore_id != datastore.id:
raise exception.DatastoreNoVersion(datastore=datastore.name,
version=datastore_version.name)
@ -616,8 +628,8 @@ def update_datastore_version(datastore, name, manager, image_id, image_tags,
class DatastoreVersionMetadata(object):
@classmethod
def _datastore_version_find(cls, datastore_name,
datastore_version_name):
def datastore_version_find(cls, datastore_name,
datastore_version_name, version_number=None):
"""
Helper to find a datastore version id for a given
datastore and datastore version name.
@ -626,17 +638,31 @@ class DatastoreVersionMetadata(object):
db_ds_record = DBDatastore.find_by(
name=datastore_name
)
db_dsv_record = DBDatastoreVersion.find_by(
datastore_id=db_ds_record.id,
name=datastore_version_name
)
if not version_number:
db_dsv_records = DBDatastoreVersion.find_all(
datastore_id=db_ds_record.id,
name=datastore_version_name,
)
if db_dsv_records.count() == 0:
raise exception.DatastoreVersionNotFound(
version=datastore_version_name)
if db_dsv_records.count() > 1:
raise exception.DatastoreVersionsNoUniqueMatch(
name=datastore_version_name)
db_dsv_record = db_dsv_records.first()
else:
db_dsv_record = DBDatastoreVersion.find_by(
datastore_id=db_ds_record.id,
name=datastore_version_name,
version=version_number
)
return db_dsv_record.id
@classmethod
def _datastore_version_metadata_add(cls, datastore_name,
datastore_version_name,
datastore_version_id,
def _datastore_version_metadata_add(cls, datastore_version_id,
key, value, exception_class):
"""
Create a record of the specified key and value in the
@ -657,8 +683,7 @@ class DatastoreVersionMetadata(object):
return
else:
raise exception_class(
datastore=datastore_name,
datastore_version=datastore_version_name,
datastore_version_id=datastore_version_id,
id=value)
except exception.NotFound:
pass
@ -669,8 +694,7 @@ class DatastoreVersionMetadata(object):
key=key, value=value)
@classmethod
def _datastore_version_metadata_delete(cls, datastore_name,
datastore_version_name,
def _datastore_version_metadata_delete(cls, datastore_version_id,
key, value, exception_class):
"""
Delete a record of the specified key and value in the
@ -679,11 +703,6 @@ class DatastoreVersionMetadata(object):
# if an association does not exist, raise an exception
# if a deleted association exists, raise an exception
# if an un-deleted association exists, delete it
datastore_version_id = cls._datastore_version_find(
datastore_name,
datastore_version_name)
try:
db_record = DBDatastoreVersionMetadata.find_by(
datastore_version_id=datastore_version_id,
@ -693,96 +712,69 @@ class DatastoreVersionMetadata(object):
return
else:
raise exception_class(
datastore=datastore_name,
datastore_version=datastore_version_name,
datastore_version_id=datastore_version_id,
id=value)
except exception.ModelNotFoundError:
raise exception_class(datastore=datastore_name,
datastore_version=datastore_version_name,
raise exception_class(datastore_version_id=datastore_version_id,
id=value)
@classmethod
def add_datastore_version_flavor_association(cls, datastore_name,
datastore_version_name,
def add_datastore_version_flavor_association(cls, datastore_version_id,
flavor_ids):
datastore_version_id = cls._datastore_version_find(
datastore_name,
datastore_version_name)
for flavor_id in flavor_ids:
cls._datastore_version_metadata_add(
datastore_name, datastore_version_name,
datastore_version_id, 'flavor', flavor_id,
exception.DatastoreFlavorAssociationAlreadyExists)
@classmethod
def delete_datastore_version_flavor_association(cls, datastore_name,
datastore_version_name,
def delete_datastore_version_flavor_association(cls, datastore_version_id,
flavor_id):
cls._datastore_version_metadata_delete(
datastore_name, datastore_version_name, 'flavor', flavor_id,
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
"""Get allowed flavors for a given datastore version.
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.
"""
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:
msg = _("Specify both the datastore and datastore_version_id.")
raise exception.BadRequest(msg)
# 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
@classmethod
def add_datastore_version_volume_type_association(cls, datastore_name,
datastore_version_name,
def add_datastore_version_volume_type_association(cls,
datastore_version_id,
volume_type_names):
datastore_version_id = cls._datastore_version_find(
datastore_name,
datastore_version_name)
# the database record will contain
# datastore_version_id, 'volume_type', volume_type_name
for volume_type_name in volume_type_names:
cls._datastore_version_metadata_add(
datastore_name, datastore_version_name,
datastore_version_id, 'volume_type', volume_type_name,
exception.DatastoreVolumeTypeAssociationAlreadyExists)
@classmethod
def delete_datastore_version_volume_type_association(
cls, datastore_name,
datastore_version_name,
volume_type_name):
cls, datastore_version_id, volume_type_name):
cls._datastore_version_metadata_delete(
datastore_name, datastore_version_name, 'volume_type',
datastore_version_id, 'volume_type',
volume_type_name,
exception.DatastoreVolumeTypeAssociationNotFound)
@ -811,7 +803,7 @@ class DatastoreVersionMetadata(object):
List the datastore associations for a given datastore and version.
"""
if datastore_name and datastore_version_name:
datastore_version_id = cls._datastore_version_find(
datastore_version_id = cls.datastore_version_find(
datastore_name, datastore_version_name)
return cls.list_datastore_version_volume_type_associations(
datastore_version_id)
@ -820,17 +812,13 @@ class DatastoreVersionMetadata(object):
raise exception.BadRequest(msg)
@classmethod
def datastore_volume_type_associations_exist(cls,
datastore_name,
datastore_version_name):
return cls.list_datastore_volume_type_associations(
datastore_name,
datastore_version_name).count() > 0
def datastore_volume_type_associations_exist(cls, datastore_version_id):
return cls.list_datastore_version_volume_type_associations(
datastore_version_id).count() > 0
@classmethod
def allowed_datastore_version_volume_types(cls, context,
datastore_name,
datastore_version_name):
datastore_version_id):
"""
List all allowed volume types for a given datastore and
datastore version. If datastore version metadata is
@ -838,59 +826,44 @@ class DatastoreVersionMetadata(object):
allowed. If datastore version metadata is not provided
then all volume types known to cinder are allowed.
"""
if datastore_name and datastore_version_name:
# first obtain the list in the dsvmetadata
datastore_version_id = cls._datastore_version_find(
datastore_name, datastore_version_name)
metadata = cls.list_datastore_version_volume_type_associations(
datastore_version_id)
metadata = cls.list_datastore_version_volume_type_associations(
datastore_version_id)
# then get the list of all volume types
all_volume_types = volume_type_models.VolumeTypes(context)
# then get the list of all volume types
all_volume_types = volume_type_models.VolumeTypes(context)
# if there's metadata: intersect,
# else, whatever cinder has.
if (metadata.count() != 0):
# the volume types from metadata first
ds_volume_types = tuple(f.value for f in metadata)
# if there's metadata: intersect,
# else, whatever cinder has.
if (metadata.count() != 0):
# the volume types from metadata first
ds_volume_types = tuple(f.value for f in metadata)
# Cinder volume type names are unique, intersect
allowed_volume_types = tuple(
f for f in all_volume_types
if ((f.name in ds_volume_types) or
(f.id in ds_volume_types)))
else:
allowed_volume_types = tuple(all_volume_types)
return allowed_volume_types
# Cinder volume type names are unique, intersect
allowed_volume_types = tuple(
f for f in all_volume_types
if ((f.name in ds_volume_types) or
(f.id in ds_volume_types)))
else:
msg = _("Specify the datastore_name and datastore_version_name.")
raise exception.BadRequest(msg)
allowed_volume_types = tuple(all_volume_types)
return allowed_volume_types
@classmethod
def validate_volume_type(cls, context, volume_type,
datastore_name, datastore_version_name):
if cls.datastore_volume_type_associations_exist(
datastore_name, datastore_version_name):
def validate_volume_type(cls, context, volume_type, datastore_version_id):
if cls.datastore_volume_type_associations_exist(datastore_version_id):
allowed = cls.allowed_datastore_version_volume_types(
context, datastore_name, datastore_version_name)
context, datastore_version_id)
if len(allowed) == 0:
raise exception.DatastoreVersionNoVolumeTypes(
datastore=datastore_name,
datastore_version=datastore_version_name)
datastore_version_id=datastore_version_id)
if volume_type is None:
raise exception.DataStoreVersionVolumeTypeRequired(
datastore=datastore_name,
datastore_version=datastore_version_name)
datastore_version_id=datastore_version_id)
allowed_names = tuple(f.name for f in allowed)
for n in allowed_names:
LOG.debug("Volume Type: %s is allowed for datastore "
"%s, version %s." %
(n, datastore_name, datastore_version_name))
LOG.debug(f"Allowed volume types: {allowed_names}")
if volume_type not in allowed_names:
raise exception.DatastoreVolumeTypeAssociationNotFound(
datastore=datastore_name,
version_id=datastore_version_name,
datastore_version_id=datastore_version_id,
id=volume_type)

View File

@ -93,7 +93,7 @@ class DatastoreController(wsgi.Controller):
context = req.environ[wsgi.CONTEXT_KEY]
flavors = (models.DatastoreVersionMetadata.
list_datastore_version_flavor_associations(
context, datastore, version_id))
context, version_id))
return wsgi.Result(flavor_views.FlavorsView(flavors, req).data(), 200)
def list_associated_volume_types(self, req, tenant_id, datastore,
@ -106,7 +106,7 @@ class DatastoreController(wsgi.Controller):
context = req.environ[wsgi.CONTEXT_KEY]
volume_types = (models.DatastoreVersionMetadata.
allowed_datastore_version_volume_types(
context, datastore, version_id))
context, version_id))
return wsgi.Result(volume_type_view.VolumeTypesView(
volume_types, req).data(), 200)

View File

@ -1133,9 +1133,8 @@ class Instance(BuiltInstance):
valid_flavors = tuple(f.value for f in bound_flavors)
if flavor_id not in valid_flavors:
raise exception.DatastoreFlavorAssociationNotFound(
datastore=datastore.name,
datastore_version=datastore_version.name,
flavor_id=flavor_id)
datastore_version_id=datastore_version.id,
id=flavor_id)
try:
flavor = nova_client.flavors.get(flavor_id)
except nova_exceptions.NotFound:
@ -1166,7 +1165,7 @@ class Instance(BuiltInstance):
volume_size = volume.size
dvm.validate_volume_type(context, volume_type,
datastore.name, datastore_version.name)
datastore_version.id)
validate_volume_size(volume_size)
call_args['volume_type'] = volume_type
call_args['volume_size'] = volume_size
@ -1335,7 +1334,7 @@ class Instance(BuiltInstance):
nics, overrides, slave_of_id, cluster_config,
volume_type=volume_type, modules=module_list,
locality=locality, access=access,
ds_version=datastore_version.name)
ds_version=datastore_version.version)
return SimpleInstance(context, db_info, service_status,
root_password, locality=locality)

View File

@ -129,6 +129,8 @@ class InstanceDetailView(InstanceView):
if self.instance.datastore_version:
result['instance']['datastore']['version'] = \
self.instance.datastore_version.name
result['instance']['datastore']['version_number'] = \
self.instance.datastore_version.version
if self.instance.fault:
result['instance']['fault'] = self._build_fault_info()

View File

@ -161,13 +161,9 @@ class DatastoreVersions(object):
@test
def test_datastore_version_not_found(self):
try:
assert_raises(exceptions.NotFound,
self.rd_client.datastore_versions.get,
self.datastore_active.name, NAME)
except exceptions.BadRequest as e:
assert_equal(e.message,
"Datastore version '%s' cannot be found." % NAME)
assert_raises(exceptions.BadRequest,
self.rd_client.datastore_versions.get,
self.datastore_active.name, NAME)
@test
def test_datastore_version_list_by_uuid(self):

View File

@ -204,7 +204,7 @@ class CheckInstance(AttrCheck):
if 'datastore' not in self.instance:
self.fail("'datastore' not found in instance.")
else:
allowed_attrs = ['type', 'version']
allowed_attrs = ['type', 'version', 'version_number']
self.contains_allowed_attrs(
self.instance['datastore'], allowed_attrs,
msg="datastore")
@ -714,18 +714,13 @@ class CreateInstanceFail(object):
users = []
datastore = CONFIG.dbaas_datastore
datastore_version = "nonexistent"
try:
assert_raises(exceptions.NotFound,
dbaas.instances.create, instance_name,
instance_info.dbaas_flavor_href,
volume, databases, users,
datastore=datastore,
datastore_version=datastore_version,
nics=instance_info.nics)
except exceptions.BadRequest as e:
assert_equal(e.message,
"Datastore version '%s' cannot be found." %
datastore_version)
assert_raises(exceptions.BadRequest,
dbaas.instances.create, instance_name,
instance_info.dbaas_flavor_href,
volume, databases, users,
datastore=datastore,
datastore_version=datastore_version,
nics=instance_info.nics)
@test(

View File

@ -41,15 +41,15 @@ class TestDatastoreBase(trove_testtools.TestCase):
datastore_models.update_datastore_version(
cls.ds_name, cls.ds_version_name, "mysql", "", "", "", True)
DatastoreVersionMetadata.add_datastore_version_flavor_association(
cls.ds_name, cls.ds_version_name, [cls.flavor_id])
DatastoreVersionMetadata.add_datastore_version_volume_type_association(
cls.ds_name, cls.ds_version_name, [cls.volume_type])
cls.datastore_version = DatastoreVersion.load(cls.datastore,
cls.ds_version_name)
cls.test_id = cls.datastore_version.id
DatastoreVersionMetadata.add_datastore_version_flavor_association(
cls.datastore_version.id, [cls.flavor_id])
DatastoreVersionMetadata.add_datastore_version_volume_type_association(
cls.datastore_version.id, [cls.volume_type])
cls.cap1 = Capability.create(cls.capability_name,
cls.capability_desc, True)
cls.cap2 = Capability.create(

View File

@ -57,48 +57,40 @@ class TestDatastoreVersionMetadata(TestDatastoreBase):
def test_add_existing_flavor_associations(self):
dsmetadata = datastore_models.DatastoreVersionMetadata
self.assertRaisesRegex(
self.assertRaises(
exception.DatastoreFlavorAssociationAlreadyExists,
"Flavor %s is already associated with datastore %s version %s"
% (self.flavor_id, self.ds_name, self.ds_version_name),
dsmetadata.add_datastore_version_flavor_association,
self.ds_name, self.ds_version_name, [self.flavor_id])
self.test_id, [self.flavor_id])
def test_add_existing_volume_type_associations(self):
dsmetadata = datastore_models.DatastoreVersionMetadata
self.assertRaises(
exception.DatastoreVolumeTypeAssociationAlreadyExists,
dsmetadata.add_datastore_version_volume_type_association,
self.ds_name, self.ds_version_name, [self.volume_type])
self.test_id, [self.volume_type])
def test_delete_nonexistent_flavor_mapping(self):
dsmeta = datastore_models.DatastoreVersionMetadata
self.assertRaisesRegex(
self.assertRaises(
exception.DatastoreFlavorAssociationNotFound,
"Flavor 2 is not supported for datastore %s version %s"
% (self.ds_name, self.ds_version_name),
dsmeta.delete_datastore_version_flavor_association,
self.ds_name, self.ds_version_name, flavor_id=2)
self.test_id, flavor_id=2)
def test_delete_nonexistent_volume_type_mapping(self):
dsmeta = datastore_models.DatastoreVersionMetadata
self.assertRaises(
exception.DatastoreVolumeTypeAssociationNotFound,
dsmeta.delete_datastore_version_volume_type_association,
self.ds_name, self.ds_version_name,
self.test_id,
volume_type_name='some random thing')
def test_delete_flavor_mapping(self):
flavor_id = 2
dsmetadata = datastore_models.DatastoreVersionMetadata
dsmetadata.add_datastore_version_flavor_association(
self.ds_name,
self.ds_version_name,
[flavor_id])
self.test_id, [flavor_id])
dsmetadata.delete_datastore_version_flavor_association(
self.ds_name,
self.ds_version_name,
flavor_id)
self.test_id, flavor_id)
datastore = datastore_models.Datastore.load(self.ds_name)
ds_version = datastore_models.DatastoreVersion.load(
datastore,
@ -108,27 +100,22 @@ class TestDatastoreVersionMetadata(TestDatastoreBase):
self.assertTrue(mapping.deleted)
# check update
dsmetadata.add_datastore_version_flavor_association(
self.ds_name, self.ds_version_name, [flavor_id])
self.test_id, [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_name,
delete_datastore_version_flavor_association(self.test_id,
flavor_id)
def test_delete_volume_type_mapping(self):
volume_type = 'this is bogus'
dsmetadata = datastore_models.DatastoreVersionMetadata
dsmetadata.add_datastore_version_volume_type_association(
self.ds_name,
self.ds_version_name,
[volume_type])
self.test_id, [volume_type])
dsmetadata.delete_datastore_version_volume_type_association(
self.ds_name,
self.ds_version_name,
volume_type)
self.test_id, volume_type)
datastore = datastore_models.Datastore.load(self.ds_name)
ds_version = datastore_models.DatastoreVersion.load(
datastore,
@ -139,19 +126,17 @@ class TestDatastoreVersionMetadata(TestDatastoreBase):
self.assertTrue(mapping.deleted)
# check update
dsmetadata.add_datastore_version_volume_type_association(
self.ds_name, self.ds_version_name, [volume_type])
self.test_id, [volume_type])
mapping = datastore_models.DBDatastoreVersionMetadata.find_by(
datastore_version_id=ds_version.id, value=volume_type,
key='volume_type')
self.assertFalse(mapping.deleted)
# clear the mapping
dsmetadata.delete_datastore_version_volume_type_association(
self.ds_name,
self.ds_version_name,
volume_type)
self.test_id, volume_type)
@mock.patch.object(datastore_models.DatastoreVersionMetadata,
'_datastore_version_find')
'datastore_version_find')
@mock.patch.object(datastore_models.DatastoreVersionMetadata,
'list_datastore_version_volume_type_associations')
@mock.patch.object(clients, 'create_cinder_client')
@ -179,7 +164,7 @@ class TestDatastoreVersionMetadata(TestDatastoreBase):
mock_list.return_value = mock_trove_list_result
return self.dsmetadata.allowed_datastore_version_volume_types(
None, 'ds', 'dsv')
None, self.random_uuid())
def _assert_equal_types(self, test_dict, output_obj):
self.assertEqual(test_dict.get('id'), output_obj.id)

View File

@ -13,7 +13,9 @@
# limitations under the License.
from unittest import mock
from trove.common import cfg
from trove.common import clients
from trove.common import exception
from trove.datastore import models as ds_models
from trove.instance import models as ins_models
from trove.instance import service
@ -21,6 +23,8 @@ from trove.instance import service_status as srvstatus
from trove.tests.unittests import trove_testtools
from trove.tests.unittests.util import util
CONF = cfg.CONF
class TestInstanceController(trove_testtools.TestCase):
@classmethod
@ -37,7 +41,14 @@ class TestInstanceController(trove_testtools.TestCase):
1)
ds_models.update_datastore_version(
cls.ds_name, 'test_image_tags', 'mysql', '', ['trove', 'mysql'],
'', 1)
'', 1, version='test_image_tags version')
ds_models.update_datastore_version(
cls.ds_name, 'test_version', 'mysql', '', ['trove'], '', 1,
version='version 1')
ds_models.update_datastore_version(
cls.ds_name, 'test_version', 'mysql', '', ['trove'], '', 1,
version='version 2')
cls.ds_version_imageid = ds_models.DatastoreVersion.load(
cls.ds, 'test_image_id')
cls.ds_version_imagetags = ds_models.DatastoreVersion.load(
@ -61,19 +72,22 @@ class TestInstanceController(trove_testtools.TestCase):
@mock.patch('trove.instance.models.Instance.create')
def test_create_by_ds_version_image_tags(self, mock_model_create,
mock_create_client):
image_id = self.random_uuid()
mock_glance_client = mock.MagicMock()
mock_glance_client.images.list.return_value = [
{'id': self.random_uuid()}]
mock_glance_client.images.list.return_value = [{'id': image_id}]
mock_create_client.return_value = mock_glance_client
name = self.random_name(name='instance',
prefix='TestInstanceController')
flavor = self.random_uuid()
body = {
'instance': {
'name': self.random_name(name='instance',
prefix='TestInstanceController'),
'flavorRef': self.random_uuid(),
'name': name,
'flavorRef': flavor,
'datastore': {
'type': self.ds_name,
'version': self.ds_version_imagetags.name
'version': self.ds_version_imagetags.name,
'version_number': self.ds_version_imagetags.version
}
}
}
@ -85,6 +99,40 @@ class TestInstanceController(trove_testtools.TestCase):
sort='created_at:desc', limit=1
)
mock_model_create.assert_called_once_with(
mock.ANY, name, flavor, image_id,
[], [],
mock.ANY, mock.ANY,
None, None, None, [], None, None,
replica_count=None, volume_type=None, modules=None, locality=None,
region_name=CONF.service_credentials.region_name, access=None
)
args = mock_model_create.call_args[0]
actual_ds_version = args[7]
self.assertEqual(self.ds_version_imagetags.name,
actual_ds_version.name)
self.assertEqual(self.ds_version_imagetags.version,
actual_ds_version.version)
def test_create_multiple_versions(self):
body = {
'instance': {
'name': self.random_name(name='instance',
prefix='TestInstanceController'),
'flavorRef': self.random_uuid(),
'datastore': {
'type': self.ds_name,
'version': 'test_version'
}
}
}
self.assertRaises(
exception.DatastoreVersionsNoUniqueMatch,
self.controller.create,
mock.MagicMock(), body, mock.ANY
)
@mock.patch.object(clients, 'create_nova_client',
return_value=mock.MagicMock())
@mock.patch('trove.rpc.get_client')