create skeleton files for event storage backends

this patch adds support to configure an event specific database.
the code currently calls existing metering/event mixed code so
basically both metering and event db share the same code.

segregation of code will be done in subsequent patches for each
driver individually.

Change-Id: I22871737cf297d1bfff6c17a7eaf9333c6415ffd
Partially-Implements: blueprint dedicated-event-db
This commit is contained in:
gordon chung 2014-10-02 13:36:10 -04:00
parent 303da461f5
commit a1ba9d7e25
18 changed files with 452 additions and 71 deletions

View File

@ -66,6 +66,7 @@ def setup_app(pecan_config=None, extra_hooks=None):
app_hooks = [hooks.ConfigHook(),
hooks.DBHook(
storage.get_connection_from_config(cfg.CONF, 'metering'),
storage.get_connection_from_config(cfg.CONF, 'event'),
storage.get_connection_from_config(cfg.CONF, 'alarm'),),
hooks.PipelineHook(),
hooks.TranslationHook()]

View File

@ -2386,7 +2386,7 @@ class TraitsController(rest.RestController):
"""
LOG.debug(_("Getting traits for %s") % event_type)
return [Trait._convert_storage_trait(t)
for t in pecan.request.storage_conn
for t in pecan.request.event_storage_conn
.get_traits(event_type, trait_name)]
@requires_admin
@ -2399,7 +2399,7 @@ class TraitsController(rest.RestController):
get_trait_name = event_models.Trait.get_name_by_type
return [TraitDescription(name=t['name'],
type=get_trait_name(t['data_type']))
for t in pecan.request.storage_conn
for t in pecan.request.event_storage_conn
.get_trait_types(event_type)]
@ -2416,7 +2416,7 @@ class EventTypesController(rest.RestController):
@wsme_pecan.wsexpose([unicode])
def get_all(self):
"""Get all event types."""
return list(pecan.request.storage_conn.get_event_types())
return list(pecan.request.event_storage_conn.get_event_types())
class EventsController(rest.RestController):
@ -2436,7 +2436,7 @@ class EventsController(rest.RestController):
generated=event.generated,
traits=event.traits)
for event in
pecan.request.storage_conn.get_events(event_filter)]
pecan.request.event_storage_conn.get_events(event_filter)]
@requires_admin
@wsme_pecan.wsexpose(Event, wtypes.text)
@ -2447,7 +2447,7 @@ class EventsController(rest.RestController):
"""
event_filter = storage.EventFilter(message_id=message_id)
events = [event for event
in pecan.request.storage_conn.get_events(event_filter)]
in pecan.request.event_storage_conn.get_events(event_filter)]
if not events:
raise EntityNotFound(_("Event"), message_id)
@ -2549,7 +2549,9 @@ class Capabilities(_Base):
storage = {wtypes.text: bool}
"A flattened dictionary of storage capabilities"
alarm_storage = {wtypes.text: bool}
"A flattened dictionary of storage capabilities"
"A flattened dictionary of alarm storage capabilities"
event_storage = {wtypes.text: bool}
"A flattened dictionary of event storage capabilities"
@classmethod
def sample(cls):
@ -2591,6 +2593,7 @@ class Capabilities(_Base):
}),
storage=_flatten_capabilities({'production_ready': True}),
alarm_storage=_flatten_capabilities({'production_ready': True}),
event_storage=_flatten_capabilities({'production_ready': True}),
)
@ -2607,14 +2610,19 @@ class CapabilitiesController(rest.RestController):
# the lack of strict feature parity across storage drivers
conn = pecan.request.storage_conn
alarm_conn = pecan.request.alarm_storage_conn
event_conn = pecan.request.event_storage_conn
driver_capabilities = conn.get_capabilities().copy()
driver_capabilities['alarms'] = alarm_conn.get_capabilities()['alarms']
driver_capabilities['events'] = event_conn.get_capabilities()['events']
driver_perf = conn.get_storage_capabilities()
alarm_driver_perf = alarm_conn.get_storage_capabilities()
event_driver_perf = event_conn.get_storage_capabilities()
return Capabilities(api=_flatten_capabilities(driver_capabilities),
storage=_flatten_capabilities(driver_perf),
alarm_storage=_flatten_capabilities(
alarm_driver_perf))
alarm_driver_perf),
event_storage=_flatten_capabilities(
event_driver_perf))
class V2Controller(object):

