Add complex query support for samples

Change-Id: I88c4eb6fa32514100187dbbca9777c7a5974fac6
This commit is contained in:
Balazs Gibizer
2014-02-18 19:36:07 +01:00
committed by Ildiko Vancsa
parent 3e8045c9ca
commit 08e644110a
5 changed files with 207 additions and 3 deletions

View File

@@ -0,0 +1,65 @@
# Copyright Ericsson AB 2014. All rights reserved
#
# Author: Balazs Gibizer <balazs.gibizer@ericsson.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from ceilometerclient.tests import utils
from ceilometerclient.v2 import query_samples
SAMPLE = {u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6',
u'metadata': {
u'name1': u'value1',
u'name2': u'value2'},
u'meter': 'instance',
u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68',
u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36',
u'source': u'openstack',
u'timestamp': u'2014-02-19T05:50:16.673604',
u'type': u'gauge',
u'unit': u'instance',
u'volume': 1,
u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'}
QUERY = {"filter": {"and": [{"=": {"source": "openstack"}},
{">": {"timestamp": "2014-02-19T05:50:16"}}]},
"orderby": [{"timestamp": "desc"}, {"volume": "asc"}],
"limit": 10}
base_url = '/v2/query/samples'
fixtures = {
base_url:
{
'POST': (
{},
[SAMPLE],
),
},
}
class QuerySamplesManagerTest(utils.BaseTestCase):
def setUp(self):
super(QuerySamplesManagerTest, self).setUp()
self.api = utils.FakeAPI(fixtures)
self.mgr = query_samples.QuerySamplesManager(self.api)
def test_query(self):
samples = self.mgr.query(**QUERY)
expect = [
('POST', '/v2/query/samples', {}, QUERY),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(1, len(samples))

View File

@@ -1,3 +1,7 @@
# Copyright Ericsson AB 2014. All rights reserved
#
# Author: Balazs Gibizer <balazs.gibizer@ericsson.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
@@ -410,3 +414,58 @@ class ShellSampleCreateCommandTest(utils.BaseTestCase):
| volume | 1.0 |
+-------------------+---------------------------------------------+
''')
class ShellQuerySamplesCommandTest(utils.BaseTestCase):
SAMPLE = [{u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6',
u'metadata': {
u'name1': u'value1',
u'name2': u'value2'},
u'meter': 'instance',
u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68',
u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36',
u'source': u'openstack',
u'timestamp': u'2014-02-19T05:50:16.673604',
u'type': u'gauge',
u'unit': u'instance',
u'volume': 1,
u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'}]
QUERY = {"filter": {"and": [{"=": {"source": "openstack"}},
{">": {"timestamp": "2014-02-19T05:50:16"}}]},
"orderby": [{"timestamp": "desc"}, {"volume": "asc"}],
"limit": 10}
def setUp(self):
super(ShellQuerySamplesCommandTest, self).setUp()
self.cc = mock.Mock()
self.args = mock.Mock()
self.args.filter = self.QUERY["filter"]
self.args.orderby = self.QUERY["orderby"]
self.args.limit = self.QUERY["limit"]
def test_query(self):
ret_sample = [samples.Sample(mock.Mock(), sample)
for sample in self.SAMPLE]
self.cc.query_samples.query.return_value = ret_sample
org_stdout = sys.stdout
try:
sys.stdout = output = six.StringIO()
ceilometer_shell.do_query_samples(self.cc, self.args)
finally:
sys.stdout = org_stdout
self.assertEqual('''\
+--------------------------------------+----------+-------+--------+---------\
-+----------------------------+
| Resource ID | Meter | Type | Volume | Unit \
| Timestamp |
+--------------------------------------+----------+-------+--------+---------\
-+----------------------------+
| bd9431c1-8d69-4ad3-803a-8d4a6b89fd36 | instance | gauge | 1 | instance\
| 2014-02-19T05:50:16.673604 |
+--------------------------------------+----------+-------+--------+---------\
-+----------------------------+
''', output.getvalue())

View File

@@ -1,5 +1,6 @@
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
# Copyright Ericsson AB 2014. All rights reserved
#
# Author: Balazs Gibizer <balazs.gibizer@ericsson.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -18,6 +19,7 @@ from ceilometerclient.v2 import alarms
from ceilometerclient.v2 import event_types
from ceilometerclient.v2 import events
from ceilometerclient.v2 import meters
from ceilometerclient.v2 import query_samples
from ceilometerclient.v2 import resources
from ceilometerclient.v2 import samples
from ceilometerclient.v2 import statistics
@@ -48,3 +50,5 @@ class Client(object):
self.traits = traits.TraitManager(self.http_client)
self.trait_info = trait_descriptions.\
TraitDescriptionManager(self.http_client)
self.query_samples = query_samples.QuerySamplesManager(
self.http_client)

View File

@@ -0,0 +1,44 @@
# Copyright Ericsson AB 2014. All rights reserved
#
# Author: Balazs Gibizer <balazs.gibizer@ericsson.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from ceilometerclient.common import base
from ceilometerclient.v2 import samples
class QuerySamplesManager(base.Manager):
resource_class = samples.Sample
@staticmethod
def _path():
return '/v2/query/samples'
def query(self, filter, orderby, limit):
query = {}
if filter:
query["filter"] = filter
if orderby:
query["orderby"] = orderby
if limit:
query["limit"] = limit
url = self._path()
resp, body = self.api.json_request('POST',
url,
body=query)
if body:
return [self.resource_class(self, b) for b in body]
else:
return []

View File

@@ -1,8 +1,10 @@
# -*- encoding: utf-8 -*-
#
# Copyright © 2013 Red Hat, Inc
# Copyright Ericsson AB 2014. All rights reserved
#
# Author: Angus Salkeld <asalkeld@redhat.com>
# Authors: Angus Salkeld <asalkeld@redhat.com>
# Balazs Gibizer <balazs.gibizer@ericsson.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -33,6 +35,9 @@ STATISTICS = ['max', 'min', 'avg', 'sum', 'count']
OPERATORS_STRING = dict(gt='>', ge='>=',
lt='<', le="<=",
eq='==', ne='!=')
ORDER_DIRECTIONS = ['asc', 'desc']
COMPLEX_OPERATORS = ['and', 'or']
SIMPLE_OPERATORS = ["=", "!=", "<", "<=", '>', '>=']
@utils.arg('-q', '--query', metavar='<QUERY>',
@@ -639,3 +644,30 @@ def do_trait_list(cc, args={}):
field_labels = ['Trait Name', 'Value', 'Data Type']
fields = ['name', 'value', 'type']
utils.print_list(traits, fields, field_labels)
@utils.arg('-f', '--filter', metavar='<FILTER>',
help=('{complex_op: [{simple_op: {field_name: value}}]} '
'The complex_op is one of: ' + str(COMPLEX_OPERATORS) + ', '
'simple_op is one of: ' + str(SIMPLE_OPERATORS) + '.'))
@utils.arg('-o', '--orderby', metavar='<ORDERBY>',
help=('[{field_name: direction}, {field_name: direction}] '
'The direction is one of: ' + str(ORDER_DIRECTIONS) + '.'))
@utils.arg('-l', '--limit', metavar='<LIMIT>',
help='Maximum number of samples to return.')
def do_query_samples(cc, args):
'''Query samples.'''
fields = {'filter': args.filter,
'orderby': args.orderby,
'limit': args.limit}
try:
samples = cc.query_samples.query(**fields)
except exc.HTTPNotFound:
raise exc.CommandError('Samples not found')
else:
field_labels = ['Resource ID', 'Meter', 'Type', 'Volume', 'Unit',
'Timestamp']
fields = ['resource_id', 'meter', 'type',
'volume', 'unit', 'timestamp']
utils.print_list(samples, fields, field_labels,
sortby=None)