Marvel: Only clean timestamped indices with the current template version

Only current timestamped indices, like .marvel-es-1-* indices should be deleted. Other indices like the ones created by pre v2.3.0 plugin versions should be kept (like .marvel-es-YYYY.MM.dd)

Original commit: elastic/x-pack-elasticsearch@b2aff31875
This commit is contained in:
Tanguy Leroux 2016-01-14 16:22:22 +01:00
parent b39f4dcc37
commit edd993077b
10 changed files with 104 additions and 42 deletions

View File

@ -24,6 +24,8 @@ public class MarvelSettings extends AbstractComponent {
public static final String MONITORING_INDICES_PREFIX = ".monitoring-es-"; public static final String MONITORING_INDICES_PREFIX = ".monitoring-es-";
public static final String MONITORING_DATA_INDEX_PREFIX = ".monitoring-es-data-"; public static final String MONITORING_DATA_INDEX_PREFIX = ".monitoring-es-data-";
public static final String LEGACY_DATA_INDEX_NAME = ".marvel-es-data";
public static final String HISTORY_DURATION_SETTING_NAME = "history.duration"; public static final String HISTORY_DURATION_SETTING_NAME = "history.duration";
public static final TimeValue MAX_LICENSE_GRACE_PERIOD = TimeValue.timeValueHours(7 * 24); public static final TimeValue MAX_LICENSE_GRACE_PERIOD = TimeValue.timeValueHours(7 * 24);

View File

@ -12,7 +12,7 @@ import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.MarvelSettings; import org.elasticsearch.marvel.MarvelSettings;
import org.elasticsearch.marvel.agent.exporter.IndexNameResolver; import org.elasticsearch.marvel.agent.exporter.MonitoringIndexNameResolver;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc; import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.exporter.MarvelTemplateUtils; import org.elasticsearch.marvel.agent.exporter.MarvelTemplateUtils;
import org.elasticsearch.marvel.license.MarvelLicensee; import org.elasticsearch.marvel.license.MarvelLicensee;
@ -27,7 +27,7 @@ public abstract class AbstractCollector<T> extends AbstractLifecycleComponent<T>
protected final ClusterService clusterService; protected final ClusterService clusterService;
protected final MarvelSettings marvelSettings; protected final MarvelSettings marvelSettings;
protected final MarvelLicensee licensee; protected final MarvelLicensee licensee;
protected final IndexNameResolver dataIndexNameResolver; private final MonitoringIndexNameResolver dataIndexNameResolver;
@Inject @Inject
public AbstractCollector(Settings settings, String name, ClusterService clusterService, public AbstractCollector(Settings settings, String name, ClusterService clusterService,
@ -116,14 +116,19 @@ public abstract class AbstractCollector<T> extends AbstractLifecycleComponent<T>
return clusterService.state().metaData().clusterUUID(); return clusterService.state().metaData().clusterUUID();
} }
protected DiscoveryNode localNode() { protected DiscoveryNode localNode() {
return clusterService.localNode(); return clusterService.localNode();
} }
public String resolveDataIndexName(long timestamp) {
return dataIndexNameResolver.resolve(timestamp);
}
/** /**
* Resolves monitoring's data index name * Resolves monitoring's data index name
*/ */
public class DataIndexNameResolver implements IndexNameResolver { public class DataIndexNameResolver implements MonitoringIndexNameResolver {
private final String index; private final String index;
@ -141,5 +146,10 @@ public abstract class AbstractCollector<T> extends AbstractLifecycleComponent<T>
public String resolve(long timestamp) { public String resolve(long timestamp) {
return index; return index;
} }
@Override
public String indexPattern() {
return index;
}
} }
} }

View File

@ -86,7 +86,7 @@ public class ClusterStateCollector extends AbstractCollector<ClusterStateCollect
results.add(clusterStateNodeDoc); results.add(clusterStateNodeDoc);
// Adds a document for every node in the monitoring data index (type "node") // Adds a document for every node in the monitoring data index (type "node")
DiscoveryNodeMarvelDoc discoveryNodeDoc = new DiscoveryNodeMarvelDoc(dataIndexNameResolver.resolve(timestamp), NODE_TYPE, DiscoveryNodeMarvelDoc discoveryNodeDoc = new DiscoveryNodeMarvelDoc(resolveDataIndexName(timestamp), NODE_TYPE,
node.getId()); node.getId());
discoveryNodeDoc.setClusterUUID(clusterUUID); discoveryNodeDoc.setClusterUUID(clusterUUID);
discoveryNodeDoc.setTimestamp(timestamp); discoveryNodeDoc.setTimestamp(timestamp);

View File

