Merge "Add a map event trait plugin"

This commit is contained in:
Zuul 2025-04-25 08:27:04 +00:00 committed by Gerrit Code Review
commit b03fea8f0b
4 changed files with 110 additions and 0 deletions

View File

@ -217,3 +217,58 @@ class TimedeltaPlugin(TraitPluginBase):
)
return [None]
return [abs((end_time - start_time).total_seconds())]
class MapTraitPlugin(TraitPluginBase):
"""A trait plugin for mapping one set of values to another."""
def __init__(self, values=None, default=None, case_sensitive=True, **kw):
"""Setup map trait.
:param values: (dict[Any, Any]) Mapping of values to their
desired target values.
:param default: (Any) Value to set if no mapping for a value is found.
:param case_sensitive: (bool) Perform case-sensitive string lookups.
"""
if not values:
raise ValueError(("The 'values' parameter is required "
"for the map trait plugin"))
if not isinstance(values, dict):
raise ValueError(("The 'values' parameter needs to be a dict "
"for the map trait plugin"))
self.case_sensitive = case_sensitive
if not self.case_sensitive:
self.values = {(k.casefold()
if isinstance(k, str)
else k): v
for k, v in values.items()}
else:
self.values = dict(values)
self.default = default
super(MapTraitPlugin, self).__init__(**kw)
def trait_values(self, match_list):
mapped_values = []
for match in match_list:
key = match[1]
folded_key = (
key.casefold()
if not self.case_sensitive and isinstance(key, str)
else key)
try:
value = self.values[folded_key]
except KeyError:
LOG.warning(
('Unknown value %s found when mapping %s, '
'mapping to default value of %s'),
repr(key),
match[0],
repr(self.default))
value = self.default
else:
LOG.debug('Value %s for %s mapped to value %s',
repr(key),
match[0],
repr(value))
mapped_values.append(value)
return mapped_values

View File

@ -113,3 +113,47 @@ class TestBitfieldPlugin(base.BaseTestCase):
plugin = self.pclass(**self.params)
value = plugin.trait_values(match_list)
self.assertEqual(0x412, value[0])
class TestMapTraitPlugin(base.BaseTestCase):
def setUp(self):
super(TestMapTraitPlugin, self).setUp()
self.pclass = trait_plugins.MapTraitPlugin
self.params = dict(values={'ACTIVE': 1, 'ERROR': 2, 3: 4},
default=-1)
def test_map(self):
match_list = [('payload.foo', 'ACTIVE'),
('payload.bar', 'ERROR'),
('thingy.boink', 3),
('thingy.invalid', 999)]
plugin = self.pclass(**self.params)
value = plugin.trait_values(match_list)
self.assertEqual([1, 2, 4, -1], value)
def test_case_sensitive(self):
match_list = [('payload.foo', 'ACTIVE'),
('payload.bar', 'error'),
('thingy.boink', 3),
('thingy.invalid', 999)]
plugin = self.pclass(case_sensitive=True, **self.params)
value = plugin.trait_values(match_list)
self.assertEqual([1, -1, 4, -1], value)
def test_case_insensitive(self):
match_list = [('payload.foo', 'active'),
('payload.bar', 'ErRoR'),
('thingy.boink', 3),
('thingy.invalid', 999)]
plugin = self.pclass(case_sensitive=False, **self.params)
value = plugin.trait_values(match_list)
self.assertEqual([1, 2, 4, -1], value)
def test_values_undefined(self):
self.assertRaises(ValueError, self.pclass)
def test_values_invalid(self):
self.assertRaises(
ValueError,
lambda: self.pclass(values=[('ACTIVE', 1), ('ERROR', 2), (3, 4)]))

View File

@ -0,0 +1,10 @@
---
features:
- |
A ``map`` event trait plugin has been added.
This allows notification meter attributes to be created
by mapping one set of values from an attribute to another
set of values defined in the meter definition.
Additional options are also available for controlling
how to handle edge cases, such as unknown values and
case sensitivity.

View File

@ -173,6 +173,7 @@ ceilometer.event.trait_plugin =
split = ceilometer.event.trait_plugins:SplitterTraitPlugin
bitfield = ceilometer.event.trait_plugins:BitfieldTraitPlugin
timedelta = ceilometer.event.trait_plugins:TimedeltaPlugin
map = ceilometer.event.trait_plugins:MapTraitPlugin
console_scripts =
ceilometer-polling = ceilometer.cmd.polling:main