[Monitoring] Add .monitoring-alerts-2 Index Template (elastic/x-pack-elasticsearch#819)

Add the `.monitoring-alerts-2` index template via the exporter. This
avoids a very common problem where the user wipes out their monitoring
indices manually, which means that the watches would then create an index
with a dynamic mappings.

This adds a mechanism for posting a template that is not associated with a
Resolver (convenient for the forthcoming work _and_ for a future Logstash
index).

Original commit: elastic/x-pack-elasticsearch@a4cfc48191
This commit is contained in:
Chris Earle 2017-03-29 13:24:22 -04:00 committed by GitHub
parent 4bb9e00dbf
commit 905fa16f81
7 changed files with 116 additions and 9 deletions

View File

@ -26,9 +26,27 @@ public final class MonitoringTemplateUtils {
*/
public static final String[] NEW_DATA_TYPES = { "kibana", "logstash", "beats" };
/**
* IDs of templates that can be used with {@linkplain #loadTemplate(String) loadTemplate} that are not managed by a Resolver.
* <p>
* This will be the complete list of template IDs when resolvers are removed.
*/
public static final String[] TEMPLATE_IDS = { "alerts" };
private MonitoringTemplateUtils() {
}
/**
* Get a template name for any template ID.
*
* @param id The template identifier.
* @return Never {@code null} {@link String} prefixed by ".monitoring-" and the
* @see #TEMPLATE_IDS
*/
public static String templateName(String id) {
return ".monitoring-" + id + "-" + TEMPLATE_VERSION;
}
public static String loadTemplate(String id) {
String resource = String.format(Locale.ROOT, TEMPLATE_FILE, id);
return TemplateUtils.loadTemplate(resource, TEMPLATE_VERSION, TEMPLATE_VERSION_PROPERTY);

View File

@ -531,13 +531,20 @@ public class HttpExporter extends Exporter {
resources.add(new DataTypeMappingHttpResource(resourceOwnerName, templateTimeout, type));
}
// add templates not managed by resolvers
for (final String templateId : MonitoringTemplateUtils.TEMPLATE_IDS) {
final String templateName = MonitoringTemplateUtils.templateName(templateId);
final Supplier<String> templateLoader = () -> MonitoringTemplateUtils.loadTemplate(templateId);
resources.add(new TemplateHttpResource(resourceOwnerName, templateTimeout, templateName, templateLoader));
}
// TODO: when resolvers are removed, all templates managed by this loop should be included in the TEMPLATE_IDS loop above
for (final MonitoringIndexNameResolver resolver : resolvers) {
final String templateName = resolver.templateName();
// ignore duplicates
if (templateNames.contains(templateName) == false) {
templateNames.add(templateName);
if (templateNames.add(templateName)) {
resources.add(new TemplateHttpResource(resourceOwnerName, templateTimeout, templateName, resolver::template));
}
}

View File

@ -145,6 +145,14 @@ public class LocalExporter extends Exporter implements ClusterStateListener, Cle
final Map<String, String> templates = StreamSupport.stream(new ResolversRegistry(Settings.EMPTY).spliterator(), false)
.collect(Collectors.toMap(MonitoringIndexNameResolver::templateName, MonitoringIndexNameResolver::template, (a, b) -> a));
// templates not managed by resolvers
// TODO: this should just become "templates" when we remove resolvers (and the above templates will disappear as a result)
final Map<String, String> nonResolverTemplates = Arrays.stream(MonitoringTemplateUtils.TEMPLATE_IDS)
.collect(Collectors.toMap(MonitoringTemplateUtils::templateName, MonitoringTemplateUtils::loadTemplate));
// add templates that don't come from resolvers
templates.putAll(nonResolverTemplates);
boolean setup = true;
// elected master node needs to setup templates; non-master nodes need to wait for it to be setup

View File

@ -0,0 +1,58 @@
{
"template": ".monitoring-alerts-${monitoring.template.version}",
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 1,
"codec": "best_compression"
}
},
"mappings": {
"doc": {
"properties": {
"timestamp": {
"type": "date"
},
"update_timestamp": {
"type": "date"
},
"resolved_timestamp": {
"type": "date"
},
"prefix": {
"type": "text"
},
"message": {
"type": "text"
},
"suffix": {
"type": "text"
},
"metadata": {
"dynamic": false,
"properties": {
"cluster_uuid": {
"type": "keyword"
},
"link": {
"type": "keyword"
},
"severity": {
"type": "short"
},
"type": {
"type": "keyword"
},
"version": {
"type": "keyword"
},
"watch": {
"type": "keyword"
}
}
}
}
}
},
"version": 50400
}

View File

@ -43,7 +43,7 @@ public class HttpExporterResourceTests extends AbstractPublishableHttpResourceTe
* kibana, logstash, beats
*/
private final int EXPECTED_TYPES = MonitoringTemplateUtils.NEW_DATA_TYPES.length;
private final int EXPECTED_TEMPLATES = 5;
private final int EXPECTED_TEMPLATES = 6;
private final RestClient client = mock(RestClient.class);
private final Response versionResponse = mock(Response.class);

View File

@ -315,7 +315,7 @@ public class HttpExporterTests extends ESTestCase {
equalTo(version + typeMappings.size() + templates.size() + pipelines.size() + bwc.size()));
assertThat(version, equalTo(1));
assertThat(typeMappings, hasSize(MonitoringTemplateUtils.NEW_DATA_TYPES.length));
assertThat(templates, hasSize(5));
assertThat(templates, hasSize(6));
assertThat(pipelines, hasSize(useIngest ? 1 : 0));
assertThat(bwc, hasSize(1));

View File

@ -36,6 +36,7 @@ import org.elasticsearch.xpack.monitoring.MonitoringService;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.client.MonitoringClient;
import org.elasticsearch.xpack.monitoring.exporter.MonitoringDoc;
import org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils;
import org.elasticsearch.xpack.monitoring.resolver.MonitoringIndexNameResolver;
import org.elasticsearch.xpack.monitoring.resolver.ResolversRegistry;
import org.elasticsearch.xpack.security.Security;
@ -54,6 +55,7 @@ import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -253,16 +255,30 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
}
protected List<Tuple<String, String>> monitoringTemplates() {
return StreamSupport.stream(new ResolversRegistry(Settings.EMPTY).spliterator(), false)
final List<Tuple<String, String>> templates = Arrays.stream(MonitoringTemplateUtils.TEMPLATE_IDS)
.map(id -> new Tuple<>(MonitoringTemplateUtils.templateName(id), MonitoringTemplateUtils.loadTemplate(id)))
.collect(Collectors.toList());
// TODO: remove this when we remove resolvers
templates.addAll(StreamSupport.stream(new ResolversRegistry(Settings.EMPTY).spliterator(), false)
.map((resolver) -> new Tuple<>(resolver.templateName(), resolver.template()))
.distinct()
.collect(Collectors.toList());
.collect(Collectors.toList()));
return templates;
}
protected Set<String> monitoringTemplateNames() {
return StreamSupport.stream(new ResolversRegistry(Settings.EMPTY).spliterator(), false)
.map(MonitoringIndexNameResolver::templateName)
final Set<String> templates = Arrays.stream(MonitoringTemplateUtils.TEMPLATE_IDS)
.map(MonitoringTemplateUtils::templateName)
.collect(Collectors.toSet());
// TODO: remove this when we remove resolvers
templates.addAll(StreamSupport.stream(new ResolversRegistry(Settings.EMPTY).spliterator(), false)
.map(MonitoringIndexNameResolver::templateName)
.collect(Collectors.toSet()));
return templates;
}
protected void assertTemplateInstalled(String name) {