View File

@ -36,12 +36,14 @@ class ConfigHook(hooks.PecanHook):
class DBHook(hooks.PecanHook):
def __init__(self, storage_connection, alarm_storage_connection):
self.storage_connection = storage_connection
self.alarm_storage_connection = alarm_storage_connection
def __init__(self, conn, event_conn, alarm_conn):
self.storage_connection = conn
self.event_storage_connection = event_conn
self.alarm_storage_connection = alarm_conn
def before(self, state):
state.request.storage_conn = self.storage_connection
state.request.event_storage_conn = self.event_storage_connection
state.request.alarm_storage_conn = self.alarm_storage_connection

View File

@ -31,6 +31,7 @@ def dbsync():
service.prepare_service()
storage.get_connection_from_config(cfg.CONF, 'metering').upgrade()
storage.get_connection_from_config(cfg.CONF, 'alarm').upgrade()
storage.get_connection_from_config(cfg.CONF, 'event').upgrade()
def expirer():

View File

@ -0,0 +1,90 @@
#
# 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 ceilometer
class Connection(object):
"""Base class for event storage system connections."""
# A dictionary representing the capabilities of this driver.
CAPABILITIES = {
'events': {'query': {'simple': False}},
}
STORAGE_CAPABILITIES = {
'storage': {'production_ready': False},
}
def __init__(self, url):
"""Constructor."""
pass
@staticmethod
def upgrade():
"""Migrate the database to `version` or the most recent version."""
@staticmethod
def clear():
"""Clear database."""
@staticmethod
def record_events(events):
"""Write the events to the backend storage system.
:param events: a list of model.Event objects.
"""
raise ceilometer.NotImplementedError('Events not implemented.')
@staticmethod
def get_events(event_filter):
"""Return an iterable of model.Event objects."""
raise ceilometer.NotImplementedError('Events not implemented.')
@staticmethod
def get_event_types():
"""Return all event types as an iterable of strings."""
raise ceilometer.NotImplementedError('Events not implemented.')
@staticmethod
def get_trait_types(event_type):
"""Return a dictionary containing the name and data type of the trait.
Only trait types for the provided event_type are
returned.
:param event_type: the type of the Event
"""
raise ceilometer.NotImplementedError('Events not implemented.')
@staticmethod
def get_traits(event_type, trait_type=None):
"""Return all trait instances associated with an event_type.
If trait_type is specified, only return instances of that trait type.
:param event_type: the type of the Event to filter by
:param trait_type: the name of the Trait to filter by
"""
raise ceilometer.NotImplementedError('Events not implemented.')
@classmethod
def get_capabilities(cls):
"""Return an dictionary with the capabilities of each driver."""
return cls.CAPABILITIES
@classmethod
def get_storage_capabilities(cls):
"""Return a dictionary representing the performance capabilities.
This is needed to evaluate the performance of each driver.
"""
return cls.STORAGE_CAPABILITIES

View File

@ -0,0 +1,20 @@
#
# 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.
"""DB2 storage backend
"""
from ceilometer.event.storage import pymongo_base
from ceilometer.storage import impl_db2
class Connection(impl_db2.Connection, pymongo_base.Connection):
"""The db2 event storage for Ceilometer."""

View File

