From 6ca501b0a3385e6d21a187253d7ff454dfaea4a9 Mon Sep 17 00:00:00 2001 From: Vitaly Gridnev Date: Tue, 29 Jul 2014 13:40:44 +0400 Subject: [PATCH] Sahara integration with Ceilometer Added ability for Ceilometer to parse notifications from Sahara Partially implement: blueprint ceilometer-integration Change-Id: I8845500082a6a6892fb1e714c75884a7dd9fff02 --- ceilometer/data_processing/__init__.py | 0 ceilometer/data_processing/notifications.py | 71 +++++++++++++ ceilometer/profiler/notifications.py | 3 +- ceilometer/tests/data_processing/__init__.py | 0 .../data_processing/test_notifications.py | 100 ++++++++++++++++++ setup.cfg | 1 + 6 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 ceilometer/data_processing/__init__.py create mode 100644 ceilometer/data_processing/notifications.py create mode 100644 ceilometer/tests/data_processing/__init__.py create mode 100644 ceilometer/tests/data_processing/test_notifications.py diff --git a/ceilometer/data_processing/__init__.py b/ceilometer/data_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ceilometer/data_processing/notifications.py b/ceilometer/data_processing/notifications.py new file mode 100644 index 000000000..d4e8a9545 --- /dev/null +++ b/ceilometer/data_processing/notifications.py @@ -0,0 +1,71 @@ +# Copyright (c) 2014 Mirantis Inc. +# +# 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.config import cfg +import oslo.messaging + +from ceilometer import plugin +from ceilometer import sample + + +OPTS = [ + cfg.StrOpt('sahara_control_exchange', + default='sahara', + help="Exchange name for Data Processing notifications"), +] + +cfg.CONF.register_opts(OPTS) +SERVICE = 'sahara' + + +class DataProcessing(plugin.NotificationBase): + + resource_name = '%s.cluster' % SERVICE + + @property + def event_types(self): + return [ + '%s.create' % (self.resource_name), + '%s.update' % (self.resource_name), + '%s.delete' % (self.resource_name), + ] + + @staticmethod + def get_targets(conf): + """Return a sequence of oslo.messaging.Target + + It is defining the exchange and topics to be connected for this plugin. + """ + return [oslo.messaging.Target(topic=topic, + exchange=conf.sahara_control_exchange) + for topic in conf.notification_topics] + + def process_notification(self, message): + name = message['event_type'].replace(self.resource_name, 'cluster') + + project_id = message['payload']['project_id'] + + user_id = message['_context_user_id'] + + yield sample.Sample.from_notification( + name=name, + type=sample.TYPE_DELTA, + unit='cluster', + volume=1, + resource_id=message['payload']['cluster_id'], + user_id=user_id, + project_id=project_id, + message=message) diff --git a/ceilometer/profiler/notifications.py b/ceilometer/profiler/notifications.py index e6c7b8749..3f51fa14b 100644 --- a/ceilometer/profiler/notifications.py +++ b/ceilometer/profiler/notifications.py @@ -42,7 +42,8 @@ class ProfilerNotifications(plugin.NotificationBase): conf.glance_control_exchange, conf.neutron_control_exchange, conf.heat_control_exchange, - conf.keystone_control_exchange + conf.keystone_control_exchange, + conf.sahara_control_exchange, ] for exchange in exchanges: diff --git a/ceilometer/tests/data_processing/__init__.py b/ceilometer/tests/data_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ceilometer/tests/data_processing/test_notifications.py b/ceilometer/tests/data_processing/test_notifications.py new file mode 100644 index 000000000..9a7f787eb --- /dev/null +++ b/ceilometer/tests/data_processing/test_notifications.py @@ -0,0 +1,100 @@ +# Copyright (c) 2014 Mirantis Inc. +# +# 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 datetime + +import mock +from oslo.config import cfg + +from ceilometer.data_processing import notifications +from ceilometer.openstack.common import log +from ceilometer.openstack.common import test +from ceilometer import sample + +NOW = datetime.datetime.isoformat(datetime.datetime.utcnow()) + +TENANT_ID = u'4c35985848bf4419b3f3d52c22e5792d' +CLUSTER_NAME = u'AS1-ASGroup-53sqbo7sor7i' +CLUSTER_ID = u'cb4a6fd1-1f5d-4002-ae91-9b91573cfb03' +USER_NAME = u'demo' +USER_ID = u'2e61f25ec63a4f6c954a6245421448a4' +CLUSTER_STATUS = u'Active' +PROJECT_ID = TENANT_ID +RESOURCE_ID = CLUSTER_ID +PUBLISHER_ID = u'data_processing.node-n5x66lxdy67d' + + +CONF = cfg.CONF +CONF.set_override('use_stderr', True) + +LOG = log.getLogger(__name__) + + +def _dp_notification_for(operation): + + return { + u'event_type': '%s.cluster.%s' % (notifications.SERVICE, + operation), + u'_context_roles': [ + u'Member', + ], + u'_context_auth_uri': u'http://0.1.0.1:1010/v2.0', + u'timestamp': NOW, + u'_context_tenant_id': TENANT_ID, + u'payload': { + u'cluster_id': CLUSTER_ID, + u'cluster_name': CLUSTER_NAME, + u'cluster_status': CLUSTER_STATUS, + u'project_id': TENANT_ID, + u'user_id': USER_ID, + }, + u'_context_username': USER_NAME, + u'_context_token': u'MIISAwYJKoZIhvcNAQcCoII...', + u'_context_user_id': USER_ID, + u'_context_tenant_name': USER_NAME, + u'priority': u'INFO', + u'_context_is_admin': False, + u'publisher_id': PUBLISHER_ID, + u'message_id': u'ef921faa-7f7b-4854-8b86-a424ab93c96e', + } + + +class TestNotification(test.BaseTestCase): + def _verify_common_sample(self, actual, operation): + self.assertIsNotNone(actual) + self.assertEqual('cluster.%s' % operation, actual.name) + self.assertEqual(NOW, actual.timestamp) + self.assertEqual(sample.TYPE_DELTA, actual.type) + self.assertEqual(PROJECT_ID, actual.project_id) + self.assertEqual(RESOURCE_ID, actual.resource_id) + self.assertEqual(USER_ID, actual.user_id) + metadata = actual.resource_metadata + self.assertEqual(PUBLISHER_ID, metadata.get('host')) + + def _test_operation(self, operation): + notif = _dp_notification_for(operation) + handler = notifications.DataProcessing(mock.Mock()) + data = list(handler.process_notification(notif)) + self.assertEqual(1, len(data)) + self._verify_common_sample(data[0], operation) + + def test_create(self): + self._test_operation('create') + + def test_update(self): + self._test_operation('update') + + def test_delete(self): + self._test_operation('delete') diff --git a/setup.cfg b/setup.cfg index 839679063..1bf09079c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,6 +65,7 @@ ceilometer.notification = http.request = ceilometer.middleware:HTTPRequest http.response = ceilometer.middleware:HTTPResponse stack_crud = ceilometer.orchestration.notifications:StackCRUD + data_processing = ceilometer.data_processing.notifications:DataProcessing profiler = ceilometer.profiler.notifications:ProfilerNotifications hardware.ipmi.temperature = ceilometer.hardware.notifications.ipmi:TemperatureSensorNotification hardware.ipmi.voltage = ceilometer.hardware.notifications.ipmi:VoltageSensorNotification