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
|
For more information see :doc:`Glance notifications <notifications>` and
|
||||||
`oslo.messaging <http://docs.openstack.org/developer/oslo.messaging/>`_.
|
`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
|
Configuring Glance Property Protections
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
@ -220,6 +220,15 @@ registry_client_protocol = http
|
|||||||
# Default publisher_id for outgoing notifications.
|
# Default publisher_id for outgoing notifications.
|
||||||
# default_publisher_id = image.localhost
|
# 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
|
# Messaging driver used for 'messaging' notifications driver
|
||||||
# rpc_backend = 'rabbit'
|
# rpc_backend = 'rabbit'
|
||||||
|
|
||||||
|
@ -48,10 +48,12 @@ CONF = cfg.CONF
|
|||||||
|
|
||||||
|
|
||||||
class NamespaceController(object):
|
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.db_api = db_api or glance.db.get_api()
|
||||||
self.policy = policy_enforcer or policy.Enforcer()
|
self.policy = policy_enforcer or policy.Enforcer()
|
||||||
|
self.notifier = notifier or glance.notifier.Notifier()
|
||||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||||
|
notifier=self.notifier,
|
||||||
policy_enforcer=self.policy)
|
policy_enforcer=self.policy)
|
||||||
self.ns_schema_link = '/v2/schemas/metadefs/namespace'
|
self.ns_schema_link = '/v2/schemas/metadefs/namespace'
|
||||||
self.obj_schema_link = '/v2/schemas/metadefs/object'
|
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)
|
namespace_repo = self.gateway.get_metadef_namespace_repo(req.context)
|
||||||
try:
|
try:
|
||||||
ns_obj = namespace_repo.get(namespace)
|
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.namespace = wsme_utils._get_value(user_ns.namespace)
|
||||||
ns_obj.display_name = wsme_utils._get_value(user_ns.display_name)
|
ns_obj.display_name = wsme_utils._get_value(user_ns.display_name)
|
||||||
ns_obj.description = wsme_utils._get_value(user_ns.description)
|
ns_obj.description = wsme_utils._get_value(user_ns.description)
|
||||||
|
@ -42,10 +42,12 @@ CONF = cfg.CONF
|
|||||||
|
|
||||||
|
|
||||||
class MetadefObjectsController(object):
|
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.db_api = db_api or glance.db.get_api()
|
||||||
self.policy = policy_enforcer or policy.Enforcer()
|
self.policy = policy_enforcer or policy.Enforcer()
|
||||||
|
self.notifier = notifier or glance.notifier.Notifier()
|
||||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||||
|
notifier=self.notifier,
|
||||||
policy_enforcer=self.policy)
|
policy_enforcer=self.policy)
|
||||||
self.obj_schema_link = '/v2/schemas/metadefs/object'
|
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)
|
meta_repo = self.gateway.get_metadef_object_repo(req.context)
|
||||||
try:
|
try:
|
||||||
metadef_object = meta_repo.get(namespace, object_name)
|
metadef_object = meta_repo.get(namespace, object_name)
|
||||||
|
metadef_object._old_name = metadef_object.name
|
||||||
metadef_object.name = wsme_utils._get_value(
|
metadef_object.name = wsme_utils._get_value(
|
||||||
metadata_object.name)
|
metadata_object.name)
|
||||||
metadef_object.description = wsme_utils._get_value(
|
metadef_object.description = wsme_utils._get_value(
|
||||||
|
@ -40,10 +40,12 @@ _LI = i18n._LI
|
|||||||
|
|
||||||
|
|
||||||
class NamespacePropertiesController(object):
|
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.db_api = db_api or glance.db.get_api()
|
||||||
self.policy = policy_enforcer or policy.Enforcer()
|
self.policy = policy_enforcer or policy.Enforcer()
|
||||||
|
self.notifier = notifier or glance.notifier.Notifier()
|
||||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||||
|
notifier=self.notifier,
|
||||||
policy_enforcer=self.policy)
|
policy_enforcer=self.policy)
|
||||||
|
|
||||||
def _to_dict(self, model_property_type):
|
def _to_dict(self, model_property_type):
|
||||||
@ -131,6 +133,7 @@ class NamespacePropertiesController(object):
|
|||||||
prop_repo = self.gateway.get_metadef_property_repo(req.context)
|
prop_repo = self.gateway.get_metadef_property_repo(req.context)
|
||||||
try:
|
try:
|
||||||
db_property_type = prop_repo.get(namespace, property_name)
|
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.name = property_type.name
|
||||||
db_property_type.schema = (self._to_dict(property_type))['schema']
|
db_property_type.schema = (self._to_dict(property_type))['schema']
|
||||||
updated_property_type = prop_repo.save(db_property_type)
|
updated_property_type = prop_repo.save(db_property_type)
|
||||||
|
@ -40,10 +40,12 @@ _LI = i18n._LI
|
|||||||
|
|
||||||
|
|
||||||
class ResourceTypeController(object):
|
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.db_api = db_api or glance.db.get_api()
|
||||||
self.policy = policy_enforcer or policy.Enforcer()
|
self.policy = policy_enforcer or policy.Enforcer()
|
||||||
|
self.notifier = notifier or glance.notifier.Notifier()
|
||||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||||
|
notifier=self.notifier,
|
||||||
policy_enforcer=self.policy)
|
policy_enforcer=self.policy)
|
||||||
|
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
|
@ -41,10 +41,12 @@ CONF = cfg.CONF
|
|||||||
|
|
||||||
|
|
||||||
class TagsController(object):
|
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.db_api = db_api or glance.db.get_api()
|
||||||
self.policy = policy_enforcer or policy.Enforcer()
|
self.policy = policy_enforcer or policy.Enforcer()
|
||||||
|
self.notifier = notifier or glance.notifier.Notifier()
|
||||||
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
self.gateway = glance.gateway.Gateway(db_api=self.db_api,
|
||||||
|
notifier=self.notifier,
|
||||||
policy_enforcer=self.policy)
|
policy_enforcer=self.policy)
|
||||||
self.tag_schema_link = '/v2/schemas/metadefs/tag'
|
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)
|
meta_repo = self.gateway.get_metadef_tag_repo(req.context)
|
||||||
try:
|
try:
|
||||||
metadef_tag = meta_repo.get(namespace, tag_name)
|
metadef_tag = meta_repo.get(namespace, tag_name)
|
||||||
|
metadef_tag._old_name = metadef_tag.name
|
||||||
metadef_tag.name = wsme_utils._get_value(
|
metadef_tag.name = wsme_utils._get_value(
|
||||||
metadata_tag.name)
|
metadata_tag.name)
|
||||||
updated_metadata_tag = meta_repo.save(metadef_tag)
|
updated_metadata_tag = meta_repo.save(metadef_tag)
|
||||||
|
@ -1060,6 +1060,15 @@ def _task_info_get(task_id):
|
|||||||
return task_info
|
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
|
@log_call
|
||||||
def metadef_namespace_create(context, values):
|
def metadef_namespace_create(context, values):
|
||||||
"""Create a namespace object"""
|
"""Create a namespace object"""
|
||||||
@ -1374,6 +1383,13 @@ def metadef_object_delete(context, namespace_name, object_name):
|
|||||||
return object
|
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
|
@log_call
|
||||||
def metadef_object_count(context, namespace_name):
|
def metadef_object_count(context, namespace_name):
|
||||||
"""Get metadef object count in a namespace"""
|
"""Get metadef object count in a namespace"""
|
||||||
@ -1550,6 +1566,14 @@ def metadef_property_delete(context, namespace_name, property_name):
|
|||||||
return property
|
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
|
@log_call
|
||||||
def metadef_resource_type_create(context, values):
|
def metadef_resource_type_create(context, values):
|
||||||
"""Create a metadef resource type"""
|
"""Create a metadef resource type"""
|
||||||
@ -1863,6 +1887,13 @@ def metadef_tag_delete(context, namespace_name, name):
|
|||||||
return tags
|
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
|
@log_call
|
||||||
def metadef_tag_count(context, namespace_name):
|
def metadef_tag_count(context, namespace_name):
|
||||||
"""Get metadef tag count in a namespace"""
|
"""Get metadef tag count in a namespace"""
|
||||||
|
@ -131,77 +131,103 @@ class Gateway(object):
|
|||||||
ns_factory = glance.domain.MetadefNamespaceFactory()
|
ns_factory = glance.domain.MetadefNamespaceFactory()
|
||||||
policy_ns_factory = policy.MetadefNamespaceFactoryProxy(
|
policy_ns_factory = policy.MetadefNamespaceFactoryProxy(
|
||||||
ns_factory, context, self.policy)
|
ns_factory, context, self.policy)
|
||||||
|
notifier_ns_factory = glance.notifier.MetadefNamespaceFactoryProxy(
|
||||||
|
policy_ns_factory, context, self.notifier)
|
||||||
authorized_ns_factory = authorization.MetadefNamespaceFactoryProxy(
|
authorized_ns_factory = authorization.MetadefNamespaceFactoryProxy(
|
||||||
policy_ns_factory, context)
|
notifier_ns_factory, context)
|
||||||
return authorized_ns_factory
|
return authorized_ns_factory
|
||||||
|
|
||||||
def get_metadef_namespace_repo(self, context):
|
def get_metadef_namespace_repo(self, context):
|
||||||
ns_repo = glance.db.MetadefNamespaceRepo(context, self.db_api)
|
ns_repo = glance.db.MetadefNamespaceRepo(context, self.db_api)
|
||||||
policy_ns_repo = policy.MetadefNamespaceRepoProxy(
|
policy_ns_repo = policy.MetadefNamespaceRepoProxy(
|
||||||
ns_repo, context, self.policy)
|
ns_repo, context, self.policy)
|
||||||
|
notifier_ns_repo = glance.notifier.MetadefNamespaceRepoProxy(
|
||||||
|
policy_ns_repo, context, self.notifier)
|
||||||
authorized_ns_repo = authorization.MetadefNamespaceRepoProxy(
|
authorized_ns_repo = authorization.MetadefNamespaceRepoProxy(
|
||||||
policy_ns_repo, context)
|
notifier_ns_repo, context)
|
||||||
return authorized_ns_repo
|
return authorized_ns_repo
|
||||||
|
|
||||||
def get_metadef_object_factory(self, context):
|
def get_metadef_object_factory(self, context):
|
||||||
object_factory = glance.domain.MetadefObjectFactory()
|
object_factory = glance.domain.MetadefObjectFactory()
|
||||||
policy_object_factory = policy.MetadefObjectFactoryProxy(
|
policy_object_factory = policy.MetadefObjectFactoryProxy(
|
||||||
object_factory, context, self.policy)
|
object_factory, context, self.policy)
|
||||||
|
notifier_object_factory = glance.notifier.MetadefObjectFactoryProxy(
|
||||||
|
policy_object_factory, context, self.notifier)
|
||||||
authorized_object_factory = authorization.MetadefObjectFactoryProxy(
|
authorized_object_factory = authorization.MetadefObjectFactoryProxy(
|
||||||
policy_object_factory, context)
|
notifier_object_factory, context)
|
||||||
return authorized_object_factory
|
return authorized_object_factory
|
||||||
|
|
||||||
def get_metadef_object_repo(self, context):
|
def get_metadef_object_repo(self, context):
|
||||||
object_repo = glance.db.MetadefObjectRepo(context, self.db_api)
|
object_repo = glance.db.MetadefObjectRepo(context, self.db_api)
|
||||||
policy_object_repo = policy.MetadefObjectRepoProxy(
|
policy_object_repo = policy.MetadefObjectRepoProxy(
|
||||||
object_repo, context, self.policy)
|
object_repo, context, self.policy)
|
||||||
|
notifier_object_repo = glance.notifier.MetadefObjectRepoProxy(
|
||||||
|
policy_object_repo, context, self.notifier)
|
||||||
authorized_object_repo = authorization.MetadefObjectRepoProxy(
|
authorized_object_repo = authorization.MetadefObjectRepoProxy(
|
||||||
policy_object_repo, context)
|
notifier_object_repo, context)
|
||||||
return authorized_object_repo
|
return authorized_object_repo
|
||||||
|
|
||||||
def get_metadef_resource_type_factory(self, context):
|
def get_metadef_resource_type_factory(self, context):
|
||||||
resource_type_factory = glance.domain.MetadefResourceTypeFactory()
|
resource_type_factory = glance.domain.MetadefResourceTypeFactory()
|
||||||
policy_resource_type_factory = policy.MetadefResourceTypeFactoryProxy(
|
policy_resource_type_factory = policy.MetadefResourceTypeFactoryProxy(
|
||||||
resource_type_factory, context, self.policy)
|
resource_type_factory, context, self.policy)
|
||||||
return authorization.MetadefResourceTypeFactoryProxy(
|
notifier_resource_type_factory = (
|
||||||
policy_resource_type_factory, context)
|
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):
|
def get_metadef_resource_type_repo(self, context):
|
||||||
resource_type_repo = glance.db.MetadefResourceTypeRepo(
|
resource_type_repo = glance.db.MetadefResourceTypeRepo(
|
||||||
context, self.db_api)
|
context, self.db_api)
|
||||||
policy_object_repo = policy.MetadefResourceTypeRepoProxy(
|
policy_object_repo = policy.MetadefResourceTypeRepoProxy(
|
||||||
resource_type_repo, context, self.policy)
|
resource_type_repo, context, self.policy)
|
||||||
return authorization.MetadefResourceTypeRepoProxy(policy_object_repo,
|
notifier_object_repo = glance.notifier.MetadefResourceTypeRepoProxy(
|
||||||
context)
|
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):
|
def get_metadef_property_factory(self, context):
|
||||||
prop_factory = glance.domain.MetadefPropertyFactory()
|
prop_factory = glance.domain.MetadefPropertyFactory()
|
||||||
policy_prop_factory = policy.MetadefPropertyFactoryProxy(
|
policy_prop_factory = policy.MetadefPropertyFactoryProxy(
|
||||||
prop_factory, context, self.policy)
|
prop_factory, context, self.policy)
|
||||||
|
notifier_prop_factory = glance.notifier.MetadefPropertyFactoryProxy(
|
||||||
|
policy_prop_factory, context, self.notifier)
|
||||||
authorized_prop_factory = authorization.MetadefPropertyFactoryProxy(
|
authorized_prop_factory = authorization.MetadefPropertyFactoryProxy(
|
||||||
policy_prop_factory, context)
|
notifier_prop_factory, context)
|
||||||
return authorized_prop_factory
|
return authorized_prop_factory
|
||||||
|
|
||||||
def get_metadef_property_repo(self, context):
|
def get_metadef_property_repo(self, context):
|
||||||
prop_repo = glance.db.MetadefPropertyRepo(context, self.db_api)
|
prop_repo = glance.db.MetadefPropertyRepo(context, self.db_api)
|
||||||
policy_prop_repo = policy.MetadefPropertyRepoProxy(
|
policy_prop_repo = policy.MetadefPropertyRepoProxy(
|
||||||
prop_repo, context, self.policy)
|
prop_repo, context, self.policy)
|
||||||
|
notifier_prop_repo = glance.notifier.MetadefPropertyRepoProxy(
|
||||||
|
policy_prop_repo, context, self.notifier)
|
||||||
authorized_prop_repo = authorization.MetadefPropertyRepoProxy(
|
authorized_prop_repo = authorization.MetadefPropertyRepoProxy(
|
||||||
policy_prop_repo, context)
|
notifier_prop_repo, context)
|
||||||
return authorized_prop_repo
|
return authorized_prop_repo
|
||||||
|
|
||||||
def get_metadef_tag_factory(self, context):
|
def get_metadef_tag_factory(self, context):
|
||||||
tag_factory = glance.domain.MetadefTagFactory()
|
tag_factory = glance.domain.MetadefTagFactory()
|
||||||
policy_tag_factory = policy.MetadefTagFactoryProxy(
|
policy_tag_factory = policy.MetadefTagFactoryProxy(
|
||||||
tag_factory, context, self.policy)
|
tag_factory, context, self.policy)
|
||||||
|
notifier_tag_factory = glance.notifier.MetadefTagFactoryProxy(
|
||||||
|
policy_tag_factory, context, self.notifier)
|
||||||
authorized_tag_factory = authorization.MetadefTagFactoryProxy(
|
authorized_tag_factory = authorization.MetadefTagFactoryProxy(
|
||||||
policy_tag_factory, context)
|
notifier_tag_factory, context)
|
||||||
return authorized_tag_factory
|
return authorized_tag_factory
|
||||||
|
|
||||||
def get_metadef_tag_repo(self, context):
|
def get_metadef_tag_repo(self, context):
|
||||||
tag_repo = glance.db.MetadefTagRepo(context, self.db_api)
|
tag_repo = glance.db.MetadefTagRepo(context, self.db_api)
|
||||||
policy_tag_repo = policy.MetadefTagRepoProxy(
|
policy_tag_repo = policy.MetadefTagRepoProxy(
|
||||||
tag_repo, context, self.policy)
|
tag_repo, context, self.policy)
|
||||||
|
notifier_tag_repo = glance.notifier.MetadefTagRepoProxy(
|
||||||
|
policy_tag_repo, context, self.notifier)
|
||||||
authorized_tag_repo = authorization.MetadefTagRepoProxy(
|
authorized_tag_repo = authorization.MetadefTagRepoProxy(
|
||||||
policy_tag_repo, context)
|
notifier_tag_repo, context)
|
||||||
return authorized_tag_repo
|
return authorized_tag_repo
|
||||||
|
@ -14,16 +14,19 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
import glance_store
|
import glance_store
|
||||||
from oslo import messaging
|
from oslo import messaging
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
|
import six
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
import glance.domain.proxy
|
from glance.domain import proxy as domain_proxy
|
||||||
from glance import i18n
|
from glance import i18n
|
||||||
import glance.openstack.common.log as logging
|
import glance.openstack.common.log as logging
|
||||||
|
|
||||||
@ -32,6 +35,15 @@ _ = i18n._
|
|||||||
notifier_opts = [
|
notifier_opts = [
|
||||||
cfg.StrOpt('default_publisher_id', default="image.localhost",
|
cfg.StrOpt('default_publisher_id', default="image.localhost",
|
||||||
help='Default publisher_id for outgoing notifications.'),
|
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
|
CONF = cfg.CONF
|
||||||
@ -69,6 +81,27 @@ class Notifier(object):
|
|||||||
self._notifier.error({}, event_type, payload)
|
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):
|
def format_image_notification(image):
|
||||||
"""
|
"""
|
||||||
Given a glance.domain.Image object, return a dictionary of relevant
|
Given a glance.domain.Image object, return a dictionary of relevant
|
||||||
@ -100,70 +133,211 @@ def format_image_notification(image):
|
|||||||
def format_task_notification(task):
|
def format_task_notification(task):
|
||||||
# NOTE(nikhil): input is not passed to the notifier payload as it may
|
# NOTE(nikhil): input is not passed to the notifier payload as it may
|
||||||
# contain sensitive info.
|
# contain sensitive info.
|
||||||
return {'id': task.task_id,
|
return {
|
||||||
'type': task.type,
|
'id': task.task_id,
|
||||||
'status': task.status,
|
'type': task.type,
|
||||||
'result': None,
|
'status': task.status,
|
||||||
'owner': task.owner,
|
'result': None,
|
||||||
'message': None,
|
'owner': task.owner,
|
||||||
'expires_at': timeutils.isotime(task.expires_at),
|
'message': None,
|
||||||
'created_at': timeutils.isotime(task.created_at),
|
'expires_at': timeutils.isotime(task.expires_at),
|
||||||
'updated_at': timeutils.isotime(task.updated_at),
|
'created_at': timeutils.isotime(task.created_at),
|
||||||
'deleted': False,
|
'updated_at': timeutils.isotime(task.updated_at),
|
||||||
'deleted_at': None,
|
'deleted': False,
|
||||||
}
|
'deleted_at': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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.context = context
|
||||||
self.notifier = notifier
|
self.notifier = notifier
|
||||||
proxy_kwargs = {'context': self.context, 'notifier': self.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):
|
proxy_class = self.get_proxy_class()
|
||||||
super(ImageRepoProxy, self).save(image, from_state=from_state)
|
super_class = self.get_super_class()
|
||||||
self.notifier.info('image.update',
|
super_class.__init__(self, repo, proxy_class, proxy_kwargs)
|
||||||
format_image_notification(image))
|
|
||||||
|
|
||||||
def add(self, image):
|
@abc.abstractmethod
|
||||||
super(ImageRepoProxy, self).add(image)
|
def get_super_class(self):
|
||||||
self.notifier.info('image.create',
|
pass
|
||||||
format_image_notification(image))
|
|
||||||
|
|
||||||
def remove(self, image):
|
@abc.abstractmethod
|
||||||
super(ImageRepoProxy, self).remove(image)
|
def get_proxy_class(self):
|
||||||
payload = format_image_notification(image)
|
pass
|
||||||
payload['deleted'] = True
|
|
||||||
payload['deleted_at'] = timeutils.isotime()
|
|
||||||
self.notifier.info('image.delete', payload)
|
|
||||||
|
|
||||||
|
|
||||||
class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class NotificationFactoryProxy(object):
|
||||||
def __init__(self, factory, context, notifier):
|
def __init__(self, factory, context, notifier):
|
||||||
kwargs = {'context': context, 'notifier': notifier}
|
kwargs = {'context': context, 'notifier': notifier}
|
||||||
super(ImageFactoryProxy, self).__init__(factory,
|
|
||||||
proxy_class=ImageProxy,
|
proxy_class = self.get_proxy_class()
|
||||||
proxy_kwargs=kwargs)
|
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):
|
def get_payload(self, obj):
|
||||||
self.image = image
|
return format_image_notification(obj)
|
||||||
self.context = context
|
|
||||||
self.notifier = notifier
|
|
||||||
super(ImageProxy, self).__init__(image)
|
|
||||||
|
|
||||||
def _format_image_send(self, bytes_sent):
|
def _format_image_send(self, bytes_sent):
|
||||||
return {
|
return {
|
||||||
'bytes_sent': bytes_sent,
|
'bytes_sent': bytes_sent,
|
||||||
'image_id': self.image.image_id,
|
'image_id': self.repo.image_id,
|
||||||
'owner_id': self.image.owner,
|
'owner_id': self.repo.owner,
|
||||||
'receiver_tenant_id': self.context.tenant,
|
'receiver_tenant_id': self.context.tenant,
|
||||||
'receiver_user_id': self.context.user,
|
'receiver_user_id': self.context.user,
|
||||||
}
|
}
|
||||||
@ -174,14 +348,14 @@ class ImageProxy(glance.domain.proxy.Image):
|
|||||||
yield chunk
|
yield chunk
|
||||||
sent += len(chunk)
|
sent += len(chunk)
|
||||||
|
|
||||||
if sent != (chunk_size or self.image.size):
|
if sent != (chunk_size or self.repo.size):
|
||||||
notify = self.notifier.error
|
notify = self.notifier.error
|
||||||
else:
|
else:
|
||||||
notify = self.notifier.info
|
notify = self.notifier.info
|
||||||
|
|
||||||
try:
|
try:
|
||||||
notify('image.send',
|
_send_notification(notify, 'image.send',
|
||||||
self._format_image_send(sent))
|
self._format_image_send(sent))
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = (_("An error occurred during image.send"
|
msg = (_("An error occurred during image.send"
|
||||||
" notification: %(err)s") % {'err': err})
|
" notification: %(err)s") % {'err': err})
|
||||||
@ -191,152 +365,454 @@ class ImageProxy(glance.domain.proxy.Image):
|
|||||||
# Due to the need of evaluating subsequent proxies, this one
|
# Due to the need of evaluating subsequent proxies, this one
|
||||||
# should return a generator, the call should be done before
|
# should return a generator, the call should be done before
|
||||||
# generator creation
|
# 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)
|
return self._get_chunk_data_iterator(data, chunk_size=chunk_size)
|
||||||
|
|
||||||
def set_data(self, data, size=None):
|
def set_data(self, data, size=None):
|
||||||
payload = format_image_notification(self.image)
|
self.send_notification('image.prepare', self.repo)
|
||||||
self.notifier.info('image.prepare', payload)
|
|
||||||
|
notify_error = self.notifier.error
|
||||||
try:
|
try:
|
||||||
self.image.set_data(data, size)
|
self.repo.set_data(data, size)
|
||||||
except glance_store.StorageFull as e:
|
except glance_store.StorageFull as e:
|
||||||
msg = (_("Image storage media is full: %s") %
|
msg = (_("Image storage media is full: %s") %
|
||||||
utils.exception_to_str(e))
|
utils.exception_to_str(e))
|
||||||
self.notifier.error('image.upload', msg)
|
_send_notification(notify_error, 'image.upload', msg)
|
||||||
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
|
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
|
||||||
except glance_store.StorageWriteDenied as e:
|
except glance_store.StorageWriteDenied as e:
|
||||||
msg = (_("Insufficient permissions on image storage media: %s")
|
msg = (_("Insufficient permissions on image storage media: %s")
|
||||||
% utils.exception_to_str(e))
|
% utils.exception_to_str(e))
|
||||||
self.notifier.error('image.upload', msg)
|
_send_notification(notify_error, 'image.upload', msg)
|
||||||
raise webob.exc.HTTPServiceUnavailable(explanation=msg)
|
raise webob.exc.HTTPServiceUnavailable(explanation=msg)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
msg = (_("Cannot save data for image %(image_id)s: %(error)s") %
|
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)})
|
'error': utils.exception_to_str(e)})
|
||||||
self.notifier.error('image.upload', msg)
|
_send_notification(notify_error, 'image.upload', msg)
|
||||||
raise webob.exc.HTTPBadRequest(
|
raise webob.exc.HTTPBadRequest(
|
||||||
explanation=utils.exception_to_str(e))
|
explanation=utils.exception_to_str(e))
|
||||||
except exception.Duplicate as e:
|
except exception.Duplicate as e:
|
||||||
msg = (_("Unable to upload duplicate image data for image"
|
msg = (_("Unable to upload duplicate image data for image"
|
||||||
"%(image_id)s: %(error)s") %
|
"%(image_id)s: %(error)s") %
|
||||||
{'image_id': self.image.image_id,
|
{'image_id': self.repo.image_id,
|
||||||
'error': utils.exception_to_str(e)})
|
'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)
|
raise webob.exc.HTTPConflict(explanation=msg)
|
||||||
except exception.Forbidden as e:
|
except exception.Forbidden as e:
|
||||||
msg = (_("Not allowed to upload image data for image %(image_id)s:"
|
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)})
|
'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)
|
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||||
except exception.NotFound as e:
|
except exception.NotFound as e:
|
||||||
msg = (_("Image %(image_id)s could not be found after upload."
|
msg = (_("Image %(image_id)s could not be found after upload."
|
||||||
" The image may have been deleted during the 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)})
|
'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))
|
raise webob.exc.HTTPNotFound(explanation=utils.exception_to_str(e))
|
||||||
except webob.exc.HTTPError as e:
|
except webob.exc.HTTPError as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
msg = (_("Failed to upload image data for image %(image_id)s"
|
msg = (_("Failed to upload image data for image %(image_id)s"
|
||||||
" due to HTTP error: %(error)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)})
|
'error': utils.exception_to_str(e)})
|
||||||
self.notifier.error('image.upload', msg)
|
_send_notification(notify_error, 'image.upload', msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
msg = (_("Failed to upload image data for image %(image_id)s "
|
msg = (_("Failed to upload image data for image %(image_id)s "
|
||||||
"due to internal error: %(error)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)})
|
'error': utils.exception_to_str(e)})
|
||||||
self.notifier.error('image.upload', msg)
|
_send_notification(notify_error, 'image.upload', msg)
|
||||||
else:
|
else:
|
||||||
payload = format_image_notification(self.image)
|
self.send_notification('image.upload', self.repo)
|
||||||
self.notifier.info('image.upload', payload)
|
self.send_notification('image.activate', self.repo)
|
||||||
self.notifier.info('image.activate', payload)
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
def get_proxy_class(self):
|
||||||
self.task_repo = task_repo
|
return ImageProxy
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
def get_proxy_class(self):
|
||||||
self.task_stub_repo = task_stub_repo
|
return ImageProxy
|
||||||
self.context = context
|
|
||||||
self.notifier = notifier
|
def get_payload(self, obj):
|
||||||
proxy_kwargs = {'context': self.context, 'notifier': self.notifier}
|
return format_image_notification(obj)
|
||||||
super(TaskStubRepoProxy, self).__init__(
|
|
||||||
task_stub_repo,
|
def save(self, image, from_state=None):
|
||||||
task_stub_proxy_class=TaskStubProxy,
|
super(ImageRepoProxy, self).save(image, from_state=from_state)
|
||||||
task_stub_proxy_kwargs=proxy_kwargs)
|
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):
|
class TaskProxy(NotificationProxy, domain_proxy.Task):
|
||||||
def __init__(self, task_factory, context, notifier):
|
def get_super_class(self):
|
||||||
kwargs = {'context': context, 'notifier': notifier}
|
return domain_proxy.Task
|
||||||
super(TaskFactoryProxy, self).__init__(
|
|
||||||
task_factory,
|
|
||||||
task_proxy_class=TaskProxy,
|
|
||||||
task_proxy_kwargs=kwargs)
|
|
||||||
|
|
||||||
|
def get_payload(self, obj):
|
||||||
class TaskProxy(glance.domain.proxy.Task):
|
return format_task_notification(obj)
|
||||||
|
|
||||||
def __init__(self, task, context, notifier):
|
|
||||||
self.task = task
|
|
||||||
self.context = context
|
|
||||||
self.notifier = notifier
|
|
||||||
super(TaskProxy, self).__init__(task)
|
|
||||||
|
|
||||||
def begin_processing(self):
|
def begin_processing(self):
|
||||||
self.notifier.info(
|
super(TaskProxy, self).begin_processing()
|
||||||
'task.processing',
|
self.send_notification('task.processing', self.repo)
|
||||||
format_task_notification(self.task)
|
|
||||||
)
|
|
||||||
return super(TaskProxy, self).begin_processing()
|
|
||||||
|
|
||||||
def succeed(self, result):
|
def succeed(self, result):
|
||||||
self.notifier.info('task.success',
|
super(TaskProxy, self).succeed(result)
|
||||||
format_task_notification(self.task))
|
self.send_notification('task.success', self.repo)
|
||||||
return super(TaskProxy, self).succeed(result)
|
|
||||||
|
|
||||||
def fail(self, message):
|
def fail(self, message):
|
||||||
self.notifier.info('task.failure',
|
super(TaskProxy, self).fail(message)
|
||||||
format_task_notification(self.task))
|
self.send_notification('task.failure', self.repo)
|
||||||
return super(TaskProxy, self).fail(message)
|
|
||||||
|
|
||||||
def run(self, executor):
|
def run(self, executor):
|
||||||
self.notifier.info('task.run',
|
super(TaskProxy, self).run(executor)
|
||||||
format_task_notification(self.task))
|
self.send_notification('task.run', self.repo)
|
||||||
return super(TaskProxy, self).run(executor)
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
def get_proxy_class(self):
|
||||||
self.task = task
|
return TaskProxy
|
||||||
self.context = context
|
|
||||||
self.notifier = notifier
|
|
||||||
super(TaskStubProxy, self).__init__(task)
|
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):
|
def test_image_get(self):
|
||||||
image = self.image_repo_proxy.get(UUID1)
|
image = self.image_repo_proxy.get(UUID1)
|
||||||
self.assertIsInstance(image, glance.notifier.ImageProxy)
|
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):
|
def test_image_list(self):
|
||||||
images = self.image_repo_proxy.list()
|
images = self.image_repo_proxy.list()
|
||||||
self.assertIsInstance(images[0], glance.notifier.ImageProxy)
|
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):
|
def test_image_get_data_should_call_next_image_get_data(self):
|
||||||
with mock.patch.object(self.image, 'get_data') as get_data_mock:
|
with mock.patch.object(self.image, 'get_data') as get_data_mock:
|
||||||
|
@ -146,6 +146,7 @@ class OptsTestCase(utils.BaseTestCase):
|
|||||||
'public_endpoint',
|
'public_endpoint',
|
||||||
'digest_algorithm',
|
'digest_algorithm',
|
||||||
'http_keepalive',
|
'http_keepalive',
|
||||||
|
'disabled_notifications',
|
||||||
]
|
]
|
||||||
|
|
||||||
self._check_opt_groups(opt_list, expected_opt_groups)
|
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.create', output_log['event_type'])
|
||||||
self.assertEqual('image-1', output_log['payload']['name'])
|
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):
|
def test_create_with_properties(self):
|
||||||
request = unit_test_utils.get_fake_request()
|
request = unit_test_utils.get_fake_request()
|
||||||
image_properties = {'foo': 'bar'}
|
image_properties = {'foo': 'bar'}
|
||||||
@ -1781,6 +1795,17 @@ class TestImagesController(base.IsolatedUnitTest):
|
|||||||
self.assertEqual('image.update', output_log['event_type'])
|
self.assertEqual('image.update', output_log['event_type'])
|
||||||
self.assertEqual(UUID1, output_log['payload']['id'])
|
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):
|
def test_delete(self):
|
||||||
request = unit_test_utils.get_fake_request()
|
request = unit_test_utils.get_fake_request()
|
||||||
self.assertIn('%s/%s' % (BASE_URI, UUID1), self.store.data)
|
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.assertEqual('deleted', deleted_img['status'])
|
||||||
self.assertNotIn('%s/%s' % (BASE_URI, UUID1), self.store.data)
|
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):
|
def test_delete_queued_updates_status(self):
|
||||||
"""Ensure status of queued image is updated (LP bug #1048851)"""
|
"""Ensure status of queued image is updated (LP bug #1048851)"""
|
||||||
request = unit_test_utils.get_fake_request(is_admin=True)
|
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