[log]: implement logging plugin
This patch introduces the logging api definition and initial implementation of LoggingApiPlugin. The api definition code will be removed after [1] has been merged on neutron lib. [1]https://review.openstack.org/#/c/415817/ Co-Authored-By: Yushiro FURUKAWA <y.furukawa_2@jp.fujitsu.com> Partially-implements: blueprint security-group-logging Related-Bug: #1468366 Change-Id: Iace31506502de25da9dce5fcfdbfe2c726bea27f
This commit is contained in:
parent
4a316960f2
commit
913c9e78b9
@ -225,5 +225,12 @@
|
||||
"get_security_group_rules": "rule:admin_or_owner",
|
||||
"get_security_group_rule": "rule:admin_or_owner",
|
||||
"create_security_group_rule": "rule:admin_or_owner",
|
||||
"delete_security_group_rule": "rule:admin_or_owner"
|
||||
"delete_security_group_rule": "rule:admin_or_owner",
|
||||
|
||||
"get_loggable_resources": "rule:admin_only",
|
||||
"create_log": "rule:admin_only",
|
||||
"update_log": "rule:admin_only",
|
||||
"delete_log": "rule:admin_only",
|
||||
"get_logs": "rule:admin_only",
|
||||
"get_log": "rule:admin_only"
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.objects.logapi import logging_resource as log_object
|
||||
from neutron.objects import network
|
||||
from neutron.objects import ports
|
||||
from neutron.objects.qos import policy
|
||||
@ -19,6 +20,7 @@ from neutron.objects import trunk
|
||||
|
||||
|
||||
# Supported types
|
||||
LOGGING_RESOURCE = log_object.Log.obj_name()
|
||||
TRUNK = trunk.Trunk.obj_name()
|
||||
QOS_POLICY = policy.QosPolicy.obj_name()
|
||||
SUBPORT = trunk.SubPort.obj_name()
|
||||
@ -38,6 +40,7 @@ _VALID_CLS = (
|
||||
network.Network,
|
||||
securitygroup.SecurityGroup,
|
||||
securitygroup.SecurityGroupRule,
|
||||
log_object.Log,
|
||||
)
|
||||
|
||||
_TYPE_TO_CLS_MAP = {cls.obj_name(): cls for cls in _VALID_CLS}
|
||||
|
158
neutron/extensions/logging.py
Normal file
158
neutron/extensions/logging.py
Normal file
@ -0,0 +1,158 @@
|
||||
# Copyright (c) 2017 Fujitsu Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
import itertools
|
||||
|
||||
from neutron_lib.api import converters
|
||||
from neutron_lib.api import extensions as api_extensions
|
||||
from neutron_lib.db import constants as db_const
|
||||
from neutron_lib.services import base as service_base
|
||||
import six
|
||||
|
||||
from neutron.api.v2 import resource_helper
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.services.logapi.common import constants as log_const
|
||||
|
||||
|
||||
LOG_PREFIX = "/log"
|
||||
# Attribute Map
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
'logs': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'project_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {
|
||||
'type:string':
|
||||
db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': db_const.NAME_FIELD_SIZE},
|
||||
'default': '', 'is_visible': True},
|
||||
'resource_type': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate':
|
||||
{'type:string': db_const.RESOURCE_TYPE_FIELD_SIZE},
|
||||
'is_visible': True},
|
||||
'resource_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'default': None, 'is_visible': True},
|
||||
'event': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:values': log_const.LOG_EVENTS},
|
||||
'default': log_const.ALL_EVENT, 'is_visible': True},
|
||||
'target_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'default': None, 'is_visible': True},
|
||||
'enabled': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': True,
|
||||
'convert_to': converters.convert_to_boolean},
|
||||
},
|
||||
|
||||
'loggable_resources': {
|
||||
'type': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True}},
|
||||
}
|
||||
|
||||
|
||||
class Logging(api_extensions.ExtensionDescriptor):
|
||||
"""Neutron logging api extension."""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Logging API Extension"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "logging"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Provides a logging API for resources such as security group"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2017-01-01T10:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_plugin_interface(cls):
|
||||
return LoggingPluginBase
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
plural_mappings = resource_helper.build_plural_mappings(
|
||||
{}, itertools.chain(RESOURCE_ATTRIBUTE_MAP))
|
||||
|
||||
resources = resource_helper.build_resource_info(
|
||||
plural_mappings,
|
||||
RESOURCE_ATTRIBUTE_MAP,
|
||||
constants.LOG_API,
|
||||
translate_name=True,
|
||||
allow_bulk=True)
|
||||
|
||||
return resources
|
||||
|
||||
def update_attributes_map(self, attributes, extension_attrs_map=None):
|
||||
super(Logging, self).update_attributes_map(
|
||||
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return dict(list(RESOURCE_ATTRIBUTE_MAP.items()))
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class LoggingPluginBase(service_base.ServicePluginBase):
|
||||
|
||||
path_prefix = LOG_PREFIX
|
||||
|
||||
def get_plugin_description(self):
|
||||
return "Logging API Service Plugin"
|
||||
|
||||
@classmethod
|
||||
def get_plugin_type(cls):
|
||||
return constants.LOG_API
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_logs(self, context, filters=None, fields=None, sorts=None,
|
||||
limit=None, marker=None, page_reverse=False):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_log(self, context, log_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_log(self, context, log):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_log(self, context, log_id, log):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_log(self, context, log_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_loggable_resources(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None,
|
||||
marker=None, page_reverse=False):
|
||||
pass
|
@ -35,4 +35,4 @@ class SecurityEvent(obj_fields.String):
|
||||
|
||||
|
||||
class SecurityEventField(obj_fields.AutoTypedField):
|
||||
AUTO_TYPE = SecurityEvent(valid_values=log_const.VALID_EVENTS)
|
||||
AUTO_TYPE = SecurityEvent(valid_values=log_const.LOG_EVENTS)
|
||||
|
@ -25,6 +25,7 @@ VPN = "VPN"
|
||||
METERING = "METERING"
|
||||
FLAVORS = "FLAVORS"
|
||||
QOS = "QOS"
|
||||
LOG_API = "LOGGING"
|
||||
|
||||
# Maps extension alias to service type that
|
||||
# can be implemented by the core plugin.
|
||||
|
@ -16,5 +16,5 @@
|
||||
ACCEPT_EVENT = 'ACCEPT'
|
||||
DROP_EVENT = 'DROP'
|
||||
ALL_EVENT = 'ALL'
|
||||
VALID_EVENTS = [ACCEPT_EVENT, DROP_EVENT, ALL_EVENT]
|
||||
LOG_EVENTS = [ACCEPT_EVENT, DROP_EVENT, ALL_EVENT]
|
||||
LOGGING_PLUGIN = 'logging-plugin'
|
||||
|
@ -1,5 +1,4 @@
|
||||
# Copyright 2016 Fujitsu Limited.
|
||||
#
|
||||
# Copyright 2017 Fujitsu Limited.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
@ -18,13 +17,9 @@ from neutron._i18n import _
|
||||
from neutron_lib import exceptions as n_exc
|
||||
|
||||
|
||||
class ResourceLogNotFound(n_exc.NotFound):
|
||||
message = _("Resource log %(id)s could not be found.")
|
||||
class LogResourceNotFound(n_exc.NotFound):
|
||||
message = _("Log resource %(log_id)s could not be found.")
|
||||
|
||||
|
||||
class ParentResourceNotFound(n_exc.NotFound):
|
||||
message = _("Parent resource %(parent_resource_id)s could not be found.")
|
||||
|
||||
|
||||
class ResourceNotFound(n_exc.NotFound):
|
||||
message = _("Resource %(resource_id)s could not be found.")
|
||||
class InvalidLogReosurceType(n_exc.InvalidInput):
|
||||
message = _("Invalid log resource_type: %(resource_type)s.")
|
||||
|
93
neutron/services/logapi/logging_plugin.py
Normal file
93
neutron/services/logapi/logging_plugin.py
Normal file
@ -0,0 +1,93 @@
|
||||
# Copyright (c) 2017 Fujitsu Limited
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import db_base_plugin_common
|
||||
from neutron.extensions import logging as log_ext
|
||||
from neutron.objects import base as base_obj
|
||||
from neutron.objects.logapi import logging_resource as log_object
|
||||
from neutron.services.logapi.common import exceptions as log_exc
|
||||
|
||||
|
||||
class LoggingPlugin(log_ext.LoggingPluginBase):
|
||||
"""Implementation of the Neutron logging api plugin."""
|
||||
|
||||
supported_extension_aliases = ['logging']
|
||||
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
||||
@property
|
||||
def supported_logging_types(self):
|
||||
# Todo(annp): supported_logging_types will dynamic load from
|
||||
# log_drivers. So return value for this function is a temporary.
|
||||
return []
|
||||
|
||||
@db_base_plugin_common.filter_fields
|
||||
@db_base_plugin_common.convert_result_to_dict
|
||||
def get_logs(self, context, filters=None, fields=None, sorts=None,
|
||||
limit=None, marker=None, page_reverse=False):
|
||||
"""Return information for available log objects"""
|
||||
filters = filters or {}
|
||||
pager = base_obj.Pager(sorts, limit, page_reverse, marker)
|
||||
return log_object.Log.get_objects(context, _pager=pager, **filters)
|
||||
|
||||
def _get_log(self, context, log_id):
|
||||
"""Return the log object or raise if not found"""
|
||||
log_obj = log_object.Log.get_object(context, id=log_id)
|
||||
if not log_obj:
|
||||
raise log_exc.LogResourceNotFound(log_id=log_id)
|
||||
return log_obj
|
||||
|
||||
@db_base_plugin_common.filter_fields
|
||||
@db_base_plugin_common.convert_result_to_dict
|
||||
def get_log(self, context, log_id, fields=None):
|
||||
return self._get_log(context, log_id)
|
||||
|
||||
@db_base_plugin_common.convert_result_to_dict
|
||||
def create_log(self, context, log):
|
||||
"""Create a log object"""
|
||||
log_data = log['log']
|
||||
with db_api.context_manager.writer.using(context):
|
||||
# body 'log' contains both tenant_id and project_id
|
||||
# but only latter needs to be used to create Log object.
|
||||
# We need to remove redundant keyword.
|
||||
log_data.pop('tenant_id', None)
|
||||
log_obj = log_object.Log(context=context, **log_data)
|
||||
log_obj.create()
|
||||
return log_obj
|
||||
|
||||
@db_base_plugin_common.convert_result_to_dict
|
||||
def update_log(self, context, log_id, log):
|
||||
"""Update information for the specified log object"""
|
||||
log_data = log['log']
|
||||
with db_api.context_manager.writer.using(context):
|
||||
log_obj = log_object.Log(context, id=log_id)
|
||||
log_obj.update_fields(log_data, reset_changes=True)
|
||||
log_obj.update()
|
||||
return log_obj
|
||||
|
||||
def delete_log(self, context, log_id):
|
||||
"""Delete the specified log object"""
|
||||
with db_api.context_manager.writer.using(context):
|
||||
log_obj = self._get_log(context, log_id)
|
||||
log_obj.delete()
|
||||
|
||||
def get_loggable_resources(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None,
|
||||
marker=None, page_reverse=False):
|
||||
"""Get supported logging types"""
|
||||
return [{'type': type_}
|
||||
for type_ in self.supported_logging_types]
|
@ -225,5 +225,12 @@
|
||||
"get_security_group_rules": "rule:admin_or_owner",
|
||||
"get_security_group_rule": "rule:admin_or_owner",
|
||||
"create_security_group_rule": "rule:admin_or_owner",
|
||||
"delete_security_group_rule": "rule:admin_or_owner"
|
||||
"delete_security_group_rule": "rule:admin_or_owner",
|
||||
|
||||
"get_loggable_resources": "rule:admin_only",
|
||||
"create_log": "rule:admin_only",
|
||||
"update_log": "rule:admin_only",
|
||||
"delete_log": "rule:admin_only",
|
||||
"get_logs": "rule:admin_only",
|
||||
"get_log": "rule:admin_only"
|
||||
}
|
||||
|
@ -323,4 +323,4 @@ def get_random_ipv6_mode():
|
||||
|
||||
|
||||
def get_random_security_event():
|
||||
return random.choice(log_const.VALID_EVENTS)
|
||||
return random.choice(log_const.LOG_EVENTS)
|
||||
|
0
neutron/tests/unit/services/logapi/__init__.py
Normal file
0
neutron/tests/unit/services/logapi/__init__.py
Normal file
38
neutron/tests/unit/services/logapi/base.py
Normal file
38
neutron/tests/unit/services/logapi/base.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from neutron.api.rpc.callbacks.consumer import registry as cons_registry
|
||||
from neutron.api.rpc.callbacks.producer import registry as prod_registry
|
||||
from neutron.api.rpc.callbacks import resource_manager
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
class BaseLogTestCase(testlib_api.SqlTestCase):
|
||||
def setUp(self):
|
||||
super(BaseLogTestCase, self).setUp()
|
||||
|
||||
with mock.patch.object(
|
||||
resource_manager.ResourceCallbacksManager, '_singleton',
|
||||
new_callable=mock.PropertyMock(return_value=False)):
|
||||
|
||||
self.cons_mgr = resource_manager.ConsumerResourceCallbacksManager()
|
||||
self.prod_mgr = resource_manager.ProducerResourceCallbacksManager()
|
||||
for mgr in (self.cons_mgr, self.prod_mgr):
|
||||
mgr.clear()
|
||||
|
||||
mock.patch.object(
|
||||
cons_registry, '_get_manager', return_value=self.cons_mgr).start()
|
||||
|
||||
mock.patch.object(
|
||||
prod_registry, '_get_manager', return_value=self.prod_mgr).start()
|
207
neutron/tests/unit/services/logapi/test_logging_plugin.py
Normal file
207
neutron/tests/unit/services/logapi/test_logging_plugin.py
Normal file
@ -0,0 +1,207 @@
|
||||
# Copyright (C) 2017 Fujitsu Limited
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from neutron_lib import context
|
||||
from neutron_lib.plugins import directory
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron import manager
|
||||
from neutron.objects.logapi import logging_resource as log_object
|
||||
from neutron.objects import ports
|
||||
from neutron.objects import securitygroup as sg_object
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.services.logapi.common import exceptions as log_exc
|
||||
from neutron.tests.unit.services.logapi import base
|
||||
|
||||
DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
|
||||
|
||||
|
||||
class TestLoggingPlugin(base.BaseLogTestCase):
|
||||
def setUp(self):
|
||||
super(TestLoggingPlugin, self).setUp()
|
||||
self.setup_coreplugin(load_plugins=False)
|
||||
|
||||
mock.patch('neutron.objects.db.api.create_object').start()
|
||||
mock.patch('neutron.objects.db.api.update_object').start()
|
||||
mock.patch('neutron.objects.db.api.delete_object').start()
|
||||
mock.patch('neutron.objects.db.api.get_object').start()
|
||||
# We don't use real models as per mocks above. We also need to mock-out
|
||||
# methods that work with real data types
|
||||
mock.patch(
|
||||
'neutron.objects.base.NeutronDbObject.modify_fields_from_db'
|
||||
).start()
|
||||
|
||||
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
|
||||
cfg.CONF.set_override("service_plugins",
|
||||
["neutron.services.logapi.logging_plugin.LoggingPlugin"])
|
||||
|
||||
manager.init()
|
||||
self.log_plugin = directory.get_plugin(constants.LOG_API)
|
||||
self.ctxt = context.Context('fake_user', 'fake_tenant')
|
||||
mock.patch.object(self.ctxt.session, 'refresh').start()
|
||||
mock.patch.object(self.ctxt.session, 'expunge').start()
|
||||
|
||||
def test_get_logs(self):
|
||||
with mock.patch.object(log_object.Log, 'get_objects')\
|
||||
as get_objects_mock:
|
||||
filters = {'filter': 'filter_id'}
|
||||
self.log_plugin.get_logs(self.ctxt, filters=filters)
|
||||
get_objects_mock.assert_called_once_with(self.ctxt,
|
||||
_pager=mock.ANY, filter='filter_id')
|
||||
|
||||
def test_get_log_without_return_value(self):
|
||||
with mock.patch.object(log_object.Log, 'get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
log_exc.LogResourceNotFound,
|
||||
self.log_plugin.get_log,
|
||||
self.ctxt,
|
||||
mock.ANY,
|
||||
)
|
||||
|
||||
def test_get_log_with_return_value(self):
|
||||
log_id = uuidutils.generate_uuid()
|
||||
with mock.patch.object(log_object.Log, 'get_object')\
|
||||
as get_object_mock:
|
||||
self.log_plugin.get_log(self.ctxt, log_id)
|
||||
get_object_mock.assert_called_once_with(self.ctxt,
|
||||
id=log_id)
|
||||
|
||||
@mock.patch('neutron.db._utils.model_query')
|
||||
def test_create_log_full_options(self, query_mock):
|
||||
log = {'log': {'resource_type': 'security_group',
|
||||
'enabled': True,
|
||||
'resource_id': uuidutils.generate_uuid(),
|
||||
'target_id': uuidutils.generate_uuid()}}
|
||||
sg = mock.Mock()
|
||||
port = mock.Mock()
|
||||
new_log = mock.Mock()
|
||||
with mock.patch.object(sg_object.SecurityGroup, 'get_object',
|
||||
return_value=sg):
|
||||
with mock.patch.object(ports.Port, 'get_object',
|
||||
return_value=port):
|
||||
with mock.patch('neutron.objects.logapi.'
|
||||
'logging_resource.Log',
|
||||
return_value=new_log) as init_log_mock:
|
||||
self.log_plugin.create_log(self.ctxt, log)
|
||||
init_log_mock.assert_called_once_with(context=self.ctxt,
|
||||
**log['log'])
|
||||
self.assertTrue(new_log.create.called)
|
||||
|
||||
def test_create_log_without_sg_resource(self):
|
||||
log = {'log': {'resource_type': 'security_group',
|
||||
'enabled': True,
|
||||
'target_id': uuidutils.generate_uuid()}}
|
||||
new_log = mock.Mock()
|
||||
new_log.enabled = True
|
||||
port = mock.Mock()
|
||||
with mock.patch.object(ports.Port, 'get_object', return_value=port):
|
||||
with mock.patch('neutron.objects.logapi.logging_resource.Log',
|
||||
return_value=new_log) as init_log_mock:
|
||||
self.log_plugin.create_log(self.ctxt, log)
|
||||
init_log_mock.assert_called_once_with(
|
||||
context=self.ctxt, **log['log'])
|
||||
self.assertTrue(new_log.create.called)
|
||||
|
||||
def test_create_log_without_parent_resource(self):
|
||||
log = {'log': {'resource_type': 'security_group',
|
||||
'enabled': True,
|
||||
'resource_id': uuidutils.generate_uuid()}}
|
||||
new_log = mock.Mock()
|
||||
new_log.enabled = True
|
||||
sg = mock.Mock()
|
||||
with mock.patch.object(sg_object.SecurityGroup, 'get_object',
|
||||
return_value=sg):
|
||||
with mock.patch('neutron.objects.logapi.logging_resource.Log',
|
||||
return_value=new_log) as init_log_mock:
|
||||
self.log_plugin.create_log(self.ctxt, log)
|
||||
init_log_mock.assert_called_once_with(context=self.ctxt,
|
||||
**log['log'])
|
||||
self.assertTrue(new_log.create.called)
|
||||
|
||||
def test_create_log_without_target(self):
|
||||
log = {'log': {'resource_type': 'security_group',
|
||||
'enabled': True, }}
|
||||
new_log = mock.Mock()
|
||||
new_log.enabled = True
|
||||
with mock.patch('neutron.objects.logapi.'
|
||||
'logging_resource.Log',
|
||||
return_value=new_log) as init_log_mock:
|
||||
self.log_plugin.create_log(self.ctxt, log)
|
||||
init_log_mock.assert_called_once_with(context=self.ctxt,
|
||||
**log['log'])
|
||||
self.assertTrue(new_log.create.called)
|
||||
|
||||
def test_create_log_disabled(self):
|
||||
log_data = {'log': {'resource_type': 'security_group',
|
||||
'enabled': False}}
|
||||
new_log = mock.Mock()
|
||||
new_log.enabled = False
|
||||
with mock.patch('neutron.objects.logapi.'
|
||||
'logging_resource.Log',
|
||||
return_value=new_log) as init_log_mock:
|
||||
self.log_plugin.create_log(self.ctxt, log_data)
|
||||
init_log_mock.assert_called_once_with(
|
||||
context=self.ctxt, **log_data['log'])
|
||||
self.assertTrue(new_log.create.called)
|
||||
|
||||
def test_update_log(self):
|
||||
log_data = {'log': {'enabled': True}}
|
||||
new_log = mock.Mock()
|
||||
new_log.id = uuidutils.generate_uuid()
|
||||
with mock.patch('neutron.objects.logapi.'
|
||||
'logging_resource.Log',
|
||||
return_value=new_log) as update_log_mock:
|
||||
self.log_plugin.update_log(self.ctxt, new_log.id, log_data)
|
||||
update_log_mock.assert_called_once_with(self.ctxt,
|
||||
id=new_log.id)
|
||||
new_log.update_fields.assert_called_once_with(log_data['log'],
|
||||
reset_changes=True)
|
||||
self.assertTrue(new_log.update.called)
|
||||
|
||||
def test_update_log_none_enabled(self):
|
||||
log_data = {'log': {}}
|
||||
new_log = mock.Mock()
|
||||
new_log.id = uuidutils.generate_uuid()
|
||||
with mock.patch('neutron.objects.logapi.'
|
||||
'logging_resource.Log',
|
||||
return_value=new_log) as update_log_mock:
|
||||
self.log_plugin.update_log(self.ctxt, new_log.id, log_data)
|
||||
update_log_mock.assert_called_once_with(self.ctxt,
|
||||
id=new_log.id)
|
||||
new_log.update_fields.assert_called_once_with(log_data['log'],
|
||||
reset_changes=True)
|
||||
self.assertTrue(new_log.update.called)
|
||||
|
||||
def test_delete_log(self):
|
||||
delete_log = mock.Mock()
|
||||
delete_log.id = uuidutils.generate_uuid()
|
||||
with mock.patch.object(log_object.Log, 'get_object',
|
||||
return_value=delete_log) as delete_log_mock:
|
||||
self.log_plugin.delete_log(self.ctxt, delete_log.id)
|
||||
delete_log_mock.assert_called_once_with(self.ctxt,
|
||||
id=delete_log.id)
|
||||
self.assertTrue(delete_log.delete.called)
|
||||
|
||||
def test_delete_nonexistent_log(self):
|
||||
with mock.patch.object(log_object.Log, 'get_object',
|
||||
return_value=None):
|
||||
self.assertRaises(
|
||||
log_exc.LogResourceNotFound,
|
||||
self.log_plugin.delete_log,
|
||||
self.ctxt,
|
||||
mock.ANY)
|
@ -82,6 +82,7 @@ neutron.service_plugins =
|
||||
timestamp = neutron.services.timestamp.timestamp_plugin:TimeStampPlugin
|
||||
trunk = neutron.services.trunk.plugin:TrunkPlugin
|
||||
loki = neutron.services.loki.loki_plugin:LokiPlugin
|
||||
logapi = neutron.services.logapi.logging_plugin:LoggingPlugin
|
||||
neutron.ml2.type_drivers =
|
||||
flat = neutron.plugins.ml2.drivers.type_flat:FlatTypeDriver
|
||||
local = neutron.plugins.ml2.drivers.type_local:LocalTypeDriver
|
||||
|
Loading…
Reference in New Issue
Block a user