Merge "Allow filtering by multiple severities"

This commit is contained in:
Jenkins 2016-06-15 03:43:16 +00:00 committed by Gerrit Code Review
commit 537e062cef
23 changed files with 319 additions and 84 deletions

View File

@ -1905,6 +1905,7 @@ None.
#### Query Parameters #### Query Parameters
* name (string(255), optional) - Name of alarm to filter by. * 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, ...`, 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,...` * 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,...`
* severity (string, optional) - One or more severities to filter by, separated with `|`, ex. `severity=LOW|MEDIUM`.
* offset (integer, optional) * offset (integer, optional)
* limit (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' * 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'
@ -2412,6 +2413,7 @@ None.
* metric_name (string(255), optional) - Name of metric 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, ...`, 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,...` * 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`. * state (string, optional) - State of alarm to filter by, either `OK`, `ALARM` or `UNDETERMINED`.
* severity (string, optional) - One or more severities to filter by, separated with `|`, ex. `severity=LOW|MEDIUM`.
* lifecycle_state (string(50), optional) - Lifecycle state to filter by. * lifecycle_state (string(50), optional) - Lifecycle state to filter by.
* link (string(512), optional) - Link to filter by. * link (string(512), optional) - Link to filter by.
* state_updated_start_time (string, optional) - The start time in ISO 8601 combined date and time format in UTC. * state_updated_start_time (string, optional) - The start time in ISO 8601 combined date and time format in UTC.
@ -2525,6 +2527,7 @@ None
* metric_name (string(255), optional) - Name of metric 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,...`
* state (string, optional) - State of alarm to filter by, either `OK`, `ALARM` or `UNDETERMINED`. * state (string, optional) - State of alarm to filter by, either `OK`, `ALARM` or `UNDETERMINED`.
* severity (string, optional) - One or more severities to filter by, separated with `|`, ex. `severity=LOW|MEDIUM`.
* lifecycle_state (string(50), optional) - Lifecycle state to filter by. * lifecycle_state (string(50), optional) - Lifecycle state to filter by.
* link (string(512), optional) - Link to filter by. * link (string(512), optional) - Link to filter by.
* state_updated_start_time (string, optional) - The start time in ISO 8601 combined date and time format in UTC. * state_updated_start_time (string, optional) - The start time in ISO 8601 combined date and time format in UTC.

View File

@ -33,14 +33,17 @@ import java.util.Map;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import monasca.api.domain.model.alarm.Alarm;
import monasca.api.resource.exception.Exceptions; import monasca.api.resource.exception.Exceptions;
import monasca.common.model.alarm.AlarmSeverity;
/** /**
* Validation related utilities. * Validation related utilities.
*/ */
public final class Validation { public final class Validation {
private static final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults(); private static final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
private static final Splitter COLON_SPLITTER = Splitter.on(':').omitEmptyStrings().trimResults().limit(2); private static final Splitter COLON_SPLITTER = Splitter.on(':').omitEmptyStrings().trimResults().limit(
2);
private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults(); private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
private static final Splitter VERTICAL_BAR_SPLITTER = Splitter.on('|').omitEmptyStrings().trimResults(); private static final Splitter VERTICAL_BAR_SPLITTER = Splitter.on('|').omitEmptyStrings().trimResults();
private static final Joiner SPACE_JOINER = Joiner.on(' '); private static final Joiner SPACE_JOINER = Joiner.on(' ');
@ -169,7 +172,8 @@ public final class Validation {
*/ */
public static void validateTimes(DateTime startTime, DateTime endTime) { public static void validateTimes(DateTime startTime, DateTime endTime) {
if (endTime != null && !startTime.isBefore(endTime)) if (endTime != null && !startTime.isBefore(endTime))
throw Exceptions.badRequest("start_time (%s) must be before end_time (%s)", startTime, endTime); throw Exceptions.badRequest("start_time (%s) must be before end_time (%s)", startTime,
endTime);
} }
public static Boolean validateAndParseMergeMetricsFlag(String mergeMetricsFlag) { public static Boolean validateAndParseMergeMetricsFlag(String mergeMetricsFlag) {
@ -246,6 +250,24 @@ public final class Validation {
return !Strings.isNullOrEmpty(crossTenantId) && !crossTenantId.equals(tenantId); return !Strings.isNullOrEmpty(crossTenantId) && !crossTenantId.equals(tenantId);
} }
public static List<AlarmSeverity> parseAndValidateSeverity(String severityStr) {
List<AlarmSeverity> severityList = null;
if (severityStr != null && !severityStr.isEmpty()) {
severityList = new ArrayList<>();
List<String> severities = Lists.newArrayList(VERTICAL_BAR_SPLITTER.split(severityStr));
for (String severity : severities) {
AlarmSeverity s = AlarmSeverity.fromString(severity);
if (s != null) {
severityList.add(s);
} else {
throw Exceptions.unprocessableEntity(String.format("Invalid severity %s",
severity));
}
}
}
return severityList;
}
public static List<String> parseAndValidateSortBy(String sortBy, final List<String> allowed_sort_by) { public static List<String> parseAndValidateSortBy(String sortBy, final List<String> allowed_sort_by) {
List<String> sortByList = new ArrayList<>(); List<String> sortByList = new ArrayList<>();
if (sortBy != null && !sortBy.isEmpty()) { if (sortBy != null && !sortBy.isEmpty()) {

View File

@ -33,7 +33,7 @@ public interface AlarmRepo {
* Returns alarms for the given criteria. * Returns alarms for the given criteria.
*/ */
List<Alarm> find(String tenantId, String alarmDefId, String metricName, Map<String, List<Alarm> find(String tenantId, String alarmDefId, String metricName, Map<String,
String> metricDimensions, AlarmState state, AlarmSeverity severity, String lifecycleState, String link, DateTime stateUpdatedStart, String> metricDimensions, AlarmState state, List<AlarmSeverity> severities, String lifecycleState, String link, DateTime stateUpdatedStart,
List<String> sort_by, String offset, int limit, boolean enforceLimit); List<String> sort_by, String offset, int limit, boolean enforceLimit);
/** /**
@ -64,7 +64,7 @@ public interface AlarmRepo {
*/ */
AlarmCount getAlarmsCount(String tenantId, String alarmDefId, String metricName, AlarmCount getAlarmsCount(String tenantId, String alarmDefId, String metricName,
Map<String, String> metricDimensions, AlarmState state, Map<String, String> metricDimensions, AlarmState state,
AlarmSeverity severity, String lifecycleState, String link, List<AlarmSeverity> severities, String lifecycleState, String link,
DateTime stateUpdatedStart, List<String> groupBy, DateTime stateUpdatedStart, List<String> groupBy,
String offset, int limit); String offset, int limit);
} }

View File

@ -49,7 +49,8 @@ public interface AlarmDefinitionRepo {
* Returns alarms for the given criteria. * Returns alarms for the given criteria.
*/ */
List<AlarmDefinition> find(String tenantId, String name, Map<String, String> dimensions, List<AlarmDefinition> find(String tenantId, String name, Map<String, String> dimensions,
AlarmSeverity severity, List<String> sortBy, String offset, int limit); List<AlarmSeverity> severities, List<String> sortBy, String offset,
int limit);
/** /**
* @throws EntityNotFoundException if an alarm cannot be found for the {@code alarmDefId} * @throws EntityNotFoundException if an alarm cannot be found for the {@code alarmDefId}

View File

@ -228,14 +228,14 @@ public class AlarmDefinitionSqlRepoImpl
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<AlarmDefinition> find(String tenantId, String name, Map<String, String> dimensions, public List<AlarmDefinition> find(String tenantId, String name, Map<String, String> dimensions,
AlarmSeverity severity, List<String> sortBy, List<AlarmSeverity> severities, List<String> sortBy,
String offset, int limit) { String offset, int limit) {
logger.trace(ORM_LOG_MARKER, "find(...) entering..."); logger.trace(ORM_LOG_MARKER, "find(...) entering...");
if (sortBy != null && !sortBy.isEmpty()) { if (sortBy != null && !sortBy.isEmpty()) {
throw Exceptions.unprocessableEntity( throw Exceptions.unprocessableEntity(
"Sort_by is not implemented for the hibernate database type"); "Sort_by is not implemented for the hibernate database type");
} }
if (severity != null) { if (severities != null && !severities.isEmpty()) {
throw Exceptions.unprocessableEntity( throw Exceptions.unprocessableEntity(
"Severity is not implemented for the hibernate database type"); "Severity is not implemented for the hibernate database type");
} }

View File

@ -160,7 +160,7 @@ public class AlarmSqlRepoImpl
final String metricName, final String metricName,
final Map<String, String> metricDimensions, final Map<String, String> metricDimensions,
final AlarmState state, final AlarmState state,
final AlarmSeverity severity, final List<AlarmSeverity> severities,
final String lifecycleState, final String lifecycleState,
final String link, final String link,
final DateTime stateUpdatedStart, final DateTime stateUpdatedStart,
@ -174,7 +174,7 @@ public class AlarmSqlRepoImpl
throw Exceptions.unprocessableEntity( throw Exceptions.unprocessableEntity(
"Sort_by is not implemented for the hibernate database type"); "Sort_by is not implemented for the hibernate database type");
} }
if (severity != null) { if (severities != null && !severities.isEmpty()) {
throw Exceptions.unprocessableEntity( throw Exceptions.unprocessableEntity(
"Severity filter is not implemented for the hibernate database type"); "Severity filter is not implemented for the hibernate database type");
} }
@ -586,7 +586,7 @@ public class AlarmSqlRepoImpl
@Override @Override
public AlarmCount getAlarmsCount(String tenantId, String alarmDefId, String metricName, public AlarmCount getAlarmsCount(String tenantId, String alarmDefId, String metricName,
Map<String, String> metricDimensions, AlarmState state, Map<String, String> metricDimensions, AlarmState state,
AlarmSeverity severity, String lifecycleState, String link, List<AlarmSeverity> severities, String lifecycleState, String link,
DateTime stateUpdatedStart, List<String> groupBy, DateTime stateUpdatedStart, List<String> groupBy,
String offset, int limit) { String offset, int limit) {
// Not Implemented // Not Implemented

View File

@ -147,7 +147,7 @@ public class AlarmDefinitionMySqlRepoImpl implements AlarmDefinitionRepo {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public List<AlarmDefinition> find(String tenantId, String name, public List<AlarmDefinition> find(String tenantId, String name,
Map<String, String> dimensions, AlarmSeverity severity, Map<String, String> dimensions, List<AlarmSeverity> severities,
List<String> sortBy, String offset, int limit) { List<String> sortBy, String offset, int limit) {
@ -174,9 +174,7 @@ public class AlarmDefinitionMySqlRepoImpl implements AlarmDefinitionRepo {
sbWhere.append(" and ad.name = :name"); sbWhere.append(" and ad.name = :name");
} }
if (severity != null) { sbWhere.append(MySQLUtils.buildSeverityAndClause(severities));
sbWhere.append(" and ad.severity = :severity");
}
String orderByPart = ""; String orderByPart = "";
if (sortBy != null && !sortBy.isEmpty()) { if (sortBy != null && !sortBy.isEmpty()) {
@ -210,9 +208,7 @@ public class AlarmDefinitionMySqlRepoImpl implements AlarmDefinitionRepo {
q.bind("name", name); q.bind("name", name);
} }
if (severity != null) { MySQLUtils.bindSeverityToQuery(q, severities);
q.bind("severity", severity.name());
}
if (limit > 0) { if (limit > 0) {
q.bind("limit", limit + 1); q.bind("limit", limit + 1);

View File

@ -137,7 +137,7 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
@Override @Override
public List<Alarm> find(String tenantId, String alarmDefId, String metricName, public List<Alarm> find(String tenantId, String alarmDefId, String metricName,
Map<String, String> metricDimensions, AlarmState state, Map<String, String> metricDimensions, AlarmState state,
AlarmSeverity severity, String lifecycleState, String link, List<AlarmSeverity> severities, String lifecycleState, String link,
DateTime stateUpdatedStart, List<String> sortBy, DateTime stateUpdatedStart, List<String> sortBy,
String offset, int limit, boolean enforceLimit) { String offset, int limit, boolean enforceLimit) {
@ -184,9 +184,7 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
sbWhere.append(" and a.state = :state"); sbWhere.append(" and a.state = :state");
} }
if (severity != null) { sbWhere.append(MySQLUtils.buildSeverityAndClause(severities));
sbWhere.append(" and ad.severity = :severity");
}
if (lifecycleState != null) { if (lifecycleState != null) {
sbWhere.append(" and a.lifecycle_state = :lifecycleState"); sbWhere.append(" and a.lifecycle_state = :lifecycleState");
@ -256,9 +254,7 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
q.bind("state", state.name()); q.bind("state", state.name());
} }
if (severity != null) { MySQLUtils.bindSeverityToQuery(q, severities);
q.bind("severity", severity.name());
}
if (lifecycleState != null) { if (lifecycleState != null) {
q.bind("lifecycleState", lifecycleState); q.bind("lifecycleState", lifecycleState);
@ -466,7 +462,7 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
@Override @Override
public AlarmCount getAlarmsCount(String tenantId, String alarmDefId, String metricName, public AlarmCount getAlarmsCount(String tenantId, String alarmDefId, String metricName,
Map<String, String> metricDimensions, AlarmState state, Map<String, String> metricDimensions, AlarmState state,
AlarmSeverity severity, String lifecycleState, String link, List<AlarmSeverity> severities, String lifecycleState, String link,
DateTime stateUpdatedStart, List<String> groupBy, DateTime stateUpdatedStart, List<String> groupBy,
String offset, int limit) { String offset, int limit) {
final String SELECT_CLAUSE = "SELECT count(*) as count%1$s " final String SELECT_CLAUSE = "SELECT count(*) as count%1$s "
@ -548,9 +544,7 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
queryBuilder.append(" AND a.state = :state"); queryBuilder.append(" AND a.state = :state");
} }
if (severity != null) { queryBuilder.append(MySQLUtils.buildSeverityAndClause(severities));
queryBuilder.append(" AND ad.severity = :severity");
}
if (lifecycleState != null) { if (lifecycleState != null) {
queryBuilder.append(" AND a.lifecycle_state = :lifecycleState"); queryBuilder.append(" AND a.lifecycle_state = :lifecycleState");
@ -602,9 +596,7 @@ public class AlarmMySqlRepoImpl implements AlarmRepo {
q.bind("state", state.name()); q.bind("state", state.name());
} }
if (severity != null) { MySQLUtils.bindSeverityToQuery(q, severities);
q.bind("severity", severity.name());
}
if (lifecycleState != null) { if (lifecycleState != null) {
q.bind("lifecycleState", lifecycleState); q.bind("lifecycleState", lifecycleState);

View File

@ -28,6 +28,7 @@ import java.util.Map;
import javax.inject.Named; import javax.inject.Named;
import monasca.api.infrastructure.persistence.Utils; import monasca.api.infrastructure.persistence.Utils;
import monasca.common.model.alarm.AlarmSeverity;
public class MySQLUtils public class MySQLUtils
extends Utils { extends Utils {
@ -82,4 +83,27 @@ public class MySQLUtils
} }
} }
public static String buildSeverityAndClause(List<AlarmSeverity> severities) {
StringBuilder sbWhere = new StringBuilder();
if (severities != null && !severities.isEmpty()) {
sbWhere.append(" and (");
for (int i = 0; i < severities.size(); i++) {
sbWhere.append("ad.severity = :severity").append(i);
if (i < severities.size() - 1) {
sbWhere.append(" or ");
}
}
sbWhere.append(") ");
}
return sbWhere.toString();
}
public static void bindSeverityToQuery(Query query, List<AlarmSeverity> severities) {
if (severities != null && !severities.isEmpty()) {
for (int i = 0; i < severities.size(); i++) {
query.bind("severity" + String.valueOf(i), severities.get(i).name());
}
}
}
} }

View File

@ -97,7 +97,7 @@ public class AlarmDefinitionResource {
public Object list(@Context UriInfo uriInfo, public Object list(@Context UriInfo uriInfo,
@HeaderParam("X-Tenant-Id") String tenantId, @QueryParam("name") String name, @HeaderParam("X-Tenant-Id") String tenantId, @QueryParam("name") String name,
@QueryParam("dimensions") String dimensionsStr, @QueryParam("dimensions") String dimensionsStr,
@QueryParam("severity") AlarmSeverity severity, @QueryParam("severity") String severityStr,
@QueryParam("sort_by") String sortByStr, @QueryParam("sort_by") String sortByStr,
@QueryParam("offset") String offset, @QueryParam("offset") String offset,
@QueryParam("limit") String limit) throws UnsupportedEncodingException { @QueryParam("limit") String limit) throws UnsupportedEncodingException {
@ -110,11 +110,13 @@ public class AlarmDefinitionResource {
Validation.parseAndValidateNumber(offset, "offset"); Validation.parseAndValidateNumber(offset, "offset");
} }
List<AlarmSeverity> severityList = Validation.parseAndValidateSeverity(severityStr);
final int paging_limit = this.persistUtils.getLimit(limit); final int paging_limit = this.persistUtils.getLimit(limit);
final List<AlarmDefinition> resources = repo.find(tenantId, final List<AlarmDefinition> resources = repo.find(tenantId,
name, name,
dimensions, dimensions,
severity, severityList,
sortByList, sortByList,
offset, offset,
paging_limit paging_limit

View File

@ -178,7 +178,7 @@ public class AlarmResource {
@QueryParam("metric_name") String metricName, @QueryParam("metric_name") String metricName,
@QueryParam("metric_dimensions") String metricDimensionsStr, @QueryParam("metric_dimensions") String metricDimensionsStr,
@QueryParam("state") AlarmState state, @QueryParam("state") AlarmState state,
@QueryParam("severity") AlarmSeverity severity, @QueryParam("severity") String severity,
@QueryParam("lifecycle_state") String lifecycleState, @QueryParam("lifecycle_state") String lifecycleState,
@QueryParam("link") String link, @QueryParam("link") String link,
@QueryParam("state_updated_start_time") String stateUpdatedStartStr, @QueryParam("state_updated_start_time") String stateUpdatedStartStr,
@ -199,10 +199,11 @@ public class AlarmResource {
if (!Strings.isNullOrEmpty(offset)) { if (!Strings.isNullOrEmpty(offset)) {
Validation.parseAndValidateNumber(offset, "offset"); Validation.parseAndValidateNumber(offset, "offset");
} }
List<AlarmSeverity> severityList = Validation.parseAndValidateSeverity(severity);
final int paging_limit = this.persistUtils.getLimit(limit); final int paging_limit = this.persistUtils.getLimit(limit);
final List<Alarm> alarms = repo.find(tenantId, alarmDefId, metricName, metricDimensions, state, final List<Alarm> alarms = repo.find(tenantId, alarmDefId, metricName, metricDimensions, state,
severity, lifecycleState, link, stateUpdatedStart, sortByList, severityList, lifecycleState, link, stateUpdatedStart, sortByList,
offset, paging_limit, true); offset, paging_limit, true);
for (final Alarm alarm : alarms) { for (final Alarm alarm : alarms) {
Links.hydrate( Links.hydrate(
@ -259,7 +260,7 @@ public class AlarmResource {
@QueryParam("metric_name") String metricName, @QueryParam("metric_name") String metricName,
@QueryParam("metric_dimensions") String metricDimensionsStr, @QueryParam("metric_dimensions") String metricDimensionsStr,
@QueryParam("state") AlarmState state, @QueryParam("state") AlarmState state,
@QueryParam("severity") AlarmSeverity severity, @QueryParam("severity") String severity,
@QueryParam("lifecycle_state") String lifecycleState, @QueryParam("lifecycle_state") String lifecycleState,
@QueryParam("link") String link, @QueryParam("link") String link,
@QueryParam("state_updated_start_time") String stateUpdatedStartStr, @QueryParam("state_updated_start_time") String stateUpdatedStartStr,
@ -274,6 +275,7 @@ public class AlarmResource {
DateTime stateUpdatedStart = DateTime stateUpdatedStart =
Validation.parseAndValidateDate(stateUpdatedStartStr, Validation.parseAndValidateDate(stateUpdatedStartStr,
"state_updated_start_time", false); "state_updated_start_time", false);
List<AlarmSeverity> severityList = Validation.parseAndValidateSeverity(severity);
List<String> groupBy = (Strings.isNullOrEmpty(groupByStr)) ? null : parseAndValidateGroupBy( List<String> groupBy = (Strings.isNullOrEmpty(groupByStr)) ? null : parseAndValidateGroupBy(
groupByStr); groupByStr);
@ -287,7 +289,7 @@ public class AlarmResource {
metricName, metricName,
metricDimensions, metricDimensions,
state, state,
severity, severityList,
lifecycleState, lifecycleState,
link, link,
stateUpdatedStart, stateUpdatedStart,

View File

@ -36,6 +36,7 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import monasca.api.infrastructure.persistence.PersistUtils; import monasca.api.infrastructure.persistence.PersistUtils;
@ -56,6 +57,7 @@ public class AlarmDefinitionMySqlRepositoryImplTest {
private List<String> alarmActions; private List<String> alarmActions;
private AlarmDefinition alarmDef_123; private AlarmDefinition alarmDef_123;
private AlarmDefinition alarmDef_234; private AlarmDefinition alarmDef_234;
private AlarmDefinition alarmDef_345;
@BeforeClass @BeforeClass
protected void setupClass() throws Exception { protected void setupClass() throws Exception {
@ -112,6 +114,21 @@ public class AlarmDefinitionMySqlRepositoryImplTest {
handle.execute("insert into alarm_action values ('234', 'ALARM', '29387234')"); handle.execute("insert into alarm_action values ('234', 'ALARM', '29387234')");
handle.execute("insert into alarm_action values ('234', 'ALARM', '77778687')"); handle.execute("insert into alarm_action values ('234', 'ALARM', '77778687')");
handle
.execute("insert into alarm_definition (id, tenant_id, name, severity, expression, match_by, actions_enabled, created_at, updated_at, deleted_at) "
+ "values ('345', 'bob', 'Testing Critical', 'CRITICAL', 'avg(test_metric{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(test_metric) < 100', 'flavor_id,image_id', 1, NOW(), NOW(), NULL)");
handle
.execute("insert into sub_alarm_definition (id, alarm_definition_id, function, metric_name, operator, threshold, period, periods, created_at, updated_at) "
+ "values ('333', '345', 'avg', 'test_metric', 'GT', 20, 60, 1, NOW(), NOW())");
handle
.execute("insert into sub_alarm_definition (id, alarm_definition_id, function, metric_name, operator, threshold, period, periods, created_at, updated_at) "
+ "values ('334', '345', 'avg', 'test_metric', 'LT', 100, 60, 1, NOW(), NOW())");
handle.execute("insert into sub_alarm_definition_dimension values ('333', 'flavor_id', '777')");
handle.execute("insert into sub_alarm_definition_dimension values ('333', 'image_id', '888')");
handle.execute("insert into sub_alarm_definition_dimension values ('333', 'metric_name', 'mem')");
handle.execute("insert into alarm_action values ('345', 'ALARM', '29387234')");
handle.execute("insert into alarm_action values ('345', 'ALARM', '77778687')");
alarmDef_123 = new AlarmDefinition("123", "90% CPU", null, "LOW", alarmDef_123 = new AlarmDefinition("123", "90% CPU", null, "LOW",
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10", "avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10",
Arrays.asList("flavor_id", "image_id"), true, Arrays.asList("29387234", "77778687"), Arrays.asList("flavor_id", "image_id"), true, Arrays.asList("29387234", "77778687"),
@ -120,6 +137,10 @@ public class AlarmDefinitionMySqlRepositoryImplTest {
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(hpcs.compute) < 100", "avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(hpcs.compute) < 100",
Arrays.asList("flavor_id", "image_id"), true, Arrays.asList("29387234", "77778687"), Arrays.asList("flavor_id", "image_id"), true, Arrays.asList("29387234", "77778687"),
Collections.<String>emptyList(), Collections.<String>emptyList()); Collections.<String>emptyList(), Collections.<String>emptyList());
alarmDef_345 = new AlarmDefinition("345","Testing Critical", null, "CRITICAL",
"avg(test_metric{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(test_metric) < 100",
Arrays.asList("flavor_id", "image_id"), true, Arrays.asList("29387234", "77778687"),
Collections.<String>emptyList(), Collections.<String>emptyList());
} }
public void shouldCreate() { public void shouldCreate() {
@ -267,7 +288,7 @@ public class AlarmDefinitionMySqlRepositoryImplTest {
final Map<String, String> dimensions = new HashMap<>(); final Map<String, String> dimensions = new HashMap<>();
dimensions.put("image_id", "888"); dimensions.put("image_id", "888");
assertEquals(Arrays.asList(alarmDef_123, alarmDef_234), assertEquals(Arrays.asList(alarmDef_123, alarmDef_234),
repo.find("bob", null, dimensions, null, null, null, 1)); repo.find("bob", null, dimensions, null, null, null, 1));
dimensions.clear(); dimensions.clear();
dimensions.put("device", "1"); dimensions.put("device", "1");
@ -285,9 +306,13 @@ public class AlarmDefinitionMySqlRepositoryImplTest {
} }
public void shouldFindBySeverity() { public void shouldFindBySeverity() {
assertEquals(Arrays.asList(alarmDef_234), repo.find("bob", null, null, AlarmSeverity.HIGH, null, null, 1)); assertEquals(Arrays.asList(alarmDef_234), repo.find("bob", null, null, Lists.newArrayList(AlarmSeverity.HIGH), null, null, 1));
assertEquals(0, repo.find("bob", null, null, AlarmSeverity.CRITICAL, null, null, 1).size()); assertEquals(0, repo.find("bob", null, null, Lists.newArrayList(AlarmSeverity.CRITICAL), null, null, 1).size());
assertEquals(Arrays.asList(alarmDef_234, alarmDef_345),
repo.find("bob", null, null, Lists.newArrayList(AlarmSeverity.HIGH, AlarmSeverity.CRITICAL),
null, null, 2));
} }
public void shouldDeleteById() { public void shouldDeleteById() {

View File

@ -331,7 +331,7 @@ public class AlarmMySqlRepositoryImplTest {
checkList(repo.find(TENANT_ID, null, null, null, null, null, null, null, null, Arrays.asList("state desc","severity"), null, 1, false), checkList(repo.find(TENANT_ID, null, null, null, null, null, null, null, null, Arrays.asList("state desc","severity"), null, 1, false),
compoundAlarm, alarm3, alarm2, alarm1); compoundAlarm, alarm3, alarm2, alarm1);
checkList(repo.find(TENANT_ID, null, null, null, null, AlarmSeverity.HIGH, null, null, null, null, null, 1, false), checkList(repo.find(TENANT_ID, null, null, null, null, Arrays.asList(AlarmSeverity.HIGH), null, null, null, null, null, 1, false),
compoundAlarm); compoundAlarm);
} }

View File

@ -17,6 +17,7 @@ package monasca.api.resource;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyList; import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
@ -101,8 +102,8 @@ public class AlarmDefinitionResourceTest extends AbstractMonApiResourceTest {
repo = mock(AlarmDefinitionRepo.class); repo = mock(AlarmDefinitionRepo.class);
when(repo.findById(eq("abc"), eq("123"))).thenReturn(alarm); when(repo.findById(eq("abc"), eq("123"))).thenReturn(alarm);
when(repo.findById(eq("abc"), eq("456"))).thenReturn(detAlarm); when(repo.findById(eq("abc"), eq("456"))).thenReturn(detAlarm);
when(repo.find(anyString(), anyString(), (Map<String, String>) anyMap(), AlarmSeverity.fromString(anyString()), when(repo.find(anyString(), anyString(), (Map<String, String>) anyMap(), anyListOf(
(List<String>) anyList(), anyString(), anyInt())).thenReturn( AlarmSeverity.class), (List<String>) anyList(), anyString(), anyInt())).thenReturn(
Arrays.asList(alarmItem)); Arrays.asList(alarmItem));
addResources(new AlarmDefinitionResource(service, repo, new PersistUtils())); addResources(new AlarmDefinitionResource(service, repo, new PersistUtils()));
@ -317,7 +318,7 @@ public class AlarmDefinitionResourceTest extends AbstractMonApiResourceTest {
assertEquals(alarms, Arrays.asList(alarmItem)); assertEquals(alarms, Arrays.asList(alarmItem));
verify(repo).find(eq("abc"), anyString(), (Map<String, String>) anyMap(), AlarmSeverity.fromString(anyString()), verify(repo).find(eq("abc"), anyString(), (Map<String, String>) anyMap(), anyListOf(AlarmSeverity.class),
(List<String>) anyList(), (List<String>) anyList(),
anyString(), anyInt()); anyString(), anyInt());
} }
@ -350,7 +351,7 @@ public class AlarmDefinitionResourceTest extends AbstractMonApiResourceTest {
List<AlarmDefinition> alarms = Arrays.asList(ad); List<AlarmDefinition> alarms = Arrays.asList(ad);
assertEquals(alarms, Arrays.asList(alarmItem)); assertEquals(alarms, Arrays.asList(alarmItem));
verify(repo).find(eq("abc"), eq("foo bar baz"), (Map<String, String>) anyMap(), AlarmSeverity.fromString(anyString()), (List<String>) anyList(), verify(repo).find(eq("abc"), eq("foo bar baz"), (Map<String, String>) anyMap(), anyListOf(AlarmSeverity.class), (List<String>) anyList(),
anyString(), anyInt()); anyString(), anyInt());
} }
@ -396,7 +397,7 @@ public class AlarmDefinitionResourceTest extends AbstractMonApiResourceTest {
public void should500OnInternalException() { public void should500OnInternalException() {
doThrow(new RuntimeException("")).when(repo).find(anyString(), anyString(), doThrow(new RuntimeException("")).when(repo).find(anyString(), anyString(),
(Map<String, String>) anyObject(), AlarmSeverity.fromString(anyString()), (List<String>) anyList(), anyString(), anyInt()); (Map<String, String>) anyObject(), anyListOf(AlarmSeverity.class), (List<String>) anyList(), anyString(), anyInt());
try { try {
client().resource("/v2.0/alarm-definitions").header("X-Tenant-Id", "abc").get(List.class); client().resource("/v2.0/alarm-definitions").header("X-Tenant-Id", "abc").get(List.class);

View File

@ -90,8 +90,9 @@ class AlarmDefinitionsRepository(mysql_repository.MySQLRepository,
parms.append(name.encode('utf8')) parms.append(name.encode('utf8'))
if severity: if severity:
parms.append(severity.encode('utf8')) severities = severity.split('|')
where_clause += " and ad.severity = %s " parms.extend([s.encode('utf8') for s in severities])
where_clause += " and (" + " or ".join(["ad.severity = %s" for s in severities]) + ")"
if sort_by is not None: if sort_by is not None:
order_by_clause = " order by ad." + ",ad.".join(sort_by) order_by_clause = " order by ad." + ",ad.".join(sort_by)
@ -131,6 +132,8 @@ class AlarmDefinitionsRepository(mysql_repository.MySQLRepository,
query = select_clause + where_clause + order_by_clause + limit_offset_clause query = select_clause + where_clause + order_by_clause + limit_offset_clause
LOG.debug("Query: {}".format(query))
return self._execute_query(query, parms) return self._execute_query(query, parms)
@mysql_repository.mysql_try_catch_block @mysql_repository.mysql_try_catch_block

View File

@ -269,8 +269,9 @@ class AlarmsRepository(mysql_repository.MySQLRepository,
sub_query += " and a.state = %s " sub_query += " and a.state = %s "
if 'severity' in query_parms: if 'severity' in query_parms:
parms.append(query_parms['severity'].encode('utf8')) severities = query_parms['severity'].split('|')
sub_query += " and ad.severity = %s" parms.extend([s.encode('utf8') for s in severities])
sub_query += " and (" + " or ".join(["ad.severity = %s" for s in severities]) + ")"
if 'lifecycle_state' in query_parms: if 'lifecycle_state' in query_parms:
parms.append(query_parms['lifecycle_state'].encode('utf8')) parms.append(query_parms['lifecycle_state'].encode('utf8'))
@ -428,8 +429,9 @@ class AlarmsRepository(mysql_repository.MySQLRepository,
where_clause += " and a.state = %s " where_clause += " and a.state = %s "
if 'severity' in query_parms: if 'severity' in query_parms:
parms.append(query_parms['severity'].encode('utf8')) severities = query_parms['severity'].split('|')
where_clause += " and ad.severity = %s " parms.extend([s.encode('utf8') for s in severities])
where_clause += " and (" + " or ".join(["ad.severity = %s" for s in severities]) + ")"
if 'lifecycle_state' in query_parms: if 'lifecycle_state' in query_parms:
parms.append(query_parms['lifecycle_state'].encode('utf8')) parms.append(query_parms['lifecycle_state'].encode('utf8'))

View File

@ -25,6 +25,7 @@ from monasca_api.common.repositories.sqla import models
from monasca_api.common.repositories.sqla import sql_repository from monasca_api.common.repositories.sqla import sql_repository
from sqlalchemy import MetaData, update, delete, insert from sqlalchemy import MetaData, update, delete, insert
from sqlalchemy import select, text, bindparam, null, literal_column from sqlalchemy import select, text, bindparam, null, literal_column
from sqlalchemy import or_
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -317,8 +318,11 @@ class AlarmDefinitionsRepository(sql_repository.SQLRepository,
parms['b_name'] = name.encode('utf8') parms['b_name'] = name.encode('utf8')
if severity: if severity:
query = query.where(ad.c.severity == bindparam('b_severity')) severities = severity.split('|')
parms['b_severity'] = severity.encode('utf8') query = query.where(
or_(ad.c.severity == bindparam('b_severity' + str(i)) for i in xrange(len(severities))))
for i, s in enumerate(severities):
parms['b_severity' + str(i)] = s.encode('utf8')
order_columns = [] order_columns = []
if sort_by is not None: if sort_by is not None:

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2014 Hewlett-Packard # Copyright 2014 Hewlett-Packard
# Copyright 2016 FUJITSU LIMITED # Copyright 2016 FUJITSU LIMITED
# (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
@ -285,8 +286,11 @@ class AlarmsRepository(sql_repository.SQLRepository,
parms['b_md_name'] = query_parms['metric_name'].encode('utf8') parms['b_md_name'] = query_parms['metric_name'].encode('utf8')
if 'severity' in query_parms: if 'severity' in query_parms:
query = query.where(ad.c.severity == bindparam('b_severity')) severities = query_parms['severity'].split('|')
parms['b_severity'] = query_parms['severity'].encode('utf8') query = query.where(
or_(ad.c.severity == bindparam('b_severity' + str(i)) for i in xrange(len(severities))))
for i, s in enumerate(severities):
parms['b_severity' + str(i)] = s.encode('utf8')
if 'state' in query_parms: if 'state' in query_parms:
query = query.where(a.c.state == bindparam('b_state')) query = query.where(a.c.state == bindparam('b_state'))
@ -493,8 +497,11 @@ class AlarmsRepository(sql_repository.SQLRepository,
query = query.where(a.c.state == bindparam('b_state')) query = query.where(a.c.state == bindparam('b_state'))
if 'severity' in query_parms: if 'severity' in query_parms:
query = query.where(ad.c.severity == bindparam('b_severity')) severities = query_parms['severity'].split('|')
parms['b_severity'] = query_parms['severity'].encode('utf8') query = query.where(
or_(ad.c.severity == bindparam('b_severity' + str(i)) for i in xrange(len(severities))))
for i, s in enumerate(severities):
parms['b_severity' + str(i)] = s.encode('utf8')
if 'lifecycle_state' in query_parms: if 'lifecycle_state' in query_parms:
parms['b_lifecycle_state'] = query_parms['lifecycle_state'].encode('utf8') parms['b_lifecycle_state'] = query_parms['lifecycle_state'].encode('utf8')

View File

@ -67,6 +67,12 @@ def validate_alarm_definition_severity(severity):
VALID_ALARM_DEFINITION_SEVERITIES)) VALID_ALARM_DEFINITION_SEVERITIES))
def validate_severity_query(severity_str):
severities = severity_str.split('|')
for severity in severities:
validate_alarm_definition_severity(severity)
def validate_sort_by(sort_by_list, allowed_sort_by): def validate_sort_by(sort_by_list, allowed_sort_by):
for sort_by_field in sort_by_list: for sort_by_field in sort_by_list:
sort_by_values = sort_by_field.split() sort_by_values = sort_by_field.split()
@ -105,3 +111,9 @@ def validate_value_meta(value_meta):
# value # value
assert isinstance(value_meta[name], (str, unicode)), "ValueMeta value must be a string" assert isinstance(value_meta[name], (str, unicode)), "ValueMeta value must be a string"
assert len(value_meta[name]) >= 1, "ValueMeta value cannot be empty" assert len(value_meta[name]) >= 1, "ValueMeta value cannot be empty"
def validate_state_query(state_str):
if state_str not in VALID_ALARM_STATES:
raise HTTPUnprocessableEntityError("Unprocessable Entity",
"state {} must be one of 'ALARM','OK','UNDETERMINED'".format(state_str))

View File

@ -85,7 +85,9 @@ class AlarmDefinitions(alarm_definitions_api_v2.AlarmDefinitionsV2API,
tenant_id = helpers.get_tenant_id(req) tenant_id = helpers.get_tenant_id(req)
name = helpers.get_query_name(req) name = helpers.get_query_name(req)
dimensions = helpers.get_query_dimensions(req) dimensions = helpers.get_query_dimensions(req)
severity = helpers.get_query_param(req, "severity") severity = helpers.get_query_param(req, "severity", default_val=None)
if severity is not None:
validation.validate_severity_query(severity)
sort_by = helpers.get_query_param(req, 'sort_by', default_val=None) sort_by = helpers.get_query_param(req, 'sort_by', default_val=None)
if sort_by is not None: if sort_by is not None:
if isinstance(sort_by, basestring): if isinstance(sort_by, basestring):

View File

@ -121,7 +121,7 @@ class Alarms(alarms_api_v2.AlarmsV2API,
validation.validate_alarm_state(query_parms['state']) validation.validate_alarm_state(query_parms['state'])
if 'severity' in query_parms: if 'severity' in query_parms:
validation.validate_alarm_definition_severity(query_parms['severity']) validation.validate_severity_query(query_parms['severity'])
if 'sort_by' in query_parms: if 'sort_by' in query_parms:
if isinstance(query_parms['sort_by'], basestring): if isinstance(query_parms['sort_by'], basestring):
@ -132,6 +132,12 @@ class Alarms(alarms_api_v2.AlarmsV2API,
'state_updated_timestamp', 'updated_timestamp', 'created_timestamp'} 'state_updated_timestamp', 'updated_timestamp', 'created_timestamp'}
validation.validate_sort_by(query_parms['sort_by'], allowed_sort_by) validation.validate_sort_by(query_parms['sort_by'], allowed_sort_by)
if 'state' in query_parms:
validation.validate_alarm_state(query_parms['state'])
if 'severity' in query_parms:
validation.validate_severity_query(query_parms['severity'])
# ensure metric_dimensions is a list # ensure metric_dimensions is a list
if 'metric_dimensions' in query_parms and isinstance(query_parms['metric_dimensions'], str): if 'metric_dimensions' in query_parms and isinstance(query_parms['metric_dimensions'], str):
query_parms['metric_dimensions'] = query_parms['metric_dimensions'].split(',') query_parms['metric_dimensions'] = query_parms['metric_dimensions'].split(',')
@ -396,7 +402,7 @@ class AlarmsCount(alarms_api_v2.AlarmsCountV2API, alarming.Alarming):
validation.validate_alarm_state(query_parms['state']) validation.validate_alarm_state(query_parms['state'])
if 'severity' in query_parms: if 'severity' in query_parms:
validation.validate_alarm_definition_severity(query_parms['severity']) validation.validate_severity_query(query_parms['severity'])
if 'group_by' in query_parms: if 'group_by' in query_parms:
if not isinstance(query_parms['group_by'], list): if not isinstance(query_parms['group_by'], list):

View File

@ -340,8 +340,7 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
# Test list alarm definition response body # Test list alarm definition response body
elements = response_body['elements'] elements = response_body['elements']
self._verify_list_get_alarm_definitions_elements(elements, 1, self._verify_alarm_definitions_list(elements, response_body_list)
response_body_list[0])
links = response_body['links'] links = response_body['links']
self._verify_list_alarm_definitions_links(links) self._verify_list_alarm_definitions_links(links)
@ -361,8 +360,8 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
query_parms) query_parms)
self._verify_list_alarm_definitions_response_body(resp, response_body) self._verify_list_alarm_definitions_response_body(resp, response_body)
elements = response_body['elements'] elements = response_body['elements']
self._verify_list_get_alarm_definitions_elements( self._verify_alarm_definitions_list(
elements, 1, res_body_create_alarm_def) elements, [res_body_create_alarm_def])
links = response_body['links'] links = response_body['links']
self._verify_list_alarm_definitions_links(links) self._verify_list_alarm_definitions_links(links)
@ -386,8 +385,7 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
list_alarm_definitions(query_parms) list_alarm_definitions(query_parms)
self._verify_list_alarm_definitions_response_body(resp, response_body) self._verify_list_alarm_definitions_response_body(resp, response_body)
elements = response_body['elements'] elements = response_body['elements']
self._verify_list_get_alarm_definitions_elements( self._verify_alarm_definitions_list(elements, [res_body_create_alarm_def])
elements, 1, res_body_create_alarm_def)
links = response_body['links'] links = response_body['links']
self._verify_list_alarm_definitions_links(links) self._verify_list_alarm_definitions_links(links)
@ -404,7 +402,7 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
name=name, name=name,
description="description", description="description",
expression=expression) expression=expression)
resp, res_body_create_alarm_def = self.monasca_client.\ resp, res_body_create_alarm_def = self.monasca_client. \
create_alarm_definitions(alarm_definition) create_alarm_definitions(alarm_definition)
self.assertEqual(201, resp.status) self.assertEqual(201, resp.status)
@ -415,8 +413,7 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
self._verify_list_alarm_definitions_response_body(resp, response_body) self._verify_list_alarm_definitions_response_body(resp, response_body)
elements = response_body['elements'] elements = response_body['elements']
self._verify_list_get_alarm_definitions_elements( self._verify_alarm_definitions_list(elements, [res_body_create_alarm_def])
elements, 1, res_body_create_alarm_def)
links = response_body['links'] links = response_body['links']
self._verify_list_alarm_definitions_links(links) self._verify_list_alarm_definitions_links(links)
@ -450,11 +447,78 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
list_alarm_definitions(query_param) list_alarm_definitions(query_param)
self._verify_list_alarm_definitions_response_body(resp, response_body) self._verify_list_alarm_definitions_response_body(resp, response_body)
elements = response_body['elements'] elements = response_body['elements']
self._verify_list_get_alarm_definitions_elements( self._verify_alarm_definitions_list(elements, [res_body_create_alarm_def])
elements, 1, res_body_create_alarm_def)
links = response_body['links'] links = response_body['links']
self._verify_list_alarm_definitions_links(links) self._verify_list_alarm_definitions_links(links)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_alarm_definitions_by_severity_invalid_severity(self):
query_parms = '?severity=false_severity'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_alarm_definitions, query_parms)
@test.attr(type="gate")
def test_list_alarm_definitions_with_multiple_severity(self):
name = data_utils.rand_name('alarm_definition')
expression = 'avg(cpu_utilization{alarm=severity}) >= 1000'
alarm_definition = helpers.create_alarm_definition(
name=name,
description="description",
expression=expression,
severity="LOW")
resp, res_body_create_alarm_def_low = self.monasca_client.\
create_alarm_definitions(alarm_definition)
self.assertEqual(201, resp.status)
name = data_utils.rand_name('alarm_definition')
expression = 'avg(cpu_utilization{alarm=severity}) >= 1000'
alarm_definition = helpers.create_alarm_definition(
name=name,
description="description",
expression=expression,
severity="MEDIUM")
resp, res_body_create_alarm_def_medium = self.monasca_client.\
create_alarm_definitions(alarm_definition)
self.assertEqual(201, resp.status)
name = data_utils.rand_name('alarm_definition')
expression = 'avg(cpu_utilization{alarm=severity}) >= 1000'
alarm_definition = helpers.create_alarm_definition(
name=name,
description="description",
expression=expression,
severity="HIGH")
resp, res_body_create_alarm_def = self.monasca_client.\
create_alarm_definitions(alarm_definition)
self.assertEqual(201, resp.status)
query_param = '?severity=MEDIUM|LOW&dimensions=alarm:severity&sort_by=severity'
resp, response_body = self.monasca_client.\
list_alarm_definitions(query_param)
self._verify_list_alarm_definitions_response_body(resp, response_body)
elements = response_body['elements']
self._verify_alarm_definitions_list(elements, [res_body_create_alarm_def_low,
res_body_create_alarm_def_medium])
links = response_body['links']
self._verify_list_alarm_definitions_links(links)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_alarm_definitions_by_severity_multiple_values_invalid_severity(self):
query_parms = '?severity=false_severity|MEDIUM'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_alarm_definitions, query_parms)
query_parms = '?severity=MEDIUM|false_severity'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_alarm_definitions, query_parms)
query_parms = '?severity=LOW|false_severity|HIGH'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_alarm_definitions, query_parms)
@test.attr(type='gate') @test.attr(type='gate')
def test_list_alarm_definitions_sort_by(self): def test_list_alarm_definitions_sort_by(self):
key = data_utils.rand_name('key') key = data_utils.rand_name('key')
@ -629,8 +693,8 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
response_body_list[0]['id']) response_body_list[0]['id'])
self.assertEqual(200, resp.status) self.assertEqual(200, resp.status)
self._verify_element_set(response_body) self._verify_element_set(response_body)
self._verify_list_get_alarm_definitions_elements(response_body, 0, self._verify_alarm_definitions_element(response_body,
response_body_list[0]) response_body_list[0])
links = response_body['links'] links = response_body['links']
self._verify_list_alarm_definitions_links(links) self._verify_list_alarm_definitions_links(links)
@ -853,16 +917,11 @@ class TestAlarmDefinitions(base.BaseMonascaTest):
self.assertIsInstance(response_body, dict) self.assertIsInstance(response_body, dict)
self.assertTrue(set(['links', 'elements']) == set(response_body)) self.assertTrue(set(['links', 'elements']) == set(response_body))
def _verify_list_get_alarm_definitions_elements(self, elements, num, def _verify_alarm_definitions_list(self, observed, reference):
res_body_create_alarm_def): self.assertEqual(len(reference), len(observed))
if num > 0: for i in xrange(len(reference)):
self.assertEqual(len(elements), num) self._verify_alarm_definitions_element(
for element in elements: reference[i], observed[i])
self._verify_alarm_definitions_element(
element, res_body_create_alarm_def)
else:
self._verify_alarm_definitions_element(elements,
res_body_create_alarm_def)
def _verify_alarm_definitions_element(self, response_body, def _verify_alarm_definitions_element(self, response_body,
res_body_create_alarm_def): res_body_create_alarm_def):

View File

@ -310,6 +310,78 @@ class TestAlarms(base.BaseMonascaTest):
for alarm in response_body['elements']: for alarm in response_body['elements']:
self.assertEqual('CRITICAL', alarm['alarm_definition']['severity']) self.assertEqual('CRITICAL', alarm['alarm_definition']['severity'])
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_alarms_by_severity_invalid_severity(self):
query_parms = '?severity=false_severity'
self.assertRaises(exceptions.UnprocessableEntity, self.monasca_client.list_alarms,
query_parms)
@test.attr(type="gate")
def test_list_alarms_by_severity_multiple_values(self):
metric_name = data_utils.rand_name("severity-metric")
alarm_defs = []
alarm_defs.append(helpers.create_alarm_definition(
name=data_utils.rand_name("alarm-severity"),
expression=metric_name + " > 12",
severity='LOW'
))
alarm_defs.append(helpers.create_alarm_definition(
name=data_utils.rand_name("alarm-severity"),
expression=metric_name + " > 12",
severity='MEDIUM'
))
alarm_defs.append(helpers.create_alarm_definition(
name=data_utils.rand_name("alarm-severity"),
expression=metric_name + " > 12",
severity='HIGH'
))
alarm_defs.append(helpers.create_alarm_definition(
name=data_utils.rand_name("alarm-severity"),
expression=metric_name + " > 12",
severity='CRITICAL'
))
alarm_def_ids = []
for definition in alarm_defs:
resp, response_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
alarm_def_ids.append(response_body['id'])
metric = helpers.create_metric(name=metric_name,
value=14)
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
for def_id in alarm_def_ids:
self._wait_for_alarms(1, def_id)
query_parms = '?severity=LOW|MEDIUM'
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
for alarm in response_body['elements']:
self.assertIn(alarm['alarm_definition']['severity'], ['LOW', 'MEDIUM'])
query_parms = '?severity=HIGH|CRITICAL'
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
for alarm in response_body['elements']:
self.assertIn(alarm['alarm_definition']['severity'], ['HIGH', 'CRITICAL'])
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_alarms_by_severity_multiple_values_invalid_severity(self):
query_parms = '?severity=false_severity|MEDIUM'
self.assertRaises(exceptions.UnprocessableEntity, self.monasca_client.list_alarms,
query_parms)
query_parms = '?severity=MEDIUM|false_severity'
self.assertRaises(exceptions.UnprocessableEntity, self.monasca_client.list_alarms,
query_parms)
query_parms = '?severity=LOW|false_severity|HIGH'
self.assertRaises(exceptions.UnprocessableEntity, self.monasca_client.list_alarms,
query_parms)
@test.attr(type="gate") @test.attr(type="gate")
def test_list_alarms_by_lifecycle_state(self): def test_list_alarms_by_lifecycle_state(self):
alarm_definition_ids, expected_metric \ alarm_definition_ids, expected_metric \