Enhance dimension filtering
Allow filtering for existence of dimension value, ex. all metrics that have a service dimension, regardless of value Change-Id: I3ffcae317e4d0bd03e8a02154858eea4afd25425
This commit is contained in:
parent
0195c9162d
commit
7e6e6972fb
|
@ -992,7 +992,7 @@ None.
|
|||
#### Query Parameters
|
||||
* tenant_id (string, optional, restricted) - Tenant ID to from which to get metrics. This parameter can be used to get metrics from a tenant other than the tenant the request auth token is scoped to. Usage of this query parameter is restricted to users with the the monasca admin role, as defined in the monasca api configuration file, which defaults to `monasca-admin`.
|
||||
* name (string(255), optional) - A metric name to filter metrics by.
|
||||
* dimensions (string, optional) - A dictionary to filter metrics by specified as a comma separated array of (key, value) pairs as `key1:value1,key2:value2, ...`
|
||||
* dimensions (string, optional) - A dictionary to filter metrics by specified as a comma separated array of (key, value) pairs as `key1:value1,key2:value2, ...`, leaving the value empty `key1,key2:value2` will return all values for that key, multiple values for a key may be specified as `key1:value1|value2|...,key2:value4,...`
|
||||
* start_time (string, optional) - The start time in ISO 8601 combined date and time format in UTC. This is useful for only listing metrics that have measurements since the specified start_time.
|
||||
* end_time (string, optional) - The end time in ISO 8601 combined date and time format in UTC. Combined with start_time, this can be useful to only list metrics that have measurements in between the specified start_time and end_time.
|
||||
* offset (integer (InfluxDB) or hexadecimal string (Vertica), optional)
|
||||
|
@ -1785,7 +1785,7 @@ None.
|
|||
|
||||
#### Query Parameters
|
||||
* name (string(255), optional) - Name of alarm to filter by.
|
||||
* dimensions (string, optional) - Dimensions of metrics to filter by specified as a comma separated array of (key, value) pairs as `key1:value1,key1:value1, ...`
|
||||
* dimensions (string, optional) - Dimensions of metrics to filter by specified as a comma separated array of (key, value) pairs as `key1:value1,key1:value1, ...`, leaving the value empty `key1,key2:value2` will return all values for that key, multiple values for a key may be specified as `key1:value1|value2|...,key2:value4,...`
|
||||
* offset (integer, optional)
|
||||
* limit (integer, optional)
|
||||
* sort_by (string, optional) - Comma separated list of fields to sort by, defaults to 'id', 'created_at'. Fields may be followed by 'asc' or 'desc' to set the direction, ex 'severity desc'
|
||||
|
@ -2251,7 +2251,7 @@ None.
|
|||
|
||||
* alarm_definition_id (string, optional) - Alarm definition ID to filter by.
|
||||
* metric_name (string(255), optional) - Name of metric to filter by.
|
||||
* metric_dimensions ({string(255): string(255)}, optional) - Dimensions of metrics to filter by specified as a comma separated array of (key, value) pairs as `key1:value1,key1:value1, ...`
|
||||
* metric_dimensions ({string(255): string(255)}, optional) - Dimensions of metrics to filter by specified as a comma separated array of (key, value) pairs as `key1:value1,key1:value1, ...`, leaving the value empty `key1,key2:value2` will return all values for that key, multiple values for a key may be specified as `key1:value1|value2|...,key2:value4,...`
|
||||
* state (string, optional) - State of alarm to filter by, either `OK`, `ALARM` or `UNDETERMINED`.
|
||||
* lifecycle_state (string(50), optional) - Lifecycle state to filter by.
|
||||
* link (string(512), optional) - Link to filter by.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (c) 2014,2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* 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
|
||||
|
@ -33,8 +33,8 @@ public final class DimensionValidation {
|
|||
private static final Map<String, DimensionValidator> VALIDATORS;
|
||||
private static final Pattern UUID_PATTERN = Pattern
|
||||
.compile("\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}");
|
||||
private static final Pattern VALID_DIMENSION_NAME = Pattern.compile("[^><={}(),\"\\\\;&]+$");
|
||||
private static final String INVALID_CHAR_STRING = "> < = { } ( ) \" \\ , ; &";
|
||||
private static final Pattern VALID_DIMENSION_NAME = Pattern.compile("[^><={}(),\"\\\\;&\\|]+$");
|
||||
private static final String INVALID_CHAR_STRING = "> < = { } ( ) \" \\ , ; & |";
|
||||
|
||||
private DimensionValidation() {}
|
||||
|
||||
|
|
|
@ -95,9 +95,11 @@ public final class Validation {
|
|||
String[] dimensionArr = Iterables.toArray(COLON_SPLITTER.split(dimensionStr), String.class);
|
||||
if (dimensionArr.length == 2)
|
||||
dimensions.put(dimensionArr[0], dimensionArr[1]);
|
||||
if (dimensionArr.length == 1)
|
||||
dimensions.put(dimensionArr[0], "");
|
||||
}
|
||||
|
||||
DimensionValidation.validate(dimensions);
|
||||
//DimensionValidation.validate(dimensions);
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (c) 2014,2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* 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
|
||||
|
@ -13,9 +13,13 @@
|
|||
*/
|
||||
package monasca.api.infrastructure.persistence;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.skife.jdbi.v2.Query;
|
||||
|
@ -38,7 +42,14 @@ public final class DimensionQueries {
|
|||
for (Iterator<Map.Entry<String, String>> it = dimensions.entrySet().iterator(); it.hasNext(); i++) {
|
||||
Map.Entry<String, String> entry = it.next();
|
||||
query.bind("dname" + i, entry.getKey());
|
||||
query.bind("dvalue" + i, entry.getValue());
|
||||
if (!Strings.isNullOrEmpty(entry.getValue())) {
|
||||
List<String> values = Splitter.on('|').splitToList(entry.getValue());
|
||||
int j = 0;
|
||||
for (String value : values) {
|
||||
query.bind("dvalue" + i + '_' + j, value);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (c) 2014,2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* 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
|
||||
|
@ -13,6 +13,8 @@
|
|||
*/
|
||||
package monasca.api.infrastructure.persistence;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -29,11 +31,18 @@ public final class SubAlarmDefinitionQueries {
|
|||
|
||||
sbJoin = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < dimensions.size(); i++) {
|
||||
sbJoin.append(" inner join sub_alarm_definition_dimension d").append(i).append(" on d").append(i)
|
||||
.append(".dimension_name = :dname").append(i).append(" and d").append(i)
|
||||
.append(".value = :dvalue").append(i).append(" and dim.sub_alarm_definition_id = d")
|
||||
int i = 0;
|
||||
for (String dimension_key : dimensions.keySet()) {
|
||||
sbJoin.append(" inner join sub_alarm_definition_dimension d").append(i).append(" on d")
|
||||
.append(i)
|
||||
.append(".dimension_name = :dname").append(i);
|
||||
if (!Strings.isNullOrEmpty(dimensions.get(dimension_key))) {
|
||||
sbJoin.append(" and d").append(i)
|
||||
.append(".value = :dvalue").append(i);
|
||||
}
|
||||
sbJoin.append(" and dim.sub_alarm_definition_id = d")
|
||||
.append(i).append(".sub_alarm_definition_id");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (c) 2015,2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* 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
|
||||
|
@ -13,6 +13,8 @@
|
|||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -166,8 +168,15 @@ public class InfluxV9Utils {
|
|||
if (dims != null && !dims.isEmpty()) {
|
||||
for (String k : dims.keySet()) {
|
||||
String v = dims.get(k);
|
||||
if (k != null && !k.isEmpty() && v != null && !v.isEmpty()) {
|
||||
sb.append(" and \"" + sanitize(k) + "\"=" + "'" + sanitize(v) + "'");
|
||||
if (k != null && !k.isEmpty()) {
|
||||
sb.append(" and \"" + sanitize(k) + "\"");
|
||||
if (Strings.isNullOrEmpty(v)) {
|
||||
sb.append("=~ /.*/");
|
||||
} else if (v.contains("|")) {
|
||||
sb.append("=~ " + "/^" + sanitize(v) + "$/");
|
||||
} else {
|
||||
sb.append("= " + "'" + sanitize(v) + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package monasca.api.infrastructure.persistence.mysql;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
|
@ -95,15 +96,28 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
|
|||
if (dimensions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dimensions.size(); i++) {
|
||||
int i = 0;
|
||||
for (String dimension_key : dimensions.keySet()) {
|
||||
final String indexStr = String.valueOf(i);
|
||||
sbJoin.append(" inner join metric_dimension md").append(indexStr).append(" on md")
|
||||
.append(indexStr)
|
||||
.append(".name = :dname").append(indexStr).append(" and md").append(indexStr)
|
||||
.append(".value = :dvalue").append(indexStr)
|
||||
.append(" and mdd.metric_dimension_set_id = md")
|
||||
.append(".name = :dname").append(indexStr);
|
||||
String dim_value = dimensions.get(dimension_key);
|
||||
if (!Strings.isNullOrEmpty(dim_value)) {
|
||||
sbJoin.append(" and (");
|
||||
List<String> values = Splitter.on('|').splitToList(dim_value);
|
||||
for (int j = 0; j < values.size(); j++) {
|
||||
sbJoin.append(" md").append(indexStr)
|
||||
.append(".value = :dvalue").append(indexStr).append('_').append(j);
|
||||
if (j < values.size() - 1) {
|
||||
sbJoin.append(" or");
|
||||
}
|
||||
}
|
||||
sbJoin.append(")");
|
||||
}
|
||||
sbJoin.append(" and mdd.metric_dimension_set_id = md")
|
||||
.append(indexStr).append(".dimension_set_id");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf8 -*-
|
||||
# Copyright 2014 Hewlett-Packard
|
||||
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP
|
||||
# Copyright 2015 Cray Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -135,11 +135,23 @@ class MetricsRepository(metrics_repository.MetricsRepository):
|
|||
sorted(dimensions.iteritems())):
|
||||
# replace ' with \' to make query parsable
|
||||
clean_dimension_name = dimension_name.replace("\'", "\\'")
|
||||
clean_dimension_value = dimension_value.replace("\'", "\\'")
|
||||
if dimension_value == "":
|
||||
where_clause += " and \"{}\" =~ /.*/ ".format(
|
||||
clean_dimension_name)
|
||||
elif '|' in dimension_value:
|
||||
# replace ' with \' to make query parsable
|
||||
clean_dimension_value = dimension_value.replace("\'", "\\'")
|
||||
|
||||
where_clause += " and \"{}\" = '{}'".format(
|
||||
clean_dimension_name.encode('utf8'),
|
||||
clean_dimension_value.encode('utf8'))
|
||||
where_clause += " and \"{}\" =~ /^{}$/ ".format(
|
||||
clean_dimension_name.encode('utf8'),
|
||||
clean_dimension_value.encode('utf8'))
|
||||
else:
|
||||
# replace ' with \' to make query parsable
|
||||
clean_dimension_value = dimension_value.replace("\'", "\\'")
|
||||
|
||||
where_clause += " and \"{}\" = '{}' ".format(
|
||||
clean_dimension_name.encode('utf8'),
|
||||
clean_dimension_value.encode('utf8'))
|
||||
|
||||
if start_timestamp is not None:
|
||||
where_clause += " and time > " + str(int(start_timestamp *
|
||||
|
|
|
@ -267,15 +267,27 @@ class AlarmsRepository(mysql_repository.MySQLRepository,
|
|||
i = 0
|
||||
for metric_dimension in query_parms['metric_dimensions']:
|
||||
parsed_dimension = metric_dimension.split(':')
|
||||
if len(parsed_dimension) == 1:
|
||||
values = None
|
||||
value_sql = ""
|
||||
elif '|' in parsed_dimension[1]:
|
||||
values = parsed_dimension[1].encode('utf8').split('|')
|
||||
value_sql = " and ("
|
||||
value_sql += " or ".join(["value = %s" for j in xrange(len(values))])
|
||||
value_sql += ') '
|
||||
else:
|
||||
values = [parsed_dimension[1]]
|
||||
value_sql = " and value = %s "
|
||||
sub_select_clause += """
|
||||
inner join (select distinct dimension_set_id
|
||||
from metric_dimension
|
||||
where name = %s and value = %s) as md{}
|
||||
where name = %s {}) as md{}
|
||||
on md{}.dimension_set_id = mdd.metric_dimension_set_id
|
||||
""".format(i, i)
|
||||
""".format(value_sql, i, i)
|
||||
i += 1
|
||||
sub_select_parms += [parsed_dimension[0].encode('utf8'),
|
||||
parsed_dimension[1].encode('utf8')]
|
||||
sub_select_parms.append(parsed_dimension[0].encode('utf8'))
|
||||
if len(parsed_dimension) > 1 and values:
|
||||
sub_select_parms.extend(values)
|
||||
|
||||
sub_select_clause += ")"
|
||||
parms += sub_select_parms
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright 2015 Cray Inc. All Rights Reserved.
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
#
|
||||
# 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
|
||||
|
@ -77,12 +78,19 @@ class TestGetQueryDimension(unittest.TestCase):
|
|||
"Dimension-2": "Value-2",
|
||||
"Dimension-3": "Value-3"})
|
||||
|
||||
def test_malformed_dimension_no_value(self):
|
||||
def test_dimension_no_value(self):
|
||||
req = Mock()
|
||||
req.query_string = ("foo=bar&dimensions=no_value")
|
||||
req.query_string = ("foo=bar&dimensions=Dimension_no_value")
|
||||
|
||||
self.assertRaises(
|
||||
HTTPUnprocessableEntityError, helpers.get_query_dimensions, req)
|
||||
result = helpers.get_query_dimensions(req)
|
||||
self.assertEqual(result, {"Dimension_no_value": ""})
|
||||
|
||||
def test_dimension_multi_value(self):
|
||||
req = Mock()
|
||||
req.query_string = ("foo=bar&dimensions=Dimension_multi_value:one|two|three")
|
||||
|
||||
result = helpers.get_query_dimensions(req)
|
||||
self.assertEqual(result, {"Dimension_multi_value": "one|two|three"})
|
||||
|
||||
def test_malformed_dimension_extra_colons(self):
|
||||
req = Mock()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Copyright 2015 Hewlett-Packard
|
||||
# Copyright 2015 Cray Inc. All Rights Reserved.
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
#
|
||||
# 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
|
||||
|
@ -23,7 +24,7 @@ import mock
|
|||
|
||||
import unittest
|
||||
|
||||
invalid_chars = "<>={}(),\"\\;&"
|
||||
invalid_chars = "<>={}(),\"\\|;&"
|
||||
|
||||
|
||||
class TestMetricNameValidation(unittest.TestCase):
|
||||
|
|
|
@ -16,7 +16,7 @@ from monasca_api.v2.common.exceptions import HTTPUnprocessableEntityError
|
|||
|
||||
import re
|
||||
|
||||
invalid_chars = "<>={}(),'\"\\\\;&"
|
||||
invalid_chars = "<>={}(),\"\\\\|;&"
|
||||
restricted_chars = re.compile('[' + invalid_chars + ']')
|
||||
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ class Alarms(alarms_api_v2.AlarmsV2API,
|
|||
# ensure metric_dimensions is a list
|
||||
if 'metric_dimensions' in query_parms and isinstance(query_parms['metric_dimensions'], str):
|
||||
query_parms['metric_dimensions'] = query_parms['metric_dimensions'].split(',')
|
||||
self._validate_dimensions(query_parms['metric_dimensions'])
|
||||
|
||||
offset = helpers.get_query_param(req, 'offset')
|
||||
if offset is not None and not isinstance(offset, int):
|
||||
|
@ -152,6 +153,20 @@ class Alarms(alarms_api_v2.AlarmsV2API,
|
|||
res.body = helpers.dumpit_utf8(result)
|
||||
res.status = falcon.HTTP_200
|
||||
|
||||
@staticmethod
|
||||
def _validate_dimensions(dimensions):
|
||||
try:
|
||||
assert isinstance(dimensions, list)
|
||||
for dimension in dimensions:
|
||||
name_value = dimension.split('=')
|
||||
validation.dimension_key(name_value[0])
|
||||
if len(name_value) > 1 and '|' in name_value[1]:
|
||||
values = name_value[1].split('|')
|
||||
for value in values:
|
||||
validation.dimension_value(value)
|
||||
except Exception as e:
|
||||
raise HTTPUnprocessableEntityError("Unprocessable Entity", e.message)
|
||||
|
||||
@resource.resource_try_catch_block
|
||||
def _alarm_update(self, tenant_id, alarm_id, new_state, lifecycle_state,
|
||||
link):
|
||||
|
|
|
@ -184,6 +184,8 @@ def get_query_dimensions(req):
|
|||
if len(dimension_name_value) == 2:
|
||||
dimensions[dimension_name_value[0]] = dimension_name_value[
|
||||
1]
|
||||
elif len(dimension_name_value) == 1:
|
||||
dimensions[dimension_name_value[0]] = ""
|
||||
else:
|
||||
raise Exception('Dimensions are malformed')
|
||||
return dimensions
|
||||
|
|
|
@ -89,6 +89,96 @@ class TestAlarms(base.BaseMonascaTest):
|
|||
self.assertEqual(alarm_definition_ids[0],
|
||||
element['alarm_definition']['id'])
|
||||
|
||||
@test.attr(type="gate")
|
||||
def test_list_alarms_by_metric_dimensions_no_value(self):
|
||||
metric_name = data_utils.rand_name('metric')
|
||||
match_by_key = data_utils.rand_name('key')
|
||||
dim_key = data_utils.rand_name('key')
|
||||
alarm_def = helpers.create_alarm_definition(
|
||||
name=data_utils.rand_name('definition'),
|
||||
expression=metric_name + " > 1",
|
||||
match_by=[match_by_key])
|
||||
metric_1 = helpers.create_metric(metric_name,
|
||||
{match_by_key: data_utils.rand_name('value'),
|
||||
dim_key: data_utils.rand_name('value')})
|
||||
metric_2 = helpers.create_metric(metric_name,
|
||||
{match_by_key: data_utils.rand_name('value'),
|
||||
dim_key: data_utils.rand_name('value')})
|
||||
metric_3 = helpers.create_metric(metric_name,
|
||||
{match_by_key: data_utils.rand_name('value')})
|
||||
metrics = [metric_1, metric_2, metric_3]
|
||||
resp, response_body = self.monasca_client.create_alarm_definitions(alarm_def)
|
||||
self.assertEqual(201, resp.status)
|
||||
|
||||
for i in xrange(constants.MAX_RETRIES):
|
||||
resp, alarm_def_result = self.monasca_client.create_metrics(metrics)
|
||||
self.assertEqual(204, resp.status)
|
||||
resp, response_body = self.monasca_client.list_alarms('?metric_name=' + metric_name)
|
||||
self.assertEqual(200, resp.status)
|
||||
if len(response_body['elements']) >= 3:
|
||||
break
|
||||
time.sleep(constants.RETRY_WAIT_SECS)
|
||||
if i >= constants.MAX_RETRIES - 1:
|
||||
self.fail("Timeout creating alarms, required 3 but found {}".format(
|
||||
len(response_body['elements'])))
|
||||
|
||||
query_parms = '?metric_dimensions=' + dim_key
|
||||
resp, response_body = self.monasca_client.list_alarms(query_parms)
|
||||
self._verify_list_alarms_elements(resp, response_body,
|
||||
expect_num_elements=2)
|
||||
dimension_sets = []
|
||||
for element in response_body['elements']:
|
||||
self.assertEqual(metric_name, element['metrics'][0]['name'])
|
||||
dimension_sets.append(element['metrics'][0]['dimensions'])
|
||||
self.assertIn(metric_1['dimensions'], dimension_sets)
|
||||
self.assertIn(metric_2['dimensions'], dimension_sets)
|
||||
self.assertNotIn(metric_3['dimensions'], dimension_sets)
|
||||
|
||||
|
||||
@test.attr(type="gate")
|
||||
def test_list_alarms_by_metric_dimensions_multi_value(self):
|
||||
metric_name = data_utils.rand_name('metric')
|
||||
match_by_key = data_utils.rand_name('key')
|
||||
dim_key = data_utils.rand_name('key')
|
||||
dim_value_1 = data_utils.rand_name('value')
|
||||
dim_value_2 = data_utils.rand_name('value')
|
||||
alarm_def = helpers.create_alarm_definition(
|
||||
name=data_utils.rand_name('definition'),
|
||||
expression=metric_name + " > 1",
|
||||
match_by=[match_by_key])
|
||||
metric_1 = helpers.create_metric(metric_name, {match_by_key: data_utils.rand_name('value'),
|
||||
dim_key: dim_value_1})
|
||||
metric_2 = helpers.create_metric(metric_name, {match_by_key: data_utils.rand_name('value'),
|
||||
dim_key: dim_value_2})
|
||||
metric_3 = helpers.create_metric(metric_name, {match_by_key: data_utils.rand_name('value')})
|
||||
metrics = [metric_1, metric_2, metric_3]
|
||||
resp, response_body = self.monasca_client.create_alarm_definitions(alarm_def)
|
||||
self.assertEqual(201, resp.status)
|
||||
for i in xrange(constants.MAX_RETRIES):
|
||||
resp, alarm_def_result = self.monasca_client.create_metrics(metrics)
|
||||
self.assertEqual(204, resp.status)
|
||||
resp, response_body = self.monasca_client.list_alarms('?metric_name=' + metric_name)
|
||||
self.assertEqual(200, resp.status)
|
||||
if len(response_body['elements']) >= 3:
|
||||
return
|
||||
time.sleep(constants.RETRY_WAIT_SECS)
|
||||
if i >= constants.MAX_RETRIES - 1:
|
||||
self.fail("Timeout creating alarms, required 3 but found {}".format(
|
||||
len(response_body['elements'])))
|
||||
|
||||
query_parms = '?metric_dimensions=' + dim_key + ':' + dim_value_1 + '|' + dim_value_2
|
||||
resp, response_body = self.monasca_client.list_alarms(query_parms)
|
||||
self._verify_list_alarms_elements(resp, response_body,
|
||||
expect_num_elements=2)
|
||||
dimension_sets = []
|
||||
for element in response_body['elements']:
|
||||
self.assertEqual(metric_name, element['metrics'][0]['name'])
|
||||
dimension_sets.append(element['metrics'][0]['dimensions'])
|
||||
self.assertIn(metric_1['dimensions'], dimension_sets)
|
||||
self.assertIn(metric_2['dimensions'], dimension_sets)
|
||||
self.assertNotIn(metric_3['dimensions'], dimension_sets)
|
||||
|
||||
|
||||
@test.attr(type="gate")
|
||||
def test_list_alarms_by_state(self):
|
||||
helpers.delete_alarm_definitions(self.monasca_client)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||
# (C) Copyright 2015,2016 Hewlett Packard Enterprise Development Company LP
|
||||
#
|
||||
# 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
|
||||
|
@ -290,6 +290,74 @@ class TestMetrics(base.BaseMonascaTest):
|
|||
"metrics = 0"
|
||||
self.fail(error_msg)
|
||||
|
||||
@test.attr(type='gate')
|
||||
def test_list_metrics_dimension_query_multi_value(self):
|
||||
name = data_utils.rand_name('name')
|
||||
key_service = "service"
|
||||
value_1 = data_utils.rand_name('value')
|
||||
value_2 = data_utils.rand_name('value')
|
||||
metric_1 = helpers.create_metric(name, {key_service: value_1})
|
||||
metric_2 = helpers.create_metric(name, {key_service: value_2})
|
||||
metric_3 = helpers.create_metric(name)
|
||||
metrics = [metric_1, metric_2, metric_3]
|
||||
resp, response_body = self.monasca_client.create_metrics(metrics)
|
||||
self.assertEqual(204, resp.status)
|
||||
query_param = '?name=' + name + '&dimensions=service:' + value_1 + '|' + value_2
|
||||
for i in xrange(constants.MAX_RETRIES):
|
||||
resp, response_body = self.monasca_client.list_metrics(query_param)
|
||||
self.assertEqual(200, resp.status)
|
||||
elements = response_body['elements']
|
||||
if len(elements) == 2:
|
||||
dimension_sets = []
|
||||
for element in elements:
|
||||
self.assertEqual(name, element['name'])
|
||||
dimension_sets.append(element['dimensions'])
|
||||
self.assertIn(metric_1['dimensions'], dimension_sets)
|
||||
self.assertIn(metric_2['dimensions'], dimension_sets)
|
||||
self.assertNotIn(metric_3['dimensions'], dimension_sets)
|
||||
return
|
||||
|
||||
time.sleep(constants.RETRY_WAIT_SECS)
|
||||
if i == constants.MAX_RETRIES - 1:
|
||||
error_msg = "Timeout on waiting for metrics: at least " \
|
||||
"2 metrics are needed. Current number of " \
|
||||
"metrics = 0"
|
||||
self.fail(error_msg)
|
||||
|
||||
@test.attr(type='gate')
|
||||
def test_list_metrics_dimension_query_no_value(self):
|
||||
name = data_utils.rand_name('name')
|
||||
key_service = "service"
|
||||
value_1 = data_utils.rand_name('value')
|
||||
value_2 = data_utils.rand_name('value')
|
||||
metric_1 = helpers.create_metric(name, {key_service: value_1})
|
||||
metric_2 = helpers.create_metric(name, {key_service: value_2})
|
||||
metric_3 = helpers.create_metric(name)
|
||||
metrics = [metric_1, metric_2, metric_3]
|
||||
resp, response_body = self.monasca_client.create_metrics(metrics)
|
||||
self.assertEqual(204, resp.status)
|
||||
query_param = '?name=' + name + '&dimensions=service'
|
||||
for i in xrange(constants.MAX_RETRIES):
|
||||
resp, response_body = self.monasca_client.list_metrics(query_param)
|
||||
self.assertEqual(200, resp.status)
|
||||
elements = response_body['elements']
|
||||
if len(elements) == 2:
|
||||
dimension_sets = []
|
||||
for element in elements:
|
||||
self.assertEqual(name, element['name'])
|
||||
dimension_sets.append(element['dimensions'])
|
||||
self.assertIn(metric_1['dimensions'], dimension_sets)
|
||||
self.assertIn(metric_2['dimensions'], dimension_sets)
|
||||
self.assertNotIn(metric_3['dimensions'], dimension_sets)
|
||||
return
|
||||
|
||||
time.sleep(constants.RETRY_WAIT_SECS)
|
||||
if i == constants.MAX_RETRIES - 1:
|
||||
error_msg = "Timeout on waiting for metrics: at least " \
|
||||
"2 metrics are needed. Current number of " \
|
||||
"metrics = 0"
|
||||
self.fail(error_msg)
|
||||
|
||||
@test.attr(type='gate')
|
||||
def test_list_metrics_with_name(self):
|
||||
name = data_utils.rand_name('name')
|
||||
|
|
Loading…
Reference in New Issue