@ -0,0 +1,83 @@
#
# 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.
"""HBase storage backend
"""
from ceilometer.openstack.common.gettextutils import _
from ceilometer.openstack.common import log
from ceilometer.storage.hbase import utils as hbase_utils
from ceilometer.storage import impl_hbase as base
from ceilometer import utils
LOG = log.getLogger(__name__)
AVAILABLE_CAPABILITIES = {
'events': {'query': {'simple': True}},
}
AVAILABLE_STORAGE_CAPABILITIES = {
'storage': {'production_ready': True},
}
class Connection(base.Connection):
"""Put the event data into a HBase database
Collections:
- events:
- row_key: timestamp of event's generation + uuid of event
in format: "%s+%s" % (ts, Event.message_id)
- Column Families:
f: contains the following qualifiers:
- event_type: description of event's type
- timestamp: time stamp of event generation
- all traits for this event in format:
.. code-block:: python
"%s+%s" % (trait_name, trait_type)
"""
CAPABILITIES = utils.update_nested(base.Connection.CAPABILITIES,
AVAILABLE_CAPABILITIES)
STORAGE_CAPABILITIES = utils.update_nested(
base.Connection.STORAGE_CAPABILITIES,
AVAILABLE_STORAGE_CAPABILITIES,
)
_memory_instance = None
EVENT_TABLE = "event"
def upgrade(self):
tables = [self.EVENT_TABLE]
column_families = {'f': dict(max_versions=1)}
with self.conn_pool.connection() as conn:
hbase_utils.create_tables(conn, tables, column_families)
def clear(self):
LOG.debug(_('Dropping HBase schema...'))
with self.conn_pool.connection() as conn:
for table in [self.EVENT_TABLE]:
try:
conn.disable_table(table)
except Exception:
LOG.debug(_('Cannot disable table but ignoring error'))
try:
conn.delete_table(table)
except Exception:
LOG.debug(_('Cannot delete table but ignoring error'))

View File

@ -0,0 +1,17 @@
#
# 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.i
from ceilometer.event.storage import base
class Connection(base.Connection):
"""Log event data."""

View File

@ -0,0 +1,19 @@
#
# 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.
"""MongoDB storage backend"""
from ceilometer.event.storage import pymongo_base
from ceilometer.storage import impl_mongodb
class Connection(impl_mongodb.Connection, pymongo_base.Connection):
"""Put the event data into a MongoDB database."""

View File

