updated with severity code

This commit is contained in:
Derrick Johnson 2014-05-09 00:53:48 -04:00
commit c4f58b2092
16 changed files with 138 additions and 102 deletions

View File

@ -93,7 +93,8 @@ public class AlarmService {
* @throws InvalidEntityException if one of the actions cannot be found
*/
public Alarm create(String tenantId, String name, @Nullable String description,
String expression, AlarmExpression alarmExpression, List<String> alarmActions,
String severity, String expression, AlarmExpression alarmExpression,
List<String> alarmActions,
@Nullable List<String> okActions, @Nullable List<String> undeterminedActions) {
// Assert no alarm exists by the name
if (repo.exists(tenantId, name))
@ -113,7 +114,7 @@ public class AlarmService {
try {
LOG.debug("Creating alarm {} for tenant {}", name, tenantId);
alarm = repo.create(tenantId, alarmId, name, description, expression, subAlarms,
alarm = repo.create(tenantId, alarmId, name, description, severity, expression, subAlarms,
alarmActions, okActions, undeterminedActions);
// Notify interested parties of new alarm
@ -158,9 +159,9 @@ public class AlarmService {
Alarm alarm = assertAlarmExists(tenantId, alarmId, command.alarmActions, command.okActions,
command.undeterminedActions);
updateInternal(tenantId, alarmId, false, command.name, command.description, command.expression,
alarmExpression, alarm.getState(), command.state, command.actionsEnabled,
command.severity, alarmExpression, alarm.getState(), command.state, command.actionsEnabled,
command.alarmActions, command.okActions, command.undeterminedActions);
return new Alarm(alarmId, command.name, command.description, command.expression, command.state,
return new Alarm(alarmId, command.name, command.description, command.severity, command.expression, command.state,
command.actionsEnabled, command.alarmActions, command.okActions,
command.undeterminedActions);
}
@ -173,34 +174,35 @@ public class AlarmService {
* @throws InvalidEntityException if one of the actions cannot be found
*/
public Alarm patch(String tenantId, String alarmId, String name, String description,
String expression, AlarmExpression alarmExpression, AlarmState state, Boolean enabled,
String severity, String expression, AlarmExpression alarmExpression, AlarmState state, Boolean enabled,
List<String> alarmActions, List<String> okActions, List<String> undeterminedActions) {
Alarm alarm = assertAlarmExists(tenantId, alarmId, alarmActions, okActions, undeterminedActions);
name = name == null ? alarm.getName() : name;
description = description == null ? alarm.getDescription() : description;
expression = expression == null ? alarm.getExpression() : expression;
severity = severity == null ? alarm.getSeverity() : severity;
alarmExpression = alarmExpression == null ? AlarmExpression.of(expression) : alarmExpression;
state = state == null ? alarm.getState() : state;
enabled = enabled == null ? alarm.isActionsEnabled() : enabled;
updateInternal(tenantId, alarmId, true, name, description, expression, alarmExpression,
updateInternal(tenantId, alarmId, true, name, description, expression, severity, alarmExpression,
alarm.getState(), state, enabled, alarmActions, okActions, undeterminedActions);
return new Alarm(alarmId, name, description, expression, state, enabled,
return new Alarm(alarmId, name, description, severity, expression, state, enabled,
alarmActions == null ? alarm.getAlarmActions() : alarmActions,
okActions == null ? alarm.getOkActions() : okActions,
undeterminedActions == null ? alarm.getUndeterminedActions() : undeterminedActions);
}
private void updateInternal(String tenantId, String alarmId, boolean patch, String name,
String description, String expression, AlarmExpression alarmExpression, AlarmState oldState,
String description, String expression, String severity, AlarmExpression alarmExpression, AlarmState oldState,
AlarmState newState, Boolean enabled, List<String> alarmActions, List<String> okActions,
List<String> undeterminedActions) {
SubExpressions subExpressions = subExpressionsFor(alarmId, alarmExpression);
try {
LOG.debug("Updating alarm {} for tenant {}", name, tenantId);
repo.update(tenantId, alarmId, patch, name, description, expression, newState, enabled,
repo.update(tenantId, alarmId, patch, name, description, expression, severity, newState, enabled,
subExpressions.oldAlarmSubExpressions.keySet(), subExpressions.changedSubExpressions,
subExpressions.newAlarmSubExpressions, alarmActions, okActions, undeterminedActions);

View File

@ -28,14 +28,17 @@ public class CreateAlarmCommand {
@NotEmpty public String name;
public String description;
@NotEmpty public String expression;
public String severity;
public List<String> alarmActions;
public List<String> okActions;
public List<String> undeterminedActions;
public CreateAlarmCommand() {
this.severity = "LOW";
}
public CreateAlarmCommand(String name, @Nullable String description, String expression,
public CreateAlarmCommand(String name, @Nullable String description, String expression, String severity,
List<String> alarmActions, List<String> okActions, List<String> undeterminedActions) {
this.name = name;
this.description = description;
@ -43,6 +46,7 @@ public class CreateAlarmCommand {
this.alarmActions = alarmActions;
this.okActions = okActions;
this.undeterminedActions = undeterminedActions;
this.severity = severity == null ? "LOW" : severity;
}
@Override
@ -71,6 +75,6 @@ public class CreateAlarmCommand {
}
public void validate() {
AlarmValidation.validate(name, description, alarmActions, okActions, undeterminedActions);
AlarmValidation.validate(name, description, severity, alarmActions, okActions, undeterminedActions);
}
}

View File

@ -30,10 +30,10 @@ public class UpdateAlarmCommand extends CreateAlarmCommand {
public UpdateAlarmCommand() {
}
public UpdateAlarmCommand(String name, @Nullable String description, String expression,
AlarmState state, boolean enabled, List<String> alarmActions, List<String> okActions,
List<String> undeterminedActions) {
super(name, description, expression, alarmActions, okActions, undeterminedActions);
public UpdateAlarmCommand(String name, @Nullable String description, String severity,
String expression, AlarmState state, boolean enabled, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions) {
super(name, description, severity, expression, alarmActions, okActions, undeterminedActions);
this.state = state;
this.actionsEnabled = enabled;
}

View File

@ -16,6 +16,7 @@
*/
package com.hpcloud.mon.app.validation;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.WebApplicationException;
@ -30,13 +31,15 @@ import com.hpcloud.mon.resource.exception.Exceptions;
* Utilities for validating AlarmExpressions.
*/
public final class AlarmValidation {
private static final List<String> VALID_ALARM_SERVERITY = Arrays.asList("low", "medium", "high", "critical");
private AlarmValidation() {
}
/**
* @throws WebApplicationException if validation fails
*/
public static void validate(String name, String description, List<String> alarmActions,
public static void validate(String name, String description, String severity, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions) {
if (name != null && name.length() > 255)
throw Exceptions.unprocessableEntity("Name %s must be 255 characters or less", name);
@ -57,6 +60,10 @@ public final class AlarmValidation {
if (action.length() > 50)
throw Exceptions.unprocessableEntity(
"Undetermined action %s must be 50 characters or less", action);
String severityLower = severity.toLowerCase();
if (!VALID_ALARM_SERVERITY.contains(severityLower)) {
throw Exceptions.unprocessableEntity("%s is not a valid severity", severity);
}
}
/**

View File

@ -38,6 +38,7 @@ public class Alarm extends AbstractEntity implements Linked {
private String expression;
private Object expressionData;
private AlarmState state;
private String severity;
private boolean actionsEnabled;
private List<String> alarmActions;
private List<String> okActions;
@ -46,12 +47,13 @@ public class Alarm extends AbstractEntity implements Linked {
public Alarm() {
}
public Alarm(String id, String name, String description, String expression, AlarmState state,
boolean actionsEnabled, List<String> alarmActions, List<String> okActions,
public Alarm(String id, String name, String description, String severity, String expression,
AlarmState state, boolean actionsEnabled, List<String> alarmActions, List<String> okActions,
List<String> undeterminedActions) {
this.id = id;
this.name = name;
setDescription(description);
setSeverity(severity);
setExpression(expression);
setState(state);
setActionsEnabled(actionsEnabled);
@ -79,6 +81,11 @@ public class Alarm extends AbstractEntity implements Linked {
return false;
} else if (!description.equals(other.description))
return false;
if (severity == null) {
if (other.severity != null)
return false;
} else if (!severity.equals(other.severity))
return false;
if (actionsEnabled != other.actionsEnabled)
return false;
if (expression == null) {
@ -119,6 +126,8 @@ public class Alarm extends AbstractEntity implements Linked {
return description;
}
public String getSeverity() { return severity; }
public String getExpression() {
return expression;
}
@ -157,6 +166,7 @@ public class Alarm extends AbstractEntity implements Linked {
int result = super.hashCode();
result = prime * result + ((alarmActions == null) ? 0 : alarmActions.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((severity == null) ? 0 : severity.hashCode());
result = prime * result + (actionsEnabled ? 1231 : 1237);
result = prime * result + ((expression == null) ? 0 : expression.hashCode());
result = prime * result + ((links == null) ? 0 : links.hashCode());
@ -215,6 +225,8 @@ public class Alarm extends AbstractEntity implements Linked {
this.state = state;
}
public void setSeverity(String severity) { this.severity = severity;}
public void setUndeterminedActions(List<String> undeterminedActions) {
this.undeterminedActions = undeterminedActions;
}

View File

@ -32,8 +32,8 @@ public interface AlarmRepository {
/**
* Creates and returns a new alarm for the criteria.
*/
Alarm create(String tenantId, String id, String name, String description, String expression,
Map<String, AlarmSubExpression> subExpressions, List<String> alarmActions,
Alarm create(String tenantId, String id, String name, String description, String severity,
String expression, Map<String, AlarmSubExpression> subExpressions, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions);
/**
@ -70,7 +70,7 @@ public interface AlarmRepository {
* Updates and returns an alarm for the criteria.
*/
void update(String tenantId, String id, boolean patch, String name, String description,
String expression, AlarmState state, boolean enabled, Collection<String> oldSubAlarmIds,
String expression, String severity, AlarmState state, boolean enabled, Collection<String> oldSubAlarmIds,
Map<String, AlarmSubExpression> changedSubAlarms,
Map<String, AlarmSubExpression> newSubAlarms, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions);

View File

@ -52,16 +52,16 @@ public class AlarmRepositoryImpl implements AlarmRepository {
}
@Override
public Alarm create(String tenantId, String id, String name, String description,
String expression, Map<String, AlarmSubExpression> subExpressions, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions) {
public Alarm create(String tenantId, String id, String name, String description, String severity,
String expression, Map<String, AlarmSubExpression> subExpressions, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions) {
Handle h = db.open();
try {
h.begin();
h.insert(
"insert into alarm (id, tenant_id, name, description, expression, state, actions_enabled, created_at, updated_at, deleted_at) values (?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), NULL)",
id, tenantId, name, description, expression, AlarmState.UNDETERMINED.toString(), true);
"insert into alarm (id, tenant_id, name, description, severity, expression, state, actions_enabled, created_at, updated_at, deleted_at) values (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), NULL)",
id, tenantId, name, description, severity, expression, AlarmState.UNDETERMINED.toString(), true);
// Persist sub-alarms
createSubExpressions(h, id, subExpressions);
@ -72,9 +72,9 @@ public class AlarmRepositoryImpl implements AlarmRepository {
persistActions(h, id, AlarmState.UNDETERMINED, undeterminedActions);
h.commit();
return new Alarm(id, name, description, expression, AlarmState.UNDETERMINED, true,
alarmActions, okActions == null ? Collections.<String>emptyList() : okActions,
undeterminedActions == null ? Collections.<String>emptyList() : undeterminedActions);
return new Alarm(id, name, description, severity, expression, AlarmState.UNDETERMINED, true,
alarmActions, okActions == null ? Collections.<String>emptyList() : okActions,
undeterminedActions == null ? Collections.<String>emptyList() : undeterminedActions);
} catch (RuntimeException e) {
h.rollback();
throw e;
@ -193,17 +193,17 @@ public class AlarmRepositoryImpl implements AlarmRepository {
@Override
public void update(String tenantId, String id, boolean patch, String name, String description,
String expression, AlarmState state, boolean actionsEnabled,
Collection<String> oldSubAlarmIds, Map<String, AlarmSubExpression> changedSubAlarms,
Map<String, AlarmSubExpression> newSubAlarms, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions) {
String expression, String severity, AlarmState state, boolean actionsEnabled,
Collection<String> oldSubAlarmIds, Map<String, AlarmSubExpression> changedSubAlarms,
Map<String, AlarmSubExpression> newSubAlarms, List<String> alarmActions,
List<String> okActions, List<String> undeterminedActions) {
Handle h = db.open();
try {
h.begin();
h.insert(
"update alarm set name = ?, description = ?, expression = ?, state = ?, actions_enabled = ?, updated_at = NOW() where tenant_id = ? and id = ?",
name, description, expression, state.name(), actionsEnabled, tenantId, id);
"update alarm set name = ?, description = ?, expression = ?, severity = ?, state = ?, actions_enabled = ?, updated_at = NOW() where tenant_id = ? and id = ?",
name, description, expression, severity, state.name(), actionsEnabled, tenantId, id);
// Delete old sub-alarms
if (oldSubAlarmIds != null)

View File

@ -89,9 +89,9 @@ public class AlarmResource {
@Valid CreateAlarmCommand command) {
command.validate();
AlarmExpression alarmExpression = AlarmValidation.validateNormalizeAndGet(command.expression);
Alarm alarm = Links.hydrate(service.create(tenantId, command.name, command.description,
command.expression, alarmExpression, command.alarmActions, command.okActions,
command.undeterminedActions), uriInfo, false, "history");
Alarm alarm = Links.hydrate(service.create(tenantId, command.name, command.description, command.severity,
command.expression, alarmExpression, command.alarmActions, command.okActions,
command.undeterminedActions), uriInfo, false, "history");
return Response.created(URI.create(alarm.getId())).entity(alarm).build();
}
@ -170,6 +170,7 @@ public class AlarmResource {
throws JsonMappingException {
String name = (String) fields.get("name");
String description = (String) fields.get("description");
String severity = (String) fields.get("severity");
String expression = (String) fields.get("expression");
String stateStr = (String) fields.get("state");
AlarmState state = stateStr == null ? null : Validation.parseAndValidate(AlarmState.class,
@ -178,13 +179,13 @@ public class AlarmResource {
List<String> alarmActions = (List<String>) fields.get("alarm_actions");
List<String> okActions = (List<String>) fields.get("ok_actions");
List<String> undeterminedActions = (List<String>) fields.get("undetermined_actions");
AlarmValidation.validate(name, description, alarmActions, okActions, undeterminedActions);
AlarmValidation.validate(name, description, severity, alarmActions, okActions, undeterminedActions);
AlarmExpression alarmExpression = expression == null ? null
: AlarmValidation.validateNormalizeAndGet(expression);
return Links.hydrate(service.patch(tenantId, alarmId, name, description, expression,
alarmExpression, state, enabled, alarmActions, okActions, undeterminedActions), uriInfo,
true, "history");
return Links.hydrate(service.patch(tenantId, alarmId, name, description, severity, expression,
alarmExpression, state, enabled, alarmActions, okActions, undeterminedActions), uriInfo,
true, "history");
}
@DELETE

View File

@ -52,15 +52,15 @@ public class AlarmServiceTest {
service = new AlarmService(config, producer, repo, notificationMethodRepo);
when(
repo.create(anyString(), anyString(), anyString(), anyString(), anyString(),
repo.create(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(),
any(Map.class), any(List.class), any(List.class), any(List.class))).thenAnswer(
new Answer<Alarm>() {
@Override
public Alarm answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return new Alarm((String) args[0], (String) args[2], (String) args[3],
(String) args[4], AlarmState.UNDETERMINED, true, (List<String>) args[6],
(List<String>) args[7], (List<String>) args[8]);
return new Alarm((String) args[0], (String) args[2], (String) args[3], (String) args[4],
(String) args[5], AlarmState.UNDETERMINED, true, (List<String>) args[7],
(List<String>) args[8], (List<String>) args[9]);
}
});
}
@ -74,13 +74,13 @@ public class AlarmServiceTest {
when(notificationMethodRepo.exists(eq("bob"), anyString())).thenReturn(true);
Alarm alarm = service.create("bob", "90% CPU", "foo", exprStr, AlarmExpression.of(exprStr),
Alarm alarm = service.create("bob", "90% CPU", "foo", "LOW", exprStr, AlarmExpression.of(exprStr),
alarmActions, okActions, undeterminedActions);
Alarm expected = new Alarm(alarm.getId(), "90% CPU", "foo", exprStr, AlarmState.UNDETERMINED,
Alarm expected = new Alarm(alarm.getId(), "90% CPU", "foo", "LOW", exprStr, AlarmState.UNDETERMINED,
true, alarmActions, okActions, undeterminedActions);
assertEquals(expected, alarm);
verify(repo).create(eq("bob"), anyString(), eq("90% CPU"), eq("foo"), eq(exprStr),
verify(repo).create(eq("bob"), anyString(), eq("90% CPU"), eq("foo"), eq("LOW"), eq(exprStr),
any(Map.class), eq(alarmActions), eq(okActions), eq(undeterminedActions));
verify(producer).send(any(KeyedMessage.class));
}
@ -92,7 +92,7 @@ public class AlarmServiceTest {
List<String> okActions = Arrays.asList("2", "3");
List<String> undeterminedActions = Arrays.asList("3");
Alarm oldAlarm = new Alarm("123", "foo bar", "foo bar", exprStr, AlarmState.OK, true,
Alarm oldAlarm = new Alarm("123", "foo bar", "foo bar", "LOW", exprStr, AlarmState.OK, true,
alarmActions, okActions, undeterminedActions);
Map<String, AlarmSubExpression> oldSubExpressions = new HashMap<>();
oldSubExpressions.put("444", AlarmSubExpression.of("avg(foo{instance_id=123}) > 90"));
@ -107,11 +107,11 @@ public class AlarmServiceTest {
List<String> newOkActions = Arrays.asList("6", "7");
List<String> newUndeterminedActions = Arrays.asList("7");
UpdateAlarmCommand command = new UpdateAlarmCommand("foo bar baz", "foo bar baz", newExprStr,
AlarmState.ALARM, false, newAlarmActions, newOkActions, newUndeterminedActions);
"LOW", AlarmState.ALARM, false, newAlarmActions, newOkActions, newUndeterminedActions);
Alarm alarm = service.update("bob", "123", AlarmExpression.of(newExprStr), command);
Alarm expected = new Alarm(alarm.getId(), "foo bar baz", "foo bar baz", newExprStr,
Alarm expected = new Alarm(alarm.getId(), "foo bar baz", "foo bar baz", "LOW", newExprStr,
AlarmState.ALARM, false, newAlarmActions, newOkActions, newUndeterminedActions);
assertEquals(expected, alarm);
verify(producer, times(2)).send(any(KeyedMessage.class));

View File

@ -16,8 +16,8 @@ import com.hpcloud.mon.domain.model.AbstractModelTest;
public class CreateAlarmCommandTest extends AbstractModelTest {
public void shouldDeserializeFromJson() throws Exception {
Map<String, String> dimensions = new HashMap<String, String>();
dimensions.put("instanceId", "392633");
CreateAlarmCommand newAlarm = new CreateAlarmCommand("Disk Exceeds 1k Operations", null,
dimensions.put("instanceId", "392633"); /** todo: Check the null value to get works **/
CreateAlarmCommand newAlarm = new CreateAlarmCommand("Disk Exceeds 1k Operations", null, null,
"avg(hpcs.compute:cpu:1:{instance_id=5}) > 5", Arrays.asList("123345345", "23423"), null,
null);

View File

@ -22,7 +22,7 @@ public class AlarmTest extends AbstractModelTest {
dimensions = new HashMap<String, String>();
dimensions.put("instance_id", "666");
dimensions.put("image_id", "345");
alarm = new Alarm("123", "90% CPU", null,
alarm = new Alarm("123", "90% CPU", null, "LOW",
"avg(hpcs.compute{instance_id=666, image_id=345}) >= 90", AlarmState.OK, false,
Arrays.asList("123345345", "23423"), null, null);
alarm.setLinks(Arrays.asList(new Link("self", "https://region-a.geo-1.maas.hpcloudsvc.com/v1.0")));

View File

@ -64,8 +64,8 @@ public class AlarmRepositoryImplTest {
handle.execute("truncate table sub_alarm_dimension");
handle.execute("truncate table alarm");
handle.execute("insert into alarm (id, tenant_id, name, expression, state, actions_enabled, created_at, updated_at, deleted_at) "
+ "values ('123', 'bob', '90% CPU', 'avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10', 'UNDETERMINED', 1, NOW(), NOW(), NULL)");
handle.execute("insert into alarm (id, tenant_id, name, severity, expression, state, actions_enabled, created_at, updated_at, deleted_at) "
+ "values ('123', 'bob', '90% CPU', 'LOW', 'avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10', 'UNDETERMINED', 1, NOW(), NOW(), NULL)");
handle.execute("insert into sub_alarm (id, alarm_id, function, metric_name, operator, threshold, period, periods, state, created_at, updated_at) "
+ "values ('111', '123', 'avg', 'hpcs.compute', 'GT', 10, 60, 1, 'UNDETERMINED', NOW(), NOW())");
handle.execute("insert into sub_alarm_dimension values ('111', 'flavor_id', '777')");
@ -75,8 +75,8 @@ public class AlarmRepositoryImplTest {
handle.execute("insert into alarm_action values ('123', 'ALARM', '29387234')");
handle.execute("insert into alarm_action values ('123', 'ALARM', '77778687')");
handle.execute("insert into alarm (id, tenant_id, name, expression, state, actions_enabled, created_at, updated_at, deleted_at) "
+ "values ('234', 'bob', '50% CPU', 'avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(hpcs.compute{flavor_id=777}) < 100', 'UNDETERMINED', 1, NOW(), NOW(), NULL)");
handle.execute("insert into alarm (id, tenant_id, name, severity, expression, state, actions_enabled, created_at, updated_at, deleted_at) "
+ "values ('234', 'bob', '50% CPU', 'LOW', 'avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(hpcs.compute{flavor_id=777}) < 100', 'UNDETERMINED', 1, NOW(), NOW(), NULL)");
handle.execute("insert into sub_alarm (id, alarm_id, function, metric_name, operator, threshold, period, periods, state, created_at, updated_at) "
+ "values ('222', '234', 'avg', 'hpcs.compute', 'GT', 20, 60, 1, 'UNDETERMINED', NOW(), NOW())");
handle.execute("insert into sub_alarm (id, alarm_id, function, metric_name, operator, threshold, period, periods, state, created_at, updated_at) "
@ -96,7 +96,7 @@ public class AlarmRepositoryImplTest {
AlarmSubExpression.of("avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu}) > 10"))
.build();
Alarm alarmA = repo.create("555", "2345", "90% CPU", null,
Alarm alarmA = repo.create("555", "2345", "90% CPU", null, "LOW",
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu}) > 10", subExpressions,
alarmActions, null, null);
Alarm alarmB = repo.findById("555", alarmA.getId());
@ -132,12 +132,12 @@ public class AlarmRepositoryImplTest {
.build();
repo.update("bob", "234", false, "90% CPU", null,
"avg(foo{flavor_id=777}) > 333 and avg(hpcs.compute{flavor_id=777}) <= 200",
"avg(foo{flavor_id=777}) > 333 and avg(hpcs.compute{flavor_id=777}) <= 200", "HIGH",
AlarmState.ALARM, false, oldSubAlarmIds, changedSubExpressions, newSubExpressions,
alarmActions, null, null);
Alarm alarm = repo.findById("bob", "234");
Alarm expected = new Alarm("234", "90% CPU", null,
Alarm expected = new Alarm("234", "90% CPU", null, "HIGH",
"avg(foo{flavor_id=777}) > 333 and avg(hpcs.compute{flavor_id=777}) <= 200",
AlarmState.ALARM, false, alarmActions, Collections.<String>emptyList(),
Collections.<String>emptyList());
@ -153,6 +153,7 @@ public class AlarmRepositoryImplTest {
assertEquals(alarm.getId(), "123");
assertEquals(alarm.getName(), "90% CPU");
assertEquals(alarm.getSeverity(), "LOW");
assertEquals(alarm.getExpression(),
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10");
assertEquals(alarm.getState(), AlarmState.UNDETERMINED);
@ -226,18 +227,30 @@ public class AlarmRepositoryImplTest {
assertEquals(
alarms,
Arrays.asList(
new Alarm("123", "90% CPU", null,
Arrays.asList(
new Alarm(
"234",
"50% CPU",
null, "LOW",
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(hpcs.compute{flavor_id=777}) < 100",
AlarmState.UNDETERMINED, true, Arrays.asList("29387234", "77778687"),
Collections.<String>emptyList(), Collections.<String>emptyList()),new Alarm("123", "90% CPU", null, "LOW",
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10",
AlarmState.UNDETERMINED, true, Arrays.asList("29387234", "77778687"),
Collections.<String>emptyList(), Collections.<String>emptyList())));
/*Arrays.asList(
new Alarm("123", "90% CPU", null, "LOW",
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=cpu, device=1}) > 10",
AlarmState.UNDETERMINED, true, Arrays.asList("29387234", "77778687"),
Collections.<String>emptyList(), Collections.<String>emptyList()),
new Alarm(
"234",
"50% CPU",
null,
null, "LOW",
"avg(hpcs.compute{flavor_id=777, image_id=888, metric_name=mem}) > 20 and avg(hpcs.compute{flavor_id=777}) < 100",
AlarmState.UNDETERMINED, true, Arrays.asList("29387234", "77778687"),
Collections.<String>emptyList(), Collections.<String>emptyList())));
Collections.<String>emptyList(), Collections.<String>emptyList())));*/
}
public void shouldDeleteById() {

View File

@ -93,7 +93,7 @@ public class AlarmIntegrationTest extends AbstractMonApiResourceTest {
alarmActions = new ArrayList<String>();
alarmActions.add("29387234");
alarmActions.add("77778687");
alarm = new Alarm("123", "90% CPU", null, "avg(hpcs.compute:cpu:{instance_id=123} > 10",
alarm = new Alarm("123", "90% CPU", null, null, "avg(hpcs.compute:cpu:{instance_id=123} > 10",
AlarmState.OK, true, alarmActions, null, null);
}
@ -108,7 +108,7 @@ public class AlarmIntegrationTest extends AbstractMonApiResourceTest {
.header("Content-Type", MediaType.APPLICATION_JSON)
.post(
ClientResponse.class,
new CreateAlarmCommand("90% CPU", null, "avg(hpcs.compute:cpu:{instance_id=123} > 10",
new CreateAlarmCommand("90% CPU", null, null, "avg(hpcs.compute:cpu:{instance_id=123} > 10",
alarmActions, null, null));
Alarm newAlarm = response.getEntity(Alarm.class);
@ -121,14 +121,14 @@ public class AlarmIntegrationTest extends AbstractMonApiResourceTest {
public void shouldCreateCaseInsensitiveAndKeywords() throws Exception {
Alarm alarm_local;
alarm_local = new Alarm("123", "90% CPU", null, "AvG(avg:cpu:{instance_id=123} gT 10",
alarm_local = new Alarm("123", "90% CPU", null, null, "AvG(avg:cpu:{instance_id=123} gT 10",
AlarmState.OK, true, alarmActions, null, null);
ClientResponse response = client().resource("/v2.0/alarms")
.header("X-Tenant-Id", TENANT_ID)
.header("Content-Type", MediaType.APPLICATION_JSON)
.post(
ClientResponse.class,
new CreateAlarmCommand("90% CPU", null, "AvG(avg:cpu:{instance_id=123} gT 10",
new CreateAlarmCommand("90% CPU", null, null, "AvG(avg:cpu:{instance_id=123} gT 10",
alarmActions, null, null));
Alarm newAlarm = response.getEntity(Alarm.class);
@ -140,7 +140,7 @@ public class AlarmIntegrationTest extends AbstractMonApiResourceTest {
}
public void shouldDelete() {
Alarm newAlarm = repo.create(TENANT_ID, "123", alarm.getName(), alarm.getName(),
Alarm newAlarm = repo.create(TENANT_ID, "123", alarm.getName(), null, alarm.getName(),
alarm.getExpression(), null, alarm.getAlarmActions(), alarm.getOkActions(),
alarm.getUndeterminedActions());
assertNotNull(repo.findById(TENANT_ID, newAlarm.getId()));

View File

@ -1,8 +1,6 @@
package com.hpcloud.mon.resource;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -11,9 +9,7 @@ import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import javax.ws.rs.core.MediaType;
@ -46,29 +42,29 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
private AlarmStateHistoryRepository stateHistoryRepo;
private List<String> alarmActions;
/*@Override
@Override
@SuppressWarnings("unchecked")
protected void setupResources() throws Exception {
super.setupResources();
expression = "avg(disk_read_ops{service=hpcs.compute, instance_id=937}) >= 90";
alarmItem = new Alarm("123", "Disk Exceeds 1k Operations", null, expression, AlarmState.OK,
alarmItem = new Alarm("123", "Disk Exceeds 1k Operations", null, "LOW", expression, AlarmState.OK,
true, null, null, null);
alarmActions = new ArrayList<String>();
alarmActions.add("29387234");
alarmActions.add("77778687");
alarm = new Alarm("123", "Disk Exceeds 1k Operations", null, expression, AlarmState.OK, true,
alarm = new Alarm("123", "Disk Exceeds 1k Operations", null, "LOW", expression, AlarmState.OK, true,
alarmActions, null, null);
service = mock(AlarmService.class);
when(
service.create(eq("abc"), eq("Disk Exceeds 1k Operations"), any(String.class),
eq(expression), eq(AlarmExpression.of(expression)), any(List.class), any(List.class),
eq("LOW"), eq(expression), eq(AlarmExpression.of(expression)), any(List.class), any(List.class),
any(List.class))).thenReturn(alarm);
repo = mock(AlarmRepository.class);
when(repo.findById(eq("abc"), eq("123"))).thenReturn(alarm);
when(repo.find(anyString(),null,null)).thenReturn(Arrays.asList(alarmItem));
when(repo.find(anyString(),(Map<String,String>)anyMap(),any(String.class))).thenReturn(Arrays.asList(alarmItem));
stateHistoryRepo = mock(AlarmStateHistoryRepository.class);
@ -78,7 +74,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
@SuppressWarnings("unchecked")
public void shouldCreate() {
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
assertEquals(response.getStatus(), 201);
Alarm newAlarm = response.getEntity(Alarm.class);
@ -86,8 +82,8 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
assertEquals(location, "/v2.0/alarms/" + newAlarm.getId());
assertEquals(newAlarm, alarm);
verify(service).create(eq("abc"), eq("Disk Exceeds 1k Operations"), any(String.class),
eq(expression), eq(AlarmExpression.of(expression)), any(List.class), any(List.class),
any(List.class));
eq("LOW"), eq(expression), eq(AlarmExpression.of(expression)), any(List.class),
any(List.class), any(List.class));
}
public void shouldUpdate() {
@ -99,7 +95,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
.header("Content-Type", MediaType.APPLICATION_JSON)
.put(
ClientResponse.class,
new UpdateAlarmCommand("Disk Exceeds 1k Operations", null, expression,
new UpdateAlarmCommand("Disk Exceeds 1k Operations", null, expression, "LOW",
AlarmState.ALARM, true, alarmActions, null, null));
assertEquals(response.getStatus(), 200);
@ -110,7 +106,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithInvalidMetricName() {
String expression = "avg(foo{service=hpcs.compute, instance_id=937}) >= 90";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"foo is not a valid metric name for namespace hpcs.compute");
@ -119,7 +115,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithInvalidDimensions() {
String expression = "avg(disk_read_ops{service=hpcs.compute, instance_id=937, foo=bar}) >= 90";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"foo is not a valid dimension name for service hpcs.compute");
@ -128,7 +124,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithDuplicateDimensions() {
String expression = "avg(hpcs.compute{instance_id=937, instance_id=123, az=2, instance_uuid=abc123, metric_name=disk_read_ops}) >= 90";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"The alarm expression is invalid",
@ -140,10 +136,10 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
String expression = "avg(foo{metric_name=bar}) >= 90";
when(
service.create(eq("abc"), eq("Disk Exceeds 1k Operations"), any(String.class),
eq(expression), eq(AlarmExpression.of(expression)), any(List.class), any(List.class),
eq("LOW"), eq(expression), eq(AlarmExpression.of(expression)), any(List.class), any(List.class),
any(List.class))).thenReturn(alarm);
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
assertEquals(response.getStatus(), 201);
}
@ -157,7 +153,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithInvalidOperator() {
String expression = "avg(hpcs.compute{instance_id=937, az=2, instance_uuid=0ff588fc-d298-482f-bb11-4b52d56801a4, metric_name=disk_read_ops}) & 90";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"The alarm expression is invalid", "Syntax Error");
@ -166,7 +162,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWith0Period() {
String expression = "avg(hpcs.compute{instance_id=937, az=2, instance_uuid=0ff588fc-d298-482f-bb11-4b52d56801a4, metric_name=disk_read_ops},0) >= 90";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"Period must not be 0");
@ -175,7 +171,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithNonMod60Period() {
String expression = "avg(hpcs.compute{instance_id=937, az=2, instance_uuid=0ff588fc-d298-482f-bb11-4b52d56801a4, metric_name=disk_read_ops},61) >= 90";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"Period 61 must be a multiple of 60");
@ -184,7 +180,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithPeriodsLessThan1() {
String expression = "avg(hpcs.compute{instance_id=937, az=2, instance_uuid=0ff588fc-d298-482f-bb11-4b52d56801a4, metric_name=disk_read_ops}) >= 90 times 0";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"Periods 0 must be greater than or equal to 1");
@ -193,7 +189,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
public void shouldErrorOnCreateWithPeriodTimesPeriodsGT2Weeks() {
String expression = "avg(hpcs.compute{instance_id=937, az=2, instance_uuid=0ff588fc-d298-482f-bb11-4b52d56801a4, metric_name=disk_read_ops},60) >= 90 times 20161";
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, expression, "LOW", alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class)).matches("unprocessable_entity", 422,
"Period 60 times 20161 must total less than 2 weeks in seconds (1209600)");
@ -205,7 +201,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
null, expression, alarmActions, null, null));
null, "LOW", expression, alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class))
.matches(
@ -218,7 +214,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
alarmActions = new ArrayList<String>();
alarmActions.add("012345678901234567890123456789012345678901234567890");
ClientResponse response = createResponseFor(new CreateAlarmCommand(
"Disk Exceeds 1k Operations", null, expression, alarmActions, null, null));
"Disk Exceeds 1k Operations", null, "LOW", expression, alarmActions, null, null));
ErrorMessages.assertThat(response.getEntity(String.class))
.matches("unprocessable_entity", 422,
@ -232,7 +228,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
});
assertEquals(alarms, Arrays.asList(alarmItem));
verify(repo).find(eq("abc"),null,null);
verify(repo).find(eq("abc"),(Map<String,String>)anyMap(),any(String.class));
}
public void shouldGet() {
@ -273,7 +269,7 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
}
public void should500OnInternalException() {
doThrow(new RuntimeException("")).when(repo).find(anyString(),null,null);
doThrow(new RuntimeException("")).when(repo).find(anyString(),(Map<String,String>)anyObject(), (String)anyObject());
try {
client().resource("/v2.0/alarms").header("X-Tenant-Id", "abc").get(List.class);
@ -324,5 +320,5 @@ public class AlarmResourceTest extends AbstractMonApiResourceTest {
.header("X-Tenant-Id", "abc")
.header("Content-Type", MediaType.APPLICATION_JSON)
.post(ClientResponse.class, request);
} */
}
}

View File

@ -4,6 +4,7 @@ CREATE TABLE `alarm` (
`name` varchar(250) DEFAULT NULL,
`description` varchar(250) DEFAULT NULL,
`expression` mediumtext,
`severity` varchar(20) NOT NULL check severity in ('LOW','MEDIUM','HIGH','CRITICAL'),
`state` varchar(20) NOT NULL check state in ('UNDETERMINED','OK','ALARM'),
`actions_enabled` tinyint(1) NOT NULL DEFAULT '1',
`created_at` datetime NOT NULL,

View File

@ -1 +1 @@
{"id":"123","links":[{"rel":"self","href":"https://region-a.geo-1.maas.hpcloudsvc.com/v1.0"}],"name":"90% CPU","description":"","expression":"avg(hpcs.compute{instance_id=666, image_id=345}) >= 90","expression_data":{"function":"AVG","metric_name":"hpcs.compute","dimensions":{"image_id":"345","instance_id":"666"},"operator":"GTE","threshold":90.0,"period":60,"periods":1},"state":"OK","actions_enabled":false,"alarm_actions":["123345345","23423"],"ok_actions":null,"undetermined_actions":null}
{"id":"123","links":[{"rel":"self","href":"https://region-a.geo-1.maas.hpcloudsvc.com/v1.0"}],"name":"90% CPU","description":"","expression":"avg(hpcs.compute{instance_id=666, image_id=345}) >= 90","expression_data":{"function":"AVG","metric_name":"hpcs.compute","dimensions":{"image_id":"345","instance_id":"666"},"operator":"GTE","threshold":90.0,"period":60,"periods":1},"state":"OK","severity":"LOW","actions_enabled":false,"alarm_actions":["123345345","23423"],"ok_actions":null,"undetermined_actions":null}