Skip to content

Commit 829070d

Browse files
authored
Install the apm templates only if DSL available (#109166)
The APM module installs component and index templates that make use of data stream lifecycle. This makes sure the templates are installed only once the cluster has the data stream lifecycle feature. Follow-up to #108860 Fixes #106461
1 parent f16f71e commit 829070d

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

x-pack/plugin/apm-data/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies {
2020
compileOnly project(path: xpackModule('core'))
2121
testImplementation project(path: ':x-pack:plugin:stack')
2222
testImplementation(testArtifact(project(xpackModule('core'))))
23+
testImplementation project(':modules:data-streams')
2324
clusterModules project(':modules:data-streams')
2425
clusterModules project(':modules:ingest-common')
2526
clusterModules project(':modules:ingest-geoip')

x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistry.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
import org.apache.logging.log4j.LogManager;
1111
import org.apache.logging.log4j.Logger;
1212
import org.elasticsearch.client.internal.Client;
13+
import org.elasticsearch.cluster.ClusterChangedEvent;
1314
import org.elasticsearch.cluster.metadata.ComponentTemplate;
1415
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
1516
import org.elasticsearch.cluster.service.ClusterService;
1617
import org.elasticsearch.common.settings.Settings;
1718
import org.elasticsearch.common.xcontent.XContentHelper;
1819
import org.elasticsearch.core.Nullable;
20+
import org.elasticsearch.features.FeatureService;
21+
import org.elasticsearch.features.NodeFeature;
1922
import org.elasticsearch.threadpool.ThreadPool;
2023
import org.elasticsearch.xcontent.NamedXContentRegistry;
2124
import org.elasticsearch.xcontent.XContentParserConfiguration;
@@ -39,12 +42,15 @@
3942
*/
4043
public class APMIndexTemplateRegistry extends IndexTemplateRegistry {
4144
private static final Logger logger = LogManager.getLogger(APMIndexTemplateRegistry.class);
42-
45+
// this node feature is a redefinition of {@link DataStreamFeatures#DATA_STREAM_LIFECYCLE} and it's meant to avoid adding a
46+
// dependency to the data-streams module just for this
47+
public static final NodeFeature DATA_STREAM_LIFECYCLE = new NodeFeature("data_stream.lifecycle");
4348
private final int version;
4449

4550
private final Map<String, ComponentTemplate> componentTemplates;
4651
private final Map<String, ComposableIndexTemplate> composableIndexTemplates;
4752
private final List<IngestPipelineConfig> ingestPipelines;
53+
private final FeatureService featureService;
4854
private volatile boolean enabled;
4955

5056
@SuppressWarnings("unchecked")
@@ -53,7 +59,8 @@ public APMIndexTemplateRegistry(
5359
ClusterService clusterService,
5460
ThreadPool threadPool,
5561
Client client,
56-
NamedXContentRegistry xContentRegistry
62+
NamedXContentRegistry xContentRegistry,
63+
FeatureService featureService
5764
) {
5865
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
5966

@@ -78,6 +85,7 @@ public APMIndexTemplateRegistry(
7885
Map.Entry<String, Map<String, Object>> pipelineConfig = map.entrySet().iterator().next();
7986
return loadIngestPipeline(pipelineConfig.getKey(), version, (List<String>) pipelineConfig.getValue().get("dependencies"));
8087
}).collect(Collectors.toList());
88+
this.featureService = featureService;
8189
} catch (IOException e) {
8290
throw new RuntimeException(e);
8391
}
@@ -105,6 +113,13 @@ protected String getOrigin() {
105113
return ClientHelper.APM_ORIGIN;
106114
}
107115

116+
@Override
117+
protected boolean isClusterReady(ClusterChangedEvent event) {
118+
// Ensure current version of the components are installed only after versions that support data stream lifecycle
119+
// due to the use of the feature in all the `@lifecycle` component templates
120+
return featureService.clusterHasFeature(event.state(), DATA_STREAM_LIFECYCLE);
121+
}
122+
108123
@Override
109124
protected boolean requiresMasterNode() {
110125
return true;

x-pack/plugin/apm-data/src/main/java/org/elasticsearch/xpack/apmdata/APMPlugin.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,14 @@ public Collection<?> createComponents(PluginServices services) {
4848
Settings settings = services.environment().settings();
4949
ClusterService clusterService = services.clusterService();
5050
registry.set(
51-
new APMIndexTemplateRegistry(settings, clusterService, services.threadPool(), services.client(), services.xContentRegistry())
51+
new APMIndexTemplateRegistry(
52+
settings,
53+
clusterService,
54+
services.threadPool(),
55+
services.client(),
56+
services.xContentRegistry(),
57+
services.featureService()
58+
)
5259
);
5360
if (enabled) {
5461
APMIndexTemplateRegistry registryInstance = registry.get();

x-pack/plugin/apm-data/src/test/java/org/elasticsearch/xpack/apmdata/APMIndexTemplateRegistryTests.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package org.elasticsearch.xpack.apmdata;
99

10+
import org.elasticsearch.Version;
1011
import org.elasticsearch.action.ActionListener;
1112
import org.elasticsearch.action.ActionRequest;
1213
import org.elasticsearch.action.ActionResponse;
@@ -29,6 +30,7 @@
2930
import org.elasticsearch.cluster.service.ClusterService;
3031
import org.elasticsearch.common.settings.ClusterSettings;
3132
import org.elasticsearch.common.settings.Settings;
33+
import org.elasticsearch.datastreams.DataStreamFeatures;
3234
import org.elasticsearch.features.FeatureService;
3335
import org.elasticsearch.ingest.IngestMetadata;
3436
import org.elasticsearch.ingest.PipelineConfiguration;
@@ -88,7 +90,7 @@ public void createRegistryAndClient() {
8890
threadPool = new TestThreadPool(this.getClass().getName());
8991
client = new VerifyingClient(threadPool);
9092
clusterService = ClusterServiceUtils.createClusterService(threadPool, clusterSettings);
91-
FeatureService featureService = new FeatureService(List.of());
93+
FeatureService featureService = new FeatureService(List.of(new DataStreamFeatures()));
9294
stackTemplateRegistryAccessor = new StackTemplateRegistryAccessor(
9395
new StackTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY, featureService)
9496
);
@@ -98,7 +100,8 @@ public void createRegistryAndClient() {
98100
clusterService,
99101
threadPool,
100102
client,
101-
NamedXContentRegistry.EMPTY
103+
NamedXContentRegistry.EMPTY,
104+
featureService
102105
);
103106
apmIndexTemplateRegistry.setEnabled(true);
104107
}
@@ -355,6 +358,25 @@ public void testIndexTemplateConventions() throws Exception {
355358
}
356359
}
357360

361+
public void testThatNothingIsInstalledWhenAllNodesAreNotUpdated() {
362+
DiscoveryNode updatedNode = DiscoveryNodeUtils.create("updatedNode");
363+
DiscoveryNode outdatedNode = DiscoveryNodeUtils.create("outdatedNode", ESTestCase.buildNewFakeTransportAddress(), Version.V_8_10_0);
364+
DiscoveryNodes nodes = DiscoveryNodes.builder()
365+
.localNodeId("updatedNode")
366+
.masterNodeId("updatedNode")
367+
.add(updatedNode)
368+
.add(outdatedNode)
369+
.build();
370+
371+
client.setVerifier((a, r, l) -> {
372+
fail("if some cluster mode are not updated to at least v.8.11.0 nothing should happen");
373+
return null;
374+
});
375+
376+
ClusterChangedEvent event = createClusterChangedEvent(Map.of(), Map.of(), nodes);
377+
apmIndexTemplateRegistry.clusterChanged(event);
378+
}
379+
358380
private Map<String, ComponentTemplate> getIndependentComponentTemplateConfigs() {
359381
return apmIndexTemplateRegistry.getComponentTemplateConfigs().entrySet().stream().filter(template -> {
360382
Settings settings = template.getValue().template().settings();

0 commit comments

Comments
 (0)