Merge "Add complex query support for alarms"
This commit is contained in:
72
ceilometerclient/tests/v2/test_query_alarms.py
Normal file
72
ceilometerclient/tests/v2/test_query_alarms.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
ALARM = {"alarm_actions": ["http://site:8000/alarm"],
|
||||||
|
"alarm_id": None,
|
||||||
|
"combination_rule": {
|
||||||
|
"alarm_ids": [
|
||||||
|
"739e99cb-c2ec-4718-b900-332502355f38",
|
||||||
|
"153462d0-a9b8-4b5b-8175-9e4b05e9b856"],
|
||||||
|
"operator": "or"},
|
||||||
|
"description": "An alarm",
|
||||||
|
"enabled": True,
|
||||||
|
"insufficient_data_actions": ["http://site:8000/nodata"],
|
||||||
|
"name": "SwiftObjectAlarm",
|
||||||
|
"ok_actions": ["http://site:8000/ok"],
|
||||||
|
"project_id": "c96c887c216949acbdfbd8b494863567",
|
||||||
|
"repeat_actions": False,
|
||||||
|
"state": "ok",
|
||||||
|
"state_timestamp": "2014-02-20T10:37:15.589860",
|
||||||
|
"threshold_rule": None,
|
||||||
|
"timestamp": "2014-02-20T10:37:15.589856",
|
||||||
|
"type": "combination",
|
||||||
|
"user_id": "c96c887c216949acbdfbd8b494863567"}
|
||||||
|
|
||||||
|
QUERY = {"filter": {"and": [{"!=": {"state": "ok"}},
|
||||||
|
{"=": {"type": "combination"}}]},
|
||||||
|
"orderby": [{"state_timestamp": "desc"}],
|
||||||
|
"limit": 10}
|
||||||
|
|
||||||
|
base_url = '/v2/query/alarms'
|
||||||
|
fixtures = {
|
||||||
|
base_url:
|
||||||
|
{
|
||||||
|
'POST': (
|
||||||
|
{},
|
||||||
|
[ALARM],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class QueryAlarmsManagerTest(utils.BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(QueryAlarmsManagerTest, self).setUp()
|
||||||
|
self.api = utils.FakeAPI(fixtures)
|
||||||
|
self.mgr = query.QueryAlarmsManager(self.api)
|
||||||
|
|
||||||
|
def test_query(self):
|
||||||
|
alarms = self.mgr.query(**QUERY)
|
||||||
|
expect = [
|
||||||
|
('POST', '/v2/query/alarms', {}, QUERY),
|
||||||
|
]
|
||||||
|
self.assertEqual(expect, self.api.calls)
|
||||||
|
self.assertEqual(1, len(alarms))
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from ceilometerclient.tests import utils
|
from ceilometerclient.tests import utils
|
||||||
from ceilometerclient.v2 import query_samples
|
from ceilometerclient.v2 import query
|
||||||
|
|
||||||
|
|
||||||
SAMPLE = {u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6',
|
SAMPLE = {u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6',
|
||||||
@@ -54,7 +54,7 @@ class QuerySamplesManagerTest(utils.BaseTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(QuerySamplesManagerTest, self).setUp()
|
super(QuerySamplesManagerTest, self).setUp()
|
||||||
self.api = utils.FakeAPI(fixtures)
|
self.api = utils.FakeAPI(fixtures)
|
||||||
self.mgr = query_samples.QuerySamplesManager(self.api)
|
self.mgr = query.QuerySamplesManager(self.api)
|
||||||
|
|
||||||
def test_query(self):
|
def test_query(self):
|
||||||
samples = self.mgr.query(**QUERY)
|
samples = self.mgr.query(**QUERY)
|
||||||
|
|||||||
@@ -469,3 +469,70 @@ class ShellQuerySamplesCommandTest(utils.BaseTestCase):
|
|||||||
+--------------------------------------+----------+-------+--------+---------\
|
+--------------------------------------+----------+-------+--------+---------\
|
||||||
-+----------------------------+
|
-+----------------------------+
|
||||||
''', output.getvalue())
|
''', output.getvalue())
|
||||||
|
|
||||||
|
|
||||||
|
class ShellQueryAlarmsCommandTest(utils.BaseTestCase):
|
||||||
|
|
||||||
|
ALARM = [{"alarm_actions": ["http://site:8000/alarm"],
|
||||||
|
"alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc",
|
||||||
|
"combination_rule": {
|
||||||
|
"alarm_ids": [
|
||||||
|
"739e99cb-c2ec-4718-b900-332502355f38",
|
||||||
|
"153462d0-a9b8-4b5b-8175-9e4b05e9b856"],
|
||||||
|
"operator": "or"},
|
||||||
|
"description": "An alarm",
|
||||||
|
"enabled": True,
|
||||||
|
"insufficient_data_actions": ["http://site:8000/nodata"],
|
||||||
|
"name": "SwiftObjectAlarm",
|
||||||
|
"ok_actions": ["http://site:8000/ok"],
|
||||||
|
"project_id": "c96c887c216949acbdfbd8b494863567",
|
||||||
|
"repeat_actions": False,
|
||||||
|
"state": "ok",
|
||||||
|
"state_timestamp": "2014-02-20T10:37:15.589860",
|
||||||
|
"threshold_rule": None,
|
||||||
|
"timestamp": "2014-02-20T10:37:15.589856",
|
||||||
|
"type": "combination",
|
||||||
|
"user_id": "c96c887c216949acbdfbd8b494863567"}]
|
||||||
|
|
||||||
|
QUERY = {"filter": {"and": [{"!=": {"state": "ok"}},
|
||||||
|
{"=": {"type": "combination"}}]},
|
||||||
|
"orderby": [{"state_timestamp": "desc"}],
|
||||||
|
"limit": 10}
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ShellQueryAlarmsCommandTest, 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_alarm = [alarms.Alarm(mock.Mock(), alarm)
|
||||||
|
for alarm in self.ALARM]
|
||||||
|
self.cc.query_alarms.query.return_value = ret_alarm
|
||||||
|
org_stdout = sys.stdout
|
||||||
|
try:
|
||||||
|
sys.stdout = output = six.StringIO()
|
||||||
|
ceilometer_shell.do_query_alarms(self.cc, self.args)
|
||||||
|
finally:
|
||||||
|
sys.stdout = org_stdout
|
||||||
|
|
||||||
|
self.assertEqual('''\
|
||||||
|
+--------------------------------------+------------------+-------+---------\
|
||||||
|
+------------+--------------------------------------------------------------\
|
||||||
|
----------------------------------------+
|
||||||
|
| Alarm ID | Name | State | Enabled \
|
||||||
|
| Continuous | Alarm condition \
|
||||||
|
|
|
||||||
|
+--------------------------------------+------------------+-------+---------\
|
||||||
|
+------------+--------------------------------------------------------------\
|
||||||
|
----------------------------------------+
|
||||||
|
| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | True \
|
||||||
|
| False | combinated states (OR) of 739e99cb-c2ec-4718-b900-332502355f3\
|
||||||
|
8, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 |
|
||||||
|
+--------------------------------------+------------------+-------+---------\
|
||||||
|
+------------+--------------------------------------------------------------\
|
||||||
|
----------------------------------------+
|
||||||
|
''', output.getvalue())
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from ceilometerclient.v2 import alarms
|
|||||||
from ceilometerclient.v2 import event_types
|
from ceilometerclient.v2 import event_types
|
||||||
from ceilometerclient.v2 import events
|
from ceilometerclient.v2 import events
|
||||||
from ceilometerclient.v2 import meters
|
from ceilometerclient.v2 import meters
|
||||||
from ceilometerclient.v2 import query_samples
|
from ceilometerclient.v2 import query
|
||||||
from ceilometerclient.v2 import resources
|
from ceilometerclient.v2 import resources
|
||||||
from ceilometerclient.v2 import samples
|
from ceilometerclient.v2 import samples
|
||||||
from ceilometerclient.v2 import statistics
|
from ceilometerclient.v2 import statistics
|
||||||
@@ -50,5 +50,7 @@ class Client(object):
|
|||||||
self.traits = traits.TraitManager(self.http_client)
|
self.traits = traits.TraitManager(self.http_client)
|
||||||
self.trait_info = trait_descriptions.\
|
self.trait_info = trait_descriptions.\
|
||||||
TraitDescriptionManager(self.http_client)
|
TraitDescriptionManager(self.http_client)
|
||||||
self.query_samples = query_samples.QuerySamplesManager(
|
self.query_samples = query.QuerySamplesManager(
|
||||||
|
self.http_client)
|
||||||
|
self.query_alarms = query.QueryAlarmsManager(
|
||||||
self.http_client)
|
self.http_client)
|
||||||
|
|||||||
@@ -15,15 +15,12 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from ceilometerclient.common import base
|
from ceilometerclient.common import base
|
||||||
|
from ceilometerclient.v2 import alarms
|
||||||
from ceilometerclient.v2 import samples
|
from ceilometerclient.v2 import samples
|
||||||
|
|
||||||
|
|
||||||
class QuerySamplesManager(base.Manager):
|
class QueryManager(base.Manager):
|
||||||
resource_class = samples.Sample
|
path_suffix = None
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _path():
|
|
||||||
return '/v2/query/samples'
|
|
||||||
|
|
||||||
def query(self, filter, orderby, limit):
|
def query(self, filter, orderby, limit):
|
||||||
query = {}
|
query = {}
|
||||||
@@ -34,7 +31,7 @@ class QuerySamplesManager(base.Manager):
|
|||||||
if limit:
|
if limit:
|
||||||
query["limit"] = limit
|
query["limit"] = limit
|
||||||
|
|
||||||
url = self._path()
|
url = '/v2/query%s' % self.path_suffix
|
||||||
resp, body = self.api.json_request('POST',
|
resp, body = self.api.json_request('POST',
|
||||||
url,
|
url,
|
||||||
body=query)
|
body=query)
|
||||||
@@ -42,3 +39,13 @@ class QuerySamplesManager(base.Manager):
|
|||||||
return [self.resource_class(self, b) for b in body]
|
return [self.resource_class(self, b) for b in body]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class QuerySamplesManager(QueryManager):
|
||||||
|
resource_class = samples.Sample
|
||||||
|
path_suffix = '/samples'
|
||||||
|
|
||||||
|
|
||||||
|
class QueryAlarmsManager(QueryManager):
|
||||||
|
resource_class = alarms.Alarm
|
||||||
|
path_suffix = '/alarms'
|
||||||
@@ -671,3 +671,31 @@ def do_query_samples(cc, args):
|
|||||||
'volume', 'unit', 'timestamp']
|
'volume', 'unit', 'timestamp']
|
||||||
utils.print_list(samples, fields, field_labels,
|
utils.print_list(samples, fields, field_labels,
|
||||||
sortby=None)
|
sortby=None)
|
||||||
|
|
||||||
|
|
||||||
|
@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 alarms to return.')
|
||||||
|
def do_query_alarms(cc, args):
|
||||||
|
'''Query Alarms.'''
|
||||||
|
fields = {'filter': args.filter,
|
||||||
|
'orderby': args.orderby,
|
||||||
|
'limit': args.limit}
|
||||||
|
try:
|
||||||
|
alarms = cc.query_alarms.query(**fields)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError('Alarms not found')
|
||||||
|
else:
|
||||||
|
field_labels = ['Alarm ID', 'Name', 'State', 'Enabled', 'Continuous',
|
||||||
|
'Alarm condition']
|
||||||
|
fields = ['alarm_id', 'name', 'state', 'enabled', 'repeat_actions',
|
||||||
|
'rule']
|
||||||
|
utils.print_list(alarms, fields, field_labels,
|
||||||
|
formatters={'rule': alarm_rule_formatter},
|
||||||
|
sortby=None)
|
||||||
|
|||||||
Reference in New Issue
Block a user