Add field translation to complex query from OldSample to Sample

Complex query returns the samples according to the new Sample model, but
it accepts the field names in the query expression only from the OldSample
model during the validation. This patch adds translation between the old
and new field names and translates the field names to the format of the
DB model.

Closes-bug: #1291415

Change-Id: I8ef71b6d43b82cd75f0d7a6ea08cdc8881ca62d3
This commit is contained in:
Ildiko Vancsa
2014-03-12 08:32:41 +01:00
parent a4f693b892
commit edd201304e
3 changed files with 47 additions and 21 deletions

View File

@@ -1134,14 +1134,14 @@ class ValidatedComplexQuery(object):
order_directions = _list_to_regexp(order_directions, regexp_prefix)
timestamp_fields = ["timestamp", "state_timestamp"]
name_mapping = {"user": "user_id",
"project": "project_id",
"resource": "resource_id"}
def __init__(self, query, db_model, additional_valid_keys,
def __init__(self, query, db_model, additional_name_mapping={},
metadata_allowed=False):
self.name_mapping = {"user": "user_id",
"project": "project_id"}
self.name_mapping.update(additional_name_mapping)
valid_keys = db_model.get_field_names()
valid_keys = list(valid_keys) + additional_valid_keys
valid_keys = list(valid_keys) + self.name_mapping.keys()
valid_fields = _list_to_regexp(valid_keys)
if metadata_allowed:
@@ -2300,9 +2300,15 @@ class QuerySamplesController(rest.RestController):
:param body: Query rules for the samples to be returned.
"""
sample_name_mapping = {"resource": "resource_id",
"meter": "counter_name",
"type": "counter_type",
"unit": "counter_unit",
"volume": "counter_volume"}
query = ValidatedComplexQuery(body,
storage.models.Sample,
["user", "project", "resource"],
sample_name_mapping,
metadata_allowed=True)
query.validate(visibility_field="project_id")
conn = pecan.request.storage_conn
@@ -2322,8 +2328,7 @@ class QueryAlarmHistoryController(rest.RestController):
:param body: Query rules for the alarm history to be returned.
"""
query = ValidatedComplexQuery(body,
storage.models.AlarmChange,
["user", "project"])
storage.models.AlarmChange)
query.validate(visibility_field="on_behalf_of")
conn = pecan.request.storage_conn
return [AlarmChange.from_db_model(s)
@@ -2344,8 +2349,7 @@ class QueryAlarmsController(rest.RestController):
:param body: Query rules for the alarms to be returned.
"""
query = ValidatedComplexQuery(body,
storage.models.Alarm,
["user", "project"])
storage.models.Alarm)
query.validate(visibility_field="project_id")
conn = pecan.request.storage_conn
return [Alarm.from_db_model(s)

View File

@@ -29,27 +29,32 @@ from ceilometer import storage as storage
class FakeComplexQuery(api.ValidatedComplexQuery):
def __init__(self, db_model, additional_valid_keys, metadata=False):
def __init__(self, db_model, additional_name_mapping={}, metadata=False):
super(FakeComplexQuery, self).__init__(query=None,
db_model=db_model,
additional_valid_keys=
additional_valid_keys,
additional_name_mapping=
additional_name_mapping,
metadata_allowed=metadata)
sample_name_mapping = {"resource": "resource_id",
"meter": "counter_name",
"type": "counter_type",
"unit": "counter_unit",
"volume": "counter_volume"}
class TestComplexQuery(test.BaseTestCase):
def setUp(self):
super(TestComplexQuery, self).setUp()
self.useFixture(fixtures.MonkeyPatch(
'pecan.response', mock.MagicMock()))
self.query = FakeComplexQuery(storage.models.Sample,
["user", "project", "resource"],
sample_name_mapping,
True)
self.query_alarm = FakeComplexQuery(storage.models.Alarm,
["user", "project"])
self.query_alarm = FakeComplexQuery(storage.models.Alarm)
self.query_alarmchange = FakeComplexQuery(
storage.models.AlarmChange,
["user", "project"])
storage.models.AlarmChange)
def test_replace_isotime_utc(self):
filter_expr = {"=": {"timestamp": "2013-12-05T19:38:29Z"}}
@@ -231,7 +236,7 @@ class TestFilterSyntaxValidation(test.BaseTestCase):
def setUp(self):
super(TestFilterSyntaxValidation, self).setUp()
self.query = FakeComplexQuery(storage.models.Sample,
["user", "project", "resource"],
sample_name_mapping,
True)
def test_simple_operator(self):

View File

@@ -67,7 +67,7 @@ class TestQueryMetersController(tests_api.FunctionalTest,
sample.Sample('meter.test',
'cumulative',
'',
1,
2,
'user-id2',
'project-id2',
'resource-id2',
@@ -81,7 +81,7 @@ class TestQueryMetersController(tests_api.FunctionalTest,
sample.Sample('meter.test',
'cumulative',
'',
1,
3,
'user-id3',
'project-id3',
'resource-id3',
@@ -224,6 +224,15 @@ class TestQueryMetersController(tests_api.FunctionalTest,
for sample in data.json:
self.assertIn(sample['user_id'], set(["user-id2"]))
def test_query_with_field_name_meter(self):
data = self.post_json(self.url,
params={"filter":
'{"=": {"meter": "meter.test"}}'})
self.assertEqual(3, len(data.json))
for sample in data.json:
self.assertIn(sample['meter'], set(["meter.test"]))
def test_query_with_lower_and_upper_case_orderby(self):
data = self.post_json(self.url,
params={"orderby": '[{"project_id": "DeSc"}]'})
@@ -240,6 +249,14 @@ class TestQueryMetersController(tests_api.FunctionalTest,
self.assertEqual(["user-id1", "user-id2", "user-id3"],
[s["user_id"] for s in data.json])
def test_query_with_volume_field_name_orderby(self):
data = self.post_json(self.url,
params={"orderby": '[{"volume": "deSc"}]'})
self.assertEqual(3, len(data.json))
self.assertEqual([3, 2, 1],
[s["volume"] for s in data.json])
def test_query_with_missing_order_in_orderby(self):
data = self.post_json(self.url,
params={"orderby": '[{"project_id": ""}]'},