Glance Metadata Definitions Catalog - DB
Implements: blueprint metadata-schema-catalog A common API hosted by the Glance service for vendors, admins, services, and users to meaningfully define available key / value pair and tag metadata. The intent is to enable better metadata collaboration across artifacts, services, and projects for OpenStack users. This is about the definition of the available metadata that can be used on different types of resources (images, artifacts, volumes, flavors, aggregates, etc). A definition includes the properties type, its key, it's description, and it's constraints. This catalogue will not store the values for specific instance properties. Change-Id: I01cc63df3d3abe383c94cfb54598868b4bb729bb DocImpact Co-Authored-By: Lakshmi N Sampath <lakshmi.sampath@hp.com> Co-Authored-By: Wayne Okuma <wayne.okuma@hp.com> Co-Authored-By: Travis Tripp <travis.tripp@hp.com> Co-Authored-By: Pawel Koniszewski <pawel.koniszewski@intel.com> Co-Authored-By: Michal Jastrzebski <michal.jastrzebski@intel.com> Co-Authored-By: Michal Dulko <michal.dulko@intel.com>
This commit is contained in:
parent
640dd1ee89
commit
7454aac835
|
@ -130,6 +130,31 @@ class ProtectedImageDelete(Forbidden):
|
|||
message = _("Image %(image_id)s is protected and cannot be deleted.")
|
||||
|
||||
|
||||
class ProtectedMetadefNamespaceDelete(Forbidden):
|
||||
message = _("Metadata definition namespace %(namespace)s is protected"
|
||||
" and cannot be deleted.")
|
||||
|
||||
|
||||
class ProtectedMetadefNamespacePropDelete(Forbidden):
|
||||
message = _("Metadata definition property %(property_name)s is protected"
|
||||
" and cannot be deleted.")
|
||||
|
||||
|
||||
class ProtectedMetadefObjectDelete(Forbidden):
|
||||
message = _("Metadata definition object %(object_name)s is protected"
|
||||
" and cannot be deleted.")
|
||||
|
||||
|
||||
class ProtectedMetadefResourceTypeAssociationDelete(Forbidden):
|
||||
message = _("Metadata definition resource-type-association"
|
||||
" %(resource_type)s is protected and cannot be deleted.")
|
||||
|
||||
|
||||
class ProtectedMetadefResourceTypeSystemDelete(Forbidden):
|
||||
message = _("Metadata definition resource-type %(resource_type_name)s is"
|
||||
" a seeded-system type and cannot be deleted.")
|
||||
|
||||
|
||||
class Invalid(GlanceException):
|
||||
message = _("Data supplied was not valid.")
|
||||
|
||||
|
@ -353,3 +378,74 @@ class InvalidParameterValue(Invalid):
|
|||
class InvalidImageStatusTransition(Invalid):
|
||||
message = _("Image status transition from %(cur_status)s to"
|
||||
" %(new_status)s is not allowed")
|
||||
|
||||
|
||||
class MetadefDuplicateNamespace(Duplicate):
|
||||
message = _("The metadata definition namespace=%(namespace_name)s"
|
||||
" already exists.")
|
||||
|
||||
|
||||
class MetadefDuplicateObject(Duplicate):
|
||||
message = _("A metadata definition object with name=%(object_name)s"
|
||||
" already exists in namespace=%(namespace_name)s.")
|
||||
|
||||
|
||||
class MetadefDuplicateProperty(Duplicate):
|
||||
message = _("A metadata definition property with name=%(property_name)s"
|
||||
" already exists in namespace=%(namespace_name)s.")
|
||||
|
||||
|
||||
class MetadefDuplicateResourceType(Duplicate):
|
||||
message = _("A metadata definition resource-type with"
|
||||
" name=%(resource_type_name)s already exists.")
|
||||
|
||||
|
||||
class MetadefDuplicateResourceTypeAssociation(Duplicate):
|
||||
message = _("The metadata definition resource-type association of"
|
||||
" resource-type=%(resource_type_name)s to"
|
||||
" namespace=%(namespace_name)s"
|
||||
" already exists.")
|
||||
|
||||
|
||||
class MetadefForbidden(Forbidden):
|
||||
message = _("You are not authorized to complete this action.")
|
||||
|
||||
|
||||
class MetadefIntegrityError(Forbidden):
|
||||
message = _("The metadata definition %(record_type)s with"
|
||||
" name=%(record_name)s not deleted."
|
||||
" Other records still refer to it.")
|
||||
|
||||
|
||||
class MetadefNamespaceNotFound(NotFound):
|
||||
message = _("Metadata definition namespace=%(namespace_name)s"
|
||||
"was not found.")
|
||||
|
||||
|
||||
class MetadefObjectNotFound(NotFound):
|
||||
message = _("The metadata definition object with"
|
||||
" name=%(object_name)s was not found in"
|
||||
" namespace=%(namespace_name)s.")
|
||||
|
||||
|
||||
class MetadefPropertyNotFound(NotFound):
|
||||
message = _("The metadata definition property with"
|
||||
" name=%(property_name)s was not found in"
|
||||
" namespace=%(namespace_name)s.")
|
||||
|
||||
|
||||
class MetadefResourceTypeNotFound(NotFound):
|
||||
message = _("The metadata definition resource-type with"
|
||||
" name=%(resource_type_name)s, was not found.")
|
||||
|
||||
|
||||
class MetadefResourceTypeAssociationNotFound(NotFound):
|
||||
message = _("The metadata definition resource-type association of"
|
||||
" resource-type=%(resource_type_name)s to"
|
||||
" namespace=%(namespace_name)s,"
|
||||
" was not found.")
|
||||
|
||||
|
||||
class MetadefRecordNotFound(NotFound):
|
||||
message = _("Metadata definition %(record_type)s record not found"
|
||||
" for id %(id)s.")
|
||||
|
|
|
@ -262,3 +262,214 @@ def task_get_all(client, filters=None, marker=None, limit=None,
|
|||
def task_create(client, values, session=None):
|
||||
"""Create a task object"""
|
||||
return client.task_create(values=values)
|
||||
|
||||
|
||||
# Metadef
|
||||
@_get_client
|
||||
def metadef_namespace_get_all(
|
||||
client, marker=None, limit=None, sort_key='created_at',
|
||||
sort_dir=None, filters=None, session=None):
|
||||
return client.metadef_namespace_get_all(
|
||||
marker=marker, limit=limit,
|
||||
sort_key=sort_key, sort_dir=sort_dir, filters=filters)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_namespace_get(client, namespace_name, session=None):
|
||||
return client.metadef_namespace_get(namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_namespace_create(client, values, session=None):
|
||||
return client.metadef_namespace_create(values=values)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_namespace_update(
|
||||
client, namespace_id, namespace_dict,
|
||||
session=None):
|
||||
return client.metadef_namespace_update(
|
||||
namespace_id=namespace_id, namespace_dict=namespace_dict)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_namespace_delete(client, namespace_name, session=None):
|
||||
return client.metadef_namespace_delete(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_get_all(client, namespace_name, session=None):
|
||||
return client.metadef_object_get_all(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_get(
|
||||
client,
|
||||
namespace_name, object_name, session=None):
|
||||
return client.metadef_object_get(
|
||||
namespace_name=namespace_name, object_name=object_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_create(
|
||||
client,
|
||||
namespace_name, object_dict, session=None):
|
||||
return client.metadef_object_create(
|
||||
namespace_name=namespace_name, object_dict=object_dict)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_update(
|
||||
client,
|
||||
namespace_name, object_id,
|
||||
object_dict, session=None):
|
||||
return client.metadef_object_update(
|
||||
namespace_name=namespace_name, object_id=object_id,
|
||||
object_dict=object_dict)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_delete(
|
||||
client,
|
||||
namespace_name, object_name,
|
||||
session=None):
|
||||
return client.metadef_object_delete(
|
||||
namespace_name=namespace_name, object_name=object_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_delete_namespace_content(
|
||||
client,
|
||||
namespace_name, session=None):
|
||||
return client.metadef_object_delete_namespace_content(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_object_count(
|
||||
client,
|
||||
namespace_name, session=None):
|
||||
return client.metadef_object_count(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_get_all(
|
||||
client,
|
||||
namespace_name, session=None):
|
||||
return client.metadef_property_get_all(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_get(
|
||||
client,
|
||||
namespace_name, property_name,
|
||||
session=None):
|
||||
return client.metadef_property_get(
|
||||
namespace_name=namespace_name, property_name=property_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_create(
|
||||
client,
|
||||
namespace_name, property_dict,
|
||||
session=None):
|
||||
return client.metadef_property_create(
|
||||
namespace_name=namespace_name, property_dict=property_dict)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_update(
|
||||
client,
|
||||
namespace_name, property_id,
|
||||
property_dict, session=None):
|
||||
return client.metadef_property_update(
|
||||
namespace_name=namespace_name, property_id=property_id,
|
||||
property_dict=property_dict)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_delete(
|
||||
client,
|
||||
namespace_name, property_name,
|
||||
session=None):
|
||||
return client.metadef_property_delete(
|
||||
namespace_name=namespace_name, property_name=property_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_delete_namespace_content(
|
||||
client,
|
||||
namespace_name, session=None):
|
||||
return client.metadef_property_delete_namespace_content(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_property_count(
|
||||
client,
|
||||
namespace_name, session=None):
|
||||
return client.metadef_property_count(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_create(client, values, session=None):
|
||||
return client.metadef_resource_type_create(values=values)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_get(
|
||||
client,
|
||||
resource_type_name, session=None):
|
||||
return client.metadef_resource_type_get(
|
||||
resource_type_name=resource_type_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_get_all(client, session=None):
|
||||
return client.metadef_resource_type_get_all()
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_delete(
|
||||
client,
|
||||
resource_type_name, session=None):
|
||||
return client.metadef_resource_type_delete(
|
||||
resource_type_name=resource_type_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_association_get(
|
||||
client,
|
||||
namespace_name, resource_type_name,
|
||||
session=None):
|
||||
return client.metadef_resource_type_association_get(
|
||||
namespace_name=namespace_name, resource_type_name=resource_type_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_association_create(
|
||||
client,
|
||||
namespace_name, values, session=None):
|
||||
return client.metadef_resource_type_association_create(
|
||||
namespace_name=namespace_name, values=values)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_association_delete(
|
||||
client,
|
||||
namespace_name, resource_type_name, session=None):
|
||||
return client.metadef_resource_type_association_delete(
|
||||
namespace_name=namespace_name, resource_type_name=resource_type_name)
|
||||
|
||||
|
||||
@_get_client
|
||||
def metadef_resource_type_association_get_all_by_namespace(
|
||||
client,
|
||||
namespace_name, session=None):
|
||||
return client.metadef_resource_type_association_get_all_by_namespace(
|
||||
namespace_name=namespace_name)
|
||||
|
|
|
@ -30,12 +30,19 @@ LOG = logging.getLogger(__name__)
|
|||
DATA = {
|
||||
'images': {},
|
||||
'members': {},
|
||||
'metadef_namespace_resource_types': [],
|
||||
'metadef_namespaces': [],
|
||||
'metadef_objects': [],
|
||||
'metadef_properties': [],
|
||||
'metadef_resource_types': [],
|
||||
'tags': {},
|
||||
'locations': [],
|
||||
'tasks': {},
|
||||
'task_info': {}
|
||||
}
|
||||
|
||||
INDEX = 0
|
||||
|
||||
|
||||
def log_call(func):
|
||||
@functools.wraps(func)
|
||||
|
@ -57,6 +64,11 @@ def reset():
|
|||
DATA = {
|
||||
'images': {},
|
||||
'members': [],
|
||||
'metadef_namespace_resource_types': [],
|
||||
'metadef_namespaces': [],
|
||||
'metadef_objects': [],
|
||||
'metadef_properties': [],
|
||||
'metadef_resource_types': [],
|
||||
'tags': {},
|
||||
'locations': [],
|
||||
'tasks': {},
|
||||
|
@ -1017,3 +1029,737 @@ def _task_info_get(task_id):
|
|||
raise exception.TaskNotFound(task_id=task_id)
|
||||
|
||||
return task_info
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_create(context, values):
|
||||
"""Create a namespace object"""
|
||||
global DATA
|
||||
|
||||
namespace_values = copy.deepcopy(values)
|
||||
namespace_name = namespace_values.get('namespace')
|
||||
required_attributes = ['namespace', 'owner']
|
||||
allowed_attributes = ['namespace', 'owner', 'display_name', 'description',
|
||||
'visibility', 'protected']
|
||||
|
||||
for namespace in DATA['metadef_namespaces']:
|
||||
if namespace['namespace'] == namespace_name:
|
||||
msg = ("Can not create the metadata definition namespace. "
|
||||
"Namespace=%s already exists.") % namespace_name
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefDuplicateNamespace(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
for key in required_attributes:
|
||||
if key not in namespace_values:
|
||||
raise exception.Invalid('%s is a required attribute' % key)
|
||||
|
||||
incorrect_keys = set(namespace_values.keys()) - set(allowed_attributes)
|
||||
if incorrect_keys:
|
||||
raise exception.Invalid(
|
||||
'The keys %s are not valid' % str(incorrect_keys))
|
||||
|
||||
namespace = _format_namespace(namespace_values)
|
||||
DATA['metadef_namespaces'].append(namespace)
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_update(context, namespace_id, values):
|
||||
"""Update a namespace object"""
|
||||
global DATA
|
||||
namespace_values = copy.deepcopy(values)
|
||||
|
||||
namespace = metadef_namespace_get_by_id(context, namespace_id)
|
||||
if namespace['namespace'] != values['namespace']:
|
||||
for db_namespace in DATA['metadef_namespaces']:
|
||||
if db_namespace['namespace'] == values['namespace']:
|
||||
msg = ("Invalid update. It would result in a duplicate"
|
||||
" metadata definition namespace with the same"
|
||||
" name of %s"
|
||||
% values['namespace'])
|
||||
LOG.debug(msg)
|
||||
emsg = (_("Invalid update. It would result in a duplicate"
|
||||
" metadata definition namespace with the same"
|
||||
" name of %s")
|
||||
% values['namespace'])
|
||||
raise exception.MetadefDuplicateNamespace(emsg)
|
||||
DATA['metadef_namespaces'].remove(namespace)
|
||||
|
||||
namespace.update(namespace_values)
|
||||
namespace['updated_at'] = timeutils.utcnow()
|
||||
DATA['metadef_namespaces'].append(namespace)
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_get_by_id(context, namespace_id):
|
||||
"""Get a namespace object"""
|
||||
try:
|
||||
namespace = next(namespace for namespace in DATA['metadef_namespaces']
|
||||
if namespace['id'] == namespace_id)
|
||||
except StopIteration:
|
||||
msg = "No namespace found with id %s" % namespace_id
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefRecordNotFound(
|
||||
record_type='namespace', id=namespace_id)
|
||||
|
||||
if not _is_namespace_visible(context, namespace):
|
||||
msg = ("Forbidding request, metadata definition namespace=%s"
|
||||
" is not visible.") % namespace.namespace
|
||||
LOG.debug(msg)
|
||||
emsg = _("Forbidding request, metadata definition namespace=%s"
|
||||
" is not visible.") % namespace.namespace
|
||||
raise exception.MetadefForbidden(emsg)
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_get(context, namespace_name):
|
||||
"""Get a namespace object"""
|
||||
try:
|
||||
namespace = next(namespace for namespace in DATA['metadef_namespaces']
|
||||
if namespace['namespace'] == namespace_name)
|
||||
except StopIteration:
|
||||
msg = "No namespace found with name %s" % namespace_name
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefNamespaceNotFound(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_get_all(context,
|
||||
marker=None,
|
||||
limit=None,
|
||||
sort_key='created_at',
|
||||
sort_dir='desc',
|
||||
filters=None):
|
||||
"""Get a namespaces list"""
|
||||
resource_types = filters.get('resource_types', []) if filters else []
|
||||
visibility = filters.get('visibility', None) if filters else None
|
||||
|
||||
namespaces = []
|
||||
for namespace in DATA['metadef_namespaces']:
|
||||
if not _is_namespace_visible(context, namespace):
|
||||
continue
|
||||
|
||||
if visibility and namespace['visibility'] != visibility:
|
||||
continue
|
||||
|
||||
if resource_types:
|
||||
for association in DATA['metadef_namespace_resource_types']:
|
||||
if association['namespace_id'] == namespace['id']:
|
||||
if association['name'] in resource_types:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
namespaces.append(namespace)
|
||||
|
||||
return namespaces
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_delete(context, namespace_name):
|
||||
"""Delete a namespace object"""
|
||||
global DATA
|
||||
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
DATA['metadef_namespaces'].remove(namespace)
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_delete_content(context, namespace_name):
|
||||
"""Delete a namespace content"""
|
||||
global DATA
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
namespace_id = namespace['id']
|
||||
|
||||
objects = []
|
||||
|
||||
for object in DATA['metadef_objects']:
|
||||
if object['namespace_id'] != namespace_id:
|
||||
objects.append(object)
|
||||
|
||||
DATA['metadef_objects'] = objects
|
||||
|
||||
properties = []
|
||||
|
||||
for property in DATA['metadef_objects']:
|
||||
if property['namespace_id'] != namespace_id:
|
||||
properties.append(object)
|
||||
|
||||
DATA['metadef_objects'] = properties
|
||||
|
||||
return namespace
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_get(context, namespace_name, object_name):
|
||||
"""Get a metadef object"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
for object in DATA['metadef_objects']:
|
||||
if (object['namespace_id'] == namespace['id'] and
|
||||
object['name'] == object_name):
|
||||
return object
|
||||
else:
|
||||
msg = ("The metadata definition object with name=%(name)s"
|
||||
" was not found in namespace=%(namespace_name)s."
|
||||
% {'name': object_name, 'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefObjectNotFound(namespace_name=namespace_name,
|
||||
object_name=object_name)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_get_by_id(context, namespace_name, object_id):
|
||||
"""Get a metadef object"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
for object in DATA['metadef_objects']:
|
||||
if (object['namespace_id'] == namespace['id'] and
|
||||
object['id'] == object_id):
|
||||
return object
|
||||
else:
|
||||
msg = ("No metadata definition object found with id %s"
|
||||
% object_id)
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefRecordNotFound(record_type='object',
|
||||
id=object_id)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_get_all(context, namespace_name):
|
||||
"""Get a metadef objects list"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
objects = []
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
for object in DATA['metadef_objects']:
|
||||
if object['namespace_id'] == namespace['id']:
|
||||
objects.append(object)
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_create(context, namespace_name, values):
|
||||
"""Create a metadef object"""
|
||||
global DATA
|
||||
|
||||
object_values = copy.deepcopy(values)
|
||||
object_name = object_values['name']
|
||||
required_attributes = ['name']
|
||||
allowed_attributes = ['name', 'description', 'schema', 'required']
|
||||
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
for object in DATA['metadef_objects']:
|
||||
if (object['name'] == object_name and
|
||||
object['namespace_id'] == namespace['id']):
|
||||
msg = ("A metadata definition object with name=%(name)s"
|
||||
" in namespace=%(namespace_name)s already exists."
|
||||
% {'name': object_name, 'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefDuplicateObject(
|
||||
object_name=object_name, namespace_name=namespace_name)
|
||||
|
||||
for key in required_attributes:
|
||||
if key not in object_values:
|
||||
raise exception.Invalid('%s is a required attribute' % key)
|
||||
|
||||
incorrect_keys = set(object_values.keys()) - set(allowed_attributes)
|
||||
if incorrect_keys:
|
||||
raise exception.Invalid(
|
||||
'The keys %s are not valid' % str(incorrect_keys))
|
||||
|
||||
object_values['namespace_id'] = namespace['id']
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
object = _format_object(object_values)
|
||||
DATA['metadef_objects'].append(object)
|
||||
|
||||
return object
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_update(context, namespace_name, object_id, values):
|
||||
"""Update a metadef object"""
|
||||
global DATA
|
||||
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
object = metadef_object_get_by_id(context, namespace_name, object_id)
|
||||
if object['name'] != values['name']:
|
||||
for db_object in DATA['metadef_objects']:
|
||||
if (db_object['name'] == values['name'] and
|
||||
db_object['namespace_id'] == namespace['id']):
|
||||
msg = ("Invalid update. It would result in a duplicate"
|
||||
" metadata definition object with same name=%(name)s "
|
||||
" in namespace=%(namespace_name)s."
|
||||
% {'name': object['name'],
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
emsg = (_("Invalid update. It would result in a duplicate"
|
||||
" metadata definition object with the same"
|
||||
" name=%(name)s "
|
||||
" in namespace=%(namespace_name)s.")
|
||||
% {'name': object['name'],
|
||||
'namespace_name': namespace_name})
|
||||
raise exception.MetadefDuplicateObject(emsg)
|
||||
DATA['metadef_objects'].remove(object)
|
||||
|
||||
object.update(values)
|
||||
object['updated_at'] = timeutils.utcnow()
|
||||
DATA['metadef_objects'].append(object)
|
||||
|
||||
return object
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_delete(context, namespace_name, object_name):
|
||||
"""Delete a metadef object"""
|
||||
global DATA
|
||||
|
||||
object = metadef_object_get(context, namespace_name, object_name)
|
||||
DATA['metadef_objects'].remove(object)
|
||||
|
||||
return object
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_count(context, namespace_name):
|
||||
"""Get metadef object count in a namespace"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
count = 0
|
||||
for object in DATA['metadef_objects']:
|
||||
if object['namespace_id'] == namespace['id']:
|
||||
count = count + 1
|
||||
|
||||
return count
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_count(context, namespace_name):
|
||||
"""Get properties count in a namespace"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
count = 0
|
||||
for property in DATA['metadef_properties']:
|
||||
if property['namespace_id'] == namespace['id']:
|
||||
count = count + 1
|
||||
|
||||
return count
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_create(context, namespace_name, values):
|
||||
"""Create a metadef property"""
|
||||
global DATA
|
||||
|
||||
property_values = copy.deepcopy(values)
|
||||
property_name = property_values['name']
|
||||
required_attributes = ['name']
|
||||
allowed_attributes = ['name', 'description', 'schema', 'required']
|
||||
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
for property in DATA['metadef_properties']:
|
||||
if (property['name'] == property_name and
|
||||
property['namespace_id'] == namespace['id']):
|
||||
msg = ("Can not create metadata definition property. A property"
|
||||
" with name=%(name)s already exists in"
|
||||
" namespace=%(namespace_name)s."
|
||||
% {'name': property_name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefDuplicateProperty(
|
||||
property_name=property_name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
for key in required_attributes:
|
||||
if key not in property_values:
|
||||
raise exception.Invalid('%s is a required attribute' % key)
|
||||
|
||||
incorrect_keys = set(property_values.keys()) - set(allowed_attributes)
|
||||
if incorrect_keys:
|
||||
raise exception.Invalid(
|
||||
'The keys %s are not valid' % str(incorrect_keys))
|
||||
|
||||
property_values['namespace_id'] = namespace['id']
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
property = _format_property(property_values)
|
||||
DATA['metadef_properties'].append(property)
|
||||
|
||||
return property
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_update(context, namespace_name, property_id, values):
|
||||
"""Update a metadef property"""
|
||||
global DATA
|
||||
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
property = metadef_property_get_by_id(context, namespace_name, property_id)
|
||||
if property['name'] != values['name']:
|
||||
for db_property in DATA['metadef_properties']:
|
||||
if (db_property['name'] == values['name'] and
|
||||
db_property['namespace_id'] == namespace['id']):
|
||||
msg = ("Invalid update. It would result in a duplicate"
|
||||
" metadata definition property with the same"
|
||||
" name=%(name)s"
|
||||
" in namespace=%(namespace_name)s."
|
||||
% {'name': property['name'],
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
emsg = (_("Invalid update. It would result in a duplicate"
|
||||
" metadata definition property with the same"
|
||||
" name=%(name)s"
|
||||
" in namespace=%(namespace_name)s.")
|
||||
% {'name': property['name'],
|
||||
'namespace_name': namespace_name})
|
||||
raise exception.MetadefDuplicateProperty(emsg)
|
||||
DATA['metadef_properties'].remove(property)
|
||||
|
||||
property.update(values)
|
||||
property['updated_at'] = timeutils.utcnow()
|
||||
DATA['metadef_properties'].append(property)
|
||||
|
||||
return property
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_get_all(context, namespace_name):
|
||||
"""Get a metadef properties list"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
properties = []
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
for property in DATA['metadef_properties']:
|
||||
if property['namespace_id'] == namespace['id']:
|
||||
properties.append(property)
|
||||
|
||||
return properties
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_get_by_id(context, namespace_name, property_id):
|
||||
"""Get a metadef property"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
for property in DATA['metadef_properties']:
|
||||
if (property['namespace_id'] == namespace['id'] and
|
||||
property['id'] == property_id):
|
||||
return property
|
||||
else:
|
||||
msg = ("No metadata definition property found with id=%s"
|
||||
% property_id)
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefRecordNotFound(record_type='property',
|
||||
id=property_id)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_get(context, namespace_name, property_name):
|
||||
"""Get a metadef property"""
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
_check_namespace_visibility(context, namespace, namespace_name)
|
||||
|
||||
for property in DATA['metadef_properties']:
|
||||
if (property['namespace_id'] == namespace['id'] and
|
||||
property['name'] == property_name):
|
||||
return property
|
||||
else:
|
||||
msg = ("No property found with name=%(name)s in"
|
||||
" namespace=%(namespace_name)s "
|
||||
% {'name': property_name, 'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefPropertyNotFound(namespace_name=namespace_name,
|
||||
property_name=property_name)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_property_delete(context, namespace_name, property_name):
|
||||
"""Delete a metadef property"""
|
||||
global DATA
|
||||
|
||||
property = metadef_property_get(context, namespace_name, property_name)
|
||||
DATA['metadef_properties'].remove(property)
|
||||
|
||||
return property
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_create(context, values):
|
||||
"""Create a metadef resource type"""
|
||||
global DATA
|
||||
|
||||
resource_type_values = copy.deepcopy(values)
|
||||
resource_type_name = resource_type_values['name']
|
||||
|
||||
allowed_attrubites = ['name', 'protected']
|
||||
|
||||
for resource_type in DATA['metadef_resource_types']:
|
||||
if resource_type['name'] == resource_type_name:
|
||||
raise exception.Duplicate()
|
||||
|
||||
incorrect_keys = set(resource_type_values.keys()) - set(allowed_attrubites)
|
||||
if incorrect_keys:
|
||||
raise exception.Invalid(
|
||||
'The keys %s are not valid' % str(incorrect_keys))
|
||||
|
||||
resource_type = _format_resource_type(resource_type_values)
|
||||
DATA['metadef_resource_types'].append(resource_type)
|
||||
|
||||
return resource_type
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_get_all(context):
|
||||
"""List all resource types"""
|
||||
return DATA['metadef_resource_types']
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_get(context, resource_type_name):
|
||||
"""Get a resource type"""
|
||||
try:
|
||||
resource_type = next(resource_type for resource_type in
|
||||
DATA['metadef_resource_types']
|
||||
if resource_type['name'] ==
|
||||
resource_type_name)
|
||||
except StopIteration:
|
||||
msg = "No resource type found with name %s" % resource_type_name
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefResourceTypeNotFound(
|
||||
resource_type_name=resource_type_name)
|
||||
|
||||
return resource_type
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_association_create(context, namespace_name,
|
||||
values):
|
||||
global DATA
|
||||
|
||||
association_values = copy.deepcopy(values)
|
||||
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
resource_type_name = association_values['name']
|
||||
resource_type = metadef_resource_type_get(context,
|
||||
resource_type_name)
|
||||
|
||||
required_attributes = ['name', 'properties_target', 'prefix']
|
||||
allowed_attributes = copy.deepcopy(required_attributes)
|
||||
|
||||
for association in DATA['metadef_namespace_resource_types']:
|
||||
if (association['namespace_id'] == namespace['id'] and
|
||||
association['resource_type'] == resource_type['id']):
|
||||
msg = ("The metadata definition resource-type association of"
|
||||
" resource_type=%(resource_type_name)s to"
|
||||
" namespace=%(namespace_name)s, already exists."
|
||||
% {'resource_type_name': resource_type_name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefDuplicateResourceTypeAssociation(
|
||||
resource_type_name=resource_type_name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
for key in required_attributes:
|
||||
if key not in association_values:
|
||||
raise exception.Invalid('%s is a required attribute' % key)
|
||||
|
||||
incorrect_keys = set(association_values.keys()) - set(allowed_attributes)
|
||||
if incorrect_keys:
|
||||
raise exception.Invalid(
|
||||
'The keys %s are not valid' % str(incorrect_keys))
|
||||
|
||||
association = _format_association(namespace, resource_type,
|
||||
association_values)
|
||||
DATA['metadef_namespace_resource_types'].append(association)
|
||||
|
||||
return association
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_association_get(context, namespace_name,
|
||||
resource_type_name):
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
resource_type = metadef_resource_type_get(context, resource_type_name)
|
||||
|
||||
for association in DATA['metadef_namespace_resource_types']:
|
||||
if (association['namespace_id'] == namespace['id'] and
|
||||
association['resource_type'] == resource_type['id']):
|
||||
return association
|
||||
else:
|
||||
msg = ("No resource type association found associated with namespace "
|
||||
"%s and resource type %s" % namespace_name, resource_type_name)
|
||||
LOG.debug(msg)
|
||||
raise exception.MetadefResourceTypeAssociationNotFound(
|
||||
resource_type_name=resource_type_name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_association_get_all_by_namespace(context,
|
||||
namespace_name):
|
||||
namespace = metadef_namespace_get(context, namespace_name)
|
||||
|
||||
namespace_resource_types = []
|
||||
for resource_type in DATA['metadef_namespace_resource_types']:
|
||||
if resource_type['namespace_id'] == namespace['id']:
|
||||
namespace_resource_types.append(resource_type)
|
||||
|
||||
return namespace_resource_types
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_association_delete(context, namespace_name,
|
||||
resource_type_name):
|
||||
global DATA
|
||||
|
||||
resource_type = metadef_resource_type_association_get(context,
|
||||
namespace_name,
|
||||
resource_type_name)
|
||||
DATA['metadef_namespace_resource_types'].remove(resource_type)
|
||||
|
||||
return resource_type
|
||||
|
||||
|
||||
def _format_association(namespace, resource_type, association_values):
|
||||
association = {
|
||||
'namespace_id': namespace['id'],
|
||||
'resource_type': resource_type['id'],
|
||||
'properties_target': None,
|
||||
'prefix': None,
|
||||
'created_at': timeutils.utcnow(),
|
||||
'updated_at': timeutils.utcnow()
|
||||
|
||||
}
|
||||
association.update(association_values)
|
||||
return association
|
||||
|
||||
|
||||
def _format_resource_type(values):
|
||||
dt = timeutils.utcnow()
|
||||
resource_type = {
|
||||
'id': _get_metadef_id(),
|
||||
'name': values['name'],
|
||||
'protected': True,
|
||||
'created_at': dt,
|
||||
'updated_at': dt
|
||||
}
|
||||
resource_type.update(values)
|
||||
return resource_type
|
||||
|
||||
|
||||
def _format_property(values):
|
||||
property = {
|
||||
'id': _get_metadef_id(),
|
||||
'namespace_id': None,
|
||||
'name': None,
|
||||
'schema': None
|
||||
}
|
||||
property.update(values)
|
||||
return property
|
||||
|
||||
|
||||
def _format_namespace(values):
|
||||
dt = timeutils.utcnow()
|
||||
namespace = {
|
||||
'id': _get_metadef_id(),
|
||||
'namespace': None,
|
||||
'display_name': None,
|
||||
'description': None,
|
||||
'visibility': 'private',
|
||||
'protected': False,
|
||||
'owner': None,
|
||||
'created_at': dt,
|
||||
'updated_at': dt
|
||||
}
|
||||
namespace.update(values)
|
||||
return namespace
|
||||
|
||||
|
||||
def _format_object(values):
|
||||
dt = timeutils.utcnow()
|
||||
object = {
|
||||
'id': _get_metadef_id(),
|
||||
'namespace_id': None,
|
||||
'name': None,
|
||||
'description': None,
|
||||
'schema': None,
|
||||
'required': None,
|
||||
'created_at': dt,
|
||||
'updated_at': dt
|
||||
}
|
||||
object.update(values)
|
||||
return object
|
||||
|
||||
|
||||
def _is_namespace_visible(context, namespace):
|
||||
"""Return true if namespace is visible in this context"""
|
||||
if context.is_admin:
|
||||
return True
|
||||
|
||||
if namespace.get('visibility', '') == 'public':
|
||||
return True
|
||||
|
||||
if namespace['owner'] is None:
|
||||
return True
|
||||
|
||||
if context.owner is not None:
|
||||
if context.owner == namespace['owner']:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _check_namespace_visibility(context, namespace, namespace_name):
|
||||
if not _is_namespace_visible(context, namespace):
|
||||
msg = ("Forbidding request, metadata definition namespace=%s"
|
||||
" not visible." % namespace_name)
|
||||
LOG.debug(msg)
|
||||
emsg = _("Forbidding request, metadata definition namespace=%s"
|
||||
" not visible.") % namespace_name
|
||||
raise exception.MetadefForbidden(emsg)
|
||||
|
||||
|
||||
def _get_metadef_id():
|
||||
global INDEX
|
||||
INDEX += 1
|
||||
return INDEX
|
||||
|
|
|
@ -39,6 +39,13 @@ from glance import i18n
|
|||
import glance.openstack.common.log as os_logging
|
||||
from glance.openstack.common import timeutils
|
||||
|
||||
from glance.db.sqlalchemy.metadef_api import namespace as metadef_namespace_api
|
||||
from glance.db.sqlalchemy.metadef_api import object as metadef_object_api
|
||||
from glance.db.sqlalchemy.metadef_api import property as metadef_property_api
|
||||
from glance.db.sqlalchemy.metadef_api\
|
||||
import resource_type as metadef_resource_type_api
|
||||
from glance.db.sqlalchemy.metadef_api\
|
||||
import resource_type_association as metadef_association_api
|
||||
|
||||
BASE = models.BASE
|
||||
sa_logger = None
|
||||
|
@ -1426,3 +1433,199 @@ def _task_format(task_ref, task_info_ref=None):
|
|||
task_dict.update(task_info_dict)
|
||||
|
||||
return task_dict
|
||||
|
||||
|
||||
def metadef_namespace_get_all(context, marker=None, limit=None, sort_key=None,
|
||||
sort_dir=None, filters=None, session=None):
|
||||
"""List all available namespaces."""
|
||||
session = session or get_session()
|
||||
namespaces = metadef_namespace_api.get_all(
|
||||
context, session, marker, limit, sort_key, sort_dir, filters)
|
||||
return namespaces
|
||||
|
||||
|
||||
def metadef_namespace_get(context, namespace_name, session=None):
|
||||
"""Get a namespace or raise if it does not exist or is not visible."""
|
||||
session = session or get_session()
|
||||
return metadef_namespace_api.get(
|
||||
context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_namespace_create(context, values, session=None):
|
||||
"""Create a namespace or raise if it already exists."""
|
||||
session = session or get_session()
|
||||
return metadef_namespace_api.create(context, values, session)
|
||||
|
||||
|
||||
def metadef_namespace_update(context, namespace_id, namespace_dict,
|
||||
session=None):
|
||||
"""Update a namespace or raise if it does not exist or not visible"""
|
||||
session = session or get_session()
|
||||
return metadef_namespace_api.\
|
||||
update(context, namespace_id, namespace_dict, session)
|
||||
|
||||
|
||||
def metadef_namespace_delete(context, namespace_name, session=None):
|
||||
"""Delete the namespace and all foreign references"""
|
||||
session = session or get_session()
|
||||
return metadef_namespace_api.delete_cascade(
|
||||
context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_object_get_all(context, namespace_name, session=None):
|
||||
"""Get a metadata-schema object or raise if it does not exist."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.get_all(
|
||||
context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_object_get(context, namespace_name, object_name, session=None):
|
||||
"""Get a metadata-schema object or raise if it does not exist."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.get(
|
||||
context, namespace_name, object_name, session)
|
||||
|
||||
|
||||
def metadef_object_create(context, namespace_name, object_dict,
|
||||
session=None):
|
||||
"""Create a metadata-schema object or raise if it already exists."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.create(
|
||||
context, namespace_name, object_dict, session)
|
||||
|
||||
|
||||
def metadef_object_update(context, namespace_name, object_id, object_dict,
|
||||
session=None):
|
||||
"""Update an object or raise if it does not exist or not visible."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.update(
|
||||
context, namespace_name, object_id, object_dict, session)
|
||||
|
||||
|
||||
def metadef_object_delete(context, namespace_name, object_name,
|
||||
session=None):
|
||||
"""Delete an object or raise if namespace or object doesn't exist."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.delete(
|
||||
context, namespace_name, object_name, session)
|
||||
|
||||
|
||||
def metadef_object_delete_namespace_content(
|
||||
context, namespace_name, session=None):
|
||||
"""Delete an object or raise if namespace or object doesn't exist."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.delete_by_namespace_name(
|
||||
context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_object_count(context, namespace_name, session=None):
|
||||
"""Get count of properties for a namespace, raise if ns doesn't exist."""
|
||||
session = session or get_session()
|
||||
return metadef_object_api.count(context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_property_get_all(context, namespace_name, session=None):
|
||||
"""Get a metadef property or raise if it does not exist."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.get_all(context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_property_get(context, namespace_name,
|
||||
property_name, session=None):
|
||||
"""Get a metadef property or raise if it does not exist."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.get(
|
||||
context, namespace_name, property_name, session)
|
||||
|
||||
|
||||
def metadef_property_create(context, namespace_name, property_dict,
|
||||
session=None):
|
||||
"""Create a metadef property or raise if it already exists."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.create(
|
||||
context, namespace_name, property_dict, session)
|
||||
|
||||
|
||||
def metadef_property_update(context, namespace_name, property_id,
|
||||
property_dict, session=None):
|
||||
"""Update an object or raise if it does not exist or not visible."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.update(
|
||||
context, namespace_name, property_id, property_dict, session)
|
||||
|
||||
|
||||
def metadef_property_delete(context, namespace_name, property_name,
|
||||
session=None):
|
||||
"""Delete a property or raise if it or namespace doesn't exist."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.delete(
|
||||
context, namespace_name, property_name, session)
|
||||
|
||||
|
||||
def metadef_property_delete_namespace_content(
|
||||
context, namespace_name, session=None):
|
||||
"""Delete a property or raise if it or namespace doesn't exist."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.delete_by_namespace_name(
|
||||
context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_property_count(context, namespace_name, session=None):
|
||||
"""Get count of properties for a namespace, raise if ns doesn't exist."""
|
||||
session = session or get_session()
|
||||
return metadef_property_api.count(context, namespace_name, session)
|
||||
|
||||
|
||||
def metadef_resource_type_create(context, values, session=None):
|
||||
"""Create a resource_type"""
|
||||
session = session or get_session()
|
||||
return metadef_resource_type_api.create(
|
||||
context, values, session)
|
||||
|
||||
|
||||
def metadef_resource_type_get(context, resource_type_name, session=None):
|
||||
"""Get a resource_type"""
|
||||
session = session or get_session()
|
||||
return metadef_resource_type_api.get(
|
||||
context, resource_type_name, session)
|
||||
|
||||
|
||||
def metadef_resource_type_get_all(context, session=None):
|
||||
"""list all resource_types"""
|
||||
session = session or get_session()
|
||||
return metadef_resource_type_api.get_all(context, session)
|
||||
|
||||
|
||||
def metadef_resource_type_delete(context, resource_type_name, session=None):
|
||||
"""Get a resource_type"""
|
||||
session = session or get_session()
|
||||
return metadef_resource_type_api.delete(
|
||||
context, resource_type_name, session)
|
||||
|
||||
|
||||
def metadef_resource_type_association_get(
|
||||
context, namespace_name, resource_type_name, session=None):
|
||||
session = session or get_session()
|
||||
return metadef_association_api.get(
|
||||
context, namespace_name, resource_type_name, session)
|
||||
|
||||
|
||||
def metadef_resource_type_association_create(
|
||||
context, namespace_name, values, session=None):
|
||||
session = session or get_session()
|
||||
return metadef_association_api.create(
|
||||
context, namespace_name, values, session)
|
||||
|
||||
|
||||
def metadef_resource_type_association_delete(
|
||||
context, namespace_name, resource_type_name, session=None):
|
||||
session = session or get_session()
|
||||
return metadef_association_api.delete(
|
||||
context, namespace_name, resource_type_name, session)
|
||||
|
||||
|
||||
def metadef_resource_type_association_get_all_by_namespace(
|
||||
context, namespace_name, session=None):
|
||||
session = session or get_session()
|
||||
return metadef_association_api.\
|
||||
get_all_by_namespace(context, namespace_name, session)
|
||||
|
|
|
@ -0,0 +1,307 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 oslo.db import exception as db_exc
|
||||
from oslo.db.sqlalchemy.utils import paginate_query
|
||||
import sqlalchemy.exc as sa_exc
|
||||
from sqlalchemy import or_
|
||||
import sqlalchemy.orm as sa_orm
|
||||
|
||||
from glance.common import exception as exc
|
||||
import glance.db.sqlalchemy.metadef_api as metadef_api
|
||||
from glance.db.sqlalchemy import models_metadef as models
|
||||
from glance import i18n
|
||||
import glance.openstack.common.log as os_logging
|
||||
|
||||
LOG = os_logging.getLogger(__name__)
|
||||
_LW = i18n._LW
|
||||
|
||||
|
||||
def _is_namespace_visible(context, namespace, status=None):
|
||||
"""Return True if the namespace is visible in this context."""
|
||||
|
||||
# Is admin == visible
|
||||
if context.is_admin:
|
||||
return True
|
||||
|
||||
# No owner == visible
|
||||
if namespace['owner'] is None:
|
||||
return True
|
||||
|
||||
# Is public == visible
|
||||
if 'visibility' in namespace:
|
||||
if namespace['visibility'] == 'public':
|
||||
return True
|
||||
|
||||
# context.owner has a value and is the namespace owner == visible
|
||||
if context.owner is not None:
|
||||
if context.owner == namespace['owner']:
|
||||
return True
|
||||
|
||||
# Private
|
||||
return False
|
||||
|
||||
|
||||
def _select_namespaces_query(context, session):
|
||||
"""Build the query to get all namespaces based on the context"""
|
||||
|
||||
LOG.debug("context.is_admin=%(is_admin)s; context.owner=%(owner)s" %
|
||||
{'is_admin': context.is_admin, 'owner': context.owner})
|
||||
|
||||
# If admin, return everything.
|
||||
query_ns = session.query(models.MetadefNamespace)
|
||||
if context.is_admin:
|
||||
return query_ns
|
||||
else:
|
||||
# If regular user, return only public namespaces.
|
||||
# However, if context.owner has a value, return both
|
||||
# public and private namespaces of the context.owner.
|
||||
if context.owner is not None:
|
||||
query = (
|
||||
query_ns.filter(
|
||||
or_(models.MetadefNamespace.owner == context.owner,
|
||||
models.MetadefNamespace.visibility == 'public')))
|
||||
else:
|
||||
query = query_ns.filter(
|
||||
models.MetadefNamespace.visibility == 'public')
|
||||
return query
|
||||
|
||||
|
||||
def _get(context, namespace_id, session):
|
||||
"""Get a namespace by id, raise if not found"""
|
||||
|
||||
try:
|
||||
query = session.query(models.MetadefNamespace)\
|
||||
.filter_by(id=namespace_id)
|
||||
namespace_rec = query.one()
|
||||
except sa_orm.exc.NoResultFound:
|
||||
LOG.warn(_LW("Metadata definition namespace not found for id=%s",
|
||||
namespace_id))
|
||||
raise exc.MetadefRecordNotFound(record_type='namespace',
|
||||
id=namespace_id)
|
||||
|
||||
# Make sure they are allowed to view it.
|
||||
if not _is_namespace_visible(context, namespace_rec.as_dict()):
|
||||
msg = ("Forbidding request, metadata definition namespace=%s"
|
||||
" is not visible.") % namespace_rec.namespace
|
||||
LOG.debug(msg)
|
||||
emsg = _("Forbidding request, metadata definition namespace=%s"
|
||||
" is not visible.") % namespace_rec.namespace
|
||||
raise exc.MetadefForbidden(emsg)
|
||||
|
||||
return namespace_rec
|
||||
|
||||
|
||||
def _get_by_name(context, name, session):
|
||||
"""Get a namespace by name, raise if not found"""
|
||||
|
||||
try:
|
||||
query = session.query(models.MetadefNamespace)\
|
||||
.filter_by(namespace=name)
|
||||
namespace_rec = query.one()
|
||||
except sa_orm.exc.NoResultFound:
|
||||
msg = "Metadata definition namespace=%s was not found." % name
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefNamespaceNotFound(namespace_name=name)
|
||||
|
||||
# Make sure they are allowed to view it.
|
||||
if not _is_namespace_visible(context, namespace_rec.as_dict()):
|
||||
msg = ("Forbidding request, metadata definition namespace=%s"
|
||||
" not visible." % name)
|
||||
LOG.debug(msg)
|
||||
emsg = _("Forbidding request, metadata definition namespace=%s"
|
||||
" not visible.") % name
|
||||
raise exc.MetadefForbidden(emsg)
|
||||
|
||||
return namespace_rec
|
||||
|
||||
|
||||
def _get_all(context, session, filters=None, marker=None,
|
||||
limit=None, sort_key='created_at', sort_dir='desc'):
|
||||
"""Get all namespaces that match zero or more filters.
|
||||
|
||||
:param filters: dict of filter keys and values.
|
||||
:param marker: namespace id after which to start page
|
||||
:param limit: maximum number of namespaces to return
|
||||
:param sort_key: namespace attribute by which results should be sorted
|
||||
:param sort_dir: direction in which results should be sorted (asc, desc)
|
||||
"""
|
||||
|
||||
filters = filters or {}
|
||||
|
||||
query = _select_namespaces_query(context, session)
|
||||
|
||||
# if visibility filter, apply it to the context based query
|
||||
visibility = filters.pop('visibility', None)
|
||||
if visibility is not None:
|
||||
query = query.filter(models.MetadefNamespace.visibility == visibility)
|
||||
|
||||
# if id_list filter, apply it to the context based query
|
||||
id_list = filters.pop('id_list', None)
|
||||
if id_list is not None:
|
||||
query = query.filter(models.MetadefNamespace.id.in_(id_list))
|
||||
|
||||
marker_namespace = None
|
||||
if marker is not None:
|
||||
marker_namespace = _get(context, marker, session)
|
||||
|
||||
sort_keys = ['created_at', 'id']
|
||||
sort_keys.insert(0, sort_key) if sort_key not in sort_keys else sort_keys
|
||||
|
||||
query = paginate_query(query=query,
|
||||
model=models.MetadefNamespace,
|
||||
limit=limit,
|
||||
sort_keys=sort_keys,
|
||||
marker=marker_namespace, sort_dir=sort_dir)
|
||||
|
||||
return query.all()
|
||||
|
||||
|
||||
def _get_all_by_resource_types(context, session, filters, marker=None,
|
||||
limit=None, sort_key=None, sort_dir=None):
|
||||
"""get all visible namespaces for the specified resource_types"""
|
||||
|
||||
resource_types = filters['resource_types']
|
||||
resource_type_list = resource_types.split(',')
|
||||
db_recs = (
|
||||
session.query(models.MetadefResourceType)
|
||||
.join(models.MetadefResourceType.associations)
|
||||
.filter(models.MetadefResourceType.name.in_(resource_type_list))
|
||||
.values(models.MetadefResourceType.name,
|
||||
models.MetadefNamespaceResourceType.namespace_id)
|
||||
)
|
||||
|
||||
namespace_id_list = []
|
||||
for name, namespace_id in db_recs:
|
||||
namespace_id_list.append(namespace_id)
|
||||
|
||||
if len(namespace_id_list) is 0:
|
||||
return []
|
||||
|
||||
filters2 = filters
|
||||
filters2.update({'id_list': namespace_id_list})
|
||||
|
||||
return _get_all(context, session, filters2,
|
||||
marker, limit, sort_key, sort_dir)
|
||||
|
||||
|
||||
def get_all(context, session, marker=None, limit=None,
|
||||
sort_key=None, sort_dir=None, filters=None):
|
||||
"""List all visible namespaces"""
|
||||
|
||||
namespaces = []
|
||||
filters = filters or {}
|
||||
|
||||
if 'resource_types' in filters:
|
||||
namespaces = _get_all_by_resource_types(
|
||||
context, session, filters, marker, limit, sort_key, sort_dir)
|
||||
else:
|
||||
namespaces = _get_all(
|
||||
context, session, filters, marker, limit, sort_key, sort_dir)
|
||||
|
||||
return map(lambda ns: ns.as_dict(), namespaces)
|
||||
|
||||
|
||||
def get(context, name, session):
|
||||
"""Get a namespace by name, raise if not found"""
|
||||
namespace_rec = _get_by_name(context, name, session)
|
||||
return namespace_rec.as_dict()
|
||||
|
||||
|
||||
def create(context, values, session):
|
||||
"""Create a namespace, raise if namespace already exists."""
|
||||
|
||||
namespace_name = values['namespace']
|
||||
namespace = models.MetadefNamespace()
|
||||
metadef_api.utils.drop_protected_attrs(models.MetadefNamespace, values)
|
||||
namespace.update(values.copy())
|
||||
try:
|
||||
namespace.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("Can not create the metadata definition namespace."
|
||||
" Namespace=%s already exists.") % namespace_name
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefDuplicateNamespace(
|
||||
namespace_name=namespace_name)
|
||||
|
||||
return namespace.as_dict()
|
||||
|
||||
|
||||
def update(context, namespace_id, values, session):
|
||||
"""Update a namespace, raise if not found/visible or duplicate result"""
|
||||
|
||||
namespace_rec = _get(context, namespace_id, session)
|
||||
metadef_api.utils.drop_protected_attrs(models.MetadefNamespace, values)
|
||||
|
||||
try:
|
||||
namespace_rec.update(values.copy())
|
||||
namespace_rec.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("Invalid update. It would result in a duplicate"
|
||||
" metadata definition namespace with the same name of %s"
|
||||
% values['namespace'])
|
||||
LOG.debug(msg)
|
||||
emsg = (_("Invalid update. It would result in a duplicate"
|
||||
" metadata definition namespace with the same name of %s")
|
||||
% values['namespace'])
|
||||
raise exc.MetadefDuplicateNamespace(emsg)
|
||||
|
||||
return namespace_rec.as_dict()
|
||||
|
||||
|
||||
def delete(context, name, session):
|
||||
"""Raise if not found, has references or not visible"""
|
||||
|
||||
namespace_rec = _get_by_name(context, name, session)
|
||||
try:
|
||||
session.delete(namespace_rec)
|
||||
session.flush()
|
||||
except db_exc.DBError as e:
|
||||
if isinstance(e.inner_exception, sa_exc.IntegrityError):
|
||||
msg = ("Metadata definition namespace=%s not deleted."
|
||||
" Other records still refer to it." % name)
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefIntegrityError(
|
||||
record_type='namespace', record_name=name)
|
||||
else:
|
||||
raise e
|
||||
|
||||
return namespace_rec.as_dict()
|
||||
|
||||
|
||||
def delete_cascade(context, name, session):
|
||||
"""Raise if not found, has references or not visible"""
|
||||
|
||||
namespace_rec = _get_by_name(context, name, session)
|
||||
with session.begin():
|
||||
try:
|
||||
metadef_api.object.delete_namespace_content(
|
||||
context, namespace_rec.id, session)
|
||||
metadef_api.property.delete_namespace_content(
|
||||
context, namespace_rec.id, session)
|
||||
metadef_api.resource_type_association.delete_namespace_content(
|
||||
context, namespace_rec.id, session)
|
||||
session.delete(namespace_rec)
|
||||
session.flush()
|
||||
except db_exc.DBError as e:
|
||||
if isinstance(e.inner_exception, sa_exc.IntegrityError):
|
||||
msg = ("Metadata definition namespace=%s not deleted."
|
||||
" Other records still refer to it." % name)
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefIntegrityError(
|
||||
record_type='namespace', record_name=name)
|
||||
else:
|
||||
raise e
|
||||
|
||||
return namespace_rec.as_dict()
|
|
@ -0,0 +1,156 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 oslo.db import exception as db_exc
|
||||
from sqlalchemy import func
|
||||
import sqlalchemy.orm as sa_orm
|
||||
|
||||
from glance.common import exception as exc
|
||||
from glance.db.sqlalchemy.metadef_api import namespace as namespace_api
|
||||
import glance.db.sqlalchemy.metadef_api.utils as metadef_utils
|
||||
from glance.db.sqlalchemy import models_metadef as models
|
||||
from glance import i18n
|
||||
import glance.openstack.common.log as os_logging
|
||||
|
||||
LOG = os_logging.getLogger(__name__)
|
||||
_LW = i18n._LW
|
||||
|
||||
|
||||
def _get(context, object_id, session):
|
||||
try:
|
||||
query = session.query(models.MetadefObject)\
|
||||
.filter_by(id=object_id)
|
||||
metadef_object = query.one()
|
||||
except sa_orm.exc.NoResultFound:
|
||||
LOG.warn(_LW("Metadata definition object not found for id %s",
|
||||
object_id))
|
||||
raise exc.MetadefRecordNotFound(record_type='object', id=object_id)
|
||||
|
||||
return metadef_object
|
||||
|
||||
|
||||
def _get_by_name(context, namespace_name, name, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
try:
|
||||
query = session.query(models.MetadefObject)\
|
||||
.filter_by(name=name, namespace_id=namespace['id'])
|
||||
metadef_object = query.one()
|
||||
except sa_orm.exc.NoResultFound:
|
||||
msg = ("The metadata definition object with name=%(name)s"
|
||||
" was not found in namespace=%(namespace_name)s."
|
||||
% {'name': name, 'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefObjectNotFound(object_name=name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
return metadef_object
|
||||
|
||||
|
||||
def get_all(context, namespace_name, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
query = session.query(models.MetadefObject)\
|
||||
.filter_by(namespace_id=namespace['id'])
|
||||
md_objects = query.all()
|
||||
|
||||
md_objects_list = []
|
||||
for obj in md_objects:
|
||||
md_objects_list.append(obj.as_dict())
|
||||
return md_objects_list
|
||||
|
||||
|
||||
def create(context, namespace_name, values, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
values.update({'namespace_id': namespace['id']})
|
||||
|
||||
md_object = models.MetadefObject()
|
||||
metadef_utils.drop_protected_attrs(models.MetadefObject, values)
|
||||
md_object.update(values.copy())
|
||||
try:
|
||||
md_object.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("A metadata definition object with name=%(name)s"
|
||||
" in namespace=%(namespace_name)s already exists."
|
||||
% {'name': md_object.name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefDuplicateObject(
|
||||
object_name=md_object.name, namespace_name=namespace_name)
|
||||
|
||||
return md_object.as_dict()
|
||||
|
||||
|
||||
def get(context, namespace_name, name, session):
|
||||
md_object = _get_by_name(context, namespace_name, name, session)
|
||||
|
||||
return md_object.as_dict()
|
||||
|
||||
|
||||
def update(context, namespace_name, object_id, values, session):
|
||||
"""Update an object, raise if ns not found/visible or duplicate result"""
|
||||
namespace_api.get(context, namespace_name, session)
|
||||
|
||||
md_object = _get(context, object_id, session)
|
||||
metadef_utils.drop_protected_attrs(models.MetadefObject, values)
|
||||
# values['updated_at'] = timeutils.utcnow() - done by TS mixin
|
||||
try:
|
||||
md_object.update(values.copy())
|
||||
md_object.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("Invalid update. It would result in a duplicate"
|
||||
" metadata definition object with same name=%(name)s"
|
||||
" in namespace=%(namespace_name)s."
|
||||
% {'name': md_object.name, 'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
emsg = (_("Invalid update. It would result in a duplicate"
|
||||
" metadata definition object with the same name=%(name)s"
|
||||
" in namespace=%(namespace_name)s.")
|
||||
% {'name': md_object.name, 'namespace_name': namespace_name})
|
||||
raise exc.MetadefDuplicateObject(emsg)
|
||||
|
||||
return md_object.as_dict()
|
||||
|
||||
|
||||
def delete(context, namespace_name, object_name, session):
|
||||
namespace_api.get(context, namespace_name, session)
|
||||
md_object = _get_by_name(context, namespace_name, object_name, session)
|
||||
|
||||
session.delete(md_object)
|
||||
session.flush()
|
||||
|
||||
return md_object.as_dict()
|
||||
|
||||
|
||||
def delete_namespace_content(context, namespace_id, session):
|
||||
"""Use this def only if the ns for the id has been verified as visible"""
|
||||
|
||||
count = 0
|
||||
query = session.query(models.MetadefObject)\
|
||||
.filter_by(namespace_id=namespace_id)
|
||||
count = query.delete(synchronize_session='fetch')
|
||||
return count
|
||||
|
||||
|
||||
def delete_by_namespace_name(context, namespace_name, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
return delete_namespace_content(context, namespace['id'], session)
|
||||
|
||||
|
||||
def count(context, namespace_name, session):
|
||||
"""Get the count of objects for a namespace, raise if ns not found"""
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
|
||||
query = session.query(func.count(models.MetadefObject.id))\
|
||||
.filter_by(namespace_id=namespace['id'])
|
||||
return query.scalar()
|
|
@ -0,0 +1,169 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 oslo.db import exception as db_exc
|
||||
from sqlalchemy import func
|
||||
import sqlalchemy.orm as sa_orm
|
||||
|
||||
from glance.common import exception as exc
|
||||
from glance.db.sqlalchemy.metadef_api import namespace as namespace_api
|
||||
from glance.db.sqlalchemy.metadef_api import utils as metadef_utils
|
||||
from glance.db.sqlalchemy import models_metadef as models
|
||||
from glance import i18n
|
||||
import glance.openstack.common.log as os_logging
|
||||
|
||||
LOG = os_logging.getLogger(__name__)
|
||||
_LW = i18n._LW
|
||||
|
||||
|
||||
def _get(context, property_id, session):
|
||||
|
||||
try:
|
||||
query = session.query(models.MetadefProperty)\
|
||||
.filter_by(id=property_id)
|
||||
property_rec = query.one()
|
||||
|
||||
except sa_orm.exc.NoResultFound:
|
||||
LOG.warn(_LW("Metadata definition property not found for id=%s",
|
||||
property_id))
|
||||
raise exc.MetadefRecordNotFound(
|
||||
record_type='property', id=property_id)
|
||||
|
||||
return property_rec
|
||||
|
||||
|
||||
def _get_by_name(context, namespace_name, name, session):
|
||||
"""get a property; raise if ns not found/visible or property not found"""
|
||||
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
try:
|
||||
query = session.query(models.MetadefProperty)\
|
||||
.filter_by(name=name, namespace_id=namespace['id'])
|
||||
property_rec = query.one()
|
||||
|
||||
except sa_orm.exc.NoResultFound:
|
||||
msg = ("The metadata definition property with name=%(name)s"
|
||||
" was not found in namespace=%(namespace_name)s."
|
||||
% {'name': name, 'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefPropertyNotFound(property_name=name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
return property_rec
|
||||
|
||||
|
||||
def get(context, namespace_name, name, session):
|
||||
"""get a property; raise if ns not found/visible or property not found"""
|
||||
|
||||
property_rec = _get_by_name(context, namespace_name, name, session)
|
||||
return property_rec.as_dict()
|
||||
|
||||
|
||||
def get_all(context, namespace_name, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
query = session.query(models.MetadefProperty)\
|
||||
.filter_by(namespace_id=namespace['id'])
|
||||
properties = query.all()
|
||||
|
||||
properties_list = []
|
||||
for prop in properties:
|
||||
properties_list.append(prop.as_dict())
|
||||
return properties_list
|
||||
|
||||
|
||||
def create(context, namespace_name, values, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
values.update({'namespace_id': namespace['id']})
|
||||
|
||||
property_rec = models.MetadefProperty()
|
||||
metadef_utils.drop_protected_attrs(models.MetadefProperty, values)
|
||||
property_rec.update(values.copy())
|
||||
|
||||
try:
|
||||
property_rec.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("Can not create metadata definition property. A property"
|
||||
" with name=%(name)s already exists in"
|
||||
" namespace=%(namespace_name)s."
|
||||
% {'name': property_rec.name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefDuplicateProperty(
|
||||
property_name=property_rec.name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
return property_rec.as_dict()
|
||||
|
||||
|
||||
def update(context, namespace_name, property_id, values, session):
|
||||
"""Update a property, raise if ns not found/visible or duplicate result"""
|
||||
|
||||
namespace_api.get(context, namespace_name, session)
|
||||
property_rec = _get(context, property_id, session)
|
||||
metadef_utils.drop_protected_attrs(models.MetadefProperty, values)
|
||||
# values['updated_at'] = timeutils.utcnow() - done by TS mixin
|
||||
try:
|
||||
property_rec.update(values.copy())
|
||||
property_rec.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("Invalid update. It would result in a duplicate"
|
||||
" metadata definition property with the same name=%(name)s"
|
||||
" in namespace=%(namespace_name)s."
|
||||
% {'name': property_rec.name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
emsg = (_("Invalid update. It would result in a duplicate"
|
||||
" metadata definition property with the same name=%(name)s"
|
||||
" in namespace=%(namespace_name)s.")
|
||||
% {'name': property_rec.name,
|
||||
'namespace_name': namespace_name})
|
||||
raise exc.MetadefDuplicateProperty(emsg)
|
||||
|
||||
return property_rec.as_dict()
|
||||
|
||||
|
||||
def delete(context, namespace_name, property_name, session):
|
||||
property_rec = _get_by_name(
|
||||
context, namespace_name, property_name, session)
|
||||
if property_rec:
|
||||
session.delete(property_rec)
|
||||
session.flush()
|
||||
|
||||
return property_rec.as_dict()
|
||||
|
||||
|
||||
def delete_namespace_content(context, namespace_id, session):
|
||||
"""Use this def only if the ns for the id has been verified as visible"""
|
||||
|
||||
count = 0
|
||||
query = session.query(models.MetadefProperty)\
|
||||
.filter_by(namespace_id=namespace_id)
|
||||
count = query.delete(synchronize_session='fetch')
|
||||
return count
|
||||
|
||||
|
||||
def delete_by_namespace_name(context, namespace_name, session):
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
return delete_namespace_content(context, namespace['id'], session)
|
||||
|
||||
|
||||
def count(context, namespace_name, session):
|
||||
"""Get the count of properties for a namespace, raise if ns not found"""
|
||||
|
||||
namespace = namespace_api.get(context, namespace_name, session)
|
||||
|
||||
query = session.query(func.count(models.MetadefProperty.id))\
|
||||
.filter_by(namespace_id=namespace['id'])
|
||||
return query.scalar()
|
|
@ -0,0 +1,111 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 oslo.db import exception as db_exc
|
||||
import sqlalchemy.exc as sa_exc
|
||||
import sqlalchemy.orm as sa_orm
|
||||
|
||||
from glance.common import exception as exc
|
||||
import glance.db.sqlalchemy.metadef_api.utils as metadef_utils
|
||||
from glance.db.sqlalchemy import models_metadef as models
|
||||
import glance.openstack.common.log as os_logging
|
||||
|
||||
LOG = os_logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get(context, name, session):
|
||||
"""Get a resource type, raise if not found"""
|
||||
|
||||
try:
|
||||
query = session.query(models.MetadefResourceType)\
|
||||
.filter_by(name=name)
|
||||
resource_type = query.one()
|
||||
except sa_orm.exc.NoResultFound:
|
||||
msg = "No metadata definition resource-type found with name %s" % name
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefResourceTypeNotFound(resource_type_name=name)
|
||||
|
||||
return resource_type.as_dict()
|
||||
|
||||
|
||||
def get_all(context, session):
|
||||
"""Get a list of all resource types"""
|
||||
|
||||
query = session.query(models.MetadefResourceType)
|
||||
resource_types = query.all()
|
||||
|
||||
resource_types_list = []
|
||||
for rt in resource_types:
|
||||
resource_types_list.append(rt.as_dict())
|
||||
|
||||
return resource_types_list
|
||||
|
||||
|
||||
def create(context, values, session):
|
||||
"""Create a resource_type, raise if it already exists."""
|
||||
|
||||
resource_type = models.MetadefResourceType()
|
||||
metadef_utils.drop_protected_attrs(models.MetadefResourceType, values)
|
||||
resource_type.update(values.copy())
|
||||
try:
|
||||
resource_type.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("Can not create the metadata definition resource-type."
|
||||
" A resource-type with name=%s already exists."
|
||||
% resource_type.name)
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefDuplicateResourceType(
|
||||
resource_type_name=resource_type.name)
|
||||
|
||||
return resource_type.as_dict()
|
||||
|
||||
|
||||
def update(context, values, session):
|
||||
"""Update a resource type, raise if not found"""
|
||||
|
||||
name = values['name']
|
||||
metadef_utils.drop_protected_attrs(models.MetadefResourceType, values)
|
||||
db_rec = get(context, name, session)
|
||||
db_rec.update(values.copy())
|
||||
db_rec.save(session=session)
|
||||
|
||||
return db_rec.as_dict()
|
||||
|
||||
|
||||
def delete(context, name, session):
|
||||
"""Delete a resource type or raise if not found or is protected"""
|
||||
|
||||
db_rec = get(context, name, session)
|
||||
if db_rec.protected is True:
|
||||
msg = ("Delete forbidden. Metadata definition resource-type %s is a"
|
||||
" seeded-system type and can not be deleted.") % name
|
||||
LOG.debug(msg)
|
||||
raise exc.ProtectedMetadefResourceTypeSystemDelete(
|
||||
resource_type_name=name)
|
||||
|
||||
try:
|
||||
session.delete(db_rec)
|
||||
session.flush()
|
||||
except db_exc.DBError as e:
|
||||
if isinstance(e.inner_exception, sa_exc.IntegrityError):
|
||||
msg = ("Could not delete Metadata definition resource-type %s"
|
||||
". It still has content") % name
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefIntegrityError(
|
||||
record_type='resource-type', record_name=name)
|
||||
else:
|
||||
raise e
|
||||
|
||||
return db_rec.as_dict()
|
|
@ -0,0 +1,217 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 oslo.db import exception as db_exc
|
||||
import sqlalchemy.orm as sa_orm
|
||||
|
||||
from glance.common import exception as exc
|
||||
from glance.db.sqlalchemy.metadef_api\
|
||||
import namespace as namespace_api
|
||||
from glance.db.sqlalchemy.metadef_api\
|
||||
import resource_type as resource_type_api
|
||||
from glance.db.sqlalchemy.metadef_api\
|
||||
import utils as metadef_utils
|
||||
from glance.db.sqlalchemy import models_metadef as models
|
||||
import glance.openstack.common.log as os_logging
|
||||
|
||||
LOG = os_logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _to_db_dict(namespace_id, resource_type_id, model_dict):
|
||||
"""transform a model dict to a metadef_namespace_resource_type dict"""
|
||||
db_dict = {'namespace_id': namespace_id,
|
||||
'resource_type_id': resource_type_id,
|
||||
'properties_target': model_dict['properties_target'],
|
||||
'prefix': model_dict['prefix']}
|
||||
return db_dict
|
||||
|
||||
|
||||
def _to_model_dict(resource_type_name, ns_res_type_dict):
|
||||
"""transform a metadef_namespace_resource_type dict to a model dict"""
|
||||
model_dict = {'name': resource_type_name,
|
||||
'properties_target': ns_res_type_dict['properties_target'],
|
||||
'prefix': ns_res_type_dict['prefix'],
|
||||
'created_at': ns_res_type_dict['created_at'],
|
||||
'updated_at': ns_res_type_dict['updated_at']}
|
||||
return model_dict
|
||||
|
||||
|
||||
def _set_model_dict(resource_type_name, properties_target, prefix,
|
||||
created_at, updated_at):
|
||||
"""return a model dict set with the passed in key values"""
|
||||
model_dict = {'name': resource_type_name,
|
||||
'properties_target': properties_target,
|
||||
'prefix': prefix,
|
||||
'created_at': created_at,
|
||||
'updated_at': updated_at}
|
||||
return model_dict
|
||||
|
||||
|
||||
def _get(context, namespace_name, resource_type_name,
|
||||
namespace_id, resource_type_id, session):
|
||||
"""Get a namespace resource_type association"""
|
||||
|
||||
# visibility check assumed done in calling routine via namespace_get
|
||||
try:
|
||||
query = session.query(models.MetadefNamespaceResourceType).\
|
||||
filter_by(namespace_id=namespace_id,
|
||||
resource_type_id=resource_type_id)
|
||||
db_rec = query.one()
|
||||
except sa_orm.exc.NoResultFound:
|
||||
msg = ("The metadata definition resource-type association of"
|
||||
" resource_type=%(resource_type_name)s to"
|
||||
" namespace_name=%(namespace_name)s was not found."
|
||||
% {'resource_type_name': resource_type_name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefResourceTypeAssociationNotFound(
|
||||
resource_type_name=resource_type_name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
return db_rec
|
||||
|
||||
|
||||
def _create_association(
|
||||
context, namespace_name, resource_type_name, values, session):
|
||||
"""Create an association, raise if it already exists."""
|
||||
|
||||
namespace_resource_type_rec = models.MetadefNamespaceResourceType()
|
||||
metadef_utils.drop_protected_attrs(
|
||||
models.MetadefNamespaceResourceType, values)
|
||||
# values['updated_at'] = timeutils.utcnow() # TS mixin should do this
|
||||
namespace_resource_type_rec.update(values.copy())
|
||||
try:
|
||||
namespace_resource_type_rec.save(session=session)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
msg = ("The metadata definition resource-type association of"
|
||||
" resource_type=%(resource_type_name)s to"
|
||||
" namespace=%(namespace_name)s, already exists."
|
||||
% {'resource_type_name': resource_type_name,
|
||||
'namespace_name': namespace_name})
|
||||
LOG.debug(msg)
|
||||
raise exc.MetadefDuplicateResourceTypeAssociation(
|
||||
resource_type_name=resource_type_name,
|
||||
namespace_name=namespace_name)
|
||||
|
||||
return namespace_resource_type_rec.as_dict()
|
||||
|
||||
|
||||
def _delete(context, namespace_name, resource_type_name,
|
||||
namespace_id, resource_type_id, session):
|
||||
"""Delete a resource type association or raise if not found."""
|
||||
|
||||
db_rec = _get(context, namespace_name, resource_type_name,
|
||||
namespace_id, resource_type_id, session)
|
||||
session.delete(db_rec)
|
||||
session.flush()
|
||||
|
||||
return db_rec.as_dict()
|
||||
|
||||
|
||||
def get(context, namespace_name, resource_type_name, session):
|
||||
"""Get a resource_type associations; raise if not found"""
|
||||
namespace = namespace_api.get(
|
||||
context, namespace_name, session)
|
||||
|
||||
resource_type = resource_type_api.get(
|
||||
context, resource_type_name, session)
|
||||
|
||||
found = _get(context, namespace_name, resource_type_name,
|
||||
namespace['id'], resource_type['id'], session)
|
||||
|
||||
return _to_model_dict(resource_type_name, found)
|
||||
|
||||
|
||||
def get_all_by_namespace(context, namespace_name, session):
|
||||
"""List resource_type associations by namespace, raise if not found"""
|
||||
|
||||
# namespace get raises an exception if not visible
|
||||
namespace = namespace_api.get(
|
||||
context, namespace_name, session)
|
||||
|
||||
db_recs = (
|
||||
session.query(models.MetadefResourceType)
|
||||
.join(models.MetadefResourceType.associations)
|
||||
.filter_by(namespace_id=namespace['id'])
|
||||
.values(models.MetadefResourceType.name,
|
||||
models.MetadefNamespaceResourceType.properties_target,
|
||||
models.MetadefNamespaceResourceType.prefix,
|
||||
models.MetadefNamespaceResourceType.created_at,
|
||||
models.MetadefNamespaceResourceType.updated_at))
|
||||
|
||||
model_dict_list = []
|
||||
for name, properties_target, prefix, created_at, updated_at in db_recs:
|
||||
model_dict_list.append(
|
||||
_set_model_dict
|
||||
(name, properties_target, prefix, created_at, updated_at)
|
||||
)
|
||||
|
||||
return model_dict_list
|
||||
|
||||
|
||||
def create(context, namespace_name, values, session):
|
||||
"""Create an association, raise if already exists or ns not found."""
|
||||
|
||||
namespace = namespace_api.get(
|
||||
context, namespace_name, session)
|
||||
|
||||
# if the resource_type does not exist, create it
|
||||
resource_type_name = values['name']
|
||||
metadef_utils.drop_protected_attrs(
|
||||
models.MetadefNamespaceResourceType, values)
|
||||
try:
|
||||
resource_type = resource_type_api.get(
|
||||
context, resource_type_name, session)
|
||||
except exc.NotFound:
|
||||
resource_type = None
|
||||
LOG.debug("Creating resource-type %s" % resource_type_name)
|
||||
|
||||
if resource_type is None:
|
||||
resource_type_dict = {'name': resource_type_name, 'protected': 0}
|
||||
resource_type = resource_type_api.create(
|
||||
context, resource_type_dict, session)
|
||||
|
||||
# Create the association record, set the field values
|
||||
ns_resource_type_dict = _to_db_dict(
|
||||
namespace['id'], resource_type['id'], values)
|
||||
new_rec = _create_association(context, namespace_name, resource_type_name,
|
||||
ns_resource_type_dict, session)
|
||||
|
||||
return _to_model_dict(resource_type_name, new_rec)
|
||||
|
||||
|
||||
def delete(context, namespace_name, resource_type_name, session):
|
||||
"""Delete an association or raise if not found"""
|
||||
|
||||
namespace = namespace_api.get(
|
||||
context, namespace_name, session)
|
||||
|
||||
resource_type = resource_type_api.get(
|
||||
context, resource_type_name, session)
|
||||
|
||||
deleted = _delete(context, namespace_name, resource_type_name,
|
||||
namespace['id'], resource_type['id'], session)
|
||||
|
||||
return _to_model_dict(resource_type_name, deleted)
|
||||
|
||||
|
||||
def delete_namespace_content(context, namespace_id, session):
|
||||
"""Use this def only if the ns for the id has been verified as visible"""
|
||||
|
||||
count = 0
|
||||
query = session.query(models.MetadefNamespaceResourceType)\
|
||||
.filter_by(namespace_id=namespace_id)
|
||||
count = query.delete(synchronize_session='fetch')
|
||||
return count
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
def drop_protected_attrs(model_class, values):
|
||||
"""
|
||||
Removed protected attributes from values dictionary using the models
|
||||
__protected_attributes__ field.
|
||||
"""
|
||||
for attr in model_class.__protected_attributes__:
|
||||
if attr in values:
|
||||
del values[attr]
|
|
@ -0,0 +1,215 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import sqlalchemy
|
||||
from sqlalchemy.schema import (
|
||||
Column, ForeignKey, Index, MetaData, Table, UniqueConstraint) # noqa
|
||||
|
||||
from glance.db.sqlalchemy.migrate_repo.schema import (
|
||||
Boolean, DateTime, Integer, String, Text, create_tables,
|
||||
drop_tables) # noqa
|
||||
from glance.openstack.common import timeutils
|
||||
|
||||
|
||||
RESOURCE_TYPES = [u'OS::Glance::Image', u'OS::Cinder::Volume',
|
||||
u'OS::Nova::Flavor', u'OS::Nova::Aggregate',
|
||||
u'OS::Nova::Instance']
|
||||
|
||||
|
||||
def _get_metadef_resource_types_table(meta):
|
||||
return sqlalchemy.Table('metadef_resource_types', meta, autoload=True)
|
||||
|
||||
|
||||
def _populate_resource_types(resource_types_table):
|
||||
now = timeutils.utcnow()
|
||||
for resource_type in RESOURCE_TYPES:
|
||||
values = {
|
||||
'name': resource_type,
|
||||
'protected': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
resource_types_table.insert(values=values).execute()
|
||||
|
||||
|
||||
def define_metadef_namespaces_table(meta):
|
||||
|
||||
# NOTE: For DB2 if UniqueConstraint is used when creating a table
|
||||
# an index will automatically be created. So, for DB2 specify the
|
||||
# index name up front. If not DB2 then create the Index.
|
||||
_constr_kwargs = {}
|
||||
if meta.bind.name == 'ibm_db_sa':
|
||||
_constr_kwargs['name'] = 'ix_namespaces_namespace'
|
||||
|
||||
namespaces = Table('metadef_namespaces',
|
||||
meta,
|
||||
Column('id', Integer(), primary_key=True,
|
||||
nullable=False),
|
||||
Column('namespace', String(80), nullable=False),
|
||||
Column('display_name', String(80)),
|
||||
Column('description', Text()),
|
||||
Column('visibility', String(32)),
|
||||
Column('protected', Boolean()),
|
||||
Column('owner', String(255), nullable=False),
|
||||
Column('created_at', DateTime(), nullable=False),
|
||||
Column('updated_at', DateTime()),
|
||||
UniqueConstraint('namespace', **_constr_kwargs),
|
||||
mysql_engine='InnoDB',
|
||||
extend_existing=True)
|
||||
|
||||
if meta.bind.name != 'ibm_db_sa':
|
||||
Index('ix_namespaces_namespace', namespaces.c.namespace)
|
||||
|
||||
return namespaces
|
||||
|
||||
|
||||
def define_metadef_objects_table(meta):
|
||||
|
||||
_constr_kwargs = {}
|
||||
if meta.bind.name == 'ibm_db_sa':
|
||||
_constr_kwargs['name'] = 'ix_objects_namespace_id_name'
|
||||
|
||||
objects = Table('metadef_objects',
|
||||
meta,
|
||||
Column('id', Integer(), primary_key=True, nullable=False),
|
||||
Column('namespace_id', Integer(),
|
||||
ForeignKey('metadef_namespaces.id'),
|
||||
nullable=False),
|
||||
Column('name', String(80), nullable=False),
|
||||
Column('description', Text()),
|
||||
Column('required', Text()),
|
||||
Column('schema', Text()),
|
||||
Column('created_at', DateTime(), nullable=False),
|
||||
Column('updated_at', DateTime()),
|
||||
UniqueConstraint('namespace_id', 'name',
|
||||
**_constr_kwargs),
|
||||
mysql_engine='InnoDB',
|
||||
extend_existing=True)
|
||||
|
||||
if meta.bind.name != 'ibm_db_sa':
|
||||
Index('ix_objects_namespace_id_name',
|
||||
objects.c.namespace_id,
|
||||
objects.c.name)
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
def define_metadef_properties_table(meta):
|
||||
|
||||
_constr_kwargs = {}
|
||||
if meta.bind.name == 'ibm_db_sa':
|
||||
_constr_kwargs['name'] = 'ix_metadef_properties_namespace_id_name'
|
||||
|
||||
metadef_properties = Table(
|
||||
'metadef_properties',
|
||||
meta,
|
||||
Column('id', Integer(), primary_key=True, nullable=False),
|
||||
Column('namespace_id', Integer(), ForeignKey('metadef_namespaces.id'),
|
||||
nullable=False),
|
||||
Column('name', String(80), nullable=False),
|
||||
Column('schema', Text()),
|
||||
Column('created_at', DateTime(), nullable=False),
|
||||
Column('updated_at', DateTime()),
|
||||
UniqueConstraint('namespace_id', 'name', **_constr_kwargs),
|
||||
mysql_engine='InnoDB',
|
||||
extend_existing=True)
|
||||
|
||||
if meta.bind.name != 'ibm_db_sa':
|
||||
Index('ix_metadef_properties_namespace_id_name',
|
||||
metadef_properties.c.namespace_id,
|
||||
metadef_properties.c.name)
|
||||
|
||||
return metadef_properties
|
||||
|
||||
|
||||
def define_metadef_resource_types_table(meta):
|
||||
|
||||
_constr_kwargs = {}
|
||||
if meta.bind.name == 'ibm_db_sa':
|
||||
_constr_kwargs['name'] = 'ix_metadef_resource_types_name'
|
||||
|
||||
metadef_res_types = Table(
|
||||
'metadef_resource_types',
|
||||
meta,
|
||||
Column('id', Integer(), primary_key=True, nullable=False),
|
||||
Column('name', String(80), nullable=False),
|
||||
Column('protected', Boolean(), nullable=False, default=False),
|
||||
Column('created_at', DateTime(), nullable=False),
|
||||
Column('updated_at', DateTime()),
|
||||
UniqueConstraint('name', **_constr_kwargs),
|
||||
mysql_engine='InnoDB',
|
||||
extend_existing=True)
|
||||
|
||||
if meta.bind.name != 'ibm_db_sa':
|
||||
Index('ix_metadef_resource_types_name',
|
||||
metadef_res_types.c.name)
|
||||
|
||||
return metadef_res_types
|
||||
|
||||
|
||||
def define_metadef_namespace_resource_types_table(meta):
|
||||
|
||||
_constr_kwargs = {}
|
||||
if meta.bind.name == 'ibm_db_sa':
|
||||
_constr_kwargs['name'] = 'ix_metadef_ns_res_types_res_type_id_ns_id'
|
||||
|
||||
metadef_associations = Table(
|
||||
'metadef_namespace_resource_types',
|
||||
meta,
|
||||
Column('resource_type_id', Integer(),
|
||||
ForeignKey('metadef_resource_types.id'),
|
||||
primary_key=True, nullable=False),
|
||||
Column('namespace_id', Integer(),
|
||||
ForeignKey('metadef_namespaces.id'),
|
||||
primary_key=True, nullable=False),
|
||||
Column('properties_target', String(80)),
|
||||
Column('prefix', String(80)),
|
||||
Column('created_at', DateTime(), nullable=False),
|
||||
Column('updated_at', DateTime()),
|
||||
UniqueConstraint('resource_type_id', 'namespace_id',
|
||||
**_constr_kwargs),
|
||||
mysql_engine='InnoDB',
|
||||
extend_existing=True)
|
||||
|
||||
if meta.bind.name != 'ibm_db_sa':
|
||||
Index('ix_metadef_ns_res_types_res_type_id_ns_id',
|
||||
metadef_associations.c.resource_type_id,
|
||||
metadef_associations.c.namespace_id)
|
||||
|
||||
return metadef_associations
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
tables = [define_metadef_namespaces_table(meta),
|
||||
define_metadef_objects_table(meta),
|
||||
define_metadef_properties_table(meta),
|
||||
define_metadef_resource_types_table(meta),
|
||||
define_metadef_namespace_resource_types_table(meta)]
|
||||
create_tables(tables)
|
||||
|
||||
resource_types_table = _get_metadef_resource_types_table(meta)
|
||||
_populate_resource_types(resource_types_table)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
tables = [define_metadef_objects_table(meta),
|
||||
define_metadef_properties_table(meta),
|
||||
define_metadef_namespace_resource_types_table(meta),
|
||||
define_metadef_resource_types_table(meta),
|
||||
define_metadef_namespaces_table(meta)]
|
||||
drop_tables(tables)
|
|
@ -0,0 +1,152 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
SQLAlchemy models for glance metadata schema
|
||||
"""
|
||||
|
||||
from oslo.db.sqlalchemy import models
|
||||
from sqlalchemy import Boolean
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy import Index
|
||||
from sqlalchemy import Integer
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy import Text
|
||||
|
||||
from glance.openstack.common import timeutils
|
||||
|
||||
|
||||
class DictionaryBase(models.ModelBase):
|
||||
metadata = None
|
||||
|
||||
def as_dict(self):
|
||||
d = {}
|
||||
for c in self.__table__.columns:
|
||||
d[c.name] = self[c.name]
|
||||
return d
|
||||
|
||||
|
||||
BASE_DICT = declarative_base(cls=DictionaryBase)
|
||||
|
||||
|
||||
class GlanceMetadefBase(models.TimestampMixin):
|
||||
"""Base class for Glance Metadef Models."""
|
||||
|
||||
__table_args__ = {'mysql_engine': 'InnoDB'}
|
||||
__table_initialized__ = False
|
||||
__protected_attributes__ = set(["created_at", "updated_at"])
|
||||
|
||||
created_at = Column(DateTime, default=lambda: timeutils.utcnow(),
|
||||
nullable=False)
|
||||
# TODO(wko): Column `updated_at` have no default value in
|
||||
# openstack common code. We should decide, is this value
|
||||
# required and make changes in oslo (if required) or
|
||||
# in glance (if not).
|
||||
updated_at = Column(DateTime, default=lambda: timeutils.utcnow(),
|
||||
nullable=False, onupdate=lambda: timeutils.utcnow())
|
||||
|
||||
|
||||
class MetadefNamespace(BASE_DICT, GlanceMetadefBase):
|
||||
"""Represents a metadata-schema namespace in the datastore."""
|
||||
__tablename__ = 'metadef_namespaces'
|
||||
__table_args__ = (Index('ix_metadef_namespaces_namespace', 'namespace'),
|
||||
Index('ix_metadef_namespaces_owner', 'owner'))
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
namespace = Column(String(80))
|
||||
display_name = Column(String(80))
|
||||
description = Column(Text())
|
||||
visibility = Column(String(32))
|
||||
protected = Column(Boolean)
|
||||
owner = Column(String(255), nullable=False)
|
||||
|
||||
|
||||
class MetadefObject(BASE_DICT, GlanceMetadefBase):
|
||||
"""Represents a metadata-schema object in the datastore."""
|
||||
__tablename__ = 'metadef_objects'
|
||||
__table_args__ = (Index('ix_metadef_objects_namespace_id', 'namespace_id'),
|
||||
Index('ix_metadef_objects_name', 'name'))
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
namespace_id = Column(Integer(), ForeignKey('metadef_namespaces.id'),
|
||||
nullable=False)
|
||||
name = Column(String(80), nullable=False)
|
||||
description = Column(Text())
|
||||
required = Column(Text())
|
||||
schema = Column(Text(), default={})
|
||||
|
||||
|
||||
class MetadefProperty(BASE_DICT, GlanceMetadefBase):
|
||||
"""Represents a metadata-schema namespace-property in the datastore."""
|
||||
__tablename__ = 'metadef_properties'
|
||||
__table_args__ = (Index('ix_metadef_properties_namespace_id',
|
||||
'namespace_id'),
|
||||
Index('ix_metadef_properties_name', 'name'))
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
namespace_id = Column(Integer(), ForeignKey('metadef_namespaces.id'),
|
||||
nullable=False)
|
||||
name = Column(String(80), nullable=False)
|
||||
schema = Column(Text(), default={})
|
||||
|
||||
|
||||
class MetadefNamespaceResourceType(BASE_DICT, GlanceMetadefBase):
|
||||
"""Represents a metadata-schema namespace-property in the datastore."""
|
||||
__tablename__ = 'metadef_namespace_resource_types'
|
||||
__table_args__ = (Index('ix_metadef_ns_res_types_res_type_id_ns_id',
|
||||
'resource_type_id', 'namespace_id'),
|
||||
Index('ix_metadef_ns_res_types_namespace_id',
|
||||
'namespace_id'))
|
||||
|
||||
resource_type_id = Column(Integer,
|
||||
ForeignKey('metadef_resource_types.id'),
|
||||
primary_key=True, nullable=False)
|
||||
namespace_id = Column(Integer, ForeignKey('metadef_namespaces.id'),
|
||||
primary_key=True, nullable=False)
|
||||
properties_target = Column(String(80))
|
||||
prefix = Column(String(80))
|
||||
|
||||
|
||||
class MetadefResourceType(BASE_DICT, GlanceMetadefBase):
|
||||
"""Represents a metadata-schema resource type in the datastore."""
|
||||
__tablename__ = 'metadef_resource_types'
|
||||
__table_args__ = (Index('ix_metadef_resource_types_name', 'name'), )
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
name = Column(String(80), nullable=False)
|
||||
protected = Column(Boolean, nullable=False, default=False)
|
||||
|
||||
associations = relationship(
|
||||
"MetadefNamespaceResourceType",
|
||||
primaryjoin=id == MetadefNamespaceResourceType.resource_type_id)
|
||||
|
||||
|
||||
def register_models(engine):
|
||||
"""Create database tables for all models with the given engine."""
|
||||
models = (MetadefNamespace, MetadefObject, MetadefProperty,
|
||||
MetadefResourceType, MetadefNamespaceResourceType)
|
||||
for model in models:
|
||||
model.metadata.create_all(engine)
|
||||
|
||||
|
||||
def unregister_models(engine):
|
||||
"""Drop database tables for all models with the given engine."""
|
||||
models = (MetadefObject, MetadefProperty, MetadefNamespaceResourceType,
|
||||
MetadefNamespace, MetadefResourceType)
|
||||
for model in models:
|
||||
model.metadata.drop_all(engine)
|
|
@ -0,0 +1,479 @@
|
|||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import copy
|
||||
|
||||
from glance import context
|
||||
import glance.tests.functional.db as db_tests
|
||||
|
||||
from glance.common import config
|
||||
from glance.common import exception
|
||||
from glance.tests import utils as test_utils
|
||||
|
||||
|
||||
def build_namespace_fixture(**kwargs):
|
||||
namespace = {
|
||||
'namespace': u'MyTestNamespace',
|
||||
'display_name': u'test-display-name',
|
||||
'description': u'test-description',
|
||||
'visibility': u'public',
|
||||
'protected': 0,
|
||||
'owner': u'test-owner'
|
||||
}
|
||||
namespace.update(kwargs)
|
||||
return namespace
|
||||
|
||||
|
||||
def build_resource_type_fixture(**kwargs):
|
||||
resource_type = {
|
||||
'name': u'MyTestResourceType',
|
||||
'protected': 0
|
||||
}
|
||||
resource_type.update(kwargs)
|
||||
return resource_type
|
||||
|
||||
|
||||
def build_association_fixture(**kwargs):
|
||||
association = {
|
||||
'name': u'MyTestResourceType',
|
||||
'properties_target': 'test-properties-target',
|
||||
'prefix': 'test-prefix'
|
||||
}
|
||||
association.update(kwargs)
|
||||
return association
|
||||
|
||||
|
||||
def build_object_fixture(**kwargs):
|
||||
# Full testing of required and schema done via rest api tests
|
||||
object = {
|
||||
'namespace_id': 1,
|
||||
'name': u'test-object-name',
|
||||
'description': u'test-object-description',
|
||||
'required': u'fake-required-properties-list',
|
||||
'schema': u'{fake-schema}'
|
||||
}
|
||||
object.update(kwargs)
|
||||
return object
|
||||
|
||||
|
||||
def build_property_fixture(**kwargs):
|
||||
# Full testing of required and schema done via rest api tests
|
||||
property = {
|
||||
'namespace_id': 1,
|
||||
'name': u'test-property-name',
|
||||
'schema': u'{fake-schema}'
|
||||
}
|
||||
property.update(kwargs)
|
||||
return property
|
||||
|
||||
|
||||
class TestMetadefDriver(test_utils.BaseTestCase):
|
||||
|
||||
"""Test Driver class for Metadef tests."""
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test method to initialize test environment."""
|
||||
super(TestMetadefDriver, self).setUp()
|
||||
config.parse_args(args=[])
|
||||
context_cls = context.RequestContext
|
||||
self.adm_context = context_cls(is_admin=True,
|
||||
auth_tok='user:user:admin')
|
||||
self.context = context_cls(is_admin=False,
|
||||
auth_tok='user:user:user')
|
||||
self.db_api = db_tests.get_db(self.config)
|
||||
db_tests.reset_db(self.db_api)
|
||||
|
||||
def _assert_saved_fields(self, expected, actual):
|
||||
for k in expected.keys():
|
||||
self.assertEqual(expected[k], actual[k])
|
||||
|
||||
|
||||
class MetadefNamespaceTests(object):
|
||||
|
||||
def test_namespace_create(self):
|
||||
fixture = build_namespace_fixture()
|
||||
created = self.db_api.metadef_namespace_create(self.context, fixture)
|
||||
self.assertIsNotNone(created)
|
||||
self._assert_saved_fields(fixture, created)
|
||||
|
||||
def test_namespace_get(self):
|
||||
fixture = build_namespace_fixture()
|
||||
created = self.db_api.metadef_namespace_create(self.context, fixture)
|
||||
self.assertIsNotNone(created)
|
||||
self._assert_saved_fields(fixture, created)
|
||||
|
||||
found = self.db_api.metadef_namespace_get(
|
||||
self.context, created['namespace'])
|
||||
self.assertIsNotNone(found, "Namespace not found.")
|
||||
|
||||
def test_namespace_get_all_with_resource_types_filter(self):
|
||||
ns_fixture = build_namespace_fixture()
|
||||
ns_created = self.db_api.metadef_namespace_create(
|
||||
self.context, ns_fixture)
|
||||
self.assertIsNotNone(ns_created, "Could not create a namespace.")
|
||||
self._assert_saved_fields(ns_fixture, ns_created)
|
||||
|
||||
fixture = build_association_fixture()
|
||||
created = self.db_api.metadef_resource_type_association_create(
|
||||
self.context, ns_created['namespace'], fixture)
|
||||
self.assertIsNotNone(created, "Could not create an association.")
|
||||
|
||||
rt_filters = {'resource_types': fixture['name']}
|
||||
found = self.db_api.\
|
||||
metadef_namespace_get_all(self.context, filters=rt_filters,
|
||||
sort_key='created_at')
|
||||
self.assertEqual(len(found), 1)
|
||||
for item in found:
|
||||
self._assert_saved_fields(ns_fixture, item)
|
||||
|
||||
def test_namespace_update(self):
|
||||
delta = {'owner': u'New Owner'}
|
||||
fixture = build_namespace_fixture()
|
||||
|
||||
created = self.db_api.metadef_namespace_create(self.context, fixture)
|
||||
self.assertIsNotNone(created['namespace'])
|
||||
self.assertEqual(created['namespace'], fixture['namespace'])
|
||||
delta_dict = copy.deepcopy(created)
|
||||
delta_dict.update(delta.copy())
|
||||
|
||||
updated = self.db_api.metadef_namespace_update(
|
||||
self.context, created['id'], delta_dict)
|
||||
self.assertEqual(delta['owner'], updated['owner'])
|
||||
|
||||
def test_namespace_delete(self):
|
||||
fixture = build_namespace_fixture()
|
||||
created = self.db_api.metadef_namespace_create(self.context, fixture)
|
||||
self.assertIsNotNone(created, "Could not create a Namespace.")
|
||||
self.db_api.metadef_namespace_delete(
|
||||
self.context, created['namespace'])
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.db_api.metadef_namespace_get,
|
||||
self.context, created['namespace'])
|
||||
|
||||
def test_namespace_delete_with_content(self):
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture_ns)
|
||||
self._assert_saved_fields(fixture_ns, created_ns)
|
||||
|
||||
# Create object content for the namespace
|
||||
fixture_obj = build_object_fixture()
|
||||
created_obj = self.db_api.metadef_object_create(
|
||||
self.context, created_ns['namespace'], fixture_obj)
|
||||
self.assertIsNotNone(created_obj)
|
||||
|
||||
# Create property content for the namespace
|
||||
fixture_prop = build_property_fixture(namespace_id=created_ns['id'])
|
||||
created_prop = self.db_api.metadef_property_create(
|
||||
self.context, created_ns['namespace'], fixture_prop)
|
||||
self.assertIsNotNone(created_prop)
|
||||
|
||||
# Create associations
|
||||
fixture_assn = build_association_fixture()
|
||||
created_assn = self.db_api.metadef_resource_type_association_create(
|
||||
self.context, created_ns['namespace'], fixture_assn)
|
||||
self.assertIsNotNone(created_assn)
|
||||
|
||||
deleted_ns = self.db_api.metadef_namespace_delete(
|
||||
self.context, created_ns['namespace'])
|
||||
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.db_api.metadef_namespace_get,
|
||||
self.context, deleted_ns['namespace'])
|
||||
|
||||
|
||||
class MetadefPropertyTests(object):
|
||||
|
||||
def test_property_create(self):
|
||||
fixture = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture)
|
||||
self.assertIsNotNone(created_ns)
|
||||
self._assert_saved_fields(fixture, created_ns)
|
||||
|
||||
fixture_prop = build_property_fixture(namespace_id=created_ns['id'])
|
||||
created_prop = self.db_api.metadef_property_create(
|
||||
self.context, created_ns['namespace'], fixture_prop)
|
||||
self._assert_saved_fields(fixture_prop, created_prop)
|
||||
|
||||
def test_property_get(self):
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture_ns)
|
||||
self.assertIsNotNone(created_ns)
|
||||
self._assert_saved_fields(fixture_ns, created_ns)
|
||||
|
||||
fixture_prop = build_property_fixture(namespace_id=created_ns['id'])
|
||||
created_prop = self.db_api.metadef_property_create(
|
||||
self.context, created_ns['namespace'], fixture_prop)
|
||||
|
||||
found_prop = self.db_api.metadef_property_get(
|
||||
self.context, created_ns['namespace'], created_prop['name'])
|
||||
self._assert_saved_fields(fixture_prop, found_prop)
|
||||
|
||||
def test_property_get_all(self):
|
||||
ns_fixture = build_namespace_fixture()
|
||||
ns_created = self.db_api.metadef_namespace_create(
|
||||
self.context, ns_fixture)
|
||||
self.assertIsNotNone(ns_created, "Could not create a namespace.")
|
||||
self._assert_saved_fields(ns_fixture, ns_created)
|
||||
|
||||
fixture1 = build_property_fixture(namespace_id=ns_created['id'])
|
||||
created_p1 = self.db_api.metadef_property_create(
|
||||
self.context, ns_created['namespace'], fixture1)
|
||||
self.assertIsNotNone(created_p1, "Could not create a property.")
|
||||
|
||||
fixture2 = build_property_fixture(namespace_id=ns_created['id'],
|
||||
name='test-prop-2')
|
||||
created_p2 = self.db_api.metadef_property_create(
|
||||
self.context, ns_created['namespace'], fixture2)
|
||||
self.assertIsNotNone(created_p2, "Could not create a property.")
|
||||
|
||||
found = self.db_api.\
|
||||
metadef_property_get_all(self.context, ns_created['namespace'])
|
||||
self.assertEqual(len(found), 2)
|
||||
|
||||
def test_property_update(self):
|
||||
delta = {'name': u'New-name', 'schema': u'new-schema'}
|
||||
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture_ns)
|
||||
self.assertIsNotNone(created_ns['namespace'])
|
||||
|
||||
prop_fixture = build_property_fixture(namespace_id=created_ns['id'])
|
||||
created_prop = self.db_api.metadef_property_create(
|
||||
self.context, created_ns['namespace'], prop_fixture)
|
||||
self.assertIsNotNone(created_prop, "Could not create a property.")
|
||||
|
||||
delta_dict = copy.deepcopy(created_prop)
|
||||
delta_dict.update(delta.copy())
|
||||
|
||||
updated = self.db_api.metadef_property_update(
|
||||
self.context, created_ns['namespace'],
|
||||
created_prop['id'], delta_dict)
|
||||
self.assertEqual(delta['name'], updated['name'])
|
||||
self.assertEqual(delta['schema'], updated['schema'])
|
||||
|
||||
def test_property_delete(self):
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture_ns)
|
||||
self.assertIsNotNone(created_ns['namespace'])
|
||||
|
||||
prop_fixture = build_property_fixture(namespace_id=created_ns['id'])
|
||||
created_prop = self.db_api.metadef_property_create(
|
||||
self.context, created_ns['namespace'], prop_fixture)
|
||||
self.assertIsNotNone(created_prop, "Could not create a property.")
|
||||
|
||||
self.db_api.metadef_property_delete(
|
||||
self.context, created_ns['namespace'], created_prop['name'])
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.db_api.metadef_property_get,
|
||||
self.context, created_ns['namespace'],
|
||||
created_prop['name'])
|
||||
|
||||
def test_property_delete_namespace_content(self):
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture_ns)
|
||||
self.assertIsNotNone(created_ns['namespace'])
|
||||
|
||||
prop_fixture = build_property_fixture(namespace_id=created_ns['id'])
|
||||
created_prop = self.db_api.metadef_property_create(
|
||||
self.context, created_ns['namespace'], prop_fixture)
|
||||
self.assertIsNotNone(created_prop, "Could not create a property.")
|
||||
|
||||
self.db_api.metadef_property_delete_namespace_content(
|
||||
self.context, created_ns['namespace'])
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.db_api.metadef_property_get,
|
||||
self.context, created_ns['namespace'],
|
||||
created_prop['name'])
|
||||
|
||||
|
||||
class MetadefObjectTests(object):
|
||||
|
||||
def test_object_create(self):
|
||||
fixture = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(self.context,
|
||||
fixture)
|
||||
self.assertIsNotNone(created_ns)
|
||||
self._assert_saved_fields(fixture, created_ns)
|
||||
|
||||
fixture_object = build_object_fixture(namespace_id=created_ns['id'])
|
||||
created_object = self.db_api.metadef_object_create(
|
||||
self.context, created_ns['namespace'], fixture_object)
|
||||
self._assert_saved_fields(fixture_object, created_object)
|
||||
|
||||
def test_object_get(self):
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(self.context,
|
||||
fixture_ns)
|
||||
self.assertIsNotNone(created_ns)
|
||||
self._assert_saved_fields(fixture_ns, created_ns)
|
||||
|
||||
fixture_object = build_object_fixture(namespace_id=created_ns['id'])
|
||||
created_object = self.db_api.metadef_object_create(
|
||||
self.context, created_ns['namespace'], fixture_object)
|
||||
|
||||
found_object = self.db_api.metadef_object_get(
|
||||
self.context, created_ns['namespace'], created_object['name'])
|
||||
self._assert_saved_fields(fixture_object, found_object)
|
||||
|
||||
def test_object_get_all(self):
|
||||
ns_fixture = build_namespace_fixture()
|
||||
ns_created = self.db_api.metadef_namespace_create(self.context,
|
||||
ns_fixture)
|
||||
self.assertIsNotNone(ns_created, "Could not create a namespace.")
|
||||
self._assert_saved_fields(ns_fixture, ns_created)
|
||||
|
||||
fixture1 = build_object_fixture(namespace_id=ns_created['id'])
|
||||
created_o1 = self.db_api.metadef_object_create(
|
||||
self.context, ns_created['namespace'], fixture1)
|
||||
self.assertIsNotNone(created_o1, "Could not create an object.")
|
||||
|
||||
fixture2 = build_object_fixture(namespace_id=ns_created['id'],
|
||||
name='test-object-2')
|
||||
created_o2 = self.db_api.metadef_object_create(
|
||||
self.context, ns_created['namespace'], fixture2)
|
||||
self.assertIsNotNone(created_o2, "Could not create an object.")
|
||||
|
||||
found = self.db_api.\
|
||||
metadef_object_get_all(self.context, ns_created['namespace'])
|
||||
self.assertEqual(len(found), 2)
|
||||
|
||||
def test_object_update(self):
|
||||
delta = {'name': u'New-name', 'schema': u'new-schema',
|
||||
'required': u'new-required'}
|
||||
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(self.context,
|
||||
fixture_ns)
|
||||
self.assertIsNotNone(created_ns['namespace'])
|
||||
|
||||
object_fixture = build_object_fixture(namespace_id=created_ns['id'])
|
||||
created_object = self.db_api.metadef_object_create(
|
||||
self.context, created_ns['namespace'], object_fixture)
|
||||
self.assertIsNotNone(created_object, "Could not create an object.")
|
||||
|
||||
delta_dict = {}
|
||||
delta_dict.update(delta.copy())
|
||||
|
||||
updated = self.db_api.metadef_object_update(
|
||||
self.context, created_ns['namespace'],
|
||||
created_object['id'], delta_dict)
|
||||
self.assertEqual(delta['name'], updated['name'])
|
||||
self.assertEqual(delta['schema'], updated['schema'])
|
||||
|
||||
def test_object_delete(self):
|
||||
fixture_ns = build_namespace_fixture()
|
||||
created_ns = self.db_api.metadef_namespace_create(
|
||||
self.context, fixture_ns)
|
||||
self.assertIsNotNone(created_ns['namespace'])
|
||||
|
||||
object_fixture = build_object_fixture(namespace_id=created_ns['id'])
|
||||
created_object = self.db_api.metadef_object_create(
|
||||
self.context, created_ns['namespace'], object_fixture)
|
||||
self.assertIsNotNone(created_object, "Could not create an object.")
|
||||
|
||||
self.db_api.metadef_object_delete(
|
||||
self.context, created_ns['namespace'], created_object['name'])
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.db_api.metadef_object_get,
|
||||
self.context, created_ns['namespace'],
|
||||
created_object['name'])
|
||||
|
||||
|
||||
class MetadefResourceTypeTests(object):
|
||||
|
||||
def test_resource_type_get_all(self):
|
||||
resource_types_orig = self.db_api.metadef_resource_type_get_all(
|
||||
self.context)
|
||||
|
||||
fixture = build_resource_type_fixture()
|
||||
self.db_api.metadef_resource_type_create(self.context, fixture)
|
||||
|
||||
resource_types = self.db_api.metadef_resource_type_get_all(
|
||||
self.context)
|
||||
|
||||
test_len = len(resource_types_orig) + 1
|
||||
self.assertEqual(len(resource_types), test_len)
|
||||
|
||||
|
||||
class MetadefResourceTypeAssociationTests(object):
|
||||
|
||||
def test_association_create(self):
|
||||
ns_fixture = build_namespace_fixture()
|
||||
ns_created = self.db_api.metadef_namespace_create(
|
||||
self.context, ns_fixture)
|
||||
self.assertIsNotNone(ns_created)
|
||||
self._assert_saved_fields(ns_fixture, ns_created)
|
||||
|
||||
assn_fixture = build_association_fixture()
|
||||
assn_created = self.db_api.metadef_resource_type_association_create(
|
||||
self.context, ns_created['namespace'], assn_fixture)
|
||||
self.assertIsNotNone(assn_created)
|
||||
self._assert_saved_fields(assn_fixture, assn_created)
|
||||
|
||||
def test_association_delete(self):
|
||||
ns_fixture = build_namespace_fixture()
|
||||
ns_created = self.db_api.metadef_namespace_create(
|
||||
self.context, ns_fixture)
|
||||
self.assertIsNotNone(ns_created, "Could not create a namespace.")
|
||||
self._assert_saved_fields(ns_fixture, ns_created)
|
||||
|
||||
fixture = build_association_fixture()
|
||||
created = self.db_api.metadef_resource_type_association_create(
|
||||
self.context, ns_created['namespace'], fixture)
|
||||
self.assertIsNotNone(created, "Could not create an association.")
|
||||
|
||||
created_resource = self.db_api.metadef_resource_type_get(
|
||||
self.context, fixture['name'])
|
||||
self.assertIsNotNone(created_resource, "resource_type not created")
|
||||
|
||||
self.db_api.metadef_resource_type_association_delete(
|
||||
self.context, ns_created['namespace'], created_resource['name'])
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.db_api.metadef_resource_type_association_get,
|
||||
self.context, ns_created['namespace'],
|
||||
created_resource['name'])
|
||||
|
||||
def test_association_get_all_by_namespace(self):
|
||||
ns_fixture = build_namespace_fixture()
|
||||
ns_created = self.db_api.metadef_namespace_create(
|
||||
self.context, ns_fixture)
|
||||
self.assertIsNotNone(ns_created, "Could not create a namespace.")
|
||||
self._assert_saved_fields(ns_fixture, ns_created)
|
||||
|
||||
fixture = build_association_fixture()
|
||||
created = self.db_api.metadef_resource_type_association_create(
|
||||
self.context, ns_created['namespace'], fixture)
|
||||
self.assertIsNotNone(created, "Could not create an association.")
|
||||
|
||||
found = self.db_api.\
|
||||
metadef_resource_type_association_get_all_by_namespace(
|
||||
self.context, ns_created['namespace'])
|
||||
self.assertEqual(len(found), 1)
|
||||
for item in found:
|
||||
self._assert_saved_fields(fixture, item)
|
||||
|
||||
|
||||
class MetadefDriverTests(MetadefNamespaceTests,
|
||||
MetadefResourceTypeTests,
|
||||
MetadefResourceTypeAssociationTests,
|
||||
MetadefPropertyTests,
|
||||
MetadefObjectTests):
|
||||
# collection class
|
||||
pass
|
|
@ -20,6 +20,7 @@ import glance.db
|
|||
from glance.tests import functional
|
||||
import glance.tests.functional.db as db_tests
|
||||
from glance.tests.functional.db import base
|
||||
from glance.tests.functional.db import base_metadef
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
@ -85,3 +86,17 @@ class TestRegistryQuota(base.DriverQuotaTests, FunctionalInitWrapper):
|
|||
def tearDown(self):
|
||||
self.registry_server.stop()
|
||||
super(TestRegistryQuota, self).tearDown()
|
||||
|
||||
|
||||
class TestRegistryMetadefDriver(base_metadef.TestMetadefDriver,
|
||||
base_metadef.MetadefDriverTests,
|
||||
FunctionalInitWrapper):
|
||||
|
||||
def setUp(self):
|
||||
db_tests.load(get_db, reset_db)
|
||||
super(TestRegistryMetadefDriver, self).setUp()
|
||||
self.addCleanup(db_tests.reset)
|
||||
|
||||
def tearDown(self):
|
||||
self.registry_server.stop()
|
||||
super(TestRegistryMetadefDriver, self).tearDown()
|
||||
|
|
|
@ -20,8 +20,10 @@ from oslo.db import options
|
|||
from glance.common import exception
|
||||
import glance.db.sqlalchemy.api
|
||||
from glance.db.sqlalchemy import models as db_models
|
||||
from glance.db.sqlalchemy import models_metadef as metadef_models
|
||||
import glance.tests.functional.db as db_tests
|
||||
from glance.tests.functional.db import base
|
||||
from glance.tests.functional.db import base_metadef
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
@ -38,6 +40,11 @@ def reset_db(db_api):
|
|||
db_models.register_models(db_api.get_engine())
|
||||
|
||||
|
||||
def reset_db_metadef(db_api):
|
||||
metadef_models.unregister_models(db_api.get_engine())
|
||||
metadef_models.register_models(db_api.get_engine())
|
||||
|
||||
|
||||
class TestSqlAlchemyDriver(base.TestDriver, base.DriverTests):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -136,3 +143,12 @@ class TestSqlAlchemyQuota(base.DriverQuotaTests):
|
|||
db_tests.load(get_db, reset_db)
|
||||
super(TestSqlAlchemyQuota, self).setUp()
|
||||
self.addCleanup(db_tests.reset)
|
||||
|
||||
|
||||
class TestMetadefSqlAlchemyDriver(base_metadef.TestMetadefDriver,
|
||||
base_metadef.MetadefDriverTests):
|
||||
|
||||
def setUp(self):
|
||||
db_tests.load(get_db, reset_db_metadef)
|
||||
super(TestMetadefSqlAlchemyDriver, self).setUp()
|
||||
self.addCleanup(db_tests.reset)
|
||||
|
|
|
@ -1338,3 +1338,125 @@ class TestMigrations(test_utils.BaseTestCase):
|
|||
def _post_downgrade_034(self, engine):
|
||||
images = get_table(engine, 'images')
|
||||
self.assertNotIn('virtual_size', images.c)
|
||||
|
||||
def _pre_upgrade_035(self, engine):
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_namespaces')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_properties')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_objects')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_resource_types')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine,
|
||||
'metadef_namespace_resource_types')
|
||||
|
||||
def _check_035(self, engine, data):
|
||||
meta = sqlalchemy.MetaData()
|
||||
meta.bind = engine
|
||||
|
||||
# metadef_namespaces
|
||||
table = sqlalchemy.Table("metadef_namespaces", meta, autoload=True)
|
||||
index_namespace = ('ix_namespaces_namespace', ['namespace'])
|
||||
index_data = [(idx.name, idx.columns.keys())
|
||||
for idx in table.indexes]
|
||||
self.assertIn(index_namespace, index_data)
|
||||
|
||||
expected_cols = [u'id',
|
||||
u'namespace',
|
||||
u'display_name',
|
||||
u'description',
|
||||
u'visibility',
|
||||
u'protected',
|
||||
u'owner',
|
||||
u'created_at',
|
||||
u'updated_at']
|
||||
col_data = [col.name for col in table.columns]
|
||||
self.assertEqual(expected_cols, col_data)
|
||||
|
||||
# metadef_objects
|
||||
table = sqlalchemy.Table("metadef_objects", meta, autoload=True)
|
||||
index_namespace_id_name = (
|
||||
'ix_objects_namespace_id_name', ['namespace_id', 'name'])
|
||||
index_data = [(idx.name, idx.columns.keys())
|
||||
for idx in table.indexes]
|
||||
self.assertIn(index_namespace_id_name, index_data)
|
||||
|
||||
expected_cols = [u'id',
|
||||
u'namespace_id',
|
||||
u'name',
|
||||
u'description',
|
||||
u'required',
|
||||
u'schema',
|
||||
u'created_at',
|
||||
u'updated_at']
|
||||
col_data = [col.name for col in table.columns]
|
||||
self.assertEqual(expected_cols, col_data)
|
||||
|
||||
# metadef_properties
|
||||
table = sqlalchemy.Table("metadef_properties", meta, autoload=True)
|
||||
index_namespace_id_name = (
|
||||
'ix_metadef_properties_namespace_id_name',
|
||||
['namespace_id', 'name'])
|
||||
index_data = [(idx.name, idx.columns.keys())
|
||||
for idx in table.indexes]
|
||||
self.assertIn(index_namespace_id_name, index_data)
|
||||
|
||||
expected_cols = [u'id',
|
||||
u'namespace_id',
|
||||
u'name',
|
||||
u'schema',
|
||||
u'created_at',
|
||||
u'updated_at']
|
||||
col_data = [col.name for col in table.columns]
|
||||
self.assertEqual(expected_cols, col_data)
|
||||
|
||||
# metadef_resource_types
|
||||
table = sqlalchemy.Table(
|
||||
"metadef_resource_types", meta, autoload=True)
|
||||
index_resource_types_name = (
|
||||
'ix_metadef_resource_types_name', ['name'])
|
||||
index_data = [(idx.name, idx.columns.keys())
|
||||
for idx in table.indexes]
|
||||
self.assertIn(index_resource_types_name, index_data)
|
||||
|
||||
expected_cols = [u'id',
|
||||
u'name',
|
||||
u'protected',
|
||||
u'created_at',
|
||||
u'updated_at']
|
||||
col_data = [col.name for col in table.columns]
|
||||
self.assertEqual(expected_cols, col_data)
|
||||
|
||||
# metadef_namespace_resource_types
|
||||
table = sqlalchemy.Table(
|
||||
"metadef_namespace_resource_types", meta, autoload=True)
|
||||
index_ns_res_types_res_type_id_ns_id = (
|
||||
'ix_metadef_ns_res_types_res_type_id_ns_id',
|
||||
['resource_type_id', 'namespace_id'])
|
||||
index_data = [(idx.name, idx.columns.keys())
|
||||
for idx in table.indexes]
|
||||
self.assertIn(index_ns_res_types_res_type_id_ns_id, index_data)
|
||||
|
||||
expected_cols = [u'resource_type_id',
|
||||
u'namespace_id',
|
||||
u'properties_target',
|
||||
u'prefix',
|
||||
u'created_at',
|
||||
u'updated_at']
|
||||
col_data = [col.name for col in table.columns]
|
||||
self.assertEqual(expected_cols, col_data)
|
||||
|
||||
def _post_downgrade_035(self, engine):
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_namespaces')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_properties')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_objects')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine, 'metadef_resource_types')
|
||||
self.assertRaises(sqlalchemy.exc.NoSuchTableError,
|
||||
get_table, engine,
|
||||
'metadef_namespace_resource_types')
|
||||
|
|
Loading…
Reference in New Issue