Merge "Enable entry points for new declarative meters"

This commit is contained in:
Jenkins 2015-08-07 14:11:20 +00:00 committed by Gerrit Code Review
commit 02a10d6735
20 changed files with 174 additions and 1152 deletions

View File

@ -93,7 +93,7 @@ class NotificationBase(PluginBase):
super(NotificationBase, self).__init__()
# NOTE(gordc): this is filter rule used by oslo.messaging to dispatch
# messages to an endpoint.
if self.event_types is not None:
if self.event_types:
self.filter_rule = oslo_messaging.NotificationFilter(
event_type='|'.join(self.event_types))
self.manager = manager

View File

@ -0,0 +1,26 @@
#
# 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
EXCHANGE_OPTS = [
cfg.StrOpt('heat_control_exchange',
default='heat',
help="Exchange name for Heat notifications"),
cfg.StrOpt('glance_control_exchange',
default='glance',
help="Exchange name for Glance notifications."),
cfg.StrOpt('magnetodb_control_exchange',
default='magnetodb',
help="Exchange name for Magnetodb notifications."),
]

View File

@ -1,126 +0,0 @@
#
# Copyright 2012 Red Hat, 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.
"""Handler for producing image metering messages from glance notification
events.
"""
from oslo_config import cfg
import oslo_messaging
from ceilometer.agent import plugin_base
from ceilometer import sample
OPTS = [
cfg.StrOpt('glance_control_exchange',
default='glance',
help="Exchange name for Glance notifications."),
]
cfg.CONF.register_opts(OPTS)
class ImageBase(plugin_base.NotificationBase):
"""Base class for image counting."""
@staticmethod
def get_targets(conf):
"""Return a sequence of oslo_messaging.Target
This sequence is defining the exchange and topics to be connected for
this plugin.
"""
return [oslo_messaging.Target(topic=topic,
exchange=conf.glance_control_exchange)
for topic in conf.notification_topics]
class ImageCRUDBase(ImageBase):
event_types = [
'image.update',
'image.upload',
'image.delete',
]
class ImageCRUD(ImageCRUDBase, plugin_base.NonMetricNotificationBase):
def process_notification(self, message):
yield sample.Sample.from_notification(
name=message['event_type'],
type=sample.TYPE_DELTA,
unit='image',
volume=1,
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
message=message)
class Image(ImageCRUDBase, plugin_base.NonMetricNotificationBase):
def process_notification(self, message):
yield sample.Sample.from_notification(
name='image',
type=sample.TYPE_GAUGE,
unit='image',
volume=1,
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
message=message)
class ImageSize(ImageCRUDBase):
def process_notification(self, message):
yield sample.Sample.from_notification(
name='image.size',
type=sample.TYPE_GAUGE,
unit='B',
volume=message['payload']['size'],
resource_id=message['payload']['id'],
user_id=None,
project_id=message['payload']['owner'],
message=message)
class ImageDownload(ImageBase):
"""Emit image_download sample when an image is downloaded."""
event_types = ['image.send']
def process_notification(self, message):
yield sample.Sample.from_notification(
name='image.download',
type=sample.TYPE_DELTA,
unit='B',
volume=message['payload']['bytes_sent'],
resource_id=message['payload']['image_id'],
user_id=message['payload']['receiver_user_id'],
project_id=message['payload']['receiver_tenant_id'],
message=message)
class ImageServe(ImageBase):
"""Emit image_serve sample when an image is served out."""
event_types = ['image.send']
def process_notification(self, message):
yield sample.Sample.from_notification(
name='image.serve',
type=sample.TYPE_DELTA,
unit='B',
volume=message['payload']['bytes_sent'],
resource_id=message['payload']['image_id'],
user_id=None,
project_id=message['payload']['owner_id'],
message=message)

View File

@ -1,79 +0,0 @@
# 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.agent import plugin_base
from ceilometer import sample
OPTS = [
cfg.StrOpt('magnetodb_control_exchange',
default='magnetodb',
help="Exchange name for Magnetodb notifications."),
]
cfg.CONF.register_opts(OPTS)
class _Base(plugin_base.NotificationBase):
"""Convert magnetodb notification into Samples."""
@staticmethod
def get_targets(conf):
"""Return a sequence of oslo_messaging.Target
Sequence defining the exchange and topics to be connected for this
plugin.
"""
return [oslo_messaging.Target(topic=topic,
exchange=conf.magnetodb_control_exchange)
for topic in conf.notification_topics]
class Table(_Base, plugin_base.NonMetricNotificationBase):
event_types = [
'magnetodb.table.create.end',
'magnetodb.table.delete.end'
]
def process_notification(self, message):
meter_name = '.'.join(message['event_type'].split('.')[:-1])
yield sample.Sample.from_notification(
name=meter_name,
type=sample.TYPE_GAUGE,
unit='table',
volume=1,
resource_id=message['payload']['table_uuid'],
user_id=message['_context_user'],
project_id=message['_context_tenant'],
message=message)
class Index(_Base):
event_types = [
'magnetodb.table.create.end'
]
def process_notification(self, message):
yield sample.Sample.from_notification(
name='magnetodb.table.index.count',
type=sample.TYPE_GAUGE,
unit='index',
volume=message['payload']['index_count'],
resource_id=message['payload']['table_uuid'],
user_id=message['_context_user'],
project_id=message['_context_tenant'],
message=message)

