[log]: db models and migration rules
This patch includes db models and migration rules for initial logging object. The implementation bases on logging api for security group spec[1] [1] https://goo.gl/t3NUlr Partially-implements: blueprint security-group-logging Related-Bug: #1468366 Change-Id: I3f91b3927c33021facc9eb9238555c0e06a918c0
This commit is contained in:
parent
31d24b4e1a
commit
ae791696b8
@ -1 +1 @@
|
|||||||
62c781cb6192
|
c8c222d42aa9
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright 2017 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""logging api
|
||||||
|
|
||||||
|
Revision ID: c8c222d42aa9
|
||||||
|
Revises: 62c781cb6192
|
||||||
|
Create Date: 2017-05-30 11:51:08.173604
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'c8c222d42aa9'
|
||||||
|
down_revision = '62c781cb6192'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from neutron_lib.db import constants as db_const
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'logs',
|
||||||
|
sa.Column('project_id',
|
||||||
|
sa.String(length=db_const.PROJECT_ID_FIELD_SIZE),
|
||||||
|
nullable=True,
|
||||||
|
index=True),
|
||||||
|
sa.Column('id', sa.String(length=db_const.UUID_FIELD_SIZE),
|
||||||
|
nullable=False),
|
||||||
|
sa.Column('standard_attr_id', sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=db_const.NAME_FIELD_SIZE),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('resource_type', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('resource_id', sa.String(length=db_const.UUID_FIELD_SIZE),
|
||||||
|
nullable=True,
|
||||||
|
index=True),
|
||||||
|
sa.Column('target_id', sa.String(length=db_const.UUID_FIELD_SIZE),
|
||||||
|
nullable=True,
|
||||||
|
index=True),
|
||||||
|
sa.Column('event', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('enabled', sa.Boolean(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.ForeignKeyConstraint(['standard_attr_id'],
|
||||||
|
['standardattributes.id'],
|
||||||
|
ondelete='CASCADE'),
|
||||||
|
sa.UniqueConstraint('standard_attr_id'))
|
37
neutron/db/models/loggingapi.py
Normal file
37
neutron/db/models/loggingapi.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# 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_lib.db import constants as db_const
|
||||||
|
from neutron_lib.db import model_base
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from neutron.db import standard_attr
|
||||||
|
|
||||||
|
|
||||||
|
class Log(standard_attr.HasStandardAttributes, model_base.BASEV2,
|
||||||
|
model_base.HasId, model_base.HasProject):
|
||||||
|
"""Represents neutron logging resource database"""
|
||||||
|
|
||||||
|
__tablename__ = 'logs'
|
||||||
|
|
||||||
|
name = sa.Column(sa.String(db_const.NAME_FIELD_SIZE))
|
||||||
|
resource_type = sa.Column(sa.String(36), nullable=False)
|
||||||
|
resource_id = sa.Column(sa.String(db_const.UUID_FIELD_SIZE),
|
||||||
|
nullable=True, index=True)
|
||||||
|
event = sa.Column(sa.String(255), nullable=False)
|
||||||
|
target_id = sa.Column(sa.String(db_const.UUID_FIELD_SIZE),
|
||||||
|
nullable=True, index=True)
|
||||||
|
enabled = sa.Column(sa.Boolean())
|
||||||
|
api_collections = ['logs']
|
0
neutron/objects/logapi/__init__.py
Normal file
0
neutron/objects/logapi/__init__.py
Normal file
38
neutron/objects/logapi/event_types.py
Normal file
38
neutron/objects/logapi/event_types.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# 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 oslo_versionedobjects import fields as obj_fields
|
||||||
|
|
||||||
|
from neutron._i18n import _
|
||||||
|
from neutron.services.logapi.common import constants as log_const
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityEvent(obj_fields.String):
|
||||||
|
def __init__(self, valid_values, **kwargs):
|
||||||
|
self._valid_values = valid_values
|
||||||
|
super(SecurityEvent, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def coerce(self, obj, attr, value):
|
||||||
|
if value not in self._valid_values:
|
||||||
|
msg = (
|
||||||
|
_("Field value %(value)s is not in the list "
|
||||||
|
"of valid values: %(values)s") %
|
||||||
|
{'value': value, 'values': self._valid_values}
|
||||||
|
)
|
||||||
|
raise ValueError(msg)
|
||||||
|
return super(SecurityEvent, self).coerce(obj, attr, value)
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityEventField(obj_fields.AutoTypedField):
|
||||||
|
AUTO_TYPE = SecurityEvent(valid_values=log_const.VALID_EVENTS)
|
45
neutron/objects/logapi/logging_resource.py
Normal file
45
neutron/objects/logapi/logging_resource.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 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 oslo_versionedobjects import base as obj_base
|
||||||
|
from oslo_versionedobjects import fields as obj_fields
|
||||||
|
|
||||||
|
from neutron.db.models import loggingapi as log_db
|
||||||
|
from neutron.objects import base
|
||||||
|
from neutron.objects import common_types
|
||||||
|
from neutron.objects.logapi import event_types
|
||||||
|
from neutron.services.logapi.common import constants as log_const
|
||||||
|
|
||||||
|
|
||||||
|
@obj_base.VersionedObjectRegistry.register
|
||||||
|
class Log(base.NeutronDbObject):
|
||||||
|
# Version 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
db_model = log_db.Log
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'id': common_types.UUIDField(),
|
||||||
|
'project_id': obj_fields.StringField(nullable=True),
|
||||||
|
'name': obj_fields.StringField(nullable=True),
|
||||||
|
'resource_type': obj_fields.StringField(),
|
||||||
|
'resource_id': common_types.UUIDField(nullable=True, default=None),
|
||||||
|
'target_id': common_types.UUIDField(nullable=True, default=None),
|
||||||
|
'event': event_types.SecurityEventField(default=log_const.ALL_EVENT),
|
||||||
|
'enabled': obj_fields.BooleanField(default=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
fields_no_update = ['project_id', 'resource_type', 'resource_id',
|
||||||
|
'target_id', 'event']
|
0
neutron/services/logapi/__init__.py
Normal file
0
neutron/services/logapi/__init__.py
Normal file
0
neutron/services/logapi/common/__init__.py
Normal file
0
neutron/services/logapi/common/__init__.py
Normal file
20
neutron/services/logapi/common/constants.py
Normal file
20
neutron/services/logapi/common/constants.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Copyright 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.
|
||||||
|
|
||||||
|
ACCEPT_EVENT = 'ACCEPT'
|
||||||
|
DROP_EVENT = 'DROP'
|
||||||
|
ALL_EVENT = 'ALL'
|
||||||
|
VALID_EVENTS = [ACCEPT_EVENT, DROP_EVENT, ALL_EVENT]
|
||||||
|
LOGGING_PLUGIN = 'logging-plugin'
|
30
neutron/services/logapi/common/exceptions.py
Normal file
30
neutron/services/logapi/common/exceptions.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Copyright 2016 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._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 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.")
|
@ -34,6 +34,7 @@ import unittest2
|
|||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common import constants as n_const
|
from neutron.common import constants as n_const
|
||||||
from neutron.plugins.common import constants as p_const
|
from neutron.plugins.common import constants as p_const
|
||||||
|
from neutron.services.logapi.common import constants as log_const
|
||||||
|
|
||||||
|
|
||||||
class AttributeMapMemento(fixtures.Fixture):
|
class AttributeMapMemento(fixtures.Fixture):
|
||||||
@ -319,3 +320,7 @@ def reset_random_seed():
|
|||||||
|
|
||||||
def get_random_ipv6_mode():
|
def get_random_ipv6_mode():
|
||||||
return random.choice(constants.IPV6_MODES)
|
return random.choice(constants.IPV6_MODES)
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_security_event():
|
||||||
|
return random.choice(log_const.VALID_EVENTS)
|
||||||
|
@ -69,7 +69,8 @@ class StandardAttrAPIImapctTestCase(testlib_api.SqlTestCase):
|
|||||||
# doc/source/devref/api_extensions.rst
|
# doc/source/devref/api_extensions.rst
|
||||||
expected = ['subnets', 'trunks', 'routers', 'segments',
|
expected = ['subnets', 'trunks', 'routers', 'segments',
|
||||||
'security_group_rules', 'networks', 'policies',
|
'security_group_rules', 'networks', 'policies',
|
||||||
'subnetpools', 'ports', 'security_groups', 'floatingips']
|
'subnetpools', 'ports', 'security_groups', 'floatingips',
|
||||||
|
'logs']
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set(expected),
|
set(expected),
|
||||||
set(standard_attr.get_standard_attr_resource_model_map().keys())
|
set(standard_attr.get_standard_attr_resource_model_map().keys())
|
||||||
|
0
neutron/tests/unit/objects/logapi/__init__.py
Normal file
0
neutron/tests/unit/objects/logapi/__init__.py
Normal file
86
neutron/tests/unit/objects/logapi/test_logging_resource.py
Normal file
86
neutron/tests/unit/objects/logapi/test_logging_resource.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from neutron.objects.logapi import logging_resource as log_res
|
||||||
|
from neutron.objects import securitygroup
|
||||||
|
from neutron.tests.unit.objects import test_base
|
||||||
|
from neutron.tests.unit import testlib_api
|
||||||
|
|
||||||
|
|
||||||
|
class LogObjectTestCase(test_base.BaseObjectIfaceTestCase):
|
||||||
|
|
||||||
|
_test_class = log_res.Log
|
||||||
|
|
||||||
|
|
||||||
|
class LogDBObjectTestCase(test_base.BaseDbObjectTestCase,
|
||||||
|
testlib_api.SqlTestCase):
|
||||||
|
|
||||||
|
_test_class = log_res.Log
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(LogDBObjectTestCase, self).setUp()
|
||||||
|
self._network_id = self._create_test_network_id()
|
||||||
|
self._port_id = self._create_test_port_id(network_id=self._network_id)
|
||||||
|
self._security_group = self._create_test_security_group()
|
||||||
|
self.update_obj_fields({'resource_id': self._security_group['id'],
|
||||||
|
'target_id': self._port_id})
|
||||||
|
|
||||||
|
def _create_test_security_group(self):
|
||||||
|
sg_fields = self.get_random_object_fields(securitygroup.SecurityGroup)
|
||||||
|
sg_obj = securitygroup.SecurityGroup(self.context, **sg_fields)
|
||||||
|
return sg_obj
|
||||||
|
|
||||||
|
def test_create_sg_log_with_secgroup(self):
|
||||||
|
sg = self._create_test_security_group()
|
||||||
|
sg_log = log_res.Log(context=self.context,
|
||||||
|
id=uuidutils.generate_uuid(),
|
||||||
|
name='test-create',
|
||||||
|
resource_type='security_group',
|
||||||
|
resource_id=sg.id,
|
||||||
|
enabled=False)
|
||||||
|
sg_log.create()
|
||||||
|
self.assertEqual(sg.id, sg_log.resource_id)
|
||||||
|
|
||||||
|
def test_create_sg_log_with_port(self):
|
||||||
|
port_id = self._create_test_port_id(network_id=self._network_id)
|
||||||
|
sg_log = log_res.Log(context=self.context,
|
||||||
|
id=uuidutils.generate_uuid(),
|
||||||
|
name='test-create',
|
||||||
|
resource_type='security_group',
|
||||||
|
target_id=port_id,
|
||||||
|
enabled=False)
|
||||||
|
sg_log.create()
|
||||||
|
self.assertEqual(port_id, sg_log.target_id)
|
||||||
|
|
||||||
|
def _test_update_multiple_fields(self):
|
||||||
|
sg_log = log_res.Log(context=self.context,
|
||||||
|
id=uuidutils.generate_uuid(),
|
||||||
|
name='test-create',
|
||||||
|
description='test-description',
|
||||||
|
resource_type='security_group',
|
||||||
|
enabled=False)
|
||||||
|
sg_log.create()
|
||||||
|
fields = {'name': 'test-update', 'description': 'test-update-descr',
|
||||||
|
'enabled': True}
|
||||||
|
sg_log.update_fields(**fields)
|
||||||
|
sg_log.update()
|
||||||
|
|
||||||
|
new_sg_log = log_res.Log.get_object(self.context, id=sg_log.id)
|
||||||
|
self._assert_attrs(new_sg_log, **fields)
|
||||||
|
|
||||||
|
def _assert_attrs(self, sg_log, **kwargs):
|
||||||
|
"""Check the values passed in kwargs match the values of the sg log"""
|
||||||
|
for k in sg_log.fields:
|
||||||
|
if k in kwargs:
|
||||||
|
self.assertEqual(kwargs[k], sg_log[k])
|
@ -40,6 +40,7 @@ from neutron.objects import common_types
|
|||||||
from neutron.objects.db import api as obj_db_api
|
from neutron.objects.db import api as obj_db_api
|
||||||
from neutron.objects import exceptions as o_exc
|
from neutron.objects import exceptions as o_exc
|
||||||
from neutron.objects import flavor
|
from neutron.objects import flavor
|
||||||
|
from neutron.objects.logapi import event_types
|
||||||
from neutron.objects import network as net_obj
|
from neutron.objects import network as net_obj
|
||||||
from neutron.objects import ports
|
from neutron.objects import ports
|
||||||
from neutron.objects import rbac_db
|
from neutron.objects import rbac_db
|
||||||
@ -445,6 +446,7 @@ FIELD_TYPE_VALUE_GENERATOR_MAP = {
|
|||||||
common_types.SetOfUUIDsField: get_set_of_random_uuids,
|
common_types.SetOfUUIDsField: get_set_of_random_uuids,
|
||||||
common_types.UUIDField: uuidutils.generate_uuid,
|
common_types.UUIDField: uuidutils.generate_uuid,
|
||||||
common_types.VlanIdRangeField: tools.get_random_vlan,
|
common_types.VlanIdRangeField: tools.get_random_vlan,
|
||||||
|
event_types.SecurityEventField: tools.get_random_security_event,
|
||||||
obj_fields.BooleanField: tools.get_random_boolean,
|
obj_fields.BooleanField: tools.get_random_boolean,
|
||||||
obj_fields.DateTimeField: tools.get_random_datetime,
|
obj_fields.DateTimeField: tools.get_random_datetime,
|
||||||
obj_fields.DictOfStringsField: get_random_dict_of_strings,
|
obj_fields.DictOfStringsField: get_random_dict_of_strings,
|
||||||
|
@ -50,6 +50,7 @@ object_data = {
|
|||||||
'IpamSubnet': '1.0-713de401682a70f34891e13af645fa08',
|
'IpamSubnet': '1.0-713de401682a70f34891e13af645fa08',
|
||||||
'MeteringLabel': '1.0-cc4b620a3425222447cbe459f62de533',
|
'MeteringLabel': '1.0-cc4b620a3425222447cbe459f62de533',
|
||||||
'MeteringLabelRule': '1.0-b5c5717e7bab8d1af1623156012a5842',
|
'MeteringLabelRule': '1.0-b5c5717e7bab8d1af1623156012a5842',
|
||||||
|
'Log': '1.0-6391351c0f34ed34375a19202f361d24',
|
||||||
'Network': '1.0-f2f6308f79731a767b92b26b0f4f3849',
|
'Network': '1.0-f2f6308f79731a767b92b26b0f4f3849',
|
||||||
'NetworkDNSDomain': '1.0-420db7910294608534c1e2e30d6d8319',
|
'NetworkDNSDomain': '1.0-420db7910294608534c1e2e30d6d8319',
|
||||||
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
|
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
|
||||||
|
Loading…
Reference in New Issue
Block a user