Merge "Fix the -q/--query in threshold alarm creation"

This commit is contained in:
Jenkins 2016-03-14 12:40:34 +00:00 committed by Gerrit Code Review
commit 03e7a45e5e
4 changed files with 90 additions and 14 deletions

View File

@ -125,7 +125,7 @@ class CliAlarmCreateTest(testtools.TestCase):
'--comparison-operator', 'le', '--comparison-operator', 'le',
'--threshold', '80', '--threshold', '80',
'--event-type', 'event', '--event-type', 'event',
'--query', '{}', '--query', 'resource=fake-resource-id',
'--granularity', '60', '--granularity', '60',
'--aggregation-method', 'last', '--aggregation-method', 'last',
'--metric', 'cpu', '--metric', 'cpu',
@ -158,11 +158,17 @@ class CliAlarmCreateTest(testtools.TestCase):
'statistic': 'max', 'statistic': 'max',
'comparison_operator': 'le', 'comparison_operator': 'le',
'threshold': 80.0, 'threshold': 80.0,
'query': '{}' 'query': [{'field': 'resource',
'op': 'eq',
'type': '',
'value': 'fake-resource-id'}]
}, },
'event_rule': { 'event_rule': {
'event_type': 'event', 'event_type': 'event',
'query': '{}' 'query': [{'field': 'resource',
'op': 'eq',
'type': '',
'value': 'fake-resource-id'}]
}, },
'gnocchi_resources_threshold_rule': { 'gnocchi_resources_threshold_rule': {
'granularity': '60', 'granularity': '60',
@ -188,7 +194,10 @@ class CliAlarmCreateTest(testtools.TestCase):
'evaluation_periods': 60, 'evaluation_periods': 60,
'comparison_operator': 'le', 'comparison_operator': 'le',
'threshold': 80.0, 'threshold': 80.0,
'query': '{}', 'query': [{'field': 'resource',
'op': 'eq',
'type': '',
'value': 'fake-resource-id'}],
'resource_type': 'generic' 'resource_type': 'generic'
}, },
'composite_rule': None, 'composite_rule': None,

View File

@ -81,3 +81,13 @@ class SearchQueryBuilderTest(base.BaseTestCase):
]}, ]},
{"=": {"foo": "quote"}}, {"=": {"foo": "quote"}},
]}) ]})
class CliQueryToArray(base.BaseTestCase):
def test_cli_query_to_arrary(self):
cli_query = "this<=34;that=string::foo"
ret_array = utils.cli_to_array(cli_query)
expected_query = [
{"field": "this", "type": "", "value": "34", "op": "le"},
{"field": "that", "type": "string", "value": "foo", "op": "eq"}]
self.assertEqual(expected_query, ret_array)

View File

@ -11,7 +11,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import re
import pyparsing as pp import pyparsing as pp
@ -48,6 +48,16 @@ expr = pp.operatorPrecedence(condition, [
("", 2, pp.opAssoc.LEFT, ), ("", 2, pp.opAssoc.LEFT, ),
]) ])
OP_LOOKUP = {'!=': 'ne',
'>=': 'ge',
'<=': 'le',
'>': 'gt',
'<': 'lt',
'=': 'eq'}
OP_LOOKUP_KEYS = '|'.join(sorted(OP_LOOKUP.keys(), key=len, reverse=True))
OP_SPLIT_RE = re.compile(r'(%s)' % OP_LOOKUP_KEYS)
def _parsed_query2dict(parsed_query): def _parsed_query2dict(parsed_query):
result = None result = None
@ -125,3 +135,44 @@ def dict_to_querystring(objs):
return "&".join(["%s=%s" % (k, v) return "&".join(["%s=%s" % (k, v)
for k, v in objs.items() for k, v in objs.items()
if v is not None]) if v is not None])
def cli_to_array(cli_query):
"""Convert CLI list of queries to the Python API format.
This will convert the following:
"this<=34;that=string::foo"
to
"[{field=this,op=le,value=34,type=''},
{field=that,op=eq,value=foo,type=string}]"
"""
opts = []
queries = cli_query.split(';')
for q in queries:
try:
field, q_operator, type_value = OP_SPLIT_RE.split(q, maxsplit=1)
except ValueError:
raise ValueError('Invalid or missing operator in query %(q)s,'
'the supported operators are: %(k)s' %
{'q': q, 'k': OP_LOOKUP.keys()})
if not field:
raise ValueError('Missing field in query %s' % q)
if not type_value:
raise ValueError('Missing value in query %s' % q)
opt = dict(field=field, op=OP_LOOKUP[q_operator])
if '::' not in type_value:
opt['type'], opt['value'] = '', type_value
else:
opt['type'], _, opt['value'] = type_value.partition('::')
if opt['type'] and opt['type'] not in (
'string', 'integer', 'float', 'datetime', 'boolean'):
err = ('Invalid value type %(type)s, the type of value'
'should be one of: integer, string, float, datetime,'
' boolean.' % opt['type'])
raise ValueError(err)
opts.append(opt)
return opts

View File

@ -156,10 +156,14 @@ class CliAlarmCreate(show.ShowOne):
common_group = parser.add_argument_group('common alarm rules') common_group = parser.add_argument_group('common alarm rules')
common_group.add_argument( common_group.add_argument(
'-q', '--query', metavar='<QUERY>', dest='query', '--query', metavar='<QUERY>', dest='query',
help='key[op]data_type::value; list. data_type is optional, ' help="For alarms of type threshold or event: "
'but if supplied must be string, integer, float, or boolean. ' "key[op]data_type::value; list. data_type is optional, "
'Used by threshold and event alarms') "but if supplied must be string, integer, float, or boolean. "
'For alarms of '
'type gnocchi_aggregation_by_resources_threshold: '
'need to specify a complex query json string, like:'
' {"and": [{"=": {"ended_at": null}}, ...]}.')
common_group.add_argument( common_group.add_argument(
'--comparison-operator', metavar='<OPERATOR>', '--comparison-operator', metavar='<OPERATOR>',
dest='comparison_operator', choices=ALARM_OPERATORS, dest='comparison_operator', choices=ALARM_OPERATORS,
@ -285,6 +289,8 @@ class CliAlarmCreate(show.ShowOne):
'state', 'severity', 'enabled', 'alarm_actions', 'state', 'severity', 'enabled', 'alarm_actions',
'ok_actions', 'insufficient_data_actions', 'ok_actions', 'insufficient_data_actions',
'time_constraints', 'repeat_actions']) 'time_constraints', 'repeat_actions'])
if parsed_args.type in ('threshold', 'event') and parsed_args.query:
parsed_args.query = utils.cli_to_array(parsed_args.query)
alarm['threshold_rule'] = utils.dict_from_parsed_args( alarm['threshold_rule'] = utils.dict_from_parsed_args(
parsed_args, ['meter_name', 'period', 'evaluation_periods', parsed_args, ['meter_name', 'period', 'evaluation_periods',
'statistic', 'comparison_operator', 'threshold', 'statistic', 'comparison_operator', 'threshold',