diff --git a/ceilometer/api/controllers/v2.py b/ceilometer/api/controllers/v2.py index 656669c9..24644537 100644 --- a/ceilometer/api/controllers/v2.py +++ b/ceilometer/api/controllers/v2.py @@ -235,6 +235,15 @@ class MeterVolumeController(object): return MeterVolume(volume=value) +def _flatten_metadata(metadata): + """Return flattened resource metadata without nested structures + and with all values converted to unicode strings. + """ + return dict((k, unicode(v)) + for k, v in metadata.iteritems() + if type(v) not in set([list, dict, set])) + + class Event(Base): source = text counter_name = text @@ -244,15 +253,15 @@ class Event(Base): project_id = text resource_id = text timestamp = datetime.datetime - # FIXME(dhellmann): Need to add the metadata back as - # a flat {text: text} mapping. - #resource_metadata = ? + resource_metadata = {text: text} message_id = text - def __init__(self, counter_volume=None, **kwds): + def __init__(self, counter_volume=None, resource_metadata={}, **kwds): if counter_volume is not None: counter_volume = float(counter_volume) + resource_metadata = _flatten_metadata(resource_metadata) super(Event, self).__init__(counter_volume=counter_volume, + resource_metadata=resource_metadata, **kwds) @@ -398,12 +407,15 @@ class Resource(Base): project_id = text user_id = text timestamp = datetime.datetime - #metadata = ? + metadata = {text: text} meter = wsattr([MeterDescription]) - def __init__(self, meter=[], **kwds): + def __init__(self, meter=[], metadata={}, **kwds): meter = [MeterDescription(**m) for m in meter] - super(Resource, self).__init__(meter=meter, **kwds) + metadata = _flatten_metadata(metadata) + super(Resource, self).__init__(meter=meter, + metadata=metadata, + **kwds) class ResourcesController(RestController): diff --git a/tests/api/v2/test_list_events.py b/tests/api/v2/test_list_events.py index e8db9fde..3bc84d74 100644 --- a/tests/api/v2/test_list_events.py +++ b/tests/api/v2/test_list_events.py @@ -44,6 +44,8 @@ class TestListEvents(FunctionalTest): timestamp=datetime.datetime(2012, 7, 2, 10, 40), resource_metadata={'display_name': 'test-server', 'tag': 'self.counter', + 'ignored_dict': {'key': 'value'}, + 'ignored_list': ['not-returned'], } ) msg = meter.meter_message_from_counter(self.counter1, @@ -106,3 +108,14 @@ class TestListEvents(FunctionalTest): def test_by_user(self): data = self.get_json('/users/user-id/meters/instance') self.assertEquals(1, len(data)) + + def test_metadata(self): + data = self.get_json('/resources/resource-id/meters/instance') + self.assertEquals(1, len(data)) + sample = data[0] + self.assert_('resource_metadata' in sample) + self.assertEqual( + list(sorted(sample['resource_metadata'].iteritems())), + [('display_name', 'test-server'), + ('tag', 'self.counter'), + ]) diff --git a/tests/api/v2/test_list_resources.py b/tests/api/v2/test_list_resources.py index c27dd38c..f908d0e1 100644 --- a/tests/api/v2/test_list_resources.py +++ b/tests/api/v2/test_list_resources.py @@ -200,3 +200,32 @@ class TestListResources(FunctionalTest): data = self.get_json('/projects/project-id/resources') ids = [r['resource_id'] for r in data] self.assertEquals(['resource-id'], ids) + + def test_metadata(self): + counter1 = counter.Counter( + 'instance', + 'cumulative', + 1, + 'user-id', + 'project-id', + 'resource-id', + timestamp=datetime.datetime(2012, 7, 2, 10, 40), + resource_metadata={'display_name': 'test-server', + 'tag': 'self.counter', + 'ignored_dict': {'key': 'value'}, + 'ignored_list': ['not-returned'], + } + ) + msg = meter.meter_message_from_counter(counter1, + cfg.CONF.metering_secret, + 'test', + ) + self.conn.record_metering_data(msg) + + data = self.get_json('/resources') + metadata = data[0]['metadata'] + self.assertEqual( + list(sorted(metadata.iteritems())), + [('display_name', 'test-server'), + ('tag', 'self.counter'), + ])