@ -85,7 +85,7 @@ public class ClusterStatsCollector extends AbstractCollector<ClusterStatsCollect
DiscoveryNode sourceNode = localNode(); DiscoveryNode sourceNode = localNode();
// Adds a cluster info document // Adds a cluster info document
String resolvedIndex = dataIndexNameResolver.resolve(timestamp); String resolvedIndex = resolveDataIndexName(timestamp);
ClusterInfoMarvelDoc clusterInfoDoc = new ClusterInfoMarvelDoc(resolvedIndex, CLUSTER_INFO_TYPE, clusterUUID); ClusterInfoMarvelDoc clusterInfoDoc = new ClusterInfoMarvelDoc(resolvedIndex, CLUSTER_INFO_TYPE, clusterUUID);
clusterInfoDoc.setClusterUUID(clusterUUID); clusterInfoDoc.setClusterUUID(clusterUUID);
clusterInfoDoc.setTimestamp(timestamp); clusterInfoDoc.setTimestamp(timestamp);

View File

@ -27,7 +27,7 @@ public abstract class Exporter {
protected final String type; protected final String type;
protected final Config config; protected final Config config;
protected final ESLogger logger; protected final ESLogger logger;
protected final IndexNameResolver indexNameResolver; protected final MonitoringIndexNameResolver indexNameResolver;
protected final @Nullable TimeValue bulkTimeout; protected final @Nullable TimeValue bulkTimeout;
public Exporter(String type, Config config) { public Exporter(String type, Config config) {
@ -46,7 +46,7 @@ public abstract class Exporter {
return config.name; return config.name;
} }
public IndexNameResolver indexNameResolver() { public MonitoringIndexNameResolver indexNameResolver() {
return indexNameResolver; return indexNameResolver;
} }
@ -128,7 +128,7 @@ public abstract class Exporter {
/** /**
* *
*/ */
public class DefaultIndexNameResolver implements IndexNameResolver { public class DefaultIndexNameResolver implements MonitoringIndexNameResolver {
private final DateTimeFormatter indexTimeFormatter; private final DateTimeFormatter indexTimeFormatter;
@ -156,6 +156,11 @@ public abstract class Exporter {
indexTimeFormatter.print(timestamp); indexTimeFormatter.print(timestamp);
} }
@Override
public String indexPattern() {
return MarvelSettings.MONITORING_INDICES_PREFIX + String.valueOf(MarvelTemplateUtils.TEMPLATE_VERSION) + "-*";
}
@Override @Override
public String toString() { public String toString() {
return indexTimeFormatter.toString(); return indexTimeFormatter.toString();

View File

@ -8,9 +8,17 @@ package org.elasticsearch.marvel.agent.exporter;
/** /**
* *
*/ */
public interface IndexNameResolver { public interface MonitoringIndexNameResolver {
String resolve(MarvelDoc doc); String resolve(MarvelDoc doc);
String resolve(long timestamp); String resolve(long timestamp);
/**
* Returns the generic part of the index name (ie without any dynamic part like a timestamp) that can be used to match indices names.
*
* @return the index pattern
*/
String indexPattern();
} }

View File

@ -15,7 +15,7 @@ import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.marvel.agent.exporter.ExportBulk; import org.elasticsearch.marvel.agent.exporter.ExportBulk;
import org.elasticsearch.marvel.agent.exporter.IndexNameResolver; import org.elasticsearch.marvel.agent.exporter.MonitoringIndexNameResolver;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc; import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.renderer.Renderer; import org.elasticsearch.marvel.agent.renderer.Renderer;
import org.elasticsearch.marvel.agent.renderer.RendererRegistry; import org.elasticsearch.marvel.agent.renderer.RendererRegistry;
@ -31,7 +31,7 @@ public class LocalBulk extends ExportBulk {
private final ESLogger logger; private final ESLogger logger;
private final Client client; private final Client client;
private final IndexNameResolver indexNameResolver; private final MonitoringIndexNameResolver indexNameResolver;
private final RendererRegistry renderers; private final RendererRegistry renderers;
private BytesStreamOutput buffer = null; private BytesStreamOutput buffer = null;
@ -39,7 +39,7 @@ public class LocalBulk extends ExportBulk {
AtomicReference<State> state = new AtomicReference<>(); AtomicReference<State> state = new AtomicReference<>();
public LocalBulk(String name, ESLogger logger, Client client, IndexNameResolver indexNameResolver, RendererRegistry renderers) { public LocalBulk(String name, ESLogger logger, Client client, MonitoringIndexNameResolver indexNameResolver, RendererRegistry renderers) {
super(name); super(name);
this.logger = logger; this.logger = logger;
this.client = client; this.client = client;

View File

@ -24,11 +24,11 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.marvel.MarvelSettings;
import org.elasticsearch.marvel.agent.exporter.ExportBulk; import org.elasticsearch.marvel.agent.exporter.ExportBulk;
import org.elasticsearch.marvel.agent.exporter.Exporter; import org.elasticsearch.marvel.agent.exporter.Exporter;
import org.elasticsearch.marvel.agent.exporter.MarvelTemplateUtils; import org.elasticsearch.marvel.agent.exporter.MarvelTemplateUtils;
import org.elasticsearch.marvel.agent.renderer.RendererRegistry; import org.elasticsearch.marvel.agent.renderer.RendererRegistry;
import org.elasticsearch.marvel.MarvelSettings;
import org.elasticsearch.marvel.cleaner.CleanerService; import org.elasticsearch.marvel.cleaner.CleanerService;
import org.elasticsearch.shield.InternalClient; import org.elasticsearch.shield.InternalClient;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -268,11 +268,15 @@ public class LocalExporter extends Exporter implements ClusterStateListener, Cle
long expirationTime = expiration.getMillis(); long expirationTime = expiration.getMillis();
Set<String> indices = new HashSet<>(); Set<String> indices = new HashSet<>();
// Only clean up indices that match the timestamped index pattern
String pattern = indexNameResolver().indexPattern();
for (ObjectObjectCursor<String, IndexMetaData> index : clusterState.getMetaData().indices()) { for (ObjectObjectCursor<String, IndexMetaData> index : clusterState.getMetaData().indices()) {
String indexName = index.key; String indexName = index.key;
if (Regex.simpleMatch(MarvelSettings.MONITORING_INDICES_PREFIX + "*", indexName)) {
// Never delete the data indices if (Regex.simpleMatch(pattern, indexName)) {
if (indexName.startsWith(MarvelSettings.MONITORING_DATA_INDEX_PREFIX)) { // Should not happen, but just in case... we never delete the data indices
if (indexName.startsWith(MarvelSettings.MONITORING_DATA_INDEX_PREFIX)
|| indexName.equalsIgnoreCase(MarvelSettings.LEGACY_DATA_INDEX_NAME)) {
continue; continue;
} }

View File

@ -10,15 +10,16 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee; import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.marvel.MarvelSettings;
import org.elasticsearch.marvel.agent.exporter.Exporter; import org.elasticsearch.marvel.agent.exporter.Exporter;
import org.elasticsearch.marvel.agent.exporter.Exporters; import org.elasticsearch.marvel.agent.exporter.Exporters;
import org.elasticsearch.marvel.agent.exporter.IndexNameResolver; import org.elasticsearch.marvel.agent.exporter.MarvelTemplateUtils;
import org.elasticsearch.marvel.MarvelSettings;
import org.elasticsearch.marvel.license.MarvelLicensee; import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.test.MarvelIntegTestCase; import org.elasticsearch.marvel.test.MarvelIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import java.util.Locale; import java.util.Locale;
@ -49,7 +50,7 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
public void testDeleteIndex() throws Exception { public void testDeleteIndex() throws Exception {
internalCluster().startNode(); internalCluster().startNode();
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + "test", now().minusDays(10)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now().minusDays(10));
assertIndicesCount(1); assertIndicesCount(1);
CleanerService.Listener listener = getListener(); CleanerService.Listener listener = getListener();
@ -57,10 +58,10 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
assertIndicesCount(0); assertIndicesCount(0);
} }
public void testIgnoreDataIndex() throws Exception { public void testIgnoreCurrentDataIndex() throws Exception {
internalCluster().startNode(); internalCluster().startNode();
createIndex(MarvelSettings.MONITORING_DATA_INDEX_PREFIX + "test", now().minusDays(10)); createDataIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now().minusDays(10));
assertIndicesCount(1); assertIndicesCount(1);
CleanerService.Listener listener = getListener(); CleanerService.Listener listener = getListener();
@ -68,24 +69,41 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
assertIndicesCount(1); assertIndicesCount(1);
} }
public void testIgnoreDataIndicesInOtherVersions() throws Exception {
internalCluster().startNode();
createIndex(MarvelSettings.LEGACY_DATA_INDEX_NAME, now().minusYears(1));
createDataIndex(0, now().minusDays(10));
createDataIndex(Integer.MAX_VALUE, now().minusDays(20));
assertIndicesCount(3);
CleanerService.Listener listener = getListener();
listener.onCleanUpIndices(days(0));
assertIndicesCount(3);
}
public void testIgnoreCurrentTimestampedIndex() throws Exception { public void testIgnoreCurrentTimestampedIndex() throws Exception {
internalCluster().startNode(); internalCluster().startNode();
IndexNameResolver indexNameResolver = null; createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now().minusDays(10));
for (Exporter exporter : internalCluster().getInstance(Exporters.class)) { createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now());
indexNameResolver = exporter.indexNameResolver();
}
assertNotNull(indexNameResolver);
DateTime tenDaysAgo = now().minusDays(10);
createIndex(indexNameResolver.resolve(tenDaysAgo.getMillis()), tenDaysAgo);
DateTime today = now();
createIndex(indexNameResolver.resolve(today.getMillis()), today);
assertIndicesCount(2); assertIndicesCount(2);
CleanerService.Listener listener = getListener(); CleanerService.Listener listener = getListener();
listener.onCleanUpIndices(days(0)); listener.onCleanUpIndices(days(0));
assertIndicesCount(1);
}
public void testIgnoreTimestampedIndicesInOtherVersions() throws Exception {
internalCluster().startNode();
createTimestampedIndex(0, now().minusDays(10));
createTimestampedIndex(Integer.MAX_VALUE, now().minusDays(10));
assertIndicesCount(2);
CleanerService.Listener listener = getListener();
listener.onCleanUpIndices(days(0));
assertIndicesCount(2);
} }
public void testDeleteIndices() throws Exception { public void testDeleteIndices() throws Exception {
@ -94,11 +112,11 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
CleanerService.Listener listener = getListener(); CleanerService.Listener listener = getListener();
final DateTime now = now(); final DateTime now = now();
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + "one-year-ago", now.minusYears(1)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusYears(1));
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + "six-months-ago", now.minusMonths(6)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusMonths(6));
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + "one-month-ago", now.minusMonths(1)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusMonths(1));
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + "ten-days-ago", now.minusDays(10)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusDays(10));
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + "one-day-ago", now.minusDays(1)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusDays(1));
assertIndicesCount(5); assertIndicesCount(5);
// Clean indices that have expired two years ago // Clean indices that have expired two years ago
@ -134,7 +152,7 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
final DateTime now = now(); final DateTime now = now();
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + String.valueOf(i), now.minusDays(i)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusDays(i));
} }
assertIndicesCount(max); assertIndicesCount(max);
@ -154,7 +172,7 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
final DateTime now = now(); final DateTime now = now();
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
createIndex(MarvelSettings.MONITORING_INDICES_PREFIX + String.valueOf(i), now.minusDays(i)); createTimestampedIndex(MarvelTemplateUtils.TEMPLATE_VERSION, now.minusDays(i));
} }
assertIndicesCount(max); assertIndicesCount(max);
@ -194,6 +212,23 @@ public abstract class AbstractIndicesCleanerTestCase extends MarvelIntegTestCase
throw new IllegalStateException("unable to find listener"); throw new IllegalStateException("unable to find listener");
} }
/**
* Creates a monitoring data index in a given version.
*/
protected void createDataIndex(int version, DateTime creationDate) {
String indexName = MarvelSettings.MONITORING_DATA_INDEX_PREFIX + String.valueOf(version);
createIndex(indexName, creationDate);
}
/**
* Creates a monitoring timestamped index in a given version.
*/
protected void createTimestampedIndex(int version, DateTime creationDate) {
String indexName = MarvelSettings.MONITORING_INDICES_PREFIX + String.valueOf(version) + "-"
+ DateTimeFormat.forPattern(Exporter.DEFAULT_INDEX_NAME_TIME_FORMAT).withZoneUTC().print(creationDate.getMillis());
createIndex(indexName, creationDate);
}
protected abstract void createIndex(String name, DateTime creationDate); protected abstract void createIndex(String name, DateTime creationDate);
protected abstract void assertIndicesCount(int count) throws Exception; protected abstract void assertIndicesCount(int count) throws Exception;

View File

@ -9,7 +9,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.marvel.agent.exporter.local.LocalExporter; import org.elasticsearch.marvel.agent.exporter.local.LocalExporter;
import org.elasticsearch.marvel.MarvelSettings;
import org.elasticsearch.marvel.cleaner.AbstractIndicesCleanerTestCase; import org.elasticsearch.marvel.cleaner.AbstractIndicesCleanerTestCase;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.InternalSettingsPlugin; import org.elasticsearch.test.InternalSettingsPlugin;
@ -52,8 +51,7 @@ public class LocalIndicesCleanerTests extends AbstractIndicesCleanerTestCase {
@Override @Override
public void run() { public void run() {
try { try {
assertThat(client().admin().indices().prepareGetSettings(MarvelSettings.MONITORING_INDICES_PREFIX + "*") assertThat(client().admin().indices().prepareGetSettings().get().getIndexToSettings().size(), equalTo(count));
.get().getIndexToSettings().size(), equalTo(count));
} catch (IndexNotFoundException e) { } catch (IndexNotFoundException e) {
if (shieldEnabled) { if (shieldEnabled) {
assertThat(0, equalTo(count)); assertThat(0, equalTo(count));