Notifications for metadefinition resources
Metadefinition resources - namespaces, objects, properties, tags and resource types - don't provide any notification events when certain operations are performed on them. This patch includes following events that will be triggered when necessary: * metadef_namespace.create - namespace has been created * metadef_namespace.update - namespace has been updated * metadef_namespace.delete - namespace has been deleted * metadef_namespace.delete_properties - all properties have been removed from namespace * metadef_namespace.delete_objects - all objects have been removed from namespace * metadef_namespace.delete_tags - all tags have been removed from namespace * metadef_object.create - object has been created * metadef_object.update - object has been updated * metadef_object.delete - object has been deleted * metadef_property.create - property has been created * metadef_property.update - property has been updated * metadef_property.delete - property has been deleted * metadef_tag.create - tag has been created * metadef_tag.update - tag has been updated * metadef_tag.delete - tag has been deleted * metadef_resource_type.create - resource type has been added to namespace * metadef_resource_type.delete - resource type has been removed from namespace Additionally new configuration option has been added to allow for disabling either individual or group of notifications. DocImpact UpgradeImpact Depends-On: Iaa771ead0114e3941667b1e07ff32472d2f77afd Change-Id: Ie1635793d80188f8f7a07aea91b9f0842900ffa6 Implements: blueprint metadefs-notifications
This commit is contained in:
parent
030250ed64
commit
fd547e3717
@ -1303,6 +1303,18 @@ Sets the notification driver used by oslo.messaging. Options include
|
||||
For more information see :doc:`Glance notifications <notifications>` and
|
||||
`oslo.messaging <http://docs.openstack.org/developer/oslo.messaging/>`_.
|
||||
|
||||
* ``disabled_notifications``
|
||||
|
||||
Optional. Default: ``[]``
|
||||
|
||||
List of disabled notifications. A notification can be given either as a
|
||||
notification type to disable a single event, or as a notification group prefix
|
||||
to disable all events within a group.
|
||||
|
||||
Example: if this config option is set to ["image.create", "metadef_namespace"],
|
||||
then "image.create" notification will not be sent after image is created and
|
||||
none of the notifications for metadefinition namespaces will be sent.
|
||||
|
||||
Configuring Glance Property Protections
|
||||
---------------------------------------
|
||||
|
||||
|
@ -220,6 +220,15 @@ registry_client_protocol = http
|
||||
# Default publisher_id for outgoing notifications.
|
||||
# default_publisher_id = image.localhost
|
||||
|
||||
# List of disabled notifications. A notification can be given either as a
|
||||
# notification type to disable a single event, or as a notification group
|
||||
# prefix to disable all events within a group.
|
||||
# Example: if this config option is set to
|
||||
# ["image.create", "metadef_namespace"], then "image.create" notification will
|
||||
# not be sent after image is created and none of the notifications for
|
||||
# metadefinition namespaces will be sent.
|
||||
# disabled_notifications = []
|
||||
|
||||
# Messaging driver used for 'messaging' notifications driver
|
||||
# rpc_backend = 'rabbit'
|
||||
|
||||
|
@ -48,10 +48,12 @@ CONF = cfg.CONF
|
||||
|
||||
|
||||
class NamespaceController(object):
|
||||
def __init__(self, db_api=None, policy_enforcer=None):
|
||||
def __init__(self, db_api=None, policy_enforcer=None, notifier=None):
|
||||
self.db_api = db_api or glance.db.get_api()
|
||||
self.policy = policy_enforcer or policy.Enforcer()
|
||||
self.notifier = notifier or glance.notifier.Notifier()
|
||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||
notifier=self.notifier,
|
||||
policy_enforcer=self.policy)
|
||||
self.ns_schema_link = '/v2/schemas/metadefs/namespace'
|
||||
self.obj_schema_link = '/v2/schemas/metadefs/object'
|
||||
@ -269,6 +271,7 @@ class NamespaceController(object):
|
||||
namespace_repo = self.gateway.get_metadef_namespace_repo(req.context)
|
||||
try:
|
||||
ns_obj = namespace_repo.get(namespace)
|
||||
ns_obj._old_namespace = ns_obj.namespace
|
||||
ns_obj.namespace = wsme_utils._get_value(user_ns.namespace)
|
||||
ns_obj.display_name = wsme_utils._get_value(user_ns.display_name)
|
||||
ns_obj.description = wsme_utils._get_value(user_ns.description)
|
||||
|
@ -42,10 +42,12 @@ CONF = cfg.CONF
|
||||
|
||||
|
||||
class MetadefObjectsController(object):
|
||||
def __init__(self, db_api=None, policy_enforcer=None):
|
||||
def __init__(self, db_api=None, policy_enforcer=None, notifier=None):
|
||||
self.db_api = db_api or glance.db.get_api()
|
||||
self.policy = policy_enforcer or policy.Enforcer()
|
||||
self.notifier = notifier or glance.notifier.Notifier()
|
||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||
notifier=self.notifier,
|
||||
policy_enforcer=self.policy)
|
||||
self.obj_schema_link = '/v2/schemas/metadefs/object'
|
||||
|
||||
@ -117,6 +119,7 @@ class MetadefObjectsController(object):
|
||||
meta_repo = self.gateway.get_metadef_object_repo(req.context)
|
||||
try:
|
||||
metadef_object = meta_repo.get(namespace, object_name)
|
||||
metadef_object._old_name = metadef_object.name
|
||||
metadef_object.name = wsme_utils._get_value(
|
||||
metadata_object.name)
|
||||
metadef_object.description = wsme_utils._get_value(
|
||||
|
@ -40,10 +40,12 @@ _LI = i18n._LI
|
||||
|
||||
|
||||
class NamespacePropertiesController(object):
|
||||
def __init__(self, db_api=None, policy_enforcer=None):
|
||||
def __init__(self, db_api=None, policy_enforcer=None, notifier=None):
|
||||
self.db_api = db_api or glance.db.get_api()
|
||||
self.policy = policy_enforcer or policy.Enforcer()
|
||||
self.notifier = notifier or glance.notifier.Notifier()
|
||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||
notifier=self.notifier,
|
||||
policy_enforcer=self.policy)
|
||||
|
||||
def _to_dict(self, model_property_type):
|
||||
@ -131,6 +133,7 @@ class NamespacePropertiesController(object):
|
||||
prop_repo = self.gateway.get_metadef_property_repo(req.context)
|
||||
try:
|
||||
db_property_type = prop_repo.get(namespace, property_name)
|
||||
db_property_type._old_name = db_property_type.name
|
||||
db_property_type.name = property_type.name
|
||||
db_property_type.schema = (self._to_dict(property_type))['schema']
|
||||
updated_property_type = prop_repo.save(db_property_type)
|
||||
|
@ -40,10 +40,12 @@ _LI = i18n._LI
|
||||
|
||||
|
||||
class ResourceTypeController(object):
|
||||
def __init__(self, db_api=None, policy_enforcer=None):
|
||||
def __init__(self, db_api=None, policy_enforcer=None, notifier=None):
|
||||
self.db_api = db_api or glance.db.get_api()
|
||||
self.policy = policy_enforcer or policy.Enforcer()
|
||||
self.notifier = notifier or glance.notifier.Notifier()
|
||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||
notifier=self.notifier,
|
||||
policy_enforcer=self.policy)
|
||||
|
||||
def index(self, req):
|
||||
|
@ -41,10 +41,12 @@ CONF = cfg.CONF
|
||||
|
||||
|
||||
class TagsController(object):
|
||||
def __init__(self, db_api=None, policy_enforcer=None):
|
||||
def __init__(self, db_api=None, policy_enforcer=None, notifier=None):
|
||||
self.db_api = db_api or glance.db.get_api()
|
||||
self.policy = policy_enforcer or policy.Enforcer()
|
||||
self.notifier = notifier or glance.notifier.Notifier()
|
||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||
notifier=self.notifier,
|
||||
policy_enforcer=self.policy)
|
||||
self.tag_schema_link = '/v2/schemas/metadefs/tag'
|
||||
|
||||
@ -141,6 +143,7 @@ class TagsController(object):
|
||||
meta_repo = self.gateway.get_metadef_tag_repo(req.context)
|
||||
try:
|
||||
metadef_tag = meta_repo.get(namespace, tag_name)
|
||||
metadef_tag._old_name = metadef_tag.name
|
||||
metadef_tag.name = wsme_utils._get_value(
|
||||
metadata_tag.name)
|
||||
updated_metadata_tag = meta_repo.save(metadef_tag)
|
||||
|
@ -1060,6 +1060,15 @@ def _task_info_get(task_id):
|
||||
return task_info
|
||||
|
||||
|
||||
def _metadef_delete_namespace_content(get_func, key, context, namespace_name):
|
||||
global DATA
|
||||
metadefs = get_func(context, namespace_name)
|
||||
data = DATA[key]
|
||||
for metadef in metadefs:
|
||||
data.remove(metadef)
|
||||
return metadefs
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_namespace_create(context, values):
|
||||
"""Create a namespace object"""
|
||||
@ -1374,6 +1383,13 @@ def metadef_object_delete(context, namespace_name, object_name):
|
||||
return object
|
||||
|
||||
|
||||
def metadef_object_delete_namespace_content(context, namespace_name,
|
||||
session=None):
|
||||
"""Delete an object or raise if namespace or object doesn't exist."""
|
||||
return _metadef_delete_namespace_content(
|
||||
metadef_object_get_all, 'metadef_objects', context, namespace_name)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_object_count(context, namespace_name):
|
||||
"""Get metadef object count in a namespace"""
|
||||
@ -1550,6 +1566,14 @@ def metadef_property_delete(context, namespace_name, property_name):
|
||||
return property
|
||||
|
||||
|
||||
def metadef_property_delete_namespace_content(context, namespace_name,
|
||||
session=None):
|
||||
"""Delete a property or raise if it or namespace doesn't exist."""
|
||||
return _metadef_delete_namespace_content(
|
||||
metadef_property_get_all, 'metadef_properties', context,
|
||||
namespace_name)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_resource_type_create(context, values):
|
||||
"""Create a metadef resource type"""
|
||||
@ -1863,6 +1887,13 @@ def metadef_tag_delete(context, namespace_name, name):
|
||||
return tags
|
||||
|
||||
|
||||
def metadef_tag_delete_namespace_content(context, namespace_name,
|
||||
session=None):
|
||||
"""Delete an tag or raise if namespace or tag doesn't exist."""
|
||||
return _metadef_delete_namespace_content(
|
||||
metadef_tag_get_all, 'metadef_tags', context, namespace_name)
|
||||
|
||||
|
||||
@log_call
|
||||
def metadef_tag_count(context, namespace_name):
|
||||
"""Get metadef tag count in a namespace"""
|
||||
|
@ -131,77 +131,103 @@ class Gateway(object):
|
||||
ns_factory = glance.domain.MetadefNamespaceFactory()
|
||||
policy_ns_factory = policy.MetadefNamespaceFactoryProxy(
|
||||
ns_factory, context, self.policy)
|
||||
notifier_ns_factory = glance.notifier.MetadefNamespaceFactoryProxy(
|
||||
policy_ns_factory, context, self.notifier)
|
||||
authorized_ns_factory = authorization.MetadefNamespaceFactoryProxy(
|
||||
policy_ns_factory, context)
|
||||
notifier_ns_factory, context)
|
||||
return authorized_ns_factory
|
||||
|
||||
def get_metadef_namespace_repo(self, context):
|
||||
ns_repo = glance.db.MetadefNamespaceRepo(context, self.db_api)
|
||||
policy_ns_repo = policy.MetadefNamespaceRepoProxy(
|
||||
ns_repo, context, self.policy)
|
||||
notifier_ns_repo = glance.notifier.MetadefNamespaceRepoProxy(
|
||||
policy_ns_repo, context, self.notifier)
|
||||
authorized_ns_repo = authorization.MetadefNamespaceRepoProxy(
|
||||
policy_ns_repo, context)
|
||||
notifier_ns_repo, context)
|
||||
return authorized_ns_repo
|
||||
|
||||
def get_metadef_object_factory(self, context):
|
||||
object_factory = glance.domain.MetadefObjectFactory()
|
||||
policy_object_factory = policy.MetadefObjectFactoryProxy(
|
||||
object_factory, context, self.policy)
|
||||
notifier_object_factory = glance.notifier.MetadefObjectFactoryProxy(
|
||||
policy_object_factory, context, self.notifier)
|
||||
authorized_object_factory = authorization.MetadefObjectFactoryProxy(
|
||||
policy_object_factory, context)
|
||||
notifier_object_factory, context)
|
||||
return authorized_object_factory
|
||||
|
||||
def get_metadef_object_repo(self, context):
|
||||
object_repo = glance.db.MetadefObjectRepo(context, self.db_api)
|
||||
policy_object_repo = policy.MetadefObjectRepoProxy(
|
||||
object_repo, context, self.policy)
|
||||
notifier_object_repo = glance.notifier.MetadefObjectRepoProxy(
|
||||
policy_object_repo, context, self.notifier)
|
||||
authorized_object_repo = authorization.MetadefObjectRepoProxy(
|
||||
policy_object_repo, context)
|
||||
notifier_object_repo, context)
|
||||
return authorized_object_repo
|
||||
|
||||
def get_metadef_resource_type_factory(self, context):
|
||||
resource_type_factory = glance.domain.MetadefResourceTypeFactory()
|
||||
policy_resource_type_factory = policy.MetadefResourceTypeFactoryProxy(
|
||||
resource_type_factory, context, self.policy)
|
||||
return authorization.MetadefResourceTypeFactoryProxy(
|
||||
policy_resource_type_factory, context)
|
||||
notifier_resource_type_factory = (
|
||||
glance.notifier.MetadefResourceTypeFactoryProxy(
|
||||
policy_resource_type_factory, context, self.notifier)
|
||||
)
|
||||
authorized_resource_type_factory = (
|
||||
authorization.MetadefResourceTypeFactoryProxy(
|
||||
notifier_resource_type_factory, context)
|
||||
)
|
||||
return authorized_resource_type_factory
|
||||
|
||||
def get_metadef_resource_type_repo(self, context):
|
||||
resource_type_repo = glance.db.MetadefResourceTypeRepo(
|
||||
context, self.db_api)
|
||||
policy_object_repo = policy.MetadefResourceTypeRepoProxy(
|
||||
resource_type_repo, context, self.policy)
|
||||
return authorization.MetadefResourceTypeRepoProxy(policy_object_repo,
|
||||
context)
|
||||
notifier_object_repo = glance.notifier.MetadefResourceTypeRepoProxy(
|
||||
policy_object_repo, context, self.notifier)
|
||||
authorized_object_repo = authorization.MetadefResourceTypeRepoProxy(
|
||||
notifier_object_repo, context)
|
||||
return authorized_object_repo
|
||||
|
||||
def get_metadef_property_factory(self, context):
|
||||
prop_factory = glance.domain.MetadefPropertyFactory()
|
||||
policy_prop_factory = policy.MetadefPropertyFactoryProxy(
|
||||
prop_factory, context, self.policy)
|
||||
notifier_prop_factory = glance.notifier.MetadefPropertyFactoryProxy(
|
||||
policy_prop_factory, context, self.notifier)
|
||||
authorized_prop_factory = authorization.MetadefPropertyFactoryProxy(
|
||||
policy_prop_factory, context)
|
||||
notifier_prop_factory, context)
|
||||
return authorized_prop_factory
|
||||
|
||||
def get_metadef_property_repo(self, context):
|
||||
prop_repo = glance.db.MetadefPropertyRepo(context, self.db_api)
|
||||
policy_prop_repo = policy.MetadefPropertyRepoProxy(
|
||||
prop_repo, context, self.policy)
|
||||
notifier_prop_repo = glance.notifier.MetadefPropertyRepoProxy(
|
||||
policy_prop_repo, context, self.notifier)
|
||||
authorized_prop_repo = authorization.MetadefPropertyRepoProxy(
|
||||
policy_prop_repo, context)
|
||||
notifier_prop_repo, context)
|
||||
return authorized_prop_repo
|
||||
|
||||
def get_metadef_tag_factory(self, context):
|
||||
tag_factory = glance.domain.MetadefTagFactory()
|
||||
policy_tag_factory = policy.MetadefTagFactoryProxy(
|
||||
tag_factory, context, self.policy)
|
||||
notifier_tag_factory = glance.notifier.MetadefTagFactoryProxy(
|
||||
policy_tag_factory, context, self.notifier)
|
||||
authorized_tag_factory = authorization.MetadefTagFactoryProxy(
|
||||
policy_tag_factory, context)
|
||||
notifier_tag_factory, context)
|
||||
return authorized_tag_factory
|
||||
|
||||
def get_metadef_tag_repo(self, context):
|
||||
tag_repo = glance.db.MetadefTagRepo(context, self.db_api)
|
||||
policy_tag_repo = policy.MetadefTagRepoProxy(
|
||||
tag_repo, context, self.policy)
|
||||
notifier_tag_repo = glance.notifier.MetadefTagRepoProxy(
|
||||
policy_tag_repo, context, self.notifier)
|
||||
authorized_tag_repo = authorization.MetadefTagRepoProxy(
|
||||
policy_tag_repo, context)
|
||||
notifier_tag_repo, context)
|
||||
return authorized_tag_repo
|
||||
|
@ -14,16 +14,19 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import glance_store
|
||||
from oslo import messaging
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
import webob
|
||||
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
import glance.domain.proxy
|
||||
from glance.domain import proxy as domain_proxy
|
||||
from glance import i18n
|
||||
import glance.openstack.common.log as logging
|
||||
|
||||
@ -32,6 +35,15 @@ _ = i18n._
|
||||
notifier_opts = [
|
||||
cfg.StrOpt('default_publisher_id', default="image.localhost",
|
||||
help='Default publisher_id for outgoing notifications.'),
|
||||
cfg.ListOpt('disabled_notifications', default=[],
|
||||
help='List of disabled notifications. A notification can be '
|
||||
'given either as a notification type to disable a single '
|
||||
'event, or as a notification group prefix to disable all '
|
||||
'events within a group. Example: if this config option '
|
||||
'is set to ["image.create", "metadef_namespace"], then '
|
||||
'"image.create" notification will not be sent after '
|
||||
'image is created and none of the notifications for '
|
||||
'metadefinition namespaces will be sent.'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -69,6 +81,27 @@ class Notifier(object):
|
||||
self._notifier.error({}, event_type, payload)
|
||||
|
||||
|
||||
def _get_notification_group(notification):
|
||||
return notification.split('.', 1)[0]
|
||||
|
||||
|
||||
def _is_notification_enabled(notification):
|
||||
disabled_notifications = CONF.disabled_notifications
|
||||
notification_group = _get_notification_group(notification)
|
||||
|
||||
notifications = (notification, notification_group)
|
||||
for disabled_notification in disabled_notifications:
|
||||
if disabled_notification in notifications:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _send_notification(notify, notification_type, payload):
|
||||
if _is_notification_enabled(notification_type):
|
||||
notify(notification_type, payload)
|
||||
|
||||
|
||||
def format_image_notification(image):
|
||||
"""
|
||||
Given a glance.domain.Image object, return a dictionary of relevant
|
||||
@ -100,7 +133,8 @@ def format_image_notification(image):
|
||||
def format_task_notification(task):
|
||||
# NOTE(nikhil): input is not passed to the notifier payload as it may
|
||||
# contain sensitive info.
|
||||
return {'id': task.task_id,
|
||||
return {
|
||||
'id': task.task_id,
|
||||
'type': task.type,
|
||||
'status': task.status,
|
||||
'result': None,
|
||||
@ -114,56 +148,196 @@ def format_task_notification(task):
|
||||
}
|
||||
|
||||
|
||||
class ImageRepoProxy(glance.domain.proxy.Repo):
|
||||
def format_metadef_namespace_notification(metadef_namespace):
|
||||
return {
|
||||
'namespace': metadef_namespace.namespace,
|
||||
'namespace_old': metadef_namespace.namespace,
|
||||
'display_name': metadef_namespace.display_name,
|
||||
'protected': metadef_namespace.protected,
|
||||
'visibility': metadef_namespace.visibility,
|
||||
'owner': metadef_namespace.owner,
|
||||
'description': metadef_namespace.description,
|
||||
'created_at': timeutils.isotime(metadef_namespace.created_at),
|
||||
'updated_at': timeutils.isotime(metadef_namespace.updated_at),
|
||||
'deleted': False,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
def __init__(self, image_repo, context, notifier):
|
||||
self.image_repo = image_repo
|
||||
|
||||
def format_metadef_object_notification(metadef_object):
|
||||
properties = []
|
||||
for name, prop in six.iteritems(metadef_object.properties):
|
||||
object_property = _format_metadef_object_property(name, prop)
|
||||
properties.append(object_property)
|
||||
|
||||
return {
|
||||
'namespace': metadef_object.namespace,
|
||||
'name': metadef_object.name,
|
||||
'name_old': metadef_object.name,
|
||||
'properties': properties,
|
||||
'required': metadef_object.required,
|
||||
'description': metadef_object.description,
|
||||
'created_at': timeutils.isotime(metadef_object.created_at),
|
||||
'updated_at': timeutils.isotime(metadef_object.updated_at),
|
||||
'deleted': False,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
def _format_metadef_object_property(name, metadef_property):
|
||||
return {
|
||||
'name': name,
|
||||
'type': metadef_property.type or None,
|
||||
'title': metadef_property.title or None,
|
||||
'description': metadef_property.description or None,
|
||||
'default': metadef_property.default or None,
|
||||
'minimum': metadef_property.minimum or None,
|
||||
'maximum': metadef_property.maximum or None,
|
||||
'enum': metadef_property.enum or None,
|
||||
'pattern': metadef_property.pattern or None,
|
||||
'minLength': metadef_property.minLength or None,
|
||||
'maxLength': metadef_property.maxLength or None,
|
||||
'confidential': metadef_property.confidential or None,
|
||||
'items': metadef_property.items or None,
|
||||
'uniqueItems': metadef_property.uniqueItems or None,
|
||||
'minItems': metadef_property.minItems or None,
|
||||
'maxItems': metadef_property.maxItems or None,
|
||||
'additionalItems': metadef_property.additionalItems or None,
|
||||
}
|
||||
|
||||
|
||||
def format_metadef_property_notification(metadef_property):
|
||||
schema = metadef_property.schema
|
||||
|
||||
return {
|
||||
'namespace': metadef_property.namespace,
|
||||
'name': metadef_property.name,
|
||||
'name_old': metadef_property.name,
|
||||
'type': schema.get('type'),
|
||||
'title': schema.get('title'),
|
||||
'description': schema.get('description'),
|
||||
'default': schema.get('default'),
|
||||
'minimum': schema.get('minimum'),
|
||||
'maximum': schema.get('maximum'),
|
||||
'enum': schema.get('enum'),
|
||||
'pattern': schema.get('pattern'),
|
||||
'minLength': schema.get('minLength'),
|
||||
'maxLength': schema.get('maxLength'),
|
||||
'confidential': schema.get('confidential'),
|
||||
'items': schema.get('items'),
|
||||
'uniqueItems': schema.get('uniqueItems'),
|
||||
'minItems': schema.get('minItems'),
|
||||
'maxItems': schema.get('maxItems'),
|
||||
'additionalItems': schema.get('additionalItems'),
|
||||
'deleted': False,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
def format_metadef_resource_type_notification(metadef_resource_type):
|
||||
return {
|
||||
'namespace': metadef_resource_type.namespace,
|
||||
'name': metadef_resource_type.name,
|
||||
'name_old': metadef_resource_type.name,
|
||||
'prefix': metadef_resource_type.prefix,
|
||||
'properties_target': metadef_resource_type.properties_target,
|
||||
'created_at': timeutils.isotime(metadef_resource_type.created_at),
|
||||
'updated_at': timeutils.isotime(metadef_resource_type.updated_at),
|
||||
'deleted': False,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
def format_metadef_tag_notification(metadef_tag):
|
||||
return {
|
||||
'namespace': metadef_tag.namespace,
|
||||
'name': metadef_tag.name,
|
||||
'name_old': metadef_tag.name,
|
||||
'created_at': timeutils.isotime(metadef_tag.created_at),
|
||||
'updated_at': timeutils.isotime(metadef_tag.updated_at),
|
||||
'deleted': False,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
class NotificationBase(object):
|
||||
def get_payload(self, obj):
|
||||
return {}
|
||||
|
||||
def send_notification(self, notification_id, obj, extra_payload=None):
|
||||
payload = self.get_payload(obj)
|
||||
if extra_payload is not None:
|
||||
payload.update(extra_payload)
|
||||
|
||||
_send_notification(self.notifier.info, notification_id, payload)
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class NotificationProxy(NotificationBase):
|
||||
def __init__(self, repo, context, notifier):
|
||||
self.repo = repo
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
|
||||
super_class = self.get_super_class()
|
||||
super_class.__init__(self, repo)
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_super_class(self):
|
||||
pass
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class NotificationRepoProxy(NotificationBase):
|
||||
def __init__(self, repo, context, notifier):
|
||||
self.repo = repo
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
proxy_kwargs = {'context': self.context, 'notifier': self.notifier}
|
||||
super(ImageRepoProxy, self).__init__(image_repo,
|
||||
item_proxy_class=ImageProxy,
|
||||
item_proxy_kwargs=proxy_kwargs)
|
||||
|
||||
def save(self, image, from_state=None):
|
||||
super(ImageRepoProxy, self).save(image, from_state=from_state)
|
||||
self.notifier.info('image.update',
|
||||
format_image_notification(image))
|
||||
proxy_class = self.get_proxy_class()
|
||||
super_class = self.get_super_class()
|
||||
super_class.__init__(self, repo, proxy_class, proxy_kwargs)
|
||||
|
||||
def add(self, image):
|
||||
super(ImageRepoProxy, self).add(image)
|
||||
self.notifier.info('image.create',
|
||||
format_image_notification(image))
|
||||
@abc.abstractmethod
|
||||
def get_super_class(self):
|
||||
pass
|
||||
|
||||
def remove(self, image):
|
||||
super(ImageRepoProxy, self).remove(image)
|
||||
payload = format_image_notification(image)
|
||||
payload['deleted'] = True
|
||||
payload['deleted_at'] = timeutils.isotime()
|
||||
self.notifier.info('image.delete', payload)
|
||||
@abc.abstractmethod
|
||||
def get_proxy_class(self):
|
||||
pass
|
||||
|
||||
|
||||
class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class NotificationFactoryProxy(object):
|
||||
def __init__(self, factory, context, notifier):
|
||||
kwargs = {'context': context, 'notifier': notifier}
|
||||
super(ImageFactoryProxy, self).__init__(factory,
|
||||
proxy_class=ImageProxy,
|
||||
proxy_kwargs=kwargs)
|
||||
|
||||
proxy_class = self.get_proxy_class()
|
||||
super_class = self.get_super_class()
|
||||
super_class.__init__(self, factory, proxy_class, kwargs)
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_super_class(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_proxy_class(self):
|
||||
pass
|
||||
|
||||
|
||||
class ImageProxy(glance.domain.proxy.Image):
|
||||
class ImageProxy(NotificationProxy, domain_proxy.Image):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.Image
|
||||
|
||||
def __init__(self, image, context, notifier):
|
||||
self.image = image
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
super(ImageProxy, self).__init__(image)
|
||||
def get_payload(self, obj):
|
||||
return format_image_notification(obj)
|
||||
|
||||
def _format_image_send(self, bytes_sent):
|
||||
return {
|
||||
'bytes_sent': bytes_sent,
|
||||
'image_id': self.image.image_id,
|
||||
'owner_id': self.image.owner,
|
||||
'image_id': self.repo.image_id,
|
||||
'owner_id': self.repo.owner,
|
||||
'receiver_tenant_id': self.context.tenant,
|
||||
'receiver_user_id': self.context.user,
|
||||
}
|
||||
@ -174,13 +348,13 @@ class ImageProxy(glance.domain.proxy.Image):
|
||||
yield chunk
|
||||
sent += len(chunk)
|
||||
|
||||
if sent != (chunk_size or self.image.size):
|
||||
if sent != (chunk_size or self.repo.size):
|
||||
notify = self.notifier.error
|
||||
else:
|
||||
notify = self.notifier.info
|
||||
|
||||
try:
|
||||
notify('image.send',
|
||||
_send_notification(notify, 'image.send',
|
||||
self._format_image_send(sent))
|
||||
except Exception as err:
|
||||
msg = (_("An error occurred during image.send"
|
||||
@ -191,152 +365,454 @@ class ImageProxy(glance.domain.proxy.Image):
|
||||
# Due to the need of evaluating subsequent proxies, this one
|
||||
# should return a generator, the call should be done before
|
||||
# generator creation
|
||||
data = self.image.get_data(offset=offset, chunk_size=chunk_size)
|
||||
data = self.repo.get_data(offset=offset, chunk_size=chunk_size)
|
||||
return self._get_chunk_data_iterator(data, chunk_size=chunk_size)
|
||||
|
||||
def set_data(self, data, size=None):
|
||||
payload = format_image_notification(self.image)
|
||||
self.notifier.info('image.prepare', payload)
|
||||
self.send_notification('image.prepare', self.repo)
|
||||
|
||||
notify_error = self.notifier.error
|
||||
try:
|
||||
self.image.set_data(data, size)
|
||||
self.repo.set_data(data, size)
|
||||
except glance_store.StorageFull as e:
|
||||
msg = (_("Image storage media is full: %s") %
|
||||
utils.exception_to_str(e))
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
|
||||
except glance_store.StorageWriteDenied as e:
|
||||
msg = (_("Insufficient permissions on image storage media: %s")
|
||||
% utils.exception_to_str(e))
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
raise webob.exc.HTTPServiceUnavailable(explanation=msg)
|
||||
except ValueError as e:
|
||||
msg = (_("Cannot save data for image %(image_id)s: %(error)s") %
|
||||
{'image_id': self.image.image_id,
|
||||
{'image_id': self.repo.image_id,
|
||||
'error': utils.exception_to_str(e)})
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
explanation=utils.exception_to_str(e))
|
||||
except exception.Duplicate as e:
|
||||
msg = (_("Unable to upload duplicate image data for image"
|
||||
"%(image_id)s: %(error)s") %
|
||||
{'image_id': self.image.image_id,
|
||||
{'image_id': self.repo.image_id,
|
||||
'error': utils.exception_to_str(e)})
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
raise webob.exc.HTTPConflict(explanation=msg)
|
||||
except exception.Forbidden as e:
|
||||
msg = (_("Not allowed to upload image data for image %(image_id)s:"
|
||||
" %(error)s") % {'image_id': self.image.image_id,
|
||||
" %(error)s") % {'image_id': self.repo.image_id,
|
||||
'error': utils.exception_to_str(e)})
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||
except exception.NotFound as e:
|
||||
msg = (_("Image %(image_id)s could not be found after upload."
|
||||
" The image may have been deleted during the upload:"
|
||||
" %(error)s") % {'image_id': self.image.image_id,
|
||||
" %(error)s") % {'image_id': self.repo.image_id,
|
||||
'error': utils.exception_to_str(e)})
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
raise webob.exc.HTTPNotFound(explanation=utils.exception_to_str(e))
|
||||
except webob.exc.HTTPError as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
msg = (_("Failed to upload image data for image %(image_id)s"
|
||||
" due to HTTP error: %(error)s") %
|
||||
{'image_id': self.image.image_id,
|
||||
{'image_id': self.repo.image_id,
|
||||
'error': utils.exception_to_str(e)})
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
msg = (_("Failed to upload image data for image %(image_id)s "
|
||||
"due to internal error: %(error)s") %
|
||||
{'image_id': self.image.image_id,
|
||||
{'image_id': self.repo.image_id,
|
||||
'error': utils.exception_to_str(e)})
|
||||
self.notifier.error('image.upload', msg)
|
||||
_send_notification(notify_error, 'image.upload', msg)
|
||||
else:
|
||||
payload = format_image_notification(self.image)
|
||||
self.notifier.info('image.upload', payload)
|
||||
self.notifier.info('image.activate', payload)
|
||||
self.send_notification('image.upload', self.repo)
|
||||
self.send_notification('image.activate', self.repo)
|
||||
|
||||
|
||||
class TaskRepoProxy(glance.domain.proxy.TaskRepo):
|
||||
class ImageFactoryProxy(NotificationFactoryProxy, domain_proxy.ImageFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.ImageFactory
|
||||
|
||||
def __init__(self, task_repo, context, notifier):
|
||||
self.task_repo = task_repo
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
proxy_kwargs = {'context': self.context, 'notifier': self.notifier}
|
||||
super(TaskRepoProxy, self).__init__(task_repo,
|
||||
task_proxy_class=TaskProxy,
|
||||
task_proxy_kwargs=proxy_kwargs)
|
||||
|
||||
def add(self, task):
|
||||
self.notifier.info('task.create',
|
||||
format_task_notification(task))
|
||||
super(TaskRepoProxy, self).add(task)
|
||||
|
||||
def remove(self, task):
|
||||
payload = format_task_notification(task)
|
||||
payload['deleted'] = True
|
||||
payload['deleted_at'] = timeutils.isotime()
|
||||
self.notifier.info('task.delete', payload)
|
||||
super(TaskRepoProxy, self).remove(task)
|
||||
def get_proxy_class(self):
|
||||
return ImageProxy
|
||||
|
||||
|
||||
class TaskStubRepoProxy(glance.domain.proxy.TaskStubRepo):
|
||||
class ImageRepoProxy(NotificationRepoProxy, domain_proxy.Repo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.Repo
|
||||
|
||||
def __init__(self, task_stub_repo, context, notifier):
|
||||
self.task_stub_repo = task_stub_repo
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
proxy_kwargs = {'context': self.context, 'notifier': self.notifier}
|
||||
super(TaskStubRepoProxy, self).__init__(
|
||||
task_stub_repo,
|
||||
task_stub_proxy_class=TaskStubProxy,
|
||||
task_stub_proxy_kwargs=proxy_kwargs)
|
||||
def get_proxy_class(self):
|
||||
return ImageProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_image_notification(obj)
|
||||
|
||||
def save(self, image, from_state=None):
|
||||
super(ImageRepoProxy, self).save(image, from_state=from_state)
|
||||
self.send_notification('image.update', image)
|
||||
|
||||
def add(self, image):
|
||||
super(ImageRepoProxy, self).add(image)
|
||||
self.send_notification('image.create', image)
|
||||
|
||||
def remove(self, image):
|
||||
super(ImageRepoProxy, self).remove(image)
|
||||
self.send_notification('image.delete', image, extra_payload={
|
||||
'deleted': True, 'deleted_at': timeutils.isotime()
|
||||
})
|
||||
|
||||
|
||||
class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
|
||||
def __init__(self, task_factory, context, notifier):
|
||||
kwargs = {'context': context, 'notifier': notifier}
|
||||
super(TaskFactoryProxy, self).__init__(
|
||||
task_factory,
|
||||
task_proxy_class=TaskProxy,
|
||||
task_proxy_kwargs=kwargs)
|
||||
class TaskProxy(NotificationProxy, domain_proxy.Task):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.Task
|
||||
|
||||
|
||||
class TaskProxy(glance.domain.proxy.Task):
|
||||
|
||||
def __init__(self, task, context, notifier):
|
||||
self.task = task
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
super(TaskProxy, self).__init__(task)
|
||||
def get_payload(self, obj):
|
||||
return format_task_notification(obj)
|
||||
|
||||
def begin_processing(self):
|
||||
self.notifier.info(
|
||||
'task.processing',
|
||||
format_task_notification(self.task)
|
||||
)
|
||||
return super(TaskProxy, self).begin_processing()
|
||||
super(TaskProxy, self).begin_processing()
|
||||
self.send_notification('task.processing', self.repo)
|
||||
|
||||
def succeed(self, result):
|
||||
self.notifier.info('task.success',
|
||||
format_task_notification(self.task))
|
||||
return super(TaskProxy, self).succeed(result)
|
||||
super(TaskProxy, self).succeed(result)
|
||||
self.send_notification('task.success', self.repo)
|
||||
|
||||
def fail(self, message):
|
||||
self.notifier.info('task.failure',
|
||||
format_task_notification(self.task))
|
||||
return super(TaskProxy, self).fail(message)
|
||||
super(TaskProxy, self).fail(message)
|
||||
self.send_notification('task.failure', self.repo)
|
||||
|
||||
def run(self, executor):
|
||||
self.notifier.info('task.run',
|
||||
format_task_notification(self.task))
|
||||
return super(TaskProxy, self).run(executor)
|
||||
super(TaskProxy, self).run(executor)
|
||||
self.send_notification('task.run', self.repo)
|
||||
|
||||
|
||||
class TaskStubProxy(glance.domain.proxy.TaskStub):
|
||||
class TaskFactoryProxy(NotificationFactoryProxy, domain_proxy.TaskFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.TaskFactory
|
||||
|
||||
def __init__(self, task, context, notifier):
|
||||
self.task = task
|
||||
self.context = context
|
||||
self.notifier = notifier
|
||||
super(TaskStubProxy, self).__init__(task)
|
||||
def get_proxy_class(self):
|
||||
return TaskProxy
|
||||
|
||||
|
||||
class TaskRepoProxy(NotificationRepoProxy, domain_proxy.TaskRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.TaskRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return TaskProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_task_notification(obj)
|
||||
|
||||
def add(self, task):
|
||||
result = super(TaskRepoProxy, self).add(task)
|
||||
self.send_notification('task.create', task)
|
||||
return result
|
||||
|
||||
def remove(self, task):
|
||||
result = super(TaskRepoProxy, self).remove(task)
|
||||
self.send_notification('task.delete', task, extra_payload={
|
||||
'deleted': True, 'deleted_at': timeutils.isotime()
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
class TaskStubProxy(NotificationProxy, domain_proxy.TaskStub):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.TaskStub
|
||||
|
||||
|
||||
class TaskStubRepoProxy(NotificationRepoProxy, domain_proxy.TaskStubRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.TaskStubRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return TaskStubProxy
|
||||
|
||||
|
||||
class MetadefNamespaceProxy(NotificationProxy, domain_proxy.MetadefNamespace):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefNamespace
|
||||
|
||||
|
||||
class MetadefNamespaceFactoryProxy(NotificationFactoryProxy,
|
||||
domain_proxy.MetadefNamespaceFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefNamespaceFactory
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefNamespaceProxy
|
||||
|
||||
|
||||
class MetadefNamespaceRepoProxy(NotificationRepoProxy,
|
||||
domain_proxy.MetadefNamespaceRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefNamespaceRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefNamespaceProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_metadef_namespace_notification(obj)
|
||||
|
||||
def save(self, metadef_namespace):
|
||||
name = getattr(metadef_namespace, '_old_namespace',
|
||||
metadef_namespace.namespace)
|
||||
result = super(MetadefNamespaceRepoProxy, self).save(metadef_namespace)
|
||||
self.send_notification(
|
||||
'metadef_namespace.update', metadef_namespace,
|
||||
extra_payload={
|
||||
'namespace_old': name,
|
||||
})
|
||||
return result
|
||||
|
||||
def add(self, metadef_namespace):
|
||||
result = super(MetadefNamespaceRepoProxy, self).add(metadef_namespace)
|
||||
self.send_notification('metadef_namespace.create', metadef_namespace)
|
||||
return result
|
||||
|
||||
def remove(self, metadef_namespace):
|
||||
result = super(MetadefNamespaceRepoProxy, self).remove(
|
||||
metadef_namespace)
|
||||
self.send_notification(
|
||||
'metadef_namespace.delete', metadef_namespace,
|
||||
extra_payload={'deleted': True, 'deleted_at': timeutils.isotime()}
|
||||
)
|
||||
return result
|
||||
|
||||
def remove_objects(self, metadef_namespace):
|
||||
result = super(MetadefNamespaceRepoProxy, self).remove_objects(
|
||||
metadef_namespace)
|
||||
self.send_notification('metadef_namespace.delete_objects',
|
||||
metadef_namespace)
|
||||
return result
|
||||
|
||||
def remove_properties(self, metadef_namespace):
|
||||
result = super(MetadefNamespaceRepoProxy, self).remove_properties(
|
||||
metadef_namespace)
|
||||
self.send_notification('metadef_namespace.delete_properties',
|
||||
metadef_namespace)
|
||||
return result
|
||||
|
||||
def remove_tags(self, metadef_namespace):
|
||||
result = super(MetadefNamespaceRepoProxy, self).remove_tags(
|
||||
metadef_namespace)
|
||||
self.send_notification('metadef_namespace.delete_tags',
|
||||
metadef_namespace)
|
||||
return result
|
||||
|
||||
|
||||
class MetadefObjectProxy(NotificationProxy, domain_proxy.MetadefObject):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefObject
|
||||
|
||||
|
||||
class MetadefObjectFactoryProxy(NotificationFactoryProxy,
|
||||
domain_proxy.MetadefObjectFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefObjectFactory
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefObjectProxy
|
||||
|
||||
|
||||
class MetadefObjectRepoProxy(NotificationRepoProxy,
|
||||
domain_proxy.MetadefObjectRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefObjectRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefObjectProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_metadef_object_notification(obj)
|
||||
|
||||
def save(self, metadef_object):
|
||||
name = getattr(metadef_object, '_old_name', metadef_object.name)
|
||||
result = super(MetadefObjectRepoProxy, self).save(metadef_object)
|
||||
self.send_notification(
|
||||
'metadef_object.update', metadef_object,
|
||||
extra_payload={
|
||||
'namespace': metadef_object.namespace.namespace,
|
||||
'name_old': name,
|
||||
})
|
||||
return result
|
||||
|
||||
def add(self, metadef_object):
|
||||
result = super(MetadefObjectRepoProxy, self).add(metadef_object)
|
||||
self.send_notification('metadef_object.create', metadef_object)
|
||||
return result
|
||||
|
||||
def remove(self, metadef_object):
|
||||
result = super(MetadefObjectRepoProxy, self).remove(metadef_object)
|
||||
self.send_notification(
|
||||
'metadef_object.delete', metadef_object,
|
||||
extra_payload={
|
||||
'deleted': True,
|
||||
'deleted_at': timeutils.isotime(),
|
||||
'namespace': metadef_object.namespace.namespace
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
class MetadefPropertyProxy(NotificationProxy, domain_proxy.MetadefProperty):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefProperty
|
||||
|
||||
|
||||
class MetadefPropertyFactoryProxy(NotificationFactoryProxy,
|
||||
domain_proxy.MetadefPropertyFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefPropertyFactory
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefPropertyProxy
|
||||
|
||||
|
||||
class MetadefPropertyRepoProxy(NotificationRepoProxy,
|
||||
domain_proxy.MetadefPropertyRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefPropertyRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefPropertyProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_metadef_property_notification(obj)
|
||||
|
||||
def save(self, metadef_property):
|
||||
name = getattr(metadef_property, '_old_name', metadef_property.name)
|
||||
result = super(MetadefPropertyRepoProxy, self).save(metadef_property)
|
||||
self.send_notification(
|
||||
'metadef_property.update', metadef_property,
|
||||
extra_payload={
|
||||
'namespace': metadef_property.namespace.namespace,
|
||||
'name_old': name,
|
||||
})
|
||||
return result
|
||||
|
||||
def add(self, metadef_property):
|
||||
result = super(MetadefPropertyRepoProxy, self).add(metadef_property)
|
||||
self.send_notification('metadef_property.create', metadef_property)
|
||||
return result
|
||||
|
||||
def remove(self, metadef_property):
|
||||
result = super(MetadefPropertyRepoProxy, self).remove(metadef_property)
|
||||
self.send_notification(
|
||||
'metadef_property.delete', metadef_property,
|
||||
extra_payload={
|
||||
'deleted': True,
|
||||
'deleted_at': timeutils.isotime(),
|
||||
'namespace': metadef_property.namespace.namespace
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
class MetadefResourceTypeProxy(NotificationProxy,
|
||||
domain_proxy.MetadefResourceType):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefResourceType
|
||||
|
||||
|
||||
class MetadefResourceTypeFactoryProxy(NotificationFactoryProxy,
|
||||
domain_proxy.MetadefResourceTypeFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefResourceTypeFactory
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefResourceTypeProxy
|
||||
|
||||
|
||||
class MetadefResourceTypeRepoProxy(NotificationRepoProxy,
|
||||
domain_proxy.MetadefResourceTypeRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefResourceTypeRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefResourceTypeProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_metadef_resource_type_notification(obj)
|
||||
|
||||
def add(self, md_resource_type):
|
||||
result = super(MetadefResourceTypeRepoProxy, self).add(
|
||||
md_resource_type)
|
||||
self.send_notification('metadef_resource_type.create',
|
||||
md_resource_type)
|
||||
return result
|
||||
|
||||
def remove(self, md_resource_type):
|
||||
result = super(MetadefResourceTypeRepoProxy, self).remove(
|
||||
md_resource_type)
|
||||
self.send_notification(
|
||||
'metadef_resource_type.delete', md_resource_type,
|
||||
extra_payload={
|
||||
'deleted': True,
|
||||
'deleted_at': timeutils.isotime(),
|
||||
'namespace': md_resource_type.namespace.namespace
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
class MetadefTagProxy(NotificationProxy, domain_proxy.MetadefTag):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefTag
|
||||
|
||||
|
||||
class MetadefTagFactoryProxy(NotificationFactoryProxy,
|
||||
domain_proxy.MetadefTagFactory):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefTagFactory
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefTagProxy
|
||||
|
||||
|
||||
class MetadefTagRepoProxy(NotificationRepoProxy, domain_proxy.MetadefTagRepo):
|
||||
def get_super_class(self):
|
||||
return domain_proxy.MetadefTagRepo
|
||||
|
||||
def get_proxy_class(self):
|
||||
return MetadefTagProxy
|
||||
|
||||
def get_payload(self, obj):
|
||||
return format_metadef_tag_notification(obj)
|
||||
|
||||
def save(self, metadef_tag):
|
||||
name = getattr(metadef_tag, '_old_name', metadef_tag.name)
|
||||
result = super(MetadefTagRepoProxy, self).save(metadef_tag)
|
||||
self.send_notification(
|
||||
'metadef_tag.update', metadef_tag,
|
||||
extra_payload={
|
||||
'namespace': metadef_tag.namespace.namespace,
|
||||
'name_old': name,
|
||||
})
|
||||
return result
|
||||
|
||||
def add(self, metadef_tag):
|
||||
result = super(MetadefTagRepoProxy, self).add(metadef_tag)
|
||||
self.send_notification('metadef_tag.create', metadef_tag)
|
||||
return result
|
||||
|
||||
def add_tags(self, metadef_tags):
|
||||
result = super(MetadefTagRepoProxy, self).add_tags(metadef_tags)
|
||||
for metadef_tag in metadef_tags:
|
||||
self.send_notification('metadef_tag.create', metadef_tag)
|
||||
|
||||
return result
|
||||
|
||||
def remove(self, metadef_tag):
|
||||
result = super(MetadefTagRepoProxy, self).remove(metadef_tag)
|
||||
self.send_notification(
|
||||
'metadef_tag.delete', metadef_tag,
|
||||
extra_payload={
|
||||
'deleted': True,
|
||||
'deleted_at': timeutils.isotime(),
|
||||
'namespace': metadef_tag.namespace.namespace
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
@ -173,12 +173,12 @@ class TestImageNotifications(utils.BaseTestCase):
|
||||
def test_image_get(self):
|
||||
image = self.image_repo_proxy.get(UUID1)
|
||||
self.assertIsInstance(image, glance.notifier.ImageProxy)
|
||||
self.assertEqual('image_from_get', image.image)
|
||||
self.assertEqual('image_from_get', image.repo)
|
||||
|
||||
def test_image_list(self):
|
||||
images = self.image_repo_proxy.list()
|
||||
self.assertIsInstance(images[0], glance.notifier.ImageProxy)
|
||||
self.assertEqual('images_from_list', images[0].image)
|
||||
self.assertEqual('images_from_list', images[0].repo)
|
||||
|
||||
def test_image_get_data_should_call_next_image_get_data(self):
|
||||
with mock.patch.object(self.image, 'get_data') as get_data_mock:
|
||||
|
@ -146,6 +146,7 @@ class OptsTestCase(utils.BaseTestCase):
|
||||
'public_endpoint',
|
||||
'digest_algorithm',
|
||||
'http_keepalive',
|
||||
'disabled_notifications',
|
||||
]
|
||||
|
||||
self._check_opt_groups(opt_list, expected_opt_groups)
|
||||
|
@ -600,6 +600,20 @@ class TestImagesController(base.IsolatedUnitTest):
|
||||
self.assertEqual('image.create', output_log['event_type'])
|
||||
self.assertEqual('image-1', output_log['payload']['name'])
|
||||
|
||||
def test_create_disabled_notification(self):
|
||||
self.config(disabled_notifications=["image.create"])
|
||||
request = unit_test_utils.get_fake_request()
|
||||
image = {'name': 'image-1'}
|
||||
output = self.controller.create(request, image=image,
|
||||
extra_properties={},
|
||||
tags=[])
|
||||
self.assertEqual('image-1', output.name)
|
||||
self.assertEqual({}, output.extra_properties)
|
||||
self.assertEqual(set([]), output.tags)
|
||||
self.assertEqual('private', output.visibility)
|
||||
output_logs = self.notifier.get_logs()
|
||||
self.assertEqual(0, len(output_logs))
|
||||
|
||||
def test_create_with_properties(self):
|
||||
request = unit_test_utils.get_fake_request()
|
||||
image_properties = {'foo': 'bar'}
|
||||
@ -1781,6 +1795,17 @@ class TestImagesController(base.IsolatedUnitTest):
|
||||
self.assertEqual('image.update', output_log['event_type'])
|
||||
self.assertEqual(UUID1, output_log['payload']['id'])
|
||||
|
||||
def test_update_disabled_notification(self):
|
||||
self.config(disabled_notifications=["image.update"])
|
||||
request = unit_test_utils.get_fake_request()
|
||||
changes = [
|
||||
{'op': 'replace', 'path': ['name'], 'value': 'Ping Pong'},
|
||||
]
|
||||
output = self.controller.update(request, UUID1, changes)
|
||||
self.assertEqual('Ping Pong', output.name)
|
||||
output_logs = self.notifier.get_logs()
|
||||
self.assertEqual(0, len(output_logs))
|
||||
|
||||
def test_delete(self):
|
||||
request = unit_test_utils.get_fake_request()
|
||||
self.assertIn('%s/%s' % (BASE_URI, UUID1), self.store.data)
|
||||
@ -1800,6 +1825,23 @@ class TestImagesController(base.IsolatedUnitTest):
|
||||
self.assertEqual('deleted', deleted_img['status'])
|
||||
self.assertNotIn('%s/%s' % (BASE_URI, UUID1), self.store.data)
|
||||
|
||||
def test_delete_disabled_notification(self):
|
||||
self.config(disabled_notifications=["image.delete"])
|
||||
request = unit_test_utils.get_fake_request()
|
||||
self.assertIn('%s/%s' % (BASE_URI, UUID1), self.store.data)
|
||||
try:
|
||||
self.controller.delete(request, UUID1)
|
||||
output_logs = self.notifier.get_logs()
|
||||
self.assertEqual(0, len(output_logs))
|
||||
except Exception as e:
|
||||
self.fail("Delete raised exception: %s" % e)
|
||||
|
||||
deleted_img = self.db.image_get(request.context, UUID1,
|
||||
force_show_deleted=True)
|
||||
self.assertTrue(deleted_img['deleted'])
|
||||
self.assertEqual('deleted', deleted_img['status'])
|
||||
self.assertNotIn('%s/%s' % (BASE_URI, UUID1), self.store.data)
|
||||
|
||||
def test_delete_queued_updates_status(self):
|
||||
"""Ensure status of queued image is updated (LP bug #1048851)"""
|
||||
request = unit_test_utils.get_fake_request(is_admin=True)
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user