From 426cd49d86626102cedcd3a468a86e1c9c314ab5 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Fri, 31 May 2013 14:00:47 +0200 Subject: [PATCH] Add support for limiting the number of samples returned Blueprint: api-limit Change-Id: Id053eb60674fea58b3d83b460fd0344dbc050cbf Signed-off-by: Julien Danjou --- ceilometer/storage/base.py | 7 +++++-- ceilometer/storage/impl_hbase.py | 14 ++++++++++++-- ceilometer/storage/impl_log.py | 3 ++- ceilometer/storage/impl_mongodb.py | 12 ++++++++---- ceilometer/storage/impl_sqlalchemy.py | 12 ++++++++++-- tests/storage/base.py | 20 ++++++++++++++++++++ 6 files changed, 57 insertions(+), 11 deletions(-) diff --git a/ceilometer/storage/base.py b/ceilometer/storage/base.py index 4771c95e4..9e3d1e76f 100644 --- a/ceilometer/storage/base.py +++ b/ceilometer/storage/base.py @@ -126,8 +126,11 @@ class Connection(object): """ @abc.abstractmethod - def get_samples(self, sample_filter): - """Return an iterable of model.Sample instances + def get_samples(self, sample_filter, limit=None): + """Return an iterable of model.Sample instances. + + :param sample_filter: Filter. + :param limit: Maximum number of results to return. """ @abc.abstractmethod diff --git a/ceilometer/storage/impl_hbase.py b/ceilometer/storage/impl_hbase.py index a06f16f74..9867042a5 100644 --- a/ceilometer/storage/impl_hbase.py +++ b/ceilometer/storage/impl_hbase.py @@ -393,8 +393,11 @@ class Connection(base.Connection): user_id=data['f:user_id'], ) - def get_samples(self, sample_filter): - """Return an iterable of models.Sample instances + def get_samples(self, sample_filter, limit=None): + """Return an iterable of models.Sample instances. + + :param sample_filter: Filter. + :param limit: Maximum number of results to return. """ def make_sample(data): """ transform HBase fields to Sample model @@ -415,6 +418,9 @@ class Connection(base.Connection): # properly. # handle metaquery metaquery = sample_filter.metaquery + # TODO(jd) implements using HBase capabilities + if limit == 0: + break if len(metaquery) > 0: # metaquery checks resource table resource = self.resource.row(meter['f:resource_id']) @@ -423,8 +429,12 @@ class Connection(base.Connection): if resource['f:r_' + k.split('.', 1)[1]] != v: break # if one metaquery doesn't match, break else: + if limit: + limit -= 1 yield make_sample(meter) else: + if limit: + limit -= 1 yield make_sample(meter) def _update_meter_stats(self, stat, meter): diff --git a/ceilometer/storage/impl_log.py b/ceilometer/storage/impl_log.py index d5ae7c39d..bd88617f4 100644 --- a/ceilometer/storage/impl_log.py +++ b/ceilometer/storage/impl_log.py @@ -100,7 +100,7 @@ class Connection(base.Connection): return [] def get_meters(self, user=None, project=None, resource=None, source=None, - metaquery={}): + limit=None, metaquery={}): """Return an iterable of dictionaries containing meter information. { 'name': name of the meter, @@ -114,6 +114,7 @@ class Connection(base.Connection): :param project: Optional ID for project that owns the resource. :param resource: Optional resource filter. :param source: Optional source filter. + :param limit: Maximum number of results to return. :param metaquery: Optional dict with metadata to match on. """ return [] diff --git a/ceilometer/storage/impl_mongodb.py b/ceilometer/storage/impl_mongodb.py index 216b0cf29..a27fc9e4a 100644 --- a/ceilometer/storage/impl_mongodb.py +++ b/ceilometer/storage/impl_mongodb.py @@ -440,12 +440,16 @@ class Connection(base.Connection): user_id=r['user_id'], ) - def get_samples(self, sample_filter): - """Return an iterable of samples as created by - :func:`ceilometer.meter.meter_message_from_counter`. + def get_samples(self, sample_filter, limit=None): + """Return an iterable of model.Sample instances. + + :param sample_filter: Filter. + :param limit: Maximum number of results to return. """ + if limit == 0: + return q = make_query_from_filter(sample_filter, require_meter=False) - samples = self.db.meter.find(q) + samples = self.db.meter.find(q).limit(limit or 0) for s in samples: # Remove the ObjectId generated by the database when # the sample was inserted. It is an implementation diff --git a/ceilometer/storage/impl_sqlalchemy.py b/ceilometer/storage/impl_sqlalchemy.py index 3481dd760..2058d58dc 100644 --- a/ceilometer/storage/impl_sqlalchemy.py +++ b/ceilometer/storage/impl_sqlalchemy.py @@ -311,12 +311,20 @@ class Connection(base.Connection): user_id=resource.user_id, ) - def get_samples(self, sample_filter): - """Return an iterable of api_models.Samples + def get_samples(self, sample_filter, limit=None): + """Return an iterable of api_models.Samples. + + :param sample_filter: Filter. + :param limit: Maximum number of results to return. """ + if limit == 0: + return + query = self.session.query(Meter) query = make_query_from_filter(query, sample_filter, require_meter=False) + if limit: + query = query.limit(limit) samples = query.all() for s in samples: diff --git a/tests/storage/base.py b/tests/storage/base.py index f0cc5d8f4..7bac5c91f 100644 --- a/tests/storage/base.py +++ b/tests/storage/base.py @@ -271,6 +271,16 @@ class MeterTest(DBTestBase): class RawSampleTest(DBTestBase): + def test_get_samples_limit_zero(self): + f = storage.SampleFilter() + results = list(self.conn.get_samples(f, limit=0)) + self.assertEqual(len(results), 0) + + def test_get_samples_limit(self): + f = storage.SampleFilter() + results = list(self.conn.get_samples(f, limit=3)) + self.assertEqual(len(results), 3) + def test_get_samples_by_user(self): f = storage.SampleFilter(user='user-id') results = list(self.conn.get_samples(f)) @@ -278,6 +288,16 @@ class RawSampleTest(DBTestBase): for meter in results: assert meter.as_dict() in [self.msg1, self.msg2] + def test_get_samples_by_user_limit(self): + f = storage.SampleFilter(user='user-id') + results = list(self.conn.get_samples(f, limit=1)) + self.assertEqual(len(results), 1) + + def test_get_samples_by_user_limit_bigger(self): + f = storage.SampleFilter(user='user-id') + results = list(self.conn.get_samples(f, limit=42)) + self.assertEqual(len(results), 2) + def test_get_samples_by_project(self): f = storage.SampleFilter(project='project-id') results = list(self.conn.get_samples(f))