@ -0,0 +1,59 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""SQLAlchemy storage backend."""
from __future__ import absolute_import
import os
from oslo.config import cfg
from oslo.db.sqlalchemy import session as db_session
from ceilometer.storage import impl_sqlalchemy as base
from ceilometer import utils
AVAILABLE_CAPABILITIES = {
'events': {'query': {'simple': True}},
}
AVAILABLE_STORAGE_CAPABILITIES = {
'storage': {'production_ready': True},
}
class Connection(base.Connection):
"""Put the event data into a SQLAlchemy database.
"""
CAPABILITIES = utils.update_nested(base.Connection.CAPABILITIES,
AVAILABLE_CAPABILITIES)
STORAGE_CAPABILITIES = utils.update_nested(
base.Connection.STORAGE_CAPABILITIES,
AVAILABLE_STORAGE_CAPABILITIES,
)
def __init__(self, url):
self._engine_facade = db_session.EngineFacade(
url,
**dict(cfg.CONF.database.items())
)
def upgrade(self):
# NOTE(gordc): to minimise memory, only import migration when needed
from oslo.db.sqlalchemy import migration
path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'..', '..', 'storage', 'sqlalchemy',
'migrate_repo')
migration.db_sync(self._engine_facade.get_engine(), path)

View 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.
"""Common functions for MongoDB and DB2 backends
"""
from ceilometer.event.storage import base as event_base
from ceilometer.storage import pymongo_base as base
from ceilometer import utils
COMMON_AVAILABLE_CAPABILITIES = {
'events': {'query': {'simple': True}},
}
AVAILABLE_STORAGE_CAPABILITIES = {
'storage': {'production_ready': True},
}
class Connection(base.Connection, event_base.Connection):
"""Base event Connection class for MongoDB and DB2 drivers."""
CAPABILITIES = utils.update_nested(base.Connection.CAPABILITIES,
COMMON_AVAILABLE_CAPABILITIES)
STORAGE_CAPABILITIES = utils.update_nested(
base.Connection.STORAGE_CAPABILITIES,
AVAILABLE_STORAGE_CAPABILITIES,
)

View File

@ -53,6 +53,10 @@ STORAGE_OPTS = [
default=None,
help='The connection string used to connect to the alarm '
'database. (if unset, connection is used)'),
cfg.StrOpt('event_connection',
default=None,
help='The connection string used to connect to the event '
'database. (if unset, connection is used)'),
]
cfg.CONF.register_opts(STORAGE_OPTS, group='database')

View File

@ -61,7 +61,7 @@ class EventTestBase(v2.FunctionalTest,
traits=trait_models))
base += 100
self.trait_time += datetime.timedelta(days=1)
self.conn.record_events(event_models)
self.event_conn.record_events(event_models)
class TestEventTypeAPI(EventTestBase):

View File

@ -52,6 +52,8 @@ class MongoDbManager(fixtures.Fixture):
self.url, 'ceilometer.metering.storage')
self.alarm_connection = storage.get_connection(
self.url, 'ceilometer.alarm.storage')
self.event_connection = storage.get_connection(
self.url, 'ceilometer.event.storage')
except storage.StorageBadVersion as e:
raise testcase.TestSkipped(six.text_type(e))
@ -74,6 +76,8 @@ class MySQLDbManager(fixtures.Fixture):
self.url, 'ceilometer.metering.storage')
self.alarm_connection = storage.get_connection(
self.url, 'ceilometer.alarm.storage')
self.event_connection = storage.get_connection(
self.url, 'ceilometer.event.storage')
@property
def url(self):
@ -90,6 +94,8 @@ class HBaseManager(fixtures.Fixture):
self.url, 'ceilometer.metering.storage')
self.alarm_connection = storage.get_connection(
self.url, 'ceilometer.alarm.storage')
self.event_connection = storage.get_connection(
self.url, 'ceilometer.event.storage')
# Unique prefix for each test to keep data is distinguished because
# all test data is stored in one table
data_prefix = str(uuid.uuid4().hex)
@ -129,6 +135,8 @@ class SQLiteManager(fixtures.Fixture):
self.url, 'ceilometer.metering.storage')
self.alarm_connection = storage.get_connection(
self.url, 'ceilometer.alarm.storage')
self.event_connection = storage.get_connection(
self.url, 'ceilometer.event.storage')
class TestBase(testscenarios.testcase.WithScenarios, test_base.BaseTestCase):
@ -166,6 +174,9 @@ class TestBase(testscenarios.testcase.WithScenarios, test_base.BaseTestCase):
self.alarm_conn = self.db_manager.alarm_connection
self.alarm_conn.upgrade()
self.event_conn = self.db_manager.event_connection
self.event_conn.upgrade()
self.useFixture(mockpatch.Patch('ceilometer.storage.get_connection',
side_effect=self._get_connection))
@ -179,6 +190,8 @@ class TestBase(testscenarios.testcase.WithScenarios, test_base.BaseTestCase):
)
def tearDown(self):
self.event_conn.clear()
self.event_conn = None
self.alarm_conn.clear()
self.alarm_conn = None
self.conn.clear()
@ -188,6 +201,8 @@ class TestBase(testscenarios.testcase.WithScenarios, test_base.BaseTestCase):
def _get_connection(self, url, namespace):
if namespace == "ceilometer.alarm.storage":
return self.alarm_conn
elif namespace == "ceilometer.event.storage":
return self.event_conn
return self.conn
def _get_driver_manager(self, engine):

View File

@ -21,6 +21,7 @@ from oslotest import base
from ceilometer.alarm.storage import impl_log as impl_log_alarm
from ceilometer.alarm.storage import impl_sqlalchemy as impl_sqlalchemy_alarm
from ceilometer.event.storage import impl_hbase as impl_hbase_event
from ceilometer import storage
from ceilometer.storage import impl_log
from ceilometer.storage import impl_sqlalchemy
@ -68,6 +69,21 @@ class ConnectionConfigTest(base.BaseTestCase):
conn = storage.get_connection_from_config(self.CONF, 'alarm')
self.assertIsInstance(conn, impl_sqlalchemy_alarm.Connection)
def test_three_urls(self):
self.CONF.set_override("connection", "log://", group="database")
self.CONF.set_override("alarm_connection", "sqlite://",
group="database")
self.CONF.set_override("event_connection", "hbase://__test__",
group="database")
conn = storage.get_connection_from_config(self.CONF)
self.assertIsInstance(conn, impl_log.Connection)
conn = storage.get_connection_from_config(self.CONF, 'metering')
self.assertIsInstance(conn, impl_log.Connection)
conn = storage.get_connection_from_config(self.CONF, 'alarm')
self.assertIsInstance(conn, impl_sqlalchemy_alarm.Connection)
conn = storage.get_connection_from_config(self.CONF, 'event')
self.assertIsInstance(conn, impl_hbase_event.Connection)
def test_sqlalchemy_driver(self):
self.CONF.set_override("connection", "sqlite+pysqlite://",
group="database")

View File

@ -52,26 +52,26 @@ class TraitTypeTest(tests_db.TestBase):
# Not applicable to other drivers.
def test_trait_type_exists(self):
tt1 = self.conn._get_or_create_trait_type("foo", 0)
tt1 = self.event_conn._get_or_create_trait_type("foo", 0)
self.assertTrue(tt1.id >= 0)
tt2 = self.conn._get_or_create_trait_type("foo", 0)
tt2 = self.event_conn._get_or_create_trait_type("foo", 0)
self.assertEqual(tt2.id, tt1.id)
self.assertEqual(tt2.desc, tt1.desc)
self.assertEqual(tt2.data_type, tt1.data_type)
def test_new_trait_type(self):
tt1 = self.conn._get_or_create_trait_type("foo", 0)
tt1 = self.event_conn._get_or_create_trait_type("foo", 0)
self.assertTrue(tt1.id >= 0)
tt2 = self.conn._get_or_create_trait_type("blah", 0)
tt2 = self.event_conn._get_or_create_trait_type("blah", 0)
self.assertNotEqual(tt1.id, tt2.id)
self.assertNotEqual(tt1.desc, tt2.desc)
# Test the method __repr__ returns a string
self.assertTrue(repr.repr(tt2))
def test_trait_different_data_type(self):
tt1 = self.conn._get_or_create_trait_type("foo", 0)
tt1 = self.event_conn._get_or_create_trait_type("foo", 0)
self.assertTrue(tt1.id >= 0)
tt2 = self.conn._get_or_create_trait_type("foo", 1)
tt2 = self.event_conn._get_or_create_trait_type("foo", 1)
self.assertNotEqual(tt1.id, tt2.id)
self.assertEqual(tt2.desc, tt1.desc)
self.assertNotEqual(tt1.data_type, tt2.data_type)
@ -85,16 +85,16 @@ class EventTypeTest(tests_db.TestBase):
# Not applicable to other drivers.
def test_event_type_exists(self):
et1 = self.conn._get_or_create_event_type("foo")
et1 = self.event_conn._get_or_create_event_type("foo")
self.assertTrue(et1.id >= 0)
et2 = self.conn._get_or_create_event_type("foo")
et2 = self.event_conn._get_or_create_event_type("foo")
self.assertEqual(et2.id, et1.id)
self.assertEqual(et2.desc, et1.desc)
def test_event_type_unique(self):
et1 = self.conn._get_or_create_event_type("foo")
et1 = self.event_conn._get_or_create_event_type("foo")
self.assertTrue(et1.id >= 0)
et2 = self.conn._get_or_create_event_type("blah")
et2 = self.event_conn._get_or_create_event_type("blah")
self.assertNotEqual(et1.id, et2.id)
self.assertNotEqual(et1.desc, et2.desc)
# Test the method __repr__ returns a string
@ -109,7 +109,7 @@ class MyException(Exception):
class EventTest(tests_db.TestBase):
def test_string_traits(self):
model = models.Trait("Foo", models.Trait.TEXT_TYPE, "my_text")
trait = self.conn._make_trait(model, None)
trait = self.event_conn._make_trait(model, None)
self.assertEqual(models.Trait.TEXT_TYPE, trait.trait_type.data_type)
self.assertIsNone(trait.t_float)
self.assertIsNone(trait.t_int)
@ -119,7 +119,7 @@ class EventTest(tests_db.TestBase):
def test_int_traits(self):
model = models.Trait("Foo", models.Trait.INT_TYPE, 100)
trait = self.conn._make_trait(model, None)
trait = self.event_conn._make_trait(model, None)
self.assertEqual(models.Trait.INT_TYPE, trait.trait_type.data_type)
self.assertIsNone(trait.t_float)
self.assertIsNone(trait.t_string)
@ -129,7 +129,7 @@ class EventTest(tests_db.TestBase):
def test_float_traits(self):
model = models.Trait("Foo", models.Trait.FLOAT_TYPE, 123.456)
trait = self.conn._make_trait(model, None)
trait = self.event_conn._make_trait(model, None)
self.assertEqual(models.Trait.FLOAT_TYPE, trait.trait_type.data_type)
self.assertIsNone(trait.t_int)
self.assertIsNone(trait.t_string)
@ -140,7 +140,7 @@ class EventTest(tests_db.TestBase):
def test_datetime_traits(self):
now = datetime.datetime.utcnow()
model = models.Trait("Foo", models.Trait.DATETIME_TYPE, now)
trait = self.conn._make_trait(model, None)
trait = self.event_conn._make_trait(model, None)
self.assertEqual(models.Trait.DATETIME_TYPE,
trait.trait_type.data_type)
self.assertIsNone(trait.t_int)
@ -154,9 +154,9 @@ class EventTest(tests_db.TestBase):
m = [models.Event("1", "Foo", now, []),
models.Event("2", "Zoo", now, [])]
with mock.patch.object(self.conn, "_record_event") as mock_save:
with mock.patch.object(self.event_conn, "_record_event") as mock_save:
mock_save.side_effect = MyException("Boom")
problem_events = self.conn.record_events(m)
problem_events = self.event_conn.record_events(m)
self.assertEqual(2, len(problem_events))
for bad, event in problem_events:
self.assertEqual(bad, models.Event.UNKNOWN_PROBLEM)
@ -227,7 +227,7 @@ class CapabilitiesTest(test_base.BaseTestCase):
'stddev': True,
'cardinality': True}}
},
'events': {'query': {'simple': True}}
'events': {'query': {'simple': True}},
}
actual_capabilities = impl_sqlalchemy.Connection.get_capabilities()

View File

@ -2723,7 +2723,7 @@ class EventTest(EventTestBase):
now = datetime.datetime.utcnow()
m = [event_models.Event("1", "Foo", now, None),
event_models.Event("1", "Zoo", now, [])]
problem_events = self.conn.record_events(m)
problem_events = self.event_conn.record_events(m)
self.assertEqual(1, len(problem_events))
bad = problem_events[0]
self.assertEqual(event_models.Event.DUPLICATE, bad[0])
@ -2753,11 +2753,11 @@ class GetEventTest(EventTestBase):
now = now + datetime.timedelta(hours=1)
self.end = now
self.conn.record_events(self.event_models)
self.event_conn.record_events(self.event_models)
def test_generated_is_datetime(self):
event_filter = storage.EventFilter(self.start, self.end)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(6, len(events))
for i, event in enumerate(events):
self.assertIsInstance(event.generated, datetime.datetime)
@ -2771,7 +2771,7 @@ class GetEventTest(EventTestBase):
def test_simple_get(self):
event_filter = storage.EventFilter(self.start, self.end)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(6, len(events))
start_time = None
for i, type in enumerate(['Foo', 'Bar', 'Zoo']):
@ -2800,7 +2800,7 @@ class GetEventTest(EventTestBase):
}
event_filter = storage.EventFilter(self.start, self.end, "Bar")
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
self.assertEqual(events[0].event_type, "Bar")
self.assertEqual(events[1].event_type, "Bar")
@ -2822,7 +2822,7 @@ class GetEventTest(EventTestBase):
trait_filters = [{'key': 'trait_B', 'integer': 101}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(1, len(events))
self.assertEqual(events[0].event_type, "Bar")
self.assertEqual(4, len(events[0].traits))
@ -2832,38 +2832,38 @@ class GetEventTest(EventTestBase):
'op': 'eq'}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
self.assertEqual("Foo", events[0].event_type)
self.assertEqual(4, len(events[0].traits))
trait_filters[0].update({'key': 'trait_A', 'op': 'lt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
self.assertEqual("Bar", events[0].event_type)
trait_filters[0].update({'key': 'trait_A', 'op': 'le'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(4, len(events))
self.assertEqual("Bar", events[1].event_type)
trait_filters[0].update({'key': 'trait_A', 'op': 'ne'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(4, len(events))
self.assertEqual("Zoo", events[3].event_type)
trait_filters[0].update({'key': 'trait_A', 'op': 'gt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
self.assertEqual("Zoo", events[0].event_type)
trait_filters[0].update({'key': 'trait_A', 'op': 'ge'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(4, len(events))
self.assertEqual("Foo", events[2].event_type)
@ -2871,38 +2871,38 @@ class GetEventTest(EventTestBase):
trait_filters = [{'key': 'trait_B', 'integer': 101, 'op': 'eq'}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(1, len(events))
self.assertEqual("Bar", events[0].event_type)
self.assertEqual(4, len(events[0].traits))
trait_filters[0].update({'key': 'trait_B', 'op': 'lt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(1, len(events))
self.assertEqual("Foo", events[0].event_type)
trait_filters[0].update({'key': 'trait_B', 'op': 'le'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
self.assertEqual("Bar", events[1].event_type)
trait_filters[0].update({'key': 'trait_B', 'op': 'ne'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(5, len(events))
self.assertEqual("Zoo", events[4].event_type)
trait_filters[0].update({'key': 'trait_B', 'op': 'gt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(4, len(events))
self.assertEqual("Zoo", events[0].event_type)
trait_filters[0].update({'key': 'trait_B', 'op': 'ge'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(5, len(events))
self.assertEqual("Foo", events[2].event_type)
@ -2910,38 +2910,38 @@ class GetEventTest(EventTestBase):
trait_filters = [{'key': 'trait_C', 'float': 300.123456, 'op': 'eq'}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(1, len(events))
self.assertEqual("Foo", events[0].event_type)
self.assertEqual(4, len(events[0].traits))
trait_filters[0].update({'key': 'trait_C', 'op': 'lt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(3, len(events))
self.assertEqual("Zoo", events[2].event_type)
trait_filters[0].update({'key': 'trait_C', 'op': 'le'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(4, len(events))
self.assertEqual("Bar", events[1].event_type)
trait_filters[0].update({'key': 'trait_C', 'op': 'ne'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(5, len(events))
self.assertEqual("Zoo", events[2].event_type)
trait_filters[0].update({'key': 'trait_C', 'op': 'gt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
self.assertEqual("Bar", events[0].event_type)
trait_filters[0].update({'key': 'trait_C', 'op': 'ge'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(3, len(events))
self.assertEqual("Zoo", events[2].event_type)
@ -2951,38 +2951,38 @@ class GetEventTest(EventTestBase):
'op': 'eq'}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(1, len(events))
self.assertEqual("Zoo", events[0].event_type)
self.assertEqual(4, len(events[0].traits))
trait_filters[0].update({'key': 'trait_D', 'op': 'lt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(2, len(events))
trait_filters[0].update({'key': 'trait_D', 'op': 'le'})
self.assertEqual("Bar", events[1].event_type)
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(3, len(events))
self.assertEqual("Bar", events[1].event_type)
trait_filters[0].update({'key': 'trait_D', 'op': 'ne'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(5, len(events))
self.assertEqual("Foo", events[2].event_type)
trait_filters[0].update({'key': 'trait_D', 'op': 'gt'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(3, len(events))
self.assertEqual("Zoo", events[2].event_type)
trait_filters[0].update({'key': 'trait_D', 'op': 'ge'})
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(4, len(events))
self.assertEqual("Bar", events[2].event_type)
@ -2991,7 +2991,7 @@ class GetEventTest(EventTestBase):
{'key': 'trait_A', 'string': 'my_Foo_text'}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(1, len(events))
self.assertEqual("Foo", events[0].event_type)
self.assertEqual(4, len(events[0].traits))
@ -3001,12 +3001,12 @@ class GetEventTest(EventTestBase):
{'key': 'trait_A', 'string': 'my_Zoo_text'}]
event_filter = storage.EventFilter(self.start, self.end,
traits_filter=trait_filters)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(0, len(events))
def test_get_event_types(self):
event_types = [e for e in
self.conn.get_event_types()]
self.event_conn.get_event_types()]
self.assertEqual(3, len(event_types))
self.assertTrue("Bar" in event_types)
@ -3015,7 +3015,7 @@ class GetEventTest(EventTestBase):
def test_get_trait_types(self):
trait_types = [tt for tt in
self.conn.get_trait_types("Foo")]
self.event_conn.get_trait_types("Foo")]
self.assertEqual(4, len(trait_types))
trait_type_names = map(lambda x: x['name'], trait_types)
self.assertIn("trait_A", trait_type_names)
@ -3025,11 +3025,11 @@ class GetEventTest(EventTestBase):
def test_get_trait_types_unknown_event(self):
trait_types = [tt for tt in
self.conn.get_trait_types("Moo")]
self.event_conn.get_trait_types("Moo")]
self.assertEqual(0, len(trait_types))
def test_get_traits(self):
traits = self.conn.get_traits("Bar")
traits = self.event_conn.get_traits("Bar")
# format results in a way that makes them easier to work with
trait_dict = {}
for trait in traits:
@ -3046,7 +3046,7 @@ class GetEventTest(EventTestBase):
trait_dict["trait_D"])
def test_get_all_traits(self):
traits = self.conn.get_traits("Foo")
traits = self.event_conn.get_traits("Foo")
traits = sorted([t for t in traits], key=operator.attrgetter('dtype'))
self.assertEqual(8, len(traits))
trait = traits[0]
@ -3056,9 +3056,9 @@ class GetEventTest(EventTestBase):
def test_simple_get_event_no_traits(self):
new_events = [event_models.Event("id_notraits", "NoTraits",
self.start, [])]
bad_events = self.conn.record_events(new_events)
bad_events = self.event_conn.record_events(new_events)
event_filter = storage.EventFilter(self.start, self.end, "NoTraits")
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(0, len(bad_events))
self.assertEqual(1, len(events))
self.assertEqual(events[0].message_id, "id_notraits")
@ -3067,7 +3067,7 @@ class GetEventTest(EventTestBase):
def test_simple_get_no_filters(self):
event_filter = storage.EventFilter(None, None, None)
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(6, len(events))
def test_get_by_message_id(self):
@ -3076,9 +3076,9 @@ class GetEventTest(EventTestBase):
self.start,
[])]
bad_events = self.conn.record_events(new_events)
bad_events = self.event_conn.record_events(new_events)
event_filter = storage.EventFilter(message_id="id_testid")
events = [event for event in self.conn.get_events(event_filter)]
events = [event for event in self.event_conn.get_events(event_filter)]
self.assertEqual(0, len(bad_events))
self.assertEqual(1, len(events))
event = events[0]

View File

@ -193,7 +193,6 @@ ceilometer.poll.central =
network.services.firewall = ceilometer.network.services.fwaas:FirewallPollster
network.services.firewall.policy = ceilometer.network.services.fwaas:FirewallPolicyPollster
ceilometer.alarm.storage =
log = ceilometer.alarm.storage.impl_log:Connection
mongodb = ceilometer.alarm.storage.impl_mongodb:Connection
@ -203,6 +202,15 @@ ceilometer.alarm.storage =
hbase = ceilometer.alarm.storage.impl_hbase:Connection
db2 = ceilometer.alarm.storage.impl_db2:Connection
ceilometer.event.storage =
log = ceilometer.event.storage.impl_log:Connection
mongodb = ceilometer.event.storage.impl_mongodb:Connection
mysql = ceilometer.event.storage.impl_sqlalchemy:Connection
postgresql = ceilometer.event.storage.impl_sqlalchemy:Connection
sqlite = ceilometer.event.storage.impl_sqlalchemy:Connection
hbase = ceilometer.event.storage.impl_hbase:Connection
db2 = ceilometer.event.storage.impl_db2:Connection
ceilometer.metering.storage =
log = ceilometer.storage.impl_log:Connection
mongodb = ceilometer.storage.impl_mongodb:Connection