Merge "timedelta plugin for meter definition process"

This commit is contained in:
Jenkins 2016-03-04 20:29:16 +00:00 committed by Gerrit Code Review
commit ec4848b9f0
5 changed files with 143 additions and 1 deletions

View File

@ -17,6 +17,7 @@ import abc
from debtcollector import moves
from oslo_log import log
from oslo_utils import timeutils
import six
from ceilometer.i18n import _LW
@ -188,3 +189,42 @@ class BitfieldTraitPlugin(TraitPluginBase):
else:
bitfield |= bit
return [bitfield]
class TimedeltaPluginMissedFields(Exception):
def __init__(self):
msg = ('It is required to use two timestamp field with Timedelta '
'plugin.')
super(TimedeltaPluginMissedFields, self).__init__(msg)
class TimedeltaPlugin(TraitPluginBase):
"""Setup timedelta meter volume of two timestamps fields.
Example::
trait's fields definition: ['payload.created_at',
'payload.launched_at']
value is been created as total seconds between 'launched_at' and
'created_at' timestamps.
"""
# TODO(idegtiarov): refactor code to have meter_plugins separate from
# trait_plugins
def trait_value(self, match_list):
if len(match_list) != 2:
LOG.warning(_LW('Timedelta plugin is required two timestamp fields'
' to create timedelta value.'))
return
start, end = match_list
try:
start_time = timeutils.parse_isotime(start[1])
end_time = timeutils.parse_isotime(end[1])
except Exception as err:
LOG.warning(_LW('Failed to parse date from set fields, both '
'fields %(start)s and %(end)s must be datetime: '
'%(err)s') %
dict(start=start[0], end=end[0], err=err)
)
return
return abs((end_time - start_time).total_seconds())

View File

@ -107,6 +107,16 @@ metric:
project_id: $.payload.tenant_id
resource_id: $.payload.instance_id
- name: 'compute.instance.booting.time'
event_type: 'compute.instance.create.end'
type: 'gauge'
unit: 'sec'
volume:
fields: [$.payload.created_at, $.payload.launched_at]
plugin: 'timedelta'
project_id: $.payload.tenant_id
resource_id: $.payload.instance_id
- name: 'disk.root.size'
event_type: 'compute.instance.*'
type: 'gauge'

View File

@ -0,0 +1,71 @@
#
# Copyright 2016 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 mock
from oslotest import base
from ceilometer.event import trait_plugins
class TestTimedeltaPlugin(base.BaseTestCase):
def setUp(self):
super(TestTimedeltaPlugin, self).setUp()
self.plugin = trait_plugins.TimedeltaPlugin()
def test_timedelta_transformation(self):
match_list = [('test.timestamp1', '2016-03-02T15:04:32'),
('test.timestamp2', '2016-03-02T16:04:32')]
value = self.plugin.trait_value(match_list)
self.assertEqual(3600, value)
def test_timedelta_missing_field(self):
match_list = [('test.timestamp1', '2016-03-02T15:04:32')]
with mock.patch('%s.LOG' % self.plugin.trait_value.__module__) as log:
self.assertIsNone(self.plugin.trait_value(match_list))
log.warning.assert_called_once_with(
'Timedelta plugin is required two timestamp fields to create '
'timedelta value.')
def test_timedelta_exceed_field(self):
match_list = [('test.timestamp1', '2016-03-02T15:04:32'),
('test.timestamp2', '2016-03-02T16:04:32'),
('test.timestamp3', '2016-03-02T16:10:32')]
with mock.patch('%s.LOG' % self.plugin.trait_value.__module__) as log:
self.assertIsNone(self.plugin.trait_value(match_list))
log.warning.assert_called_once_with(
'Timedelta plugin is required two timestamp fields to create '
'timedelta value.')
def test_timedelta_invalid_timestamp(self):
match_list = [('test.timestamp1', '2016-03-02T15:04:32'),
('test.timestamp2', '2016-03-02T15:004:32')]
with mock.patch('%s.LOG' % self.plugin.trait_value.__module__) as log:
self.assertIsNone(self.plugin.trait_value(match_list))
msg = log.warning._mock_call_args[0][0]
self.assertTrue(msg.startswith('Failed to parse date from set '
'fields, both fields ')
)
def test_timedelta_reverse_timestamp_order(self):
match_list = [('test.timestamp1', '2016-03-02T15:15:32'),
('test.timestamp2', '2016-03-02T15:10:32')]
value = self.plugin.trait_value(match_list)
self.assertEqual(300, value)
def test_timedelta_precise_difference(self):
match_list = [('test.timestamp1', '2016-03-02T15:10:32.786893'),
('test.timestamp2', '2016-03-02T15:10:32.786899')]
value = self.plugin.trait_value(match_list)
self.assertEqual(0.000006, value)

View File

@ -33,7 +33,9 @@ NOTIFICATION = {
'timestamp': u'2015-06-1909: 19: 35.786893',
'payload': {u'user_id': u'e1d870e51c7340cb9d555b15cbfcaec2',
u'resource_id': u'bea70e51c7340cb9d555b15cbfcaec23',
u'timestamp': u'2015-06-19T09: 19: 35.785330',
u'timestamp': u'2015-06-19T09:19:35.785330',
u'created_at': u'2015-06-19T09:25:35.785330',
u'launched_at': u'2015-06-19T09:25:40.785330',
u'message_signature': u'fake_signature1',
u'resource_metadata': {u'foo': u'bar'},
u'source': u'30be1fc9a03c4e94ab05c403a8a377f2: openstack',
@ -455,6 +457,23 @@ class TestMeterProcessing(test.BaseTestCase):
meta['event_type'] = NOTIFICATION['event_type']
self.assertEqual(meta, s1['resource_metadata'])
def test_datetime_plugin(self):
cfg = yaml.dump(
{'metric': [dict(name="test1",
event_type="test.*",
type="gauge",
unit="sec",
volume={"fields": ["$.payload.created_at",
"$.payload.launched_at"],
"plugin": "timedelta"},
resource_id="$.payload.resource_id",
project_id="$.payload.project_id")]})
self._load_meter_def_file(cfg)
c = list(self.handler.process_notification(NOTIFICATION))
self.assertEqual(1, len(c))
s1 = c[0].as_dict()
self.assertEqual(5.0, s1['volume'])
def test_custom_metadata(self):
cfg = yaml.dump(
{'metric': [dict(name="test1",

View File

@ -237,6 +237,8 @@ ceilometer.event.publisher =
ceilometer.event.trait_plugin =
split = ceilometer.event.trait_plugins:SplitterTraitPlugin
bitfield = ceilometer.event.trait_plugins:BitfieldTraitPlugin
timedelta = ceilometer.event.trait_plugins:TimedeltaPlugin
console_scripts =
ceilometer-api = ceilometer.cmd.api:main