View File

@ -0,0 +1,126 @@
---
metric:
# Image
- name: "image.size"
event_type:
- "image.upload"
- "image.delete"
- "image.update"
type: "gauge"
unit: B
volume: payload.size
resource_id: payload.id
project_id: payload.owner
- name: "image.download"
event_type: "image.send"
type: "delta"
unit: "B"
volume: payload.bytes_sent
resource_id: payload.image_id
user_id: payload.receiver_user_id
project_id: payload.receiver_tenant_id
- name: "image.serve"
event_type: "image.send"
type: "delta"
unit: "B"
volume: payload.bytes_sent
resource_id: payload.image_id
project_id: payload.owner_id
# MagnetoDB
- name: 'magnetodb.table.index.count'
type: 'gauge'
unit: 'index'
event_type: 'magnetodb.table.create.end'
volume: payload.index_count
resource_id: payload.table_uuid
user_id: _context_user
# NOTE: non-metric meters are generally events/existence meters
# These are expected to be DEPRECATED in future releases
#
# Image
- name: "image"
event_type:
- "image.upload"
- "image.delete"
- "image.update"
type: "gauge"
unit: 'image'
volume: 1
resource_id: payload.id
project_id: payload.owner
# Orchestration
- name: 'stack.create'
event_type:
- 'orchestration.stack.create.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.update'
event_type:
- 'orchestration.stack.update.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.delete'
event_type:
- 'orchestration.stack.delete.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.resume'
event_type:
- 'orchestration.stack.resume.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.suspend'
event_type:
- 'orchestration.stack.suspend.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
# MagnetoDB
- name: 'magnetodb.table.create'
type: 'gauge'
unit: 'table'
volume: 1
event_type: 'magnetodb.table.create.end'
resource_id: payload.table_uuid
user_id: _context_user
project_id: _context_tenant
- name: 'magnetodb.table.delete'
type: 'gauge'
unit: 'table'
volume: 1
event_type: 'magnetodb.table.delete.end'
resource_id: payload.table_uuid
user_id: _context_user
project_id: _context_tenant

View File

@ -13,6 +13,7 @@
import fnmatch
import os
import pkg_resources
import six
import yaml
@ -95,6 +96,9 @@ def get_config_file():
config_file = cfg.CONF.meter.meter_definitions_cfg_file
if not os.path.exists(config_file):
config_file = cfg.CONF.find_file(config_file)
if not config_file:
config_file = pkg_resources.resource_filename(
__name__, "data/meters.yaml")
return config_file
@ -127,7 +131,7 @@ def setup_meters_config():
else:
LOG.debug(_LE("No Meter Definitions configuration file found!"
" Using default config."))
meters_config = []
meters_config = {}
LOG.info(_LE("Meter Definitions: %s"), meters_config)
@ -135,13 +139,15 @@ def setup_meters_config():
def load_definitions(config_def):
if not config_def:
return []
return [MeterDefinition(event_def)
for event_def in reversed(config_def['metric'])]
class ProcessMeterNotifications(plugin_base.NotificationBase):
event_types = None
event_types = []
def __init__(self, manager):
super(ProcessMeterNotifications, self).__init__(manager)

View File

@ -22,7 +22,7 @@ from ceilometer import sample
cfg.CONF.import_opt('nova_control_exchange',
'ceilometer.compute.notifications')
cfg.CONF.import_opt('glance_control_exchange',
'ceilometer.image.notifications')
'ceilometer.notification')
cfg.CONF.import_opt('neutron_control_exchange',
'ceilometer.network.notifications')
cfg.CONF.import_opt('cinder_control_exchange',

View File

@ -23,6 +23,7 @@ from ceilometer.agent import plugin_base as base
from ceilometer import coordination
from ceilometer.event import endpoint as event_endpoint
from ceilometer.i18n import _, _LI, _LW
from ceilometer import exchange_control
from ceilometer import messaging
from ceilometer import pipeline
from ceilometer import service_base
@ -60,6 +61,7 @@ OPTS = [
"(DEFAULT/transport_url is used if empty)"),
]
cfg.CONF.register_opts(exchange_control.EXCHANGE_OPTS)
cfg.CONF.register_opts(OPTS, group="notification")
cfg.CONF.import_opt('telemetry_driver', 'ceilometer.publisher.messaging',
group='publisher_notifier')

