Make IndexTemplateRegistry project-aware

This commit is contained in:
Niels Bauman 2025-04-16 13:41:58 +02:00
parent e74c237059
commit 0f33b8114d
No known key found for this signature in database
GPG key ID: 1E23BD8DDAC3C49C
53 changed files with 523 additions and 260 deletions

View file

@ -2790,16 +2790,12 @@ public abstract class ESRestTestCase extends ESTestCase {
if (indexTemplates != null) {
var templateNames = indexTemplates.keySet().stream().filter(name -> isXPackTemplate(name) == false).toList();
assertThat("Project [" + projectId + "] should not have index templates", templateNames, empty());
} else if (projectId.equals(Metadata.DEFAULT_PROJECT_ID.id())) {
fail("Expected default project to have standard templates, but was null");
}
final Map<String, Object> componentTemplates = state.evaluate("metadata.component_template.component_template");
if (componentTemplates != null) {
var templateNames = componentTemplates.keySet().stream().filter(name -> isXPackTemplate(name) == false).toList();
assertThat("Project [" + projectId + "] should not have component templates", templateNames, empty());
} else if (projectId.equals(Metadata.DEFAULT_PROJECT_ID.id())) {
fail("Expected default project to have standard component templates, but was null");
}
final List<Map<String, ?>> pipelines = state.evaluate("metadata.ingest.pipeline");
@ -2809,8 +2805,6 @@ public abstract class ESRestTestCase extends ESTestCase {
.filter(id -> isXPackIngestPipeline(id) == false)
.toList();
assertThat("Project [" + projectId + "] should not have ingest pipelines", pipelineNames, empty());
} else if (projectId.equals(Metadata.DEFAULT_PROJECT_ID.id())) {
fail("Expected default project to have standard ingest pipelines, but was null");
}
if (has(ProductFeature.ILM)) {
@ -2819,8 +2813,6 @@ public abstract class ESRestTestCase extends ESTestCase {
var policyNames = new HashSet<>(ilmPolicies.keySet());
policyNames.removeAll(preserveILMPolicyIds());
assertThat("Project [" + projectId + "] should not have ILM Policies", policyNames, empty());
} else if (projectId.equals(Metadata.DEFAULT_PROJECT_ID.id())) {
fail("Expected default project to have standard ILM policies, but was null");
}
}
}

View file

@ -8,6 +8,7 @@
package org.elasticsearch.xpack.apmdata;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -32,7 +33,8 @@ public class APMIndexTemplateRegistry extends YamlTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(
nodeSettings,
@ -40,7 +42,8 @@ public class APMIndexTemplateRegistry extends YamlTemplateRegistry {
threadPool,
client,
xContentRegistry,
templateFilter(isDataStreamsLifecycleOnlyMode(clusterService.getSettings()))
templateFilter(isDataStreamsLifecycleOnlyMode(clusterService.getSettings())),
projectResolver
);
}

View file

@ -48,7 +48,14 @@ public class APMPlugin extends Plugin implements ActionPlugin {
Settings settings = services.environment().settings();
ClusterService clusterService = services.clusterService();
registry.set(
new APMIndexTemplateRegistry(settings, clusterService, services.threadPool(), services.client(), services.xContentRegistry())
new APMIndexTemplateRegistry(
settings,
clusterService,
services.threadPool(),
services.client(),
services.xContentRegistry(),
services.projectResolver()
)
);
if (enabled) {
APMIndexTemplateRegistry registryInstance = registry.get();

View file

@ -11,6 +11,7 @@ import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.DataStreamLifecycle;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
@ -59,7 +60,8 @@ public class APMDSLOnlyTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
apmIndexTemplateRegistry.setEnabled(true);
}

View file

@ -26,6 +26,8 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
@ -89,8 +91,9 @@ public class APMIndexTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool, clusterSettings);
ProjectResolver projectResolver = TestProjectResolvers.mustExecuteFirst();
stackTemplateRegistryAccessor = new StackTemplateRegistryAccessor(
new StackTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY)
new StackTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY, projectResolver)
);
apmIndexTemplateRegistry = new APMIndexTemplateRegistry(
@ -98,7 +101,8 @@ public class APMIndexTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
projectResolver
);
apmIndexTemplateRegistry.setEnabled(true);
}

View file

@ -17,6 +17,7 @@ import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.DataStream;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.datastreams.DataStreamsPlugin;
import org.elasticsearch.index.mapper.DateFieldMapper;
@ -58,7 +59,8 @@ public class IndexTemplateRegistryRolloverIT extends ESIntegTestCase {
clusterService.threadPool(),
client,
xContentRegistry(),
3L
3L,
TestProjectResolvers.mustExecuteFirst()
);
registry.initialize();
ensureGreen();

View file

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.core.template;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -28,9 +29,10 @@ public class RolloverEnabledTestTemplateRegistry extends IndexTemplateRegistry {
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry,
long version
long version,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.version = version;
}

View file

