Fixes Hbase metadata query return wrong result

Based on current implement of Hbase metadata query  in Ceilometer,
it's trying to compare the metadata value with the metadata stored
in table "resource" instead of table "meter", when user query a
specific meter name. As a result, the query result will be wrong.
See:
https://github.com/openstack/ceilometer/blob/master/ceilometer/storage/impl_hbase.py#L441
https://github.com/openstack/ceilometer/blob/master/ceilometer/storage/impl_mongodb.py#L535

Fixes bug 1205759

Change-Id: I3f8168fa5371985ac135b0a9d41e76d7bc71c4a7
This commit is contained in:
Fei Long Wang 2013-07-28 16:45:29 +08:00
parent dbb8ca35fc
commit ea76c9be8c
2 changed files with 98 additions and 6 deletions

View File

@ -418,7 +418,6 @@ class Connection(base.Connection):
data['timestamp'] = timeutils.parse_strtime(data['timestamp'])
return models.Sample(**data)
resource_table = self.conn.table(self.RESOURCE_TABLE)
meter_table = self.conn.table(self.METER_TABLE)
q, start, stop = make_query_from_filter(sample_filter,
@ -437,11 +436,10 @@ class Connection(base.Connection):
if limit == 0:
break
if len(metaquery) > 0:
# metaquery checks resource table
resource = resource_table.row(meter['f:resource_id'])
for k, v in metaquery.iteritems():
if resource['f:r_' + k.split('.', 1)[1]] != v:
message = json.loads(meter['f:message'])
metadata = message['resource_metadata']
if metadata[k.split('.', 1)[1]] != v:
break # if one metaquery doesn't match, break
else:
if limit:
@ -764,6 +762,8 @@ def make_query(user=None, project=None, meter=None,
# query other tables should have no start and end passed in
if meter:
start_row, end_row = _make_rowkey_scan(meter, rts_start, rts_end)
q.append("SingleColumnValueFilter "
"('f', 'counter_name', =, 'binary:%s')" % meter)
elif require_meter:
raise RuntimeError('Missing required meter specifier')
else:

View File

@ -71,7 +71,7 @@ class TestListMeters(FunctionalTest,
'resource-id',
timestamp=datetime.datetime(2012, 7, 2, 11, 40),
resource_metadata={'display_name': 'test-server',
'tag': 'self.counter'}),
'tag': 'self.counter1'}),
sample.Sample(
'meter.mine',
'gauge',
@ -123,6 +123,34 @@ class TestListMeters(FunctionalTest,
set(['meter.test',
'meter.mine']))
def test_list_meters_metadata_query(self):
data = self.get_json('/meters/meter.test',
q=[{'field': 'metadata.tag',
'op': 'eq',
'value': 'self.counter1',
}],)
self.assertEquals(1, len(data))
self.assertEquals(set(r['resource_id'] for r in data),
set(['resource-id']))
self.assertEquals(set(r['counter_name'] for r in data),
set(['meter.test']))
def test_list_meters_multi_metadata_query(self):
data = self.get_json('/meters/meter.test',
q=[{'field': 'metadata.tag',
'op': 'eq',
'value': 'self.counter1',
},
{'field': 'metadata.display_name',
'op': 'eq',
'value': 'test-server',
}],)
self.assertEquals(1, len(data))
self.assertEquals(set(r['resource_id'] for r in data),
set(['resource-id']))
self.assertEquals(set(r['counter_name'] for r in data),
set(['meter.test']))
def test_with_resource(self):
data = self.get_json('/meters', q=[{'field': 'resource_id',
'value': 'resource-id',
@ -130,6 +158,22 @@ class TestListMeters(FunctionalTest,
ids = set(r['name'] for r in data)
self.assertEquals(set(['meter.test']), ids)
def test_with_resource_and_metadata_query(self):
data = self.get_json('/meters/meter.mine',
q=[{'field': 'resource_id',
'op': 'eq',
'value': 'resource-id2',
},
{'field': 'metadata.tag',
'op': 'eq',
'value': 'self.counter2',
}])
self.assertEquals(1, len(data))
self.assertEquals(set(r['resource_id'] for r in data),
set(['resource-id2']))
self.assertEquals(set(r['counter_name'] for r in data),
set(['meter.mine']))
def test_with_source(self):
data = self.get_json('/meters', q=[{'field': 'source',
'value': 'test_source',
@ -140,6 +184,22 @@ class TestListMeters(FunctionalTest,
'resource-id3',
'resource-id4']), ids)
def test_with_source_and_metadata_query(self):
data = self.get_json('/meters/meter.mine',
q=[{'field': 'source',
'op': 'eq',
'value': 'test_source',
},
{'field': 'metadata.tag',
'op': 'eq',
'value': 'self.counter2',
}])
self.assertEquals(1, len(data))
self.assertEquals(set(r['source'] for r in data),
set(['test_source']))
self.assertEquals(set(r['counter_name'] for r in data),
set(['meter.mine']))
def test_with_source_non_existent(self):
data = self.get_json('/meters',
q=[{'field': 'source',
@ -164,6 +224,22 @@ class TestListMeters(FunctionalTest,
rids = set(r['resource_id'] for r in data)
self.assertEquals(set(['resource-id', 'resource-id2']), rids)
def test_with_user_and_metadata_query(self):
data = self.get_json('/meters/meter.test',
q=[{'field': 'user_id',
'op': 'eq',
'value': 'user-id',
},
{'field': 'metadata.tag',
'op': 'eq',
'value': 'self.counter1',
}])
self.assertEquals(1, len(data))
self.assertEquals(set(r['user_id'] for r in data),
set(['user-id']))
self.assertEquals(set(r['counter_name'] for r in data),
set(['meter.test']))
def test_with_user_non_existent(self):
data = self.get_json('/meters',
q=[{'field': 'user_id',
@ -181,6 +257,22 @@ class TestListMeters(FunctionalTest,
ids = set(r['resource_id'] for r in data)
self.assertEquals(set(['resource-id3', 'resource-id4']), ids)
def test_with_project_and_metadata_query(self):
data = self.get_json('/meters/meter.test',
q=[{'field': 'project_id',
'op': 'eq',
'value': 'project-id',
},
{'field': 'metadata.tag',
'op': 'eq',
'value': 'self.counter1',
}])
self.assertEquals(1, len(data))
self.assertEquals(set(r['project_id'] for r in data),
set(['project-id']))
self.assertEquals(set(r['counter_name'] for r in data),
set(['meter.test']))
def test_with_project_non_existent(self):
data = self.get_json('/meters',
q=[{'field': 'project_id',