diff --git a/aodhclient/tests/functional/test_alarm.py b/aodhclient/tests/functional/test_alarm.py index b22b52b..55bfa6c 100644 --- a/aodhclient/tests/functional/test_alarm.py +++ b/aodhclient/tests/functional/test_alarm.py @@ -84,6 +84,13 @@ class AodhClientTest(base.ClientTestBase): if alarm_list["alarm_id"] == ALARM_ID: self.assertEqual('ev_alarm1', alarm_list['name']) + # LIST WITH QUERY + result = self.aodh('alarm', + params=("list --query project_id=%s" % PROJECT_ID)) + alarm_list = self.parser.listing(result)[0] + self.assertEqual(ALARM_ID, alarm_list["alarm_id"]) + self.assertEqual('ev_alarm1', alarm_list['name']) + # DELETE result = self.aodh('alarm', params="delete %s" % ALARM_ID) self.assertEqual("", result) @@ -180,6 +187,13 @@ class AodhClientTest(base.ClientTestBase): if alarm_list["alarm_id"] == ALARM_ID: self.assertEqual('alarm1', alarm_list['name']) + # LIST WITH QUERY + result = self.aodh('alarm', + params=("list --query project_id=%s" % PROJECT_ID)) + alarm_list = self.parser.listing(result)[0] + self.assertEqual(ALARM_ID, alarm_list["alarm_id"]) + self.assertEqual('alarm1', alarm_list['name']) + # DELETE result = self.aodh('alarm', params="delete %s" % ALARM_ID) self.assertEqual("", result) @@ -269,6 +283,13 @@ class AodhClientTest(base.ClientTestBase): if alarm_list["alarm_id"] == alarm_id: self.assertEqual('calarm1', alarm_list['name']) + # LIST WITH QUERY + result = self.aodh('alarm', + params=("list --query project_id=%s" % project_id)) + alarm_list = self.parser.listing(result)[0] + self.assertEqual(alarm_id, alarm_list["alarm_id"]) + self.assertEqual('calarm1', alarm_list['name']) + # DELETE result = self.aodh('alarm', params="delete %s" % alarm_id) self.assertEqual("", result) @@ -376,6 +397,13 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase): if alarm_list["alarm_id"] == ALARM_ID: self.assertEqual('alarm1', alarm_list['name']) + # LIST WITH QUERY + result = self.aodh('alarm', + params=("list --query project_id=%s" % PROJECT_ID)) + alarm_list = self.parser.listing(result)[0] + self.assertEqual(ALARM_ID, alarm_list["alarm_id"]) + self.assertEqual('alarm1', alarm_list['name']) + # DELETE result = self.aodh('alarm', params="delete %s" % ALARM_ID) self.assertEqual("", result) @@ -589,6 +617,13 @@ class AodhClientGnocchiRulesTest(base.ClientTestBase): if alarm_list["alarm_id"] == ALARM_ID: self.assertEqual('alarm1', alarm_list['name']) + # LIST WITH QUERY + result = self.aodh('alarm', + params=("list --query project_id=%s" % PROJECT_ID)) + alarm_list = self.parser.listing(result)[0] + self.assertEqual(ALARM_ID, alarm_list["alarm_id"]) + self.assertEqual('alarm1', alarm_list['name']) + # DELETE result = self.aodh('alarm', params="delete %s" % ALARM_ID) self.assertEqual("", result) diff --git a/aodhclient/tests/unit/test_alarm_manager.py b/aodhclient/tests/unit/test_alarm_manager.py index 331aa02..3a8ce7c 100644 --- a/aodhclient/tests/unit/test_alarm_manager.py +++ b/aodhclient/tests/unit/test_alarm_manager.py @@ -46,6 +46,20 @@ class AlarmManagerTest(testtools.TestCase): am.list() mock_am.assert_called_with('v2/alarms') + @mock.patch.object(alarm.AlarmManager, '_post') + def test_list_with_query(self, mock_am): + am = alarm.AlarmManager(self.client) + query = '{"=": {"type": "event"}}' + am.list(query) + url = 'v2/query/alarms' + expected_value = ('{"filter": "{\\"=\\": {\\"type\\":' + ' \\"event\\"}}"}') + headers_value = {'Content-Type': "application/json"} + mock_am.assert_called_with( + url, + data=expected_value, + headers=headers_value) + @mock.patch.object(alarm.AlarmManager, '_get') def test_get(self, mock_am): am = alarm.AlarmManager(self.client) diff --git a/aodhclient/tests/unit/test_utils.py b/aodhclient/tests/unit/test_utils.py index 5037eb4..263f193 100644 --- a/aodhclient/tests/unit/test_utils.py +++ b/aodhclient/tests/unit/test_utils.py @@ -28,37 +28,27 @@ class SearchQueryBuilderTest(base.BaseTestCase): self._do_test('foo=True', {"=": {"foo": True}}) self._do_test('foo=null', {"=": {"foo": None}}) self._do_test('foo="null"', {"=": {"foo": "null"}}) - self._do_test('foo in ["null", "foo"]', - {"in": {"foo": ["null", "foo"]}}) - self._do_test(u'foo="quote" and bar≠1', - {"and": [{u"≠": {"bar": 1}}, - {"=": {"foo": "quote"}}]}) - self._do_test('foo="quote" or bar like "%%foo"', - {"or": [{"like": {"bar": "%%foo"}}, - {"=": {"foo": "quote"}}]}) - self._do_test('not (foo="quote" or bar like "%%foo" or foo="what!" ' + self._do_test('not (foo="quote" or foo="what!" ' 'or bar="who?")', {"not": {"or": [ {"=": {"bar": "who?"}}, {"=": {"foo": "what!"}}, - {"like": {"bar": "%%foo"}}, {"=": {"foo": "quote"}}, ]}}) - self._do_test('(foo="quote" or bar like "%%foo" or not foo="what!" ' + self._do_test('(foo="quote" or not foo="what!" ' 'or bar="who?") and cat="meme"', {"and": [ {"=": {"cat": "meme"}}, {"or": [ {"=": {"bar": "who?"}}, {"not": {"=": {"foo": "what!"}}}, - {"like": {"bar": "%%foo"}}, {"=": {"foo": "quote"}}, ]} ]}) - self._do_test('foo="quote" or bar like "%%foo" or foo="what!" ' + self._do_test('foo="quote" or foo="what!" ' 'or bar="who?" and cat="meme"', {"or": [ {"and": [ @@ -66,20 +56,18 @@ class SearchQueryBuilderTest(base.BaseTestCase): {"=": {"bar": "who?"}}, ]}, {"=": {"foo": "what!"}}, - {"like": {"bar": "%%foo"}}, {"=": {"foo": "quote"}}, ]}) - self._do_test('foo="quote" or bar like "%%foo" and foo="what!" ' + self._do_test('foo="quote" and foo="what!" ' 'or bar="who?" or cat="meme"', - {"or": [ - {"=": {"cat": "meme"}}, - {"=": {"bar": "who?"}}, - {"and": [ - {"=": {"foo": "what!"}}, - {"like": {"bar": "%%foo"}}, - ]}, - {"=": {"foo": "quote"}}, + {'or': [ + {'=': {'cat': 'meme'}}, + {'=': {'bar': 'who?'}}, + {'and': [ + {'=': {'foo': 'what!'}}, + {'=': {'foo': 'quote'}} + ]} ]}) diff --git a/aodhclient/utils.py b/aodhclient/utils.py index f15aa1e..311b749 100644 --- a/aodhclient/utils.py +++ b/aodhclient/utils.py @@ -17,9 +17,8 @@ import pyparsing as pp uninary_operators = ("not", ) binary_operator = (u">=", u"<=", u"!=", u">", u"<", u"=", u"==", u"eq", u"ne", - u"lt", u"gt", u"ge", u"le", u"in", u"like", u"≠", u"≥", - u"≤", u"like" "in") -multiple_operators = (u"and", u"or", u"∧", u"∨") + u"lt", u"gt", u"ge", u"le") +multiple_operators = (u"and", u"or") operator = pp.Regex(u"|".join(binary_operator)) null = pp.Regex("None|none|null").setParseAction(pp.replaceWith(None)) @@ -37,15 +36,13 @@ in_list = pp.Group(pp.Suppress('[') + pp.Optional(pp.delimitedList(comparison_term)) + pp.Suppress(']'))("list") comparison_term << (null | boolean | uuid | identifier | number | - quoted_string | in_list) + quoted_string) condition = pp.Group(comparison_term + operator + comparison_term) expr = pp.operatorPrecedence(condition, [ ("not", 1, pp.opAssoc.RIGHT, ), ("and", 2, pp.opAssoc.LEFT, ), - ("∧", 2, pp.opAssoc.LEFT, ), ("or", 2, pp.opAssoc.LEFT, ), - ("∨", 2, pp.opAssoc.LEFT, ), ]) OP_LOOKUP = {'!=': 'ne', diff --git a/aodhclient/v2/alarm.py b/aodhclient/v2/alarm.py index 9fd0196..60ce900 100644 --- a/aodhclient/v2/alarm.py +++ b/aodhclient/v2/alarm.py @@ -21,9 +21,16 @@ class AlarmManager(base.Manager): url = "v2/alarms" - def list(self): + def list(self, query=None): """List alarms""" - return self._get(self.url).json() + if query: + query = {'filter': query} + url = "v2/query/alarms" + return self._post(url, + headers={'Content-Type': "application/json"}, + data=jsonutils.dumps(query)).json() + else: + return self._get(self.url).json() def get(self, alarm_id): """Get an alarm diff --git a/aodhclient/v2/alarm_cli.py b/aodhclient/v2/alarm_cli.py index 94ff92f..4f7c9e9 100644 --- a/aodhclient/v2/alarm_cli.py +++ b/aodhclient/v2/alarm_cli.py @@ -36,8 +36,21 @@ ALARM_LIST_COLS = ['alarm_id', 'type', 'name', 'state', 'severity', 'enabled'] class CliAlarmList(lister.Lister): """List alarms""" + def get_parser(self, prog_name): + parser = super(CliAlarmList, self).get_parser(prog_name) + parser.add_argument("--query", + help="Rich query supported by aodh, " + "e.g. project_id!=my-id " + "user_id=foo or user_id=bar"), + return parser + def take_action(self, parsed_args): - alarms = self.app.client.alarm.list() + if parsed_args.query: + query = jsonutils.dumps( + utils.search_query_builder(parsed_args.query)) + else: + query = None + alarms = self.app.client.alarm.list(query) return utils.list2cols(ALARM_LIST_COLS, alarms)