Skip to content

Commit

Permalink
Added maintenance functionality for resolving orphaned alerts and con…
Browse files Browse the repository at this point in the history
…ditions. Added system config for maintenance tasks.
  • Loading branch information
Christiaan van Tienhoven committed Nov 13, 2017
1 parent d3dca5f commit 75964a8
Show file tree
Hide file tree
Showing 12 changed files with 597 additions and 272 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<groupId>org.graylog.plugins.aggregates</groupId>
<artifactId>graylog-plugin-aggregates</artifactId>
<version>2.1.1</version>
<version>2.2.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>${project.artifactId}</name>
Expand Down
278 changes: 129 additions & 149 deletions src/main/java/org/graylog/plugins/aggregates/Aggregates.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package org.graylog.plugins.aggregates;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import javax.inject.Inject;

import com.google.common.collect.ImmutableList;
import org.graylog.plugins.aggregates.alert.AggregatesAlertCondition;
import org.graylog.plugins.aggregates.history.HistoryItemService;
import org.graylog.plugins.aggregates.rule.Rule;
import org.graylog.plugins.aggregates.rule.RuleService;
import org.graylog.plugins.aggregates.util.AggregatesUtil;
import org.graylog2.alerts.Alert;
import org.graylog2.alerts.AlertConditionFactory;
import org.graylog2.alerts.AlertService;
import org.graylog2.database.NotFoundException;
import org.graylog2.indexer.searches.Searches;
import org.graylog2.indexer.searches.SearchesClusterConfig;
import org.graylog2.indexer.cluster.Cluster;
import org.graylog2.plugin.alarms.AlertCondition;
import org.graylog2.plugin.cluster.ClusterConfigService;
import org.graylog2.plugin.configuration.ConfigurationException;
import org.graylog2.plugin.database.ValidationException;
Expand All @@ -37,149 +38,128 @@
* This is the plugin. Your class should implement one of the existing plugin
* interfaces. (i.e. AlarmCallback, MessageInput, MessageOutput)
*/
public class Aggregates extends Periodical {
private int sequence = 0;
private int maxInterval = 1; // max interval detected in rules

private final ClusterConfigService clusterConfigService;
private final Searches searches;
private final Cluster cluster;
private final RuleService ruleService;
private final HistoryItemService historyItemService;
private final AlertConditionFactory alertConditionFactory;
private final StreamService streamService;

private static final Logger LOG = LoggerFactory.getLogger(Aggregates.class);
private List<Rule> list;

@Inject
public Aggregates(Searches searches, ClusterConfigService clusterConfigService,
Cluster cluster, RuleService ruleService, HistoryItemService historyItemService, AlertConditionFactory alertConditionFactory,
StreamService streamService) {
this.searches = searches;
this.clusterConfigService = clusterConfigService;
this.cluster = cluster;
this.ruleService = ruleService;
this.historyItemService = historyItemService;
this.alertConditionFactory = alertConditionFactory;
this.streamService = streamService;
}

@VisibleForTesting
boolean shouldRun(){
return cluster.isHealthy();
}


@Override
public void doRun() {

if (!shouldRun()) {
LOG.warn("Indexer is not running, not checking any rules this run.");
} else {
list = ruleService.all();

if (sequence == maxInterval) {
sequence = 0;
}

sequence++;

for (Rule rule : list) {
if (!rule.isEnabled()){
LOG.debug("Rule '" + rule.getName() + "' is disabled, skipping.");
continue;
}


Stream triggeredStream = null;
try {
triggeredStream = streamService.load(rule.getStreamId());
} catch (NotFoundException e) {
LOG.error("Stream with ID [{}] not found, skipping rule with name [{}]", rule.getStreamId(), rule.getName());
continue;
}


try {
streamService.getAlertCondition(triggeredStream, rule.getAlertConditionId());
} catch (NotFoundException e) {
LOG.warn("Alert Condition removed for rule [{}], re-instantiating", rule.getName());

ruleService.update(rule.getName(), ruleService.createAlertConditionForRule(rule));
}

}
}

}

@VisibleForTesting
TimeRange buildRelativeTimeRange(int range) {
try {
return restrictTimeRange(RelativeRange.create(range));
} catch (InvalidRangeParametersException e) {
LOG.warn("Invalid timerange parameters provided, not executing rule");
return null;
}
}

protected org.graylog2.plugin.indexer.searches.timeranges.TimeRange restrictTimeRange(
final org.graylog2.plugin.indexer.searches.timeranges.TimeRange timeRange) {
final DateTime originalFrom = timeRange.getFrom();
final DateTime to = timeRange.getTo();
final DateTime from;

final SearchesClusterConfig config = clusterConfigService.get(SearchesClusterConfig.class);

if (config == null || Period.ZERO.equals(config.queryTimeRangeLimit())) {
from = originalFrom;
} else {
final DateTime limitedFrom = to.minus(config.queryTimeRangeLimit());
from = limitedFrom.isAfter(originalFrom) ? limitedFrom : originalFrom;
}

return AbsoluteRange.create(from, to);
}

@Override
public int getInitialDelaySeconds() {
return 0;
}

@Override
protected Logger getLogger() {
return LOG;
}

@Override
public int getPeriodSeconds() {
return 60;
}

@Override
public boolean isDaemon() {
return true;
}

@Override
public boolean masterOnly() {

return true;
}

@Override
public boolean runsForever() {
return false;
}

@Override
public boolean startOnThisNode() {
return true;
}

@Override
public boolean stopOnGracefulShutdown() {
return true;
}
public class Aggregates{//} extends Periodical {
/*
private int sequence = 0;
private int maxInterval = 1; // max interval detected in rules
private final ClusterConfigService clusterConfigService;
private final Searches searches;
private final Cluster cluster;
private final RuleService ruleService;
private final HistoryItemService historyItemService;
private final AlertConditionFactory alertConditionFactory;
private final StreamService streamService;
private final AlertService alertService;
private static final Logger LOG = LoggerFactory.getLogger(Aggregates.class);
private List<Rule> list;
@Inject
public Aggregates(Searches searches, ClusterConfigService clusterConfigService,
Cluster cluster, RuleService ruleService, HistoryItemService historyItemService, AlertConditionFactory alertConditionFactory,
StreamService streamService, AlertService alertService) {
this.searches = searches;
this.clusterConfigService = clusterConfigService;
this.cluster = cluster;
this.ruleService = ruleService;
this.historyItemService = historyItemService;
this.alertConditionFactory = alertConditionFactory;
this.streamService = streamService;
this.alertService = alertService;
}
@VisibleForTesting
boolean shouldRun() {
return cluster.isHealthy();
}
@Override
public void doRun() {
if (!shouldRun()) {
LOG.warn("Indexer is not running, not checking any rules this run.");
} else {
list = ruleService.all();
if (sequence == maxInterval) {
sequence = 0;
}
sequence++;
}
}
@VisibleForTesting
TimeRange buildRelativeTimeRange(int range) {
try {
return restrictTimeRange(RelativeRange.create(range));
} catch (InvalidRangeParametersException e) {
LOG.warn("Invalid timerange parameters provided, not executing rule");
return null;
}
}
protected org.graylog2.plugin.indexer.searches.timeranges.TimeRange restrictTimeRange(
final org.graylog2.plugin.indexer.searches.timeranges.TimeRange timeRange) {
final DateTime originalFrom = timeRange.getFrom();
final DateTime to = timeRange.getTo();
final DateTime from;
final SearchesClusterConfig config = clusterConfigService.get(SearchesClusterConfig.class);
if (config == null || Period.ZERO.equals(config.queryTimeRangeLimit())) {
from = originalFrom;
} else {
final DateTime limitedFrom = to.minus(config.queryTimeRangeLimit());
from = limitedFrom.isAfter(originalFrom) ? limitedFrom : originalFrom;
}
return AbsoluteRange.create(from, to);
}
@Override
public int getInitialDelaySeconds() {
return 0;
}
@Override
protected Logger getLogger() {
return LOG;
}
@Override
public int getPeriodSeconds() {
return 60;
}
@Override
public boolean isDaemon() {
return true;
}
@Override
public boolean masterOnly() {
return true;
}
@Override
public boolean runsForever() {
return false;
}
@Override
public boolean startOnThisNode() {
return true;
}
@Override
public boolean stopOnGracefulShutdown() {
return true;
}
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public URI getURL() {

@Override
public Version getVersion() {
return new Version(2, 1, 1);
return new Version(2, 2, 0);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected void configure() {
bind(ReportScheduleService.class).to(ReportScheduleServiceImpl.class);
bind(HistoryItemService.class).to(HistoryItemServiceImpl.class);

addPeriodical(Aggregates.class);
//saddPeriodical(Aggregates.class);
addPeriodical(AggregatesReport.class);
addPeriodical(AggregatesMaintenance.class);
addPermissions(RuleRestPermissions.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.graylog.plugins.aggregates.config;

import com.google.auto.value.AutoValue;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonAutoDetect
@JsonIgnoreProperties(ignoreUnknown = true)
@AutoValue
public abstract class AggregatesConfig {

@JsonProperty("purgeHistory")
public abstract boolean purgeHistory();

@JsonProperty("historyRetention")
public abstract String historyRetention();

@JsonProperty("resolveOrphanedAlerts")
public abstract boolean resolveOrphanedAlerts();


@JsonCreator
public static AggregatesConfig create(@JsonProperty("purgeHistory") boolean purgeHistory,
@JsonProperty("historyRetention") String historyRetention,
@JsonProperty("resolveOrphanedAlerts") boolean resolveOrphanedAlerts) {
return builder()
.purgeHistory(purgeHistory)
.historyRetention(historyRetention)
.resolveOrphanedAlerts(resolveOrphanedAlerts)
.build();
}

public static AggregatesConfig defaultConfig() {
return builder()
.purgeHistory(true)
.historyRetention("P1M")
.resolveOrphanedAlerts(false)
.build();
}

public static Builder builder() {
return new AutoValue_AggregatesConfig.Builder();
}

public abstract Builder toBuilder();

@AutoValue.Builder
public static abstract class Builder {
public abstract Builder purgeHistory(boolean purgeHistory);
public abstract Builder historyRetention(String historyRetention);
public abstract Builder resolveOrphanedAlerts(boolean resolveOrphanedAlerts);

public abstract AggregatesConfig build();
}
}
Loading

0 comments on commit 75964a8

Please sign in to comment.