View File

@ -38,7 +38,6 @@ import ceilometer.event.converter
import ceilometer.hardware.discovery
import ceilometer.identity.notifications
import ceilometer.image.glance
import ceilometer.image.notifications
import ceilometer.ipmi.notifications.ironic
import ceilometer.ipmi.platform.intel_node_manager
import ceilometer.ipmi.pollsters
@ -49,7 +48,6 @@ import ceilometer.notification
import ceilometer.nova_client
import ceilometer.objectstore.rgw
import ceilometer.objectstore.swift
import ceilometer.orchestration.notifications
import ceilometer.pipeline
import ceilometer.profiler.notifications
import ceilometer.publisher.messaging
@ -75,13 +73,11 @@ def list_opts():
ceilometer.dispatcher.OPTS,
ceilometer.identity.notifications.OPTS,
ceilometer.image.glance.OPTS,
ceilometer.image.notifications.OPTS,
ceilometer.ipmi.notifications.ironic.OPTS,
ceilometer.middleware.OPTS,
ceilometer.network.notifications.OPTS,
ceilometer.nova_client.OPTS,
ceilometer.objectstore.swift.OPTS,
ceilometer.orchestration.notifications.OPTS,
ceilometer.pipeline.OPTS,
ceilometer.profiler.notifications.OPTS,
ceilometer.sample.OPTS,

View File

@ -1,76 +0,0 @@
# 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.
"""Handler for producing orchestration metering from Heat notification
events.
"""
from oslo_config import cfg
import oslo_messaging
from ceilometer.agent import plugin_base
from ceilometer import sample
OPTS = [
cfg.StrOpt('heat_control_exchange',
default='heat',
help="Exchange name for Heat notifications"),
]
cfg.CONF.register_opts(OPTS)
SERVICE = 'orchestration'
class StackCRUD(plugin_base.NotificationBase,
plugin_base.NonMetricNotificationBase):
resource_name = '%s.stack' % SERVICE
@property
def event_types(self):
return [
'%s.create.end' % self.resource_name,
'%s.update.end' % self.resource_name,
'%s.delete.end' % self.resource_name,
'%s.resume.end' % self.resource_name,
'%s.suspend.end' % 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.heat_control_exchange)
for topic in conf.notification_topics]
def process_notification(self, message):
name = (message['event_type'].replace(self.resource_name, 'stack')
.replace('.end', ''))
project_id = message['payload']['tenant_id']
# Trying to use the trustor_id if trusts is used by Heat,
user_id = (message.get('_context_trustor_user_id') or
message['_context_user_id'])
yield sample.Sample.from_notification(
name=name,
type=sample.TYPE_DELTA,
unit='stack',
volume=1,
resource_id=message['payload']['stack_identity'],
user_id=user_id,
project_id=project_id,
message=message)

View File

@ -33,6 +33,7 @@ from ceilometer.compute.notifications import instance
from ceilometer import messaging
from ceilometer import notification
from ceilometer.publisher import test as test_publisher
from ceilometer import service
from ceilometer.tests import base as tests_base
TEST_NOTICE_CTXT = {
@ -198,6 +199,7 @@ class BaseRealNotification(tests_base.BaseTestCase):
def setUp(self):
super(BaseRealNotification, self).setUp()
self.CONF = self.useFixture(fixture_config.Config()).conf
service.prepare_service([])
self.setup_messaging(self.CONF, 'nova')
pipeline_cfg_file = self.setup_pipeline(['instance', 'memory'])

View File

@ -1,197 +0,0 @@
#
# Copyright 2012 Red Hat 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 oslotest import base
from ceilometer.image import notifications
from ceilometer import sample
def fake_uuid(x):
return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12)
NOW = datetime.datetime.isoformat(datetime.datetime.utcnow())
NOTIFICATION_SEND = {
u'event_type': u'image.send',
u'timestamp': NOW,
u'message_id': fake_uuid('a'),
u'priority': u'INFO',
u'publisher_id': u'images.example.com',
u'payload': {u'receiver_tenant_id': fake_uuid('b'),
u'destination_ip': u'1.2.3.4',
u'bytes_sent': 42,
u'image_id': fake_uuid('c'),
u'receiver_user_id': fake_uuid('d'),
u'owner_id': fake_uuid('e')}
}
IMAGE_META = {u'status': u'saving',
u'name': u'fake image #3',
u'deleted': False,
u'container_format': u'ovf',
u'created_at': u'2012-09-18T10:13:44.571370',
u'disk_format': u'vhd',
u'updated_at': u'2012-09-18T10:13:44.623120',
u'properties': {u'key2': u'value2',
u'key1': u'value1'},
u'min_disk': 0,
u'protected': False,
u'id': fake_uuid('c'),
u'location': None,
u'checksum': u'd990432ef91afef3ad9dbf4a975d3365',
u'owner': "fake",
u'is_public': False,
u'deleted_at': None,
u'min_ram': 0,
u'size': 19}
NOTIFICATION_UPDATE = {"message_id": "0c65cb9c-018c-11e2-bc91-5453ed1bbb5f",
"publisher_id": "images.example.com",
"event_type": "image.update",
"priority": "info",
"payload": IMAGE_META,
"timestamp": NOW}
NOTIFICATION_UPLOAD = {"message_id": "0c65cb9c-018c-11e2-bc91-5453ed1bbb5f",
"publisher_id": "images.example.com",
"event_type": "image.upload",
"priority": "info",
"payload": IMAGE_META,
"timestamp": NOW}
NOTIFICATION_DELETE = {"message_id": "0c65cb9c-018c-11e2-bc91-5453ed1bbb5f",
"publisher_id": "images.example.com",
"event_type": "image.delete",
"priority": "info",
"payload": IMAGE_META,
"timestamp": NOW}
class TestNotification(base.BaseTestCase):
def _verify_common_counter(self, c, name, volume):
self.assertIsNotNone(c)
self.assertEqual(name, c.name)
self.assertEqual(fake_uuid('c'), c.resource_id)
self.assertEqual(NOW, c.timestamp)
self.assertEqual(volume, c.volume)
metadata = c.resource_metadata
self.assertEqual(u'images.example.com', metadata.get('host'))
def test_image_download(self):
handler = notifications.ImageDownload(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_SEND))
self.assertEqual(1, len(counters))
download = counters[0]
self._verify_common_counter(download, 'image.download', 42)
self.assertEqual(fake_uuid('d'), download.user_id)
self.assertEqual(fake_uuid('b'), download.project_id)
self.assertEqual(sample.TYPE_DELTA, download.type)
def test_image_serve(self):
handler = notifications.ImageServe(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_SEND))
self.assertEqual(1, len(counters))
serve = counters[0]
self._verify_common_counter(serve, 'image.serve', 42)
self.assertEqual(fake_uuid('e'), serve.project_id)
self.assertEqual(fake_uuid('d'),
serve.resource_metadata.get('receiver_user_id'))
self.assertEqual(fake_uuid('b'),
serve.resource_metadata.get('receiver_tenant_id'))
self.assertEqual(sample.TYPE_DELTA, serve.type)
def test_image_crud_on_update(self):
handler = notifications.ImageCRUD(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_UPDATE))
self.assertEqual(1, len(counters))
update = counters[0]
self._verify_common_counter(update, 'image.update', 1)
self.assertEqual(sample.TYPE_DELTA, update.type)
def test_image_on_update(self):
handler = notifications.Image(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_UPDATE))
self.assertEqual(1, len(counters))
update = counters[0]
self._verify_common_counter(update, 'image', 1)
self.assertEqual(sample.TYPE_GAUGE, update.type)
def test_image_size_on_update(self):
handler = notifications.ImageSize(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_UPDATE))
self.assertEqual(1, len(counters))
update = counters[0]
self._verify_common_counter(update, 'image.size',
IMAGE_META['size'])
self.assertEqual(sample.TYPE_GAUGE, update.type)
def test_image_crud_on_upload(self):
handler = notifications.ImageCRUD(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_UPLOAD))
self.assertEqual(1, len(counters))
upload = counters[0]
self._verify_common_counter(upload, 'image.upload', 1)
self.assertEqual(sample.TYPE_DELTA, upload.type)
def test_image_on_upload(self):
handler = notifications.Image(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_UPLOAD))
self.assertEqual(1, len(counters))
upload = counters[0]
self._verify_common_counter(upload, 'image', 1)
self.assertEqual(sample.TYPE_GAUGE, upload.type)
def test_image_size_on_upload(self):
handler = notifications.ImageSize(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_UPLOAD))
self.assertEqual(1, len(counters))
upload = counters[0]
self._verify_common_counter(upload, 'image.size',
IMAGE_META['size'])
self.assertEqual(sample.TYPE_GAUGE, upload.type)
def test_image_crud_on_delete(self):
handler = notifications.ImageCRUD(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_DELETE))
self.assertEqual(1, len(counters))
delete = counters[0]
self._verify_common_counter(delete, 'image.delete', 1)
self.assertEqual(sample.TYPE_DELTA, delete.type)
def test_image_on_delete(self):
handler = notifications.Image(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_DELETE))
self.assertEqual(1, len(counters))
delete = counters[0]
self._verify_common_counter(delete, 'image', 1)
self.assertEqual(sample.TYPE_GAUGE, delete.type)
def test_image_size_on_delete(self):
handler = notifications.ImageSize(mock.Mock())
counters = list(handler.process_notification(NOTIFICATION_DELETE))
self.assertEqual(1, len(counters))
delete = counters[0]
self._verify_common_counter(delete, 'image.size',
IMAGE_META['size'])
self.assertEqual(sample.TYPE_GAUGE, delete.type)