@ -30,9 +30,11 @@ import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.metadata.DataStream;
import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
import org.elasticsearch.cluster.metadata.MetadataIndexTemplateService;
import org.elasticsearch.cluster.metadata.ProjectId;
import org.elasticsearch.cluster.metadata.ProjectMetadata;
import org.elasticsearch.cluster.metadata.Template;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.regex.Regex;
@ -85,10 +87,14 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
protected final ThreadPool threadPool;
protected final NamedXContentRegistry xContentRegistry;
protected final ClusterService clusterService;
protected final ConcurrentMap<String, AtomicBoolean> templateCreationsInProgress = new ConcurrentHashMap<>();
protected final ConcurrentMap<String, AtomicBoolean> policyCreationsInProgress = new ConcurrentHashMap<>();
protected final ConcurrentMap<String, AtomicBoolean> pipelineCreationsInProgress = new ConcurrentHashMap<>();
protected final ConcurrentMap<ProjectId, ConcurrentHashMap<String, AtomicBoolean>> templateCreationsInProgress =
new ConcurrentHashMap<>();
protected final ConcurrentMap<ProjectId, ConcurrentHashMap<String, AtomicBoolean>> policyCreationsInProgress =
new ConcurrentHashMap<>();
protected final ConcurrentMap<ProjectId, ConcurrentHashMap<String, AtomicBoolean>> pipelineCreationsInProgress =
new ConcurrentHashMap<>();
protected final List<LifecyclePolicy> lifecyclePolicies;
protected final ProjectResolver projectResolver;
@SuppressWarnings("this-escape")
public IndexTemplateRegistry(
@ -96,13 +102,15 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
this.settings = nodeSettings;
this.client = client;
this.threadPool = threadPool;
this.xContentRegistry = xContentRegistry;
this.clusterService = clusterService;
this.projectResolver = projectResolver;
if (isDataStreamsLifecycleOnlyMode(clusterService.getSettings()) == false) {
this.lifecyclePolicies = getLifecycleConfigs().stream()
.map(config -> config.load(LifecyclePolicyConfig.DEFAULT_X_CONTENT_REGISTRY))
@ -235,10 +243,13 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
DiscoveryNode localNode = event.state().getNodes().getLocalNode();
boolean localNodeVersionAfterMaster = localNode.getVersion().after(masterNode.getVersion());
if (event.localNodeMaster() || localNodeVersionAfterMaster) {
addIngestPipelinesIfMissing(state);
addTemplatesIfMissing(state);
addIndexLifecyclePoliciesIfMissing(state);
if (event.localNodeMaster() == false && localNodeVersionAfterMaster == false) {
return;
}
for (ProjectMetadata project : event.state().metadata().projects().values()) {
addIngestPipelinesIfMissing(project);
addTemplatesIfMissing(project);
addIndexLifecyclePoliciesIfMissing(project);
}
}
@ -259,13 +270,13 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
return false;
}
private void addTemplatesIfMissing(ClusterState state) {
addLegacyTemplatesIfMissing(state);
addComponentTemplatesIfMissing(state);
addComposableTemplatesIfMissing(state.metadata().getProject());
private void addTemplatesIfMissing(ProjectMetadata project) {
addLegacyTemplatesIfMissing(project);
addComponentTemplatesIfMissing(project);
addComposableTemplatesIfMissing(project);
}
private void addLegacyTemplatesIfMissing(ClusterState state) {
private void addLegacyTemplatesIfMissing(ProjectMetadata project) {
if (isDataStreamsLifecycleOnlyMode(clusterService.getSettings())) {
// data stream lifecycle cannot be configured via legacy templates
return;
@ -273,12 +284,13 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
final List<IndexTemplateConfig> indexTemplates = getLegacyTemplateConfigs();
for (IndexTemplateConfig newTemplate : indexTemplates) {
final String templateName = newTemplate.getTemplateName();
final AtomicBoolean creationCheck = templateCreationsInProgress.computeIfAbsent(templateName, key -> new AtomicBoolean(false));
final AtomicBoolean creationCheck = templateCreationsInProgress.computeIfAbsent(project.id(), key -> new ConcurrentHashMap<>())
.computeIfAbsent(templateName, key -> new AtomicBoolean(false));
if (creationCheck.compareAndSet(false, true)) {
IndexTemplateMetadata currentTemplate = state.metadata().getProject().templates().get(templateName);
IndexTemplateMetadata currentTemplate = project.templates().get(templateName);
if (Objects.isNull(currentTemplate)) {
logger.debug("adding legacy template [{}] for [{}], because it doesn't exist", templateName, getOrigin());
putLegacyTemplate(newTemplate, creationCheck);
putLegacyTemplate(project.id(), newTemplate, creationCheck);
} else if (Objects.isNull(currentTemplate.getVersion()) || newTemplate.getVersion() > currentTemplate.getVersion()) {
// IndexTemplateConfig now enforces templates contain a `version` property, so if the template doesn't have one we can
// safely assume it's an old version of the template.
@ -289,7 +301,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
currentTemplate.getVersion(),
newTemplate.getVersion()
);
putLegacyTemplate(newTemplate, creationCheck);
putLegacyTemplate(project.id(), newTemplate, creationCheck);
} else {
creationCheck.set(false);
logger.trace(
@ -309,14 +321,15 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
}
}
private void addComponentTemplatesIfMissing(ClusterState state) {
private void addComponentTemplatesIfMissing(ProjectMetadata project) {
final Map<String, ComponentTemplate> indexTemplates = getComponentTemplateConfigs();
for (Map.Entry<String, ComponentTemplate> newTemplate : indexTemplates.entrySet()) {
final String templateName = newTemplate.getKey();
final AtomicBoolean creationCheck = templateCreationsInProgress.computeIfAbsent(templateName, key -> new AtomicBoolean(false));
final AtomicBoolean creationCheck = templateCreationsInProgress.computeIfAbsent(project.id(), key -> new ConcurrentHashMap<>())
.computeIfAbsent(templateName, key -> new AtomicBoolean(false));
if (creationCheck.compareAndSet(false, true)) {
ComponentTemplate currentTemplate = state.metadata().getProject().componentTemplates().get(templateName);
if (templateDependenciesSatisfied(state, newTemplate.getValue()) == false) {
ComponentTemplate currentTemplate = project.componentTemplates().get(templateName);
if (templateDependenciesSatisfied(project, newTemplate.getValue()) == false) {
creationCheck.set(false);
logger.trace(
"not adding index template [{}] for [{}] because its required dependencies do not exist",
@ -325,7 +338,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
);
} else if (Objects.isNull(currentTemplate)) {
logger.debug("adding component template [{}] for [{}], because it doesn't exist", templateName, getOrigin());
putComponentTemplate(templateName, newTemplate.getValue(), creationCheck);
putComponentTemplate(project.id(), templateName, newTemplate.getValue(), creationCheck);
} else if (Objects.isNull(currentTemplate.version()) || newTemplate.getValue().version() > currentTemplate.version()) {
// IndexTemplateConfig now enforces templates contain a `version` property, so if the template doesn't have one we can
// safely assume it's an old version of the template.
@ -336,7 +349,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
currentTemplate.version(),
newTemplate.getValue().version()
);
putComponentTemplate(templateName, newTemplate.getValue(), creationCheck);
putComponentTemplate(project.id(), templateName, newTemplate.getValue(), creationCheck);
} else {
creationCheck.set(false);
logger.trace(
@ -359,7 +372,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
/**
* Returns true if the cluster state contains all of the dependencies required by the provided component template
*/
private static boolean templateDependenciesSatisfied(ClusterState state, ComponentTemplate indexTemplate) {
private static boolean templateDependenciesSatisfied(ProjectMetadata project, ComponentTemplate indexTemplate) {
Template template = indexTemplate.template();
if (template == null) {
return true;
@ -368,7 +381,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
if (settings == null) {
return true;
}
IngestMetadata ingestMetadata = state.metadata().getProject().custom(IngestMetadata.TYPE);
IngestMetadata ingestMetadata = project.custom(IngestMetadata.TYPE);
String defaultPipeline = settings.get("index.default_pipeline");
if (defaultPipeline != null) {
if (ingestMetadata == null || ingestMetadata.getPipelines().containsKey(defaultPipeline) == false) {
@ -382,14 +395,15 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
return true;
}
private void addComposableTemplatesIfMissing(ProjectMetadata projectMetadata) {
private void addComposableTemplatesIfMissing(ProjectMetadata project) {
final Map<String, ComposableIndexTemplate> indexTemplates = getComposableTemplateConfigs();
for (Map.Entry<String, ComposableIndexTemplate> newTemplate : indexTemplates.entrySet()) {
final String templateName = newTemplate.getKey();
final AtomicBoolean creationCheck = templateCreationsInProgress.computeIfAbsent(templateName, key -> new AtomicBoolean(false));
final AtomicBoolean creationCheck = templateCreationsInProgress.computeIfAbsent(project.id(), key -> new ConcurrentHashMap<>())
.computeIfAbsent(templateName, key -> new AtomicBoolean(false));
if (creationCheck.compareAndSet(false, true)) {
ComposableIndexTemplate currentTemplate = projectMetadata.templatesV2().get(templateName);
boolean componentTemplatesAvailable = componentTemplatesInstalled(projectMetadata, newTemplate.getValue());
ComposableIndexTemplate currentTemplate = project.templatesV2().get(templateName);
boolean componentTemplatesAvailable = componentTemplatesInstalled(project, newTemplate.getValue());
if (componentTemplatesAvailable == false) {
creationCheck.set(false);
if (logger.isTraceEnabled()) {
@ -402,7 +416,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
}
} else if (Objects.isNull(currentTemplate)) {
logger.debug("adding composable template [{}] for [{}], because it doesn't exist", templateName, getOrigin());
putComposableTemplate(projectMetadata, templateName, newTemplate.getValue(), creationCheck);
putComposableTemplate(project, templateName, newTemplate.getValue(), creationCheck);
} else if (Objects.isNull(currentTemplate.version()) || newTemplate.getValue().version() > currentTemplate.version()) {
// IndexTemplateConfig now enforces templates contain a `version` property, so if the template doesn't have one we can
// safely assume it's an old version of the template.
@ -413,7 +427,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
currentTemplate.version(),
newTemplate.getValue().version()
);
putComposableTemplate(projectMetadata, templateName, newTemplate.getValue(), creationCheck);
putComposableTemplate(project, templateName, newTemplate.getValue(), creationCheck);
} else {
creationCheck.set(false);
logger.trace(
@ -463,9 +477,9 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
return true;
}
private void putLegacyTemplate(final IndexTemplateConfig config, final AtomicBoolean creationCheck) {
private void putLegacyTemplate(final ProjectId projectId, final IndexTemplateConfig config, final AtomicBoolean creationCheck) {
final Executor executor = threadPool.generic();
executor.execute(() -> {
final Runnable runnable = () -> {
final String templateName = config.getTemplateName();
PutIndexTemplateRequest request = new PutIndexTemplateRequest(templateName).source(config.loadBytes(), XContentType.JSON);
@ -495,12 +509,18 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
},
client.admin().indices()::putTemplate
);
});
};
projectResolver.executeOnProject(projectId, () -> executor.execute(runnable));
}
private void putComponentTemplate(final String templateName, final ComponentTemplate template, final AtomicBoolean creationCheck) {
private void putComponentTemplate(
final ProjectId projectId,
final String templateName,
final ComponentTemplate template,
final AtomicBoolean creationCheck
) {
final Executor executor = threadPool.generic();
executor.execute(() -> {
final Runnable runnable = () -> {
PutComponentTemplateAction.Request request = new PutComponentTemplateAction.Request(templateName).componentTemplate(template);
request.masterNodeTimeout(TimeValue.MAX_VALUE);
executeAsyncWithOrigin(
@ -528,17 +548,18 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
},
(req, listener) -> client.execute(PutComponentTemplateAction.INSTANCE, req, listener)
);
});
};
projectResolver.executeOnProject(projectId, () -> executor.execute(runnable));
}
private void putComposableTemplate(
ProjectMetadata projectMetadata,
final ProjectMetadata projectMetadata,
final String templateName,
final ComposableIndexTemplate indexTemplate,
final AtomicBoolean creationCheck
) {
final Executor executor = threadPool.generic();
executor.execute(() -> {
final Runnable runnable = () -> {
TransportPutComposableIndexTemplateAction.Request request = new TransportPutComposableIndexTemplateAction.Request(templateName)
.indexTemplate(indexTemplate);
request.masterNodeTimeout(TimeValue.MAX_VALUE);
@ -573,30 +594,28 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
},
(req, listener) -> client.execute(TransportPutComposableIndexTemplateAction.TYPE, req, listener)
);
});
};
projectResolver.executeOnProject(projectMetadata.id(), () -> executor.execute(runnable));
}
private void addIndexLifecyclePoliciesIfMissing(ClusterState state) {
private void addIndexLifecyclePoliciesIfMissing(ProjectMetadata project) {
if (isDataStreamsLifecycleOnlyMode(clusterService.getSettings())) {
logger.trace("running in data stream lifecycle only mode. skipping the installation of ILM policies.");
return;
}
final IndexLifecycleMetadata metadata = state.metadata().getProject().custom(IndexLifecycleMetadata.TYPE);
final IndexLifecycleMetadata metadata = project.custom(IndexLifecycleMetadata.TYPE);
final Map<String, LifecyclePolicy> policies = metadata != null ? metadata.getPolicies() : Map.of();
for (LifecyclePolicy policy : getLifecyclePolicies()) {
final AtomicBoolean creationCheck = policyCreationsInProgress.computeIfAbsent(
policy.getName(),
key -> new AtomicBoolean(false)
);
final AtomicBoolean creationCheck = policyCreationsInProgress.computeIfAbsent(project.id(), key -> new ConcurrentHashMap<>())
.computeIfAbsent(policy.getName(), key -> new AtomicBoolean(false));
if (creationCheck.compareAndSet(false, true)) {
final LifecyclePolicy currentPolicy = policies.get(policy.getName());
if (Objects.isNull(currentPolicy)) {
logger.debug("adding lifecycle policy [{}] for [{}], because it doesn't exist", policy.getName(), getOrigin());
putPolicy(policy, creationCheck);
putPolicy(project.id(), policy, creationCheck);
} else if (isUpgradeRequired(currentPolicy, policy)) {
logger.info("upgrading lifecycle policy [{}] for [{}]", policy.getName(), getOrigin());
putPolicy(policy, creationCheck);
putPolicy(project.id(), policy, creationCheck);
} else {
logger.trace("not adding lifecycle policy [{}] for [{}], because it already exists", policy.getName(), getOrigin());
creationCheck.set(false);
@ -616,9 +635,9 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
return false;
}
private void putPolicy(final LifecyclePolicy policy, final AtomicBoolean creationCheck) {
private void putPolicy(ProjectId projectId, final LifecyclePolicy policy, final AtomicBoolean creationCheck) {
final Executor executor = threadPool.generic();
executor.execute(() -> {
final Runnable runnable = () -> {
PutLifecycleRequest request = new PutLifecycleRequest(REGISTRY_ACTION_TIMEOUT, REGISTRY_ACTION_TIMEOUT, policy);
request.masterNodeTimeout(TimeValue.MAX_VALUE);
executeAsyncWithOrigin(
@ -646,7 +665,8 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
},
(req, listener) -> client.execute(ILMActions.PUT, req, listener)
);
});
};
projectResolver.executeOnProject(projectId, () -> executor.execute(runnable));
}
protected static Map<String, ComposableIndexTemplate> parseComposableTemplates(IndexTemplateConfig... config) {
@ -659,16 +679,14 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
}));
}
private void addIngestPipelinesIfMissing(ClusterState state) {
private void addIngestPipelinesIfMissing(ProjectMetadata project) {
for (IngestPipelineConfig requiredPipeline : getIngestPipelines()) {
final AtomicBoolean creationCheck = pipelineCreationsInProgress.computeIfAbsent(
requiredPipeline.getId(),
key -> new AtomicBoolean(false)
);
final AtomicBoolean creationCheck = pipelineCreationsInProgress.computeIfAbsent(project.id(), key -> new ConcurrentHashMap<>())
.computeIfAbsent(requiredPipeline.getId(), key -> new AtomicBoolean(false));
if (creationCheck.compareAndSet(false, true)) {
List<String> pipelineDependencies = requiredPipeline.getPipelineDependencies();
if (pipelineDependencies != null && pipelineDependenciesExist(state, pipelineDependencies) == false) {
if (pipelineDependencies != null && pipelineDependenciesExist(project, pipelineDependencies) == false) {
creationCheck.set(false);
logger.trace(
"not adding ingest pipeline [{}] for [{}] because its dependencies do not exist",
@ -676,7 +694,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
getOrigin()
);
} else {
PipelineConfiguration existingPipeline = findInstalledPipeline(state, requiredPipeline.getId());
PipelineConfiguration existingPipeline = findInstalledPipeline(project, requiredPipeline.getId());
if (existingPipeline != null) {
Integer existingPipelineVersion = existingPipeline.getVersion();
if (existingPipelineVersion == null || existingPipelineVersion < requiredPipeline.getVersion()) {
@ -687,7 +705,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
existingPipelineVersion,
requiredPipeline.getVersion()
);
putIngestPipeline(requiredPipeline, creationCheck);
putIngestPipeline(project.id(), requiredPipeline, creationCheck);
} else {
creationCheck.set(false);
logger.debug(
@ -702,16 +720,16 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
requiredPipeline.getId(),
getOrigin()
);
putIngestPipeline(requiredPipeline, creationCheck);
putIngestPipeline(project.id(), requiredPipeline, creationCheck);
}
}
}
}
}
private static boolean pipelineDependenciesExist(ClusterState state, List<String> dependencies) {
private static boolean pipelineDependenciesExist(ProjectMetadata project, List<String> dependencies) {
for (String dependency : dependencies) {
if (findInstalledPipeline(state, dependency) == null) {
if (findInstalledPipeline(project, dependency) == null) {
return false;
}
}
@ -719,14 +737,14 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
}
@Nullable
private static PipelineConfiguration findInstalledPipeline(ClusterState state, String pipelineId) {
Optional<IngestMetadata> maybeMeta = Optional.ofNullable(state.metadata().getProject().custom(IngestMetadata.TYPE));
private static PipelineConfiguration findInstalledPipeline(ProjectMetadata project, String pipelineId) {
Optional<IngestMetadata> maybeMeta = Optional.ofNullable(project.custom(IngestMetadata.TYPE));
return maybeMeta.map(ingestMetadata -> ingestMetadata.getPipelines().get(pipelineId)).orElse(null);
}
private void putIngestPipeline(final IngestPipelineConfig pipelineConfig, final AtomicBoolean creationCheck) {
private void putIngestPipeline(ProjectId projectId, final IngestPipelineConfig pipelineConfig, final AtomicBoolean creationCheck) {
final Executor executor = threadPool.generic();
executor.execute(() -> {
final Runnable runnable = () -> {
PutPipelineRequest request = new PutPipelineRequest(
MasterNodeRequest.INFINITE_MASTER_NODE_TIMEOUT,
MasterNodeRequest.INFINITE_MASTER_NODE_TIMEOUT,
@ -762,7 +780,8 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
},
(req, listener) -> client.execute(PutPipelineTransportAction.TYPE, req, listener)
);
});
};
projectResolver.executeOnProject(projectId, () -> executor.execute(runnable));
}
/**
@ -798,6 +817,7 @@ public abstract class IndexTemplateRegistry implements ClusterStateListener {
final Runnable runAfter
) {
final Executor executor = threadPool.generic();
// This runnable does not need to be run inside `projectResolver.executeOnProject` because this method's caller already does that
executor.execute(() -> {
List<String> rolloverTargets = findRolloverTargetDataStreams(projectMetadata, templateName, indexTemplate);
if (rolloverTargets.isEmpty()) {

View file

@ -13,6 +13,7 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentHelper;
@ -54,9 +55,10 @@ public abstract class YamlTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
this(nodeSettings, clusterService, threadPool, client, xContentRegistry, ignored -> true);
this(nodeSettings, clusterService, threadPool, client, xContentRegistry, ignored -> true, projectResolver);
}
@SuppressWarnings({ "unchecked", "this-escape" })
@ -66,9 +68,10 @@ public abstract class YamlTemplateRegistry extends IndexTemplateRegistry {
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry,
Predicate<String> templateFilter
Predicate<String> templateFilter,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
try {
final Map<String, Object> resources = XContentHelper.convertToMap(
YamlXContent.yamlXContent,

View file

@ -13,7 +13,6 @@ import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.ActionType;
import org.elasticsearch.action.admin.indices.rollover.RolloverAction;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.template.put.PutComponentTemplateAction;
import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction;
import org.elasticsearch.action.ingest.PutPipelineRequest;
@ -27,17 +26,20 @@ import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.metadata.DataStreamTestHelper;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.metadata.ProjectId;
import org.elasticsearch.cluster.metadata.ProjectMetadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.Strings;
import org.elasticsearch.index.Index;
import org.elasticsearch.ingest.IngestMetadata;
import org.elasticsearch.ingest.PipelineConfiguration;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.ClusterServiceUtils;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.client.NoOpClient;
@ -60,14 +62,13 @@ import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.contains;
@ -83,6 +84,9 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
public class IndexTemplateRegistryTests extends ESTestCase {
private final ProjectId projectId = randomUniqueProjectId();
private TestRegistryWithCustomPlugin registry;
private ClusterService clusterService;
private ThreadPool threadPool;
@ -93,7 +97,14 @@ public class IndexTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new TestRegistryWithCustomPlugin(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new TestRegistryWithCustomPlugin(
Settings.EMPTY,
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.usingRequestHeader(threadPool.getThreadContext())
);
}
@After
@ -107,9 +118,10 @@ public class IndexTemplateRegistryTests extends ESTestCase {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == PutPipelineTransportAction.TYPE) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutPipelineAction(calledTimes, action, request, listener, "custom-plugin-final_pipeline");
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
@ -125,16 +137,17 @@ public class IndexTemplateRegistryTests extends ESTestCase {
ClusterChangedEvent event = createClusterChangedEvent(Collections.emptyMap(), nodes);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
public void testThatDependentPipelinesAreAddedIfDependenciesExist() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == PutPipelineTransportAction.TYPE) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutPipelineAction(calledTimes, action, request, listener, "custom-plugin-default_pipeline");
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
@ -155,16 +168,17 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
public void testThatTemplateIsAddedIfAllDependenciesExist() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action instanceof PutComponentTemplateAction) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutComponentTemplate(calledTimes, action, request, listener);
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
@ -184,16 +198,17 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
public void testThatTemplateIsNotAddedIfNotAllDependenciesExist() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == PutPipelineTransportAction.TYPE) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutPipelineAction(calledTimes, action, request, listener, "custom-plugin-default_pipeline");
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
@ -213,16 +228,17 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
public void testThatComposableTemplateIsAddedIfDependenciesExist() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutComposableIndexTemplateAction(calledTimes, action, request, listener);
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
@ -240,16 +256,17 @@ public class IndexTemplateRegistryTests extends ESTestCase {
ClusterChangedEvent event = createClusterChangedEvent(Collections.singletonMap("custom-plugin-settings", 3), nodes);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
public void testThatComposableTemplateIsAddedIfDependenciesHaveRightVersion() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutComposableIndexTemplateAction(calledTimes, action, request, listener);
return AcknowledgedResponse.TRUE;
} else if (action instanceof PutComponentTemplateAction) {
@ -272,26 +289,27 @@ public class IndexTemplateRegistryTests extends ESTestCase {
// to their version
ClusterChangedEvent event = createClusterChangedEvent(Collections.singletonMap("custom-plugin-settings", 2), nodes);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
// when a registry requires rollovers after index template updates, the upgrade should occur only if the dependencies are have
// the required version
registry.setApplyRollover(true);
calledTimes.set(0);
calledTimesMap.values().forEach(calledTimes -> calledTimes.set(0));
registry.clusterChanged(event);
Thread.sleep(100L);
assertThat(calledTimes.get(), equalTo(0));
assertCalledTimes(calledTimesMap, event, 0);
event = createClusterChangedEvent(Collections.singletonMap("custom-plugin-settings", 3), nodes);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
public void testThatTemplatesAreUpgradedWhenNeeded() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
if (action == PutPipelineTransportAction.TYPE) {
assertPutPipelineAction(
calledTimes,
@ -324,7 +342,7 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(4)));
assertCalledTimes(calledTimesMap, event, 4);
}
public void testAutomaticRollover() throws Exception {
@ -338,11 +356,12 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
Map<String, ComposableIndexTemplate> composableTemplateConfigs = registry.getComposableTemplateConfigs();
final var metadataBuilder = Metadata.builder(state.metadata());
for (Map.Entry<String, ComposableIndexTemplate> entry : composableTemplateConfigs.entrySet()) {
ComposableIndexTemplate template = entry.getValue();
state = ClusterState.builder(state)
.metadata(
Metadata.builder(Objects.requireNonNull(state).metadata())
for (var project : state.metadata().projects().values()) {
metadataBuilder.put(
metadataBuilder.getProject(project.id())
.put(
entry.getKey(),
ComposableIndexTemplate.builder()
@ -355,84 +374,101 @@ public class IndexTemplateRegistryTests extends ESTestCase {
.dataStreamTemplate(template.getDataStreamTemplate())
.build()
)
)
.build();
);
}
}
state = ClusterState.builder(state)
.metadata(
Metadata.builder(Objects.requireNonNull(state).metadata())
for (var project : state.metadata().projects().values()) {
metadataBuilder.put(
metadataBuilder.getProject(project.id())
.put(DataStreamTestHelper.newInstance("logs-my_app-1", Collections.singletonList(new Index(".ds-ds1-000001", "ds1i"))))
.put(DataStreamTestHelper.newInstance("logs-my_app-2", Collections.singletonList(new Index(".ds-ds2-000001", "ds2i"))))
.put(
DataStreamTestHelper.newInstance("traces-my_app-1", Collections.singletonList(new Index(".ds-ds3-000001", "ds3i")))
)
)
.build();
);
}
state = ClusterState.builder(state).metadata(metadataBuilder).build();
ClusterChangedEvent event = createClusterChangedEvent(nodes, state);
AtomicInteger rolloverCounter = new AtomicInteger(0);
AtomicInteger putIndexTemplateCounter = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> rolloverCounterMap = new ConcurrentHashMap<>();
Map<ProjectId, AtomicInteger> putIndexTemplateCounterMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action instanceof RolloverAction) {
final var rolloverCounter = rolloverCounterMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
rolloverCounter.incrementAndGet();
RolloverRequest rolloverRequest = ((RolloverRequest) request);
assertThat(rolloverRequest.getRolloverTarget(), startsWith("logs-my_app-"));
assertThat(rolloverRequest.isLazy(), equalTo(true));
} else if (action == TransportPutComposableIndexTemplateAction.TYPE) {
final var putIndexTemplateCounter = putIndexTemplateCounterMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
putIndexTemplateCounter.incrementAndGet();
}
return AcknowledgedResponse.TRUE;
});
registry.clusterChanged(event);
assertBusy(() -> assertThat(putIndexTemplateCounter.get(), equalTo(1)));
assertCalledTimes(putIndexTemplateCounterMap, event, 1);
// no rollover on upgrade because the test registry doesn't support automatic rollover by default
Thread.sleep(100L);
assertThat(rolloverCounter.get(), equalTo(0));
assertCalledTimes(rolloverCounterMap, event, 0);
// test successful rollovers
registry.setApplyRollover(true);
putIndexTemplateCounter.set(0);
putIndexTemplateCounterMap.values().forEach(calledTimes -> calledTimes.set(0));
registry.clusterChanged(event);
assertBusy(() -> assertThat(putIndexTemplateCounter.get(), equalTo(1)));
assertBusy(() -> assertThat(rolloverCounter.get(), equalTo(2)));
AtomicReference<Collection<RolloverResponse>> rolloverResponsesRef = registry.getRolloverResponses();
assertBusy(() -> assertNotNull(rolloverResponsesRef.get()));
assertThat(rolloverResponsesRef.get(), hasSize(2));
assertCalledTimes(putIndexTemplateCounterMap, event, 1);
assertCalledTimes(rolloverCounterMap, event, 2);
var rolloverResponsesRef = registry.getRolloverResponses();
int nrOfProjects = state.metadata().projects().size();
assertBusy(() -> {
assertThat(rolloverResponsesRef.size(), equalTo(nrOfProjects));
for (var rolloverResponses : rolloverResponsesRef.values()) {
assertNotNull(rolloverResponses.get());
assertThat(rolloverResponses.get(), hasSize(2));
}
;
});
// test again, to verify that the per-index-template creation lock gets released for reuse
putIndexTemplateCounter.set(0);
rolloverCounter.set(0);
rolloverResponsesRef.set(Collections.emptySet());
putIndexTemplateCounterMap.values().forEach(calledTimes -> calledTimes.set(0));
rolloverCounterMap.values().forEach(calledTimes -> calledTimes.set(0));
rolloverResponsesRef.values().forEach(v -> v.set(Set.of()));
registry.clusterChanged(event);
assertBusy(() -> assertThat(putIndexTemplateCounter.get(), equalTo(1)));
assertBusy(() -> assertThat(rolloverCounter.get(), equalTo(2)));
assertBusy(() -> assertThat(rolloverResponsesRef.get(), hasSize(2)));
assertCalledTimes(putIndexTemplateCounterMap, event, 1);
assertCalledTimes(rolloverCounterMap, event, 2);
assertBusy(() -> rolloverResponsesRef.values().forEach(v -> assertThat(v.get(), hasSize(2))));
// test rollover failures
putIndexTemplateCounter.set(0);
rolloverCounter.set(0);
client.setVerifier((action, request, listener) -> {
putIndexTemplateCounterMap.values().forEach(calledTimes -> calledTimes.set(0));
rolloverCounterMap.values().forEach(calledTimes -> calledTimes.set(0));
client.setVerifier((projectId, action, request, listener) -> {
if (action instanceof RolloverAction) {
final var rolloverCounter = rolloverCounterMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
rolloverCounter.incrementAndGet();
RolloverRequest rolloverRequest = ((RolloverRequest) request);
assertThat(rolloverRequest.getRolloverTarget(), startsWith("logs-my_app-"));
throw new RuntimeException("Failed to rollover " + rolloverRequest.getRolloverTarget());
} else if (action == TransportPutComposableIndexTemplateAction.TYPE) {
final var putIndexTemplateCounter = putIndexTemplateCounterMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
putIndexTemplateCounter.incrementAndGet();
}
return AcknowledgedResponse.TRUE;
});
registry.clusterChanged(event);
assertBusy(() -> assertThat(putIndexTemplateCounter.get(), equalTo(1)));
assertBusy(() -> assertThat(rolloverCounter.get(), equalTo(2)));
AtomicReference<Exception> rolloverFailureRef = registry.getRolloverFailure();
assertBusy(() -> assertNotNull(rolloverFailureRef.get()));
Exception rolloverFailure = rolloverFailureRef.get();
assertThat(rolloverFailure.getMessage(), startsWith("Failed to rollover logs-my_app-"));
Throwable[] suppressed = rolloverFailure.getSuppressed();
assertThat(suppressed.length, equalTo(1));
assertThat(suppressed[0].getMessage(), startsWith("Failed to rollover logs-my_app-"));
assertCalledTimes(putIndexTemplateCounterMap, event, 1);
assertCalledTimes(rolloverCounterMap, event, 2);
var rolloverFailureRefMap = registry.getRolloverFailure();
assertBusy(() -> {
assertThat(rolloverFailureRefMap.size(), equalTo(nrOfProjects));
rolloverFailureRefMap.values().forEach(rolloverFailureRef -> {
assertNotNull(rolloverFailureRef.get());
Exception rolloverFailure = rolloverFailureRef.get();
assertThat(rolloverFailure.getMessage(), startsWith("Failed to rollover logs-my_app-"));
Throwable[] suppressed = rolloverFailure.getSuppressed();
assertThat(suppressed.length, equalTo(1));
assertThat(suppressed[0].getMessage(), startsWith("Failed to rollover logs-my_app-"));
});
});
}
public void testRolloverForFreshInstalledIndexTemplate() throws Exception {
@ -445,26 +481,30 @@ public class IndexTemplateRegistryTests extends ESTestCase {
Map.of("custom-plugin-default_pipeline", 3, "custom-plugin-final_pipeline", 3),
nodes
);
state = ClusterState.builder(state)
.metadata(
Metadata.builder(Objects.requireNonNull(state).metadata())
final var metadataBuilder = Metadata.builder(state.metadata());
for (var project : state.metadata().projects().values()) {
metadataBuilder.put(
metadataBuilder.getProject(project.id())
.put(DataStreamTestHelper.newInstance("logs-my_app-1", Collections.singletonList(new Index(".ds-ds1-000001", "ds1i"))))
.put(DataStreamTestHelper.newInstance("logs-my_app-2", Collections.singletonList(new Index(".ds-ds2-000001", "ds2i"))))
.put(
DataStreamTestHelper.newInstance("traces-my_app-1", Collections.singletonList(new Index(".ds-ds3-000001", "ds3i")))
)
)
.build();
);
}
state = ClusterState.builder(state).metadata(metadataBuilder).build();
ClusterChangedEvent event = createClusterChangedEvent(nodes, state);
AtomicInteger rolloverCounter = new AtomicInteger(0);
AtomicInteger putIndexTemplateCounter = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> rolloverCounterMap = new ConcurrentHashMap<>();
Map<ProjectId, AtomicInteger> putIndexTemplateCounterMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action instanceof RolloverAction) {
final var rolloverCounter = rolloverCounterMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
rolloverCounter.incrementAndGet();
RolloverRequest rolloverRequest = ((RolloverRequest) request);
assertThat(rolloverRequest.getRolloverTarget(), startsWith("logs-my_app-"));
} else if (action == TransportPutComposableIndexTemplateAction.TYPE) {
final var putIndexTemplateCounter = putIndexTemplateCounterMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
putIndexTemplateCounter.incrementAndGet();
}
return AcknowledgedResponse.TRUE;
@ -472,18 +512,18 @@ public class IndexTemplateRegistryTests extends ESTestCase {
registry.setApplyRollover(true);
registry.clusterChanged(event);
assertBusy(() -> assertThat(putIndexTemplateCounter.get(), equalTo(1)));
assertCalledTimes(putIndexTemplateCounterMap, event, 1);
// rollover should be triggered even for the first installation, since the template
// may now take precedence over a data stream's existing index template
assertBusy(() -> assertThat(rolloverCounter.get(), equalTo(2)));
assertCalledTimes(rolloverCounterMap, event, 2);
}
public void testThatTemplatesAreNotUpgradedWhenNotNeeded() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
// ignore this
return AcknowledgedResponse.TRUE;
@ -503,19 +543,20 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(0)));
assertCalledTimes(calledTimesMap, event, 0);
}
public void testThatNonExistingPoliciesAreAddedImmediately() throws Exception {
DiscoveryNode node = DiscoveryNodeUtils.create("node");
DiscoveryNodes nodes = DiscoveryNodes.builder().localNodeId("node").masterNodeId("node").add(node).build();
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
// ignore this
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutLifecycleAction(calledTimes, action, request, listener);
return AcknowledgedResponse.TRUE;
} else {
@ -531,7 +572,7 @@ public class IndexTemplateRegistryTests extends ESTestCase {
nodes
);
registry.clusterChanged(event);
assertBusy(() -> assertThat(calledTimes.get(), equalTo(registry.getLifecyclePolicies().size())));
assertCalledTimes(calledTimesMap, event, registry.getLifecyclePolicies().size());
}
public void testPolicyAlreadyExists() {
@ -543,7 +584,7 @@ public class IndexTemplateRegistryTests extends ESTestCase {
assertThat(policies, hasSize(1));
policies.forEach(p -> policyMap.put(p.getName(), p));
client.setVerifier((action, request, listener) -> {
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
// ignore this
return AcknowledgedResponse.TRUE;
@ -575,7 +616,7 @@ public class IndexTemplateRegistryTests extends ESTestCase {
assertThat(policies, hasSize(1));
policies.forEach(p -> policyMap.put(p.getName(), p));
client.setVerifier((action, request, listener) -> {
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
// ignore this
return AcknowledgedResponse.TRUE;
@ -627,12 +668,13 @@ public class IndexTemplateRegistryTests extends ESTestCase {
assertThat(policies, hasSize(1));
policies.forEach(p -> policyMap.put(p.getName(), p));
AtomicInteger calledTimes = new AtomicInteger(0);
client.setVerifier((action, request, listener) -> {
Map<ProjectId, AtomicInteger> calledTimesMap = new ConcurrentHashMap<>();
client.setVerifier((projectId, action, request, listener) -> {
if (action == TransportPutComposableIndexTemplateAction.TYPE) {
// ignore this
return AcknowledgedResponse.TRUE;
} else if (action == ILMActions.PUT) {
final var calledTimes = calledTimesMap.computeIfAbsent(projectId, k -> new AtomicInteger(0));
assertPutLifecycleAction(calledTimes, action, request, listener);
return AcknowledgedResponse.TRUE;
@ -669,7 +711,7 @@ public class IndexTemplateRegistryTests extends ESTestCase {
);
registry.clusterChanged(event);
// we've changed one policy that should be upgraded
assertBusy(() -> assertThat(calledTimes.get(), equalTo(1)));
assertCalledTimes(calledTimesMap, event, 1);
}
}
@ -749,6 +791,18 @@ public class IndexTemplateRegistryTests extends ESTestCase {
calledTimes.incrementAndGet();
}
private static void assertCalledTimes(Map<ProjectId, AtomicInteger> calledTimesMap, ClusterChangedEvent event, int expectedTimes)
throws Exception {
assertBusy(() -> {
if (expectedTimes > 0) {
assertThat(calledTimesMap.size(), equalTo(event.state().metadata().projects().size()));
}
for (var calledTimes : calledTimesMap.values()) {
assertThat(calledTimes.get(), equalTo(expectedTimes));
}
});
}
private ClusterChangedEvent createClusterChangedEvent(Map<String, Integer> existingTemplates, DiscoveryNodes nodes) {
return createClusterChangedEvent(existingTemplates, Collections.emptyMap(), Collections.emptyMap(), nodes);
}
@ -810,10 +864,21 @@ public class IndexTemplateRegistryTests extends ESTestCase {
return ClusterState.builder(new ClusterName("test"))
.metadata(
Metadata.builder()
.componentTemplates(componentTemplates)
.transientSettings(Settings.EMPTY)
.putCustom(IndexLifecycleMetadata.TYPE, ilmMeta)
.putCustom(IngestMetadata.TYPE, ingestMetadata)
.put(
ProjectMetadata.builder(Metadata.DEFAULT_PROJECT_ID)
.componentTemplates(componentTemplates)
.putCustom(IndexLifecycleMetadata.TYPE, ilmMeta)
.putCustom(IngestMetadata.TYPE, ingestMetadata)
.build()
)
.put(
ProjectMetadata.builder(projectId)
.componentTemplates(componentTemplates)
.putCustom(IndexLifecycleMetadata.TYPE, ilmMeta)
.putCustom(IngestMetadata.TYPE, ingestMetadata)
.build()
)
.build()
)
.blocks(new ClusterBlocks.Builder().build())
@ -872,7 +937,7 @@ public class IndexTemplateRegistryTests extends ESTestCase {
*/
public static class VerifyingClient extends NoOpClient {
private TriFunction<ActionType<?>, ActionRequest, ActionListener<?>, ActionResponse> verifier = (a, r, l) -> {
private Verifier verifier = (p, a, r, l) -> {
fail("verifier not set");
return null;
};
@ -889,15 +954,22 @@ public class IndexTemplateRegistryTests extends ESTestCase {
ActionListener<Response> listener
) {
try {
listener.onResponse((Response) verifier.apply(action, request, listener));
final ProjectId projectId = ProjectId.fromId(
threadPool().getThreadContext().getHeader(Task.X_ELASTIC_PROJECT_ID_HTTP_HEADER)
);
listener.onResponse((Response) verifier.verify(projectId, action, request, listener));
} catch (Exception e) {
listener.onFailure(e);
}
}
public VerifyingClient setVerifier(TriFunction<ActionType<?>, ActionRequest, ActionListener<?>, ActionResponse> verifier) {
public VerifyingClient setVerifier(Verifier verifier) {
this.verifier = verifier;
return this;
}
}
private interface Verifier {
ActionResponse verify(ProjectId projectId, ActionType<?> action, ActionRequest request, ActionListener<?> listener);
}
}

View file

@ -11,8 +11,11 @@ import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.metadata.ProjectId;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xcontent.XContentParserConfiguration;
@ -24,6 +27,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@ -35,17 +39,21 @@ class TestRegistryWithCustomPlugin extends IndexTemplateRegistry {
private final AtomicBoolean policyUpgradeRequired = new AtomicBoolean(false);
private final AtomicBoolean applyRollover = new AtomicBoolean(false);
private final AtomicReference<Collection<RolloverResponse>> rolloverResponses = new AtomicReference<>();
private final AtomicReference<Exception> rolloverFailure = new AtomicReference<>();
private final Map<ProjectId, AtomicReference<Collection<RolloverResponse>>> rolloverResponses = new ConcurrentHashMap<>();
private final Map<ProjectId, AtomicReference<Exception>> rolloverFailure = new ConcurrentHashMap<>();
private final ThreadPool threadPool;
TestRegistryWithCustomPlugin(
Settings nodeSettings,
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.threadPool = threadPool;
}
@Override
@ -128,19 +136,21 @@ class TestRegistryWithCustomPlugin extends IndexTemplateRegistry {
@Override
void onRolloversBulkResponse(Collection<RolloverResponse> rolloverResponses) {
this.rolloverResponses.set(rolloverResponses);
final var projectId = ProjectId.fromId(threadPool.getThreadContext().getHeader(Task.X_ELASTIC_PROJECT_ID_HTTP_HEADER));
this.rolloverResponses.computeIfAbsent(projectId, k -> new AtomicReference<>()).set(rolloverResponses);
}
public AtomicReference<Collection<RolloverResponse>> getRolloverResponses() {
public Map<ProjectId, AtomicReference<Collection<RolloverResponse>>> getRolloverResponses() {
return rolloverResponses;
}
@Override
void onRolloverFailure(Exception e) {
rolloverFailure.set(e);
final var projectId = ProjectId.fromId(threadPool.getThreadContext().getHeader(Task.X_ELASTIC_PROJECT_ID_HTTP_HEADER));
rolloverFailure.computeIfAbsent(projectId, k -> new AtomicReference<>()).set(e);
}
public AtomicReference<Exception> getRolloverFailure() {
public Map<ProjectId, AtomicReference<Exception>> getRolloverFailure() {
return rolloverFailure;
}

View file

@ -85,7 +85,8 @@ public class Deprecation extends Plugin implements ActionPlugin {
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
templateRegistry.initialize();

View file

@ -10,6 +10,7 @@ package org.elasticsearch.xpack.deprecation.logging;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -49,9 +50,10 @@ public class DeprecationIndexingTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
private static final Map<String, ComponentTemplate> COMPONENT_TEMPLATE_CONFIGS;

View file

@ -469,7 +469,8 @@ public class EnterpriseSearch extends Plugin implements ActionPlugin, SystemInde
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
analyticsTemplateRegistry.initialize();
@ -478,7 +479,8 @@ public class EnterpriseSearch extends Plugin implements ActionPlugin, SystemInde
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
connectorTemplateRegistry.initialize();

View file

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.application.analytics;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.UpdateForV10;
@ -105,9 +106,10 @@ public class AnalyticsTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry);
super(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -10,6 +10,7 @@ package org.elasticsearch.xpack.application.connector;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -144,9 +145,10 @@ public class ConnectorTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry);
super(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -25,6 +25,7 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.bytes.BytesArray;
@ -75,7 +76,13 @@ public class AnalyticsTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new AnalyticsTemplateRegistry(clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new AnalyticsTemplateRegistry(
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
}
@After

View file

@ -25,6 +25,7 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.bytes.BytesArray;
@ -78,7 +79,13 @@ public class ConnectorTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new ConnectorTemplateRegistry(clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new ConnectorTemplateRegistry(
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
}
@After

View file

@ -95,7 +95,8 @@ public class Fleet extends Plugin implements SystemIndexPlugin {
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
registry.initialize();
return List.of();

View file

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.fleet;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -67,9 +68,10 @@ public class FleetTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -235,7 +235,8 @@ public class SamlServiceProviderIndexTests extends ESSingleNodeTestCase {
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
indexTemplateRegistry.initialize();
return List.of(indexTemplateRegistry);

View file

@ -84,7 +84,8 @@ public class IdentityProviderPlugin extends Plugin implements ActionPlugin {
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
indexTemplateRegistry.initialize();

View file

@ -8,6 +8,7 @@
package org.elasticsearch.xpack.idp.saml.sp;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -31,9 +32,10 @@ public class SamlServiceProviderIndexTemplateRegistry extends IndexTemplateRegis
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -146,7 +146,8 @@ public class IndexLifecycle extends Plugin implements ActionPlugin, HealthPlugin
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
ilmTemplateRegistry.initialize();
ilmHistoryStore.set(

View file

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.ilm.history;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -55,9 +56,10 @@ public class ILMHistoryTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.ilmHistoryEnabled = LifecycleSettings.LIFECYCLE_HISTORY_INDEX_ENABLED_SETTING.get(nodeSettings);
}

View file

@ -25,6 +25,7 @@ import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.LifecycleExecutionState;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.settings.ClusterSettings;
@ -80,7 +81,8 @@ public class ILMHistoryStoreTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
ClusterState state = clusterService.state();
ClusterServiceUtils.setState(

View file

@ -89,7 +89,8 @@ public class MigratePlugin extends Plugin implements ActionPlugin, PersistentTas
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
registry.initialize();
return List.of(registry);

View file

@ -7,6 +7,7 @@
package org.elasticsearch.xpack.migrate;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -31,9 +32,10 @@ public class MigrateTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -937,7 +937,8 @@ public class MachineLearning extends Plugin
threadPool,
client,
machineLearningExtension.get().useIlm(),
xContentRegistry
xContentRegistry,
services.projectResolver()
);
registry.initialize();

View file

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.ml;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -126,9 +127,10 @@ public class MlIndexTemplateRegistry extends IndexTemplateRegistry {
ThreadPool threadPool,
Client client,
boolean useIlm,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.useIlm = useIlm;
this.composableIndexTemplateConfigs = parseComposableTemplates(
anomalyDetectionResultsTemplate(),

View file

@ -20,6 +20,7 @@ import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.CollectionUtils;
@ -91,7 +92,8 @@ public class MlIndexTemplateRegistryTests extends ESTestCase {
threadPool,
client,
true,
xContentRegistry
xContentRegistry,
TestProjectResolvers.mustExecuteFirst()
);
registry.clusterChanged(createClusterChangedEvent(nodes));
@ -119,7 +121,8 @@ public class MlIndexTemplateRegistryTests extends ESTestCase {
threadPool,
client,
false,
xContentRegistry
xContentRegistry,
TestProjectResolvers.mustExecuteFirst()
);
registry.clusterChanged(createClusterChangedEvent(nodes));

View file

@ -162,7 +162,8 @@ public class Monitoring extends Plugin implements ActionPlugin, ReloadablePlugin
clusterService,
threadPool,
client,
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
templateRegistry.initialize();

View file

@ -11,6 +11,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
@ -243,9 +244,10 @@ public class MonitoringTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.clusterService = clusterService;
this.monitoringTemplatesEnabled = MONITORING_TEMPLATES_ENABLED.get(nodeSettings);
}

View file

@ -24,6 +24,7 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.settings.Setting;
@ -82,7 +83,14 @@ public class MonitoringTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new MonitoringTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new MonitoringTemplateRegistry(
Settings.EMPTY,
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
}
@After
@ -115,7 +123,8 @@ public class MonitoringTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
assertThat(disabledRegistry.getLegacyTemplateConfigs(), is(empty()));
assertThat(disabledRegistry.getComposableTemplateConfigs(), anEmptyMap());
@ -194,7 +203,8 @@ public class MonitoringTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
testRegistry.clusterChanged(event);
} else {

View file

@ -8,6 +8,7 @@
package org.elasticsearch.xpack.oteldata;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -26,9 +27,10 @@ public class OTelIndexTemplateRegistry extends YamlTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -48,7 +48,14 @@ public class OTelPlugin extends Plugin implements ActionPlugin {
Settings settings = services.environment().settings();
ClusterService clusterService = services.clusterService();
registry.set(
new OTelIndexTemplateRegistry(settings, clusterService, services.threadPool(), services.client(), services.xContentRegistry())
new OTelIndexTemplateRegistry(
settings,
clusterService,
services.threadPool(),
services.client(),
services.xContentRegistry(),
services.projectResolver()
)
);
if (enabled) {
OTelIndexTemplateRegistry registryInstance = registry.get();

View file

@ -97,7 +97,16 @@ public class ProfilingPlugin extends Plugin implements ActionPlugin {
ThreadPool threadPool = services.threadPool();
logger.info("Profiling is {}", enabled ? "enabled" : "disabled");
registry.set(new ProfilingIndexTemplateRegistry(settings, clusterService, threadPool, client, services.xContentRegistry()));
registry.set(
new ProfilingIndexTemplateRegistry(
settings,
clusterService,
threadPool,
client,
services.xContentRegistry(),
services.projectResolver()
)
);
indexStateResolver.set(new IndexStateResolver(PROFILING_CHECK_OUTDATED_INDICES.get(settings)));
clusterService.getClusterSettings().addSettingsUpdateConsumer(PROFILING_CHECK_OUTDATED_INDICES, this::updateCheckOutdatedIndices);

View file

@ -13,6 +13,7 @@ import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -79,9 +80,10 @@ public class ProfilingIndexTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
public void setTemplatesEnabled(boolean templatesEnabled) {

View file

@ -25,6 +25,7 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ClusterServiceUtils;
@ -76,7 +77,14 @@ public class ProfilingIndexTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new ProfilingIndexTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new ProfilingIndexTemplateRegistry(
Settings.EMPTY,
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
registry.setTemplatesEnabled(true);
}

View file

@ -128,7 +128,8 @@ public class SnapshotLifecycle extends Plugin implements ActionPlugin, HealthPlu
clusterService,
threadPool,
client,
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
templateRegistry.initialize();
snapshotHistoryStore.set(new SnapshotHistoryStore(new OriginSettingClient(client, INDEX_LIFECYCLE_ORIGIN), clusterService));

View file

@ -10,6 +10,7 @@ package org.elasticsearch.xpack.slm.history;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -62,9 +63,10 @@ public class SnapshotLifecycleTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
slmHistoryEnabled = SLM_HISTORY_INDEX_ENABLED_SETTING.get(nodeSettings);
}

View file

@ -23,6 +23,7 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.settings.Settings;
@ -100,7 +101,14 @@ public class SnapshotLifecycleTemplateRegistryTests extends ESTestCase {
)
);
xContentRegistry = new NamedXContentRegistry(entries);
registry = new SnapshotLifecycleTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry);
registry = new SnapshotLifecycleTemplateRegistry(
Settings.EMPTY,
clusterService,
threadPool,
client,
xContentRegistry,
TestProjectResolvers.mustExecuteFirst()
);
}
@After
@ -117,7 +125,8 @@ public class SnapshotLifecycleTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
xContentRegistry
xContentRegistry,
TestProjectResolvers.mustExecuteFirst()
);
assertThat(disabledRegistry.getComposableTemplateConfigs(), anEmptyMap());
assertThat(disabledRegistry.getLifecyclePolicies(), hasSize(0));

View file

@ -49,3 +49,15 @@ tasks.named("yamlRestCompatTestTransform") { task ->
task.skipTest("stack/10_basic/Test kibana reporting index auto creation", "warning does not exist for compatibility")
task.skipTest("cat.shards/10_basic/Help", "sync_id is removed in 9.0")
}
configurations {
basicRestSpecs {
attributes {
attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.DIRECTORY_TYPE)
}
}
}
artifacts {
basicRestSpecs(new File(projectDir, "src/yamlRestTest/resources/rest-api-spec/test"))
}

View file

@ -12,6 +12,7 @@ import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -91,9 +92,10 @@ public class LegacyStackTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.clusterService = clusterService;
this.stackTemplateEnabled = STACK_TEMPLATES_ENABLED.get(nodeSettings);
}

View file

@ -33,7 +33,8 @@ public class StackPlugin extends Plugin implements ActionPlugin {
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
legacyStackTemplateRegistry.initialize();
StackTemplateRegistry stackTemplateRegistry = new StackTemplateRegistry(
@ -41,7 +42,8 @@ public class StackPlugin extends Plugin implements ActionPlugin {
services.clusterService(),
services.threadPool(),
services.client(),
services.xContentRegistry()
services.xContentRegistry(),
services.projectResolver()
);
stackTemplateRegistry.initialize();
return List.of(legacyStackTemplateRegistry, stackTemplateRegistry);

View file

@ -12,6 +12,7 @@ import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
@ -118,9 +119,10 @@ public class StackTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
this.clusterService = clusterService;
this.stackTemplateEnabled = STACK_TEMPLATES_ENABLED.get(nodeSettings);
this.componentTemplateConfigs = loadComponentTemplateConfigs();

View file

@ -10,6 +10,7 @@ package org.elasticsearch.xpack.stack;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComponentTemplate;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.ingest.PipelineConfiguration;
@ -33,7 +34,14 @@ public class LegacyStackTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
Client client = new NoOpClient(threadPool);
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new LegacyStackTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new LegacyStackTemplateRegistry(
Settings.EMPTY,
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
}
@After

View file

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.stack;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -23,9 +24,10 @@ class StackRegistryWithNonRequiredTemplates extends StackTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
@Override

View file

@ -25,6 +25,7 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.TriFunction;
import org.elasticsearch.common.settings.Settings;
@ -84,7 +85,14 @@ public class StackTemplateRegistryTests extends ESTestCase {
threadPool = new TestThreadPool(this.getClass().getName());
client = new VerifyingClient(threadPool);
clusterService = ClusterServiceUtils.createClusterService(threadPool);
registry = new StackTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, NamedXContentRegistry.EMPTY);
registry = new StackTemplateRegistry(
Settings.EMPTY,
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
}
@After
@ -101,7 +109,8 @@ public class StackTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
assertThat(disabledRegistry.getComposableTemplateConfigs(), anEmptyMap());
}
@ -113,7 +122,8 @@ public class StackTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
assertThat(disabledRegistry.getComponentTemplateConfigs(), not(anEmptyMap()));
assertThat(
@ -357,7 +367,8 @@ public class StackTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
NamedXContentRegistry.EMPTY
NamedXContentRegistry.EMPTY,
TestProjectResolvers.mustExecuteFirst()
);
DiscoveryNode node = DiscoveryNodeUtils.create("node");

View file

@ -342,7 +342,8 @@ public class Watcher extends Plugin implements SystemIndexPlugin, ScriptPlugin,
clusterService,
threadPool,
client,
xContentRegistry
xContentRegistry,
services.projectResolver()
);
templateRegistry.initialize();

View file

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.watcher.support;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -37,9 +38,10 @@ public class WatcherIndexTemplateRegistry extends IndexTemplateRegistry {
ClusterService clusterService,
ThreadPool threadPool,
Client client,
NamedXContentRegistry xContentRegistry
NamedXContentRegistry xContentRegistry,
ProjectResolver projectResolver
) {
super(nodeSettings, clusterService, threadPool, client, xContentRegistry);
super(nodeSettings, clusterService, threadPool, client, xContentRegistry, projectResolver);
ilmManagementEnabled = Watcher.USE_ILM_INDEX_MANAGEMENT.get(nodeSettings);
}

View file

@ -24,6 +24,8 @@ import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.project.TestProjectResolvers;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.EsExecutors;
@ -80,6 +82,7 @@ public class WatcherIndexTemplateRegistryTests extends ESTestCase {
private ClusterService clusterService;
private ThreadPool threadPool;
private Client client;
private ProjectResolver projectResolver;
@SuppressWarnings("unchecked")
@Before
@ -114,7 +117,8 @@ public class WatcherIndexTemplateRegistryTests extends ESTestCase {
)
);
xContentRegistry = new NamedXContentRegistry(entries);
registry = new WatcherIndexTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry);
projectResolver = TestProjectResolvers.mustExecuteFirst();
registry = new WatcherIndexTemplateRegistry(Settings.EMPTY, clusterService, threadPool, client, xContentRegistry, projectResolver);
}
public void testThatNonExistingTemplatesAreAddedImmediately() {
@ -152,7 +156,8 @@ public class WatcherIndexTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
xContentRegistry
xContentRegistry,
projectResolver
);
ClusterChangedEvent event = createClusterChangedEvent(Settings.EMPTY, Collections.emptyMap(), Collections.emptyMap(), nodes);
registry.clusterChanged(event);
@ -204,7 +209,8 @@ public class WatcherIndexTemplateRegistryTests extends ESTestCase {
clusterService,
threadPool,
client,
xContentRegistry
xContentRegistry,
projectResolver
);
ClusterChangedEvent event = createClusterChangedEvent(Settings.EMPTY, Collections.emptyMap(), Collections.emptyMap(), nodes);
registry.clusterChanged(event);

View file

@ -10,6 +10,7 @@ dependencies {
testImplementation(testArtifact(project(":x-pack:plugin:security:qa:service-account"), "javaRestTest"))
restXpackTestConfig project(path: ':x-pack:plugin:ilm:qa:rest', configuration: "basicRestSpecs")
restXpackTestConfig project(path: ':x-pack:plugin:downsample:qa:rest', configuration: "basicRestSpecs")
restXpackTestConfig project(path: ':x-pack:plugin:stack', configuration: "basicRestSpecs")
}
// let the yamlRestTests see the classpath of test