Merge "Allow filtering by multiple severities"
This commit is contained in:
commit
537e062cef
|
@ -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.
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'))
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
Loading…
Reference in New Issue