View File

@ -1,124 +0,0 @@
# 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 fixture as fixture_config
from ceilometer.meter import notifications
from ceilometer import sample
from ceilometer.tests import base as test
def fake_uuid(x):
return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12)
NOW = datetime.datetime.isoformat(datetime.datetime.utcnow())
TABLE_CREATE_PAYLOAD = {
u'table_uuid': fake_uuid('r'),
u'index_count': 2,
u'table_name': u'email_data'
}
TABLE_DELETE_PAYLOAD = {
u'table_uuid': fake_uuid('r'),
u'table_name': u'email_data'
}
NOTIFICATION_TABLE_CREATE = {
u'_context_request_id': u'req-d6e9b7ec-976f-443f-ba6e-e2b89b18aa75',
u'_context_tenant': fake_uuid('t'),
u'_context_user': fake_uuid('u'),
u'_context_auth_token': u'',
u'_context_show_deleted': False,
u'_context_is_admin': u'False',
u'_context_read_only': False,
'payload': TABLE_CREATE_PAYLOAD,
'publisher_id': u'magnetodb.winterfell.com',
'message_id': u'3d71fb8a-f1d7-4a4e-b29f-7a711a761ba1',
'event_type': u'magnetodb.table.create.end',
'timestamp': NOW,
'priority': 'info'
}
NOTIFICATION_TABLE_DELETE = {
u'_context_request_id': u'req-d6e9b7ec-976f-443f-ba6e-e2b89b18aa75',
u'_context_tenant': fake_uuid('t'),
u'_context_user': fake_uuid('u'),
u'_context_auth_token': u'',
u'_context_show_deleted': False,
u'_context_is_admin': u'False',
u'_context_read_only': False,
'payload': TABLE_DELETE_PAYLOAD,
'publisher_id': u'magnetodb.winterfell.com',
'message_id': u'4c8f5940-3c90-41af-ac16-f0e3055a305d',
'event_type': u'magnetodb.table.delete.end',
'timestamp': NOW,
'priority': 'info'
}
class TestNotification(test.BaseTestCase):
def setUp(self):
super(TestNotification, self).setUp()
self.CONF = self.useFixture(fixture_config.Config()).conf
self.CONF.set_override(
'meter_definitions_cfg_file',
self.path_get('etc/ceilometer/meters.yaml'), group='meter')
self.handler = notifications.ProcessMeterNotifications(mock.Mock())
def _verify_common_counter(self, c, name, volume):
self.assertIsNotNone(c)
self.assertEqual(name, c.name)
self.assertEqual(fake_uuid('r'), c.resource_id)
self.assertEqual(NOW, c.timestamp)
self.assertEqual(volume, c.volume)
metadata = c.resource_metadata
self.assertEqual(u'magnetodb.winterfell.com', metadata.get('host'))
def test_create_table(self):
counters = list(self.handler.process_notification(
NOTIFICATION_TABLE_CREATE))
self.assertEqual(2, len(counters))
table = [item for item in counters
if item.name == "magnetodb.table.create"][0]
self._verify_common_counter(table, 'magnetodb.table.create', 1)
self.assertEqual(fake_uuid('u'), table.user_id)
self.assertEqual(fake_uuid('t'), table.project_id)
self.assertEqual(sample.TYPE_GAUGE, table.type)
def test_delete_table(self):
counters = list(self.handler.process_notification(
NOTIFICATION_TABLE_DELETE))
self.assertEqual(1, len(counters))
table = counters[0]
self._verify_common_counter(table, 'magnetodb.table.delete', 1)
self.assertEqual(fake_uuid('u'), table.user_id)
self.assertEqual(fake_uuid('t'), table.project_id)
self.assertEqual(sample.TYPE_GAUGE, table.type)
def test_index_count(self):
counters = list(self.handler.process_notification(
NOTIFICATION_TABLE_CREATE))
self.assertEqual(2, len(counters))
table = [item for item in counters
if item.name == "magnetodb.table.index.count"][0]
self._verify_common_counter(table, 'magnetodb.table.index.count', 2)
self.assertEqual(fake_uuid('u'), table.user_id)
self.assertEqual(fake_uuid('t'), table.project_id)
self.assertEqual(sample.TYPE_GAUGE, table.type)

View File

@ -20,6 +20,7 @@ from oslo_config import fixture as fixture_config
from oslo_utils import fileutils
from ceilometer.meter import notifications
from ceilometer import service as ceilometer_service
from ceilometer.tests import base as test
NOTIFICATION = {
@ -82,11 +83,13 @@ class TestMeterProcessing(test.BaseTestCase):
def setUp(self):
super(TestMeterProcessing, self).setUp()
self.CONF = self.useFixture(fixture_config.Config()).conf
self.CONF.set_override(
'meter_definitions_cfg_file',
self.path_get('etc/ceilometer/meters.yaml'), group='meter')
ceilometer_service.prepare_service([])
self.handler = notifications.ProcessMeterNotifications(mock.Mock())
def test_fallback_meter_path(self):
fall_bak_path = notifications.get_config_file()
self.assertIn("meter/data/meters.yaml", fall_bak_path)
def __setup_meter_def_file(self, cfg):
if six.PY3:
cfg = cfg.encode('utf-8')

View File

@ -1,138 +0,0 @@
# 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 oslo_config import fixture as fixture_config
from oslo_log import log
from ceilometer.meter import notifications
from ceilometer import sample
from ceilometer.tests import base as test
NOW = datetime.datetime.isoformat(datetime.datetime.utcnow())
TENANT_ID = u'4c35985848bf4419b3f3d52c22e5792d'
STACK_NAME = u'AS1-ASGroup-53sqbo7sor7i'
STACK_ID = u'cb4a6fd1-1f5d-4002-ae91-9b91573cfb03'
USER_NAME = u'demo'
USER_ID = u'2e61f25ec63a4f6c954a6245421448a4'
TRUSTOR_ID = u'foo-Trustor-Id'
STACK_ARN = u'arn:openstack:heat::%s:stacks/%s/%s' % (TENANT_ID,
STACK_NAME,
STACK_ID)
CONF = cfg.CONF
log.register_options(CONF)
CONF.set_override('use_stderr', True)
LOG = log.getLogger(__name__)
def stack_notification_for(operation, use_trust=None):
if use_trust:
trust_id = 'footrust'
trustor_id = TRUSTOR_ID
else:
trust_id = None
trustor_id = None
return {
u'event_type': 'orchestration.stack.%s.end' % operation,
u'_context_roles': [
u'Member',
],
u'_context_request_id': u'req-cf24cf30-af35-4a47-ae29-e74d75ebc6de',
u'_context_auth_url': u'http://0.1.0.1:1010/v2.0',
u'timestamp': NOW,
u'_unique_id': u'1afb4283660f410c802af4d5992a39f2',
u'_context_tenant_id': TENANT_ID,
u'payload': {
u'state_reason': u'Stack create completed successfully',
u'user_id': USER_NAME,
u'stack_identity': STACK_ARN,
u'stack_name': STACK_NAME,
u'tenant_id': TENANT_ID,
u'create_at': u'2014-01-27T13:13:19Z',
u'state': u'CREATE_COMPLETE'
},
u'_context_username': USER_NAME,
u'_context_auth_token': u'MIISAwYJKoZIhvcNAQcCoII...',
u'_context_password': u'password',
u'_context_user_id': USER_ID,
u'_context_trustor_user_id': trustor_id,
u'_context_aws_creds': None,
u'_context_show_deleted': False,
u'_context_tenant': USER_NAME,
u'_context_trust_id': trust_id,
u'priority': u'INFO',
u'_context_is_admin': False,
u'_context_user': USER_NAME,
u'publisher_id': u'orchestration.node-n5x66lxdy67d',
u'message_id': u'ef921faa-7f7b-4854-8b86-a424ab93c96e',
}
class TestNotification(test.BaseTestCase):
def setUp(self):
super(TestNotification, self).setUp()
self.CONF = self.useFixture(fixture_config.Config()).conf
self.CONF.set_override(
'meter_definitions_cfg_file',
self.path_get('etc/ceilometer/meters.yaml'), group='meter')
self.handler = notifications.ProcessMeterNotifications(mock.Mock())
def _verify_common_sample(self, s, name, volume):
self.assertIsNotNone(s)
self.assertEqual('stack.%s' % name, s.name)
self.assertEqual(NOW, s.timestamp)
self.assertEqual(sample.TYPE_DELTA, s.type)
self.assertEqual(TENANT_ID, s.project_id)
self.assertEqual(STACK_ARN, s.resource_id)
metadata = s.resource_metadata
self.assertEqual(u'orchestration.node-n5x66lxdy67d',
metadata.get('host'))
def _test_operation(self, operation, trust=None):
notif = stack_notification_for(operation, trust)
data = list(self.handler.process_notification(notif))
self.assertEqual(1, len(data))
if trust:
self.assertEqual(TRUSTOR_ID, data[0].user_id)
else:
self.assertEqual(USER_ID, data[0].user_id)
self._verify_common_sample(data[0], operation, 1)
def test_create(self):
self._test_operation('create')
def test_create_trust(self):
self._test_operation('create', trust=True)
def test_update(self):
self._test_operation('update')
def test_delete(self):
self._test_operation('delete')
def test_resume(self):
self._test_operation('resume')
def test_suspend(self):
self._test_operation('suspend')

View File

@ -256,6 +256,7 @@ function configure_ceilometer {
cp $CEILOMETER_DIR/etc/ceilometer/event_definitions.yaml $CEILOMETER_CONF_DIR
cp $CEILOMETER_DIR/etc/ceilometer/gnocchi_archive_policy_map.yaml $CEILOMETER_CONF_DIR
cp $CEILOMETER_DIR/etc/ceilometer/gnocchi_resources.yaml $CEILOMETER_CONF_DIR
cp $CEILOMETER_DIR/ceilometer/meter/data/meters.yaml $CEILOMETER_CONF_DIR
if [ "$CEILOMETER_PIPELINE_INTERVAL" ]; then
sed -i "s/interval:.*/interval: ${CEILOMETER_PIPELINE_INTERVAL}/" $CEILOMETER_CONF_DIR/pipeline.yaml

View File

@ -1,393 +0,0 @@
---
metric:
- name: "image.size"
event_type:
- "image.upload"
- "image.delete"
- "image.update"
type: "gauge"
unit: B
volume: payload.size
resource_id: payload.id
project_id: payload.owner
- name: "image.download"
event_type: "image.send"
type: "delta"
unit: "B"
volume: payload.bytes_sent
resource_id: payload.image_id
user_id: payload.receiver_user_id
project_id: payload.receiver_tenant_id
- name: "image.serve"
event_type: "image.send"
type: "delta"
unit: "B"
volume: payload.bytes_sent
resource_id: payload.image_id
project_id: payload.owner_id
- name: 'bandwidth'
event_type: 'l3.meter'
type: 'delta'
unit: 'B'
volume: payload.bytes
project_id: payload.tenant_id
resource_id: payload.label_id
- name: 'magnetodb.table.index.count'
type: 'gauge'
unit: 'index'
event_type: 'magnetodb.table.create.end'
volume: payload.index_count
resource_id: payload.table_uuid
user_id: _context_user
- name: 'memory'
event_type: 'compute.instance.*'
type: 'gauge'
unit: 'MB'
volume: payload.memory_mb
user_id: payload.user_id
project_id: payload.tenant_id
resource_id: payload.instance_id
- name: 'vcpus'
event_type: 'compute.instance.*'
type: 'gauge'
unit: 'vcpu'
volume: payload.vcpus
user_id: payload.user_id
project_id: payload.tenant_id
resource_id: payload.instance_id
- name: 'disk.root.size'
event_type: 'compute.instance.*'
type: 'gauge'
unit: 'GB'
volume: payload.root_gb
user_id: payload.user_id
project_id: payload.tenant_id
resource_id: payload.instance_id
- name: 'disk.ephemeral.size'
event_type: 'compute.instance.*'
type: 'gauge'
unit: 'GB'
volume: payload.ephemeral_gb
user_id: payload.user_id
project_id: payload.tenant_id
resource_id: payload.instance_id
- name: 'volume.size'
event_type:
- 'volume.exists'
- 'volume.create.*'
- 'volume.delete.*'
- 'volume.resize.*'
- 'volume.attach.*'
- 'volume.detach.*'
- 'volume.update.*'
type: 'gauge'
unit: 'GB'
volume: payload.size
user_id: payload.user_id
project_id: payload.tenant_id
resource_id: payload.volume_id
- name: 'snapshot.size'
event_type:
- 'snapshot.exists'
- 'snapshot.create.*'
- 'snapshot.delete.*'
type: 'gauge'
unit: 'GB'
volume: payload.volume_size
user_id: payload.user_id
project_id: payload.tenant_id
resource_id: payload.snapshot_id
# NOTE: non-metric meters are generally events/existence meters
# These are expected to be DEPRECATED in future releases
#
- name: 'stack.create'
event_type:
- 'orchestration.stack.create.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.update'
event_type:
- 'orchestration.stack.update.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.delete'
event_type:
- 'orchestration.stack.delete.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.resume'
event_type:
- 'orchestration.stack.resume.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'stack.suspend'
event_type:
- 'orchestration.stack.suspend.end'
type: 'delta'
unit: 'stack'
volume: 1
user_id: _context_trustor_user_id
project_id: payload.tenant_id
resource_id: payload.stack_identity
- name: 'magnetodb.table.create'
type: 'gauge'
unit: 'table'
volume: 1
event_type: 'magnetodb.table.create.end'
resource_id: payload.table_uuid
user_id: _context_user
project_id: _context_tenant
- name: 'magnetodb.table.delete'
type: 'gauge'
unit: 'table'
volume: 1
event_type: 'magnetodb.table.delete.end'
resource_id: payload.table_uuid
user_id: _context_user
project_id: _context_tenant
- name: 'volume'
type: 'gauge'
unit: 'volume'
volume: 1
event_type:
- 'volume.exists'
- 'volume.create.*'
- 'volume.delete.*'
- 'volume.resize.*'
- 'volume.attach.*'
- 'volume.detach.*'
- 'volume.update.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.exists'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.exists'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.create.start'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.create.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.create.end'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.create.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.delete.start'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.delete.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.delete.end'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.delete.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.update.end'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.update.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.update.start'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.update.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.resize.end'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.resize.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.resize.start'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.resize.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.attach.end'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.attach.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.attach.start'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.attach.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.detach.end'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.detach.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'volume.detach.start'
type: 'delta'
unit: 'volume'
volume: 1
event_type:
- 'volume.detach.*'
resource_id: payload.volume_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'snapshot'
type: 'gauge'
unit: 'snapshot'
volume: 1
event_type:
- 'snapshot.exists'
- 'snapshot.create.*'
- 'snapshot.delete.*'
resource_id: payload.snapshot_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'snapshot.exists'
type: 'delta'
unit: 'snapshot'
volume: 1
event_type:
- 'snapshot.exists'
resource_id: payload.snapshot_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'snapshot.create.start'
type: 'delta'
unit: 'snapshot'
volume: 1
event_type:
- 'snapshot.create.*'
resource_id: payload.snapshot_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'snapshot.create.end'
type: 'delta'
unit: 'snapshot'
volume: 1
event_type:
- 'snapshot.create.*'
resource_id: payload.snapshot_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'snapshot.delete.start'
type: 'delta'
unit: 'snapshot'
volume: 1
event_type:
- 'snapshot.delete.*'
resource_id: payload.snapshot_id
user_id: payload.user_id
project_id: payload.tenant_id
- name: 'snapshot.delete.end'
type: 'delta'
unit: 'snapshot'
volume: 1
event_type:
- 'snapshot.delete.*'
resource_id: payload.snapshot_id
user_id: payload.user_id
project_id: payload.tenant_id

View File

@ -28,8 +28,6 @@ packages =
[entry_points]
ceilometer.notification =
magnetodb_table = ceilometer.key_value_storage.notifications:Table
magnetodb_index_count = ceilometer.key_value_storage.notifications:Index
instance = ceilometer.compute.notifications.instance:Instance
instance_flavor = ceilometer.compute.notifications.instance:InstanceFlavor
instance_delete = ceilometer.compute.notifications.instance:InstanceDelete
@ -61,11 +59,6 @@ ceilometer.notification =
project = ceilometer.identity.notifications:Project
trust = ceilometer.identity.notifications:Trust
role_assignment = ceilometer.identity.notifications:RoleAssignment
image_crud = ceilometer.image.notifications:ImageCRUD
image = ceilometer.image.notifications:Image
image_size = ceilometer.image.notifications:ImageSize
image_download = ceilometer.image.notifications:ImageDownload
image_serve = ceilometer.image.notifications:ImageServe
network = ceilometer.network.notifications:Network
subnet = ceilometer.network.notifications:Subnet
port = ceilometer.network.notifications:Port
@ -74,7 +67,6 @@ ceilometer.notification =
bandwidth = ceilometer.network.notifications:Bandwidth
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.ipmi.notifications.ironic:TemperatureSensorNotification
@ -97,6 +89,7 @@ ceilometer.notification =
_sample = ceilometer.telemetry.notifications:TelemetryApiPost
trove.instance.exists = ceilometer.database.notifications:InstanceExists
dns.domain.exists = ceilometer.dns.notifications:DomainExists
meter = ceilometer.meter.notifications:ProcessMeterNotifications
ceilometer.discover =
local_instances = ceilometer.compute.discovery:InstanceDiscovery