4747import org .elasticsearch .index .mapper .MapperService ;
4848import org .elasticsearch .index .mapper .MapperService .MergeReason ;
4949import org .elasticsearch .index .mapper .RoutingFieldMapper ;
50- import org .elasticsearch .index .shard .IndexLongFieldRange ;
5150import org .elasticsearch .indices .IndexTemplateMissingException ;
5251import org .elasticsearch .indices .IndicesService ;
5352import org .elasticsearch .indices .InvalidIndexTemplateException ;
@@ -173,9 +172,12 @@ private abstract static class TemplateClusterStateUpdateTask implements ClusterS
173172 }
174173
175174 public final ClusterState execute (ClusterState currentState ) throws Exception {
176- ProjectMetadata metadata = currentState .metadata ().getProject (projectId );
177- ProjectMetadata newMetadata = execute (metadata );
178- return metadata == newMetadata ? currentState : ClusterState .builder (currentState ).putProjectMetadata (newMetadata ).build ();
175+ ProjectMetadata currentProject = currentState .metadata ().getProject (projectId );
176+ ProjectMetadata newProject = execute (currentProject );
177+ if (currentProject == newProject ) {
178+ return currentState ;
179+ }
180+ return ClusterState .builder (currentState ).metadata (currentState .metadata ().withUpdatedProject (newProject )).build ();
179181 }
180182
181183 public abstract ProjectMetadata execute (ProjectMetadata currentProject ) throws Exception ;
@@ -384,19 +386,17 @@ public ProjectMetadata addComponentTemplate(
384386 }
385387
386388 validateTemplate (finalSettings , wrappedMappings , indicesService );
387- validate (name , finalComponentTemplate );
389+ validate (name , finalComponentTemplate . template (), List . of (), null );
388390
391+ ProjectMetadata projectWithComponentTemplateAdded = ProjectMetadata .builder (project ).put (name , finalComponentTemplate ).build ();
389392 // Validate all composable index templates that use this component template
390- if (templatesUsingComponent .size () > 0 ) {
391- ProjectMetadata tempProjectWithComponentTemplateAdded = ProjectMetadata .builder (project )
392- .put (name , finalComponentTemplate )
393- .build ();
393+ if (templatesUsingComponent .isEmpty () == false ) {
394394 Exception validationFailure = null ;
395395 for (Map .Entry <String , ComposableIndexTemplate > entry : templatesUsingComponent .entrySet ()) {
396396 final String composableTemplateName = entry .getKey ();
397397 final ComposableIndexTemplate composableTemplate = entry .getValue ();
398398 try {
399- validateIndexTemplateV2 (tempProjectWithComponentTemplateAdded , composableTemplateName , composableTemplate );
399+ validateIndexTemplateV2 (projectWithComponentTemplateAdded , composableTemplateName , composableTemplate );
400400 } catch (Exception e ) {
401401 if (validationFailure == null ) {
402402 validationFailure = new IllegalArgumentException (
@@ -426,7 +426,7 @@ public ProjectMetadata addComponentTemplate(
426426 }
427427
428428 logger .info ("{} component template [{}]" , existing == null ? "adding" : "updating" , name );
429- return ProjectMetadata . builder ( project ). put ( name , finalComponentTemplate ). build () ;
429+ return projectWithComponentTemplateAdded ;
430430 }
431431
432432 /**
@@ -784,8 +784,9 @@ void validateIndexTemplateV2(ProjectMetadata projectMetadata, String name, Compo
784784 var finalTemplate = indexTemplate .template ();
785785 final var now = instantSource .instant ();
786786
787- final var combinedMappings = collectMappings (indexTemplate , projectMetadata .componentTemplates (), "tmp_idx" );
788- final var combinedSettings = resolveSettings (indexTemplate , projectMetadata .componentTemplates ());
787+ final var componentTemplates = projectMetadata .componentTemplates ();
788+ final var combinedMappings = collectMappings (indexTemplate , componentTemplates , "tmp_idx" );
789+ final var combinedSettings = resolveSettings (indexTemplate , componentTemplates );
789790 var additionalSettingsBuilder = Settings .builder ();
790791 ImmutableOpenMap .Builder <String , Map <String , String >> customMetadataBuilder = ImmutableOpenMap .builder ();
791792 for (var provider : indexSettingProviders ) {
@@ -820,11 +821,11 @@ void validateIndexTemplateV2(ProjectMetadata projectMetadata, String name, Compo
820821
821822 validate (name , templateToValidate , additionalSettings );
822823 validateDataStreamsStillReferenced (projectMetadata , name , templateToValidate );
823- validateLifecycle (projectMetadata , name , templateToValidate , globalRetentionSettings .get (false ));
824- validateDataStreamOptions (projectMetadata , name , templateToValidate , globalRetentionSettings .get (true ));
824+ validateLifecycle (componentTemplates , name , templateToValidate , globalRetentionSettings .get (false ));
825+ validateDataStreamOptions (componentTemplates , name , templateToValidate , globalRetentionSettings .get (true ));
825826
826827 if (templateToValidate .isDeprecated () == false ) {
827- validateUseOfDeprecatedComponentTemplates (name , templateToValidate , projectMetadata . componentTemplates () );
828+ validateUseOfDeprecatedComponentTemplates (name , templateToValidate , componentTemplates );
828829 validateUseOfDeprecatedIngestPipelines (name , projectMetadata .custom (IngestMetadata .TYPE ), combinedSettings );
829830 // TODO come up with a plan how to validate usage of deprecated ILM policies
830831 // we don't have access to the core/main plugin here so we can't use the IndexLifecycleMetadata type
@@ -900,12 +901,12 @@ private void emitWarningIfPipelineIsDeprecated(String name, Map<String, Pipeline
900901
901902 // Visible for testing
902903 static void validateLifecycle (
903- ProjectMetadata project ,
904+ Map < String , ComponentTemplate > componentTemplates ,
904905 String indexTemplateName ,
905906 ComposableIndexTemplate template ,
906907 @ Nullable DataStreamGlobalRetention globalRetention
907908 ) {
908- DataStreamLifecycle .Builder builder = resolveLifecycle (template , project . componentTemplates () );
909+ DataStreamLifecycle .Builder builder = resolveLifecycle (template , componentTemplates );
909910 if (builder != null ) {
910911 if (template .getDataStreamTemplate () == null ) {
911912 throw new IllegalArgumentException (
@@ -925,12 +926,12 @@ static void validateLifecycle(
925926
926927 // Visible for testing
927928 static void validateDataStreamOptions (
928- ProjectMetadata projectMetadata ,
929+ Map < String , ComponentTemplate > componentTemplates ,
929930 String indexTemplateName ,
930931 ComposableIndexTemplate template ,
931932 DataStreamGlobalRetention globalRetention
932933 ) {
933- DataStreamOptions .Builder dataStreamOptionsBuilder = resolveDataStreamOptions (template , projectMetadata . componentTemplates () );
934+ DataStreamOptions .Builder dataStreamOptionsBuilder = resolveDataStreamOptions (template , componentTemplates );
934935 if (dataStreamOptionsBuilder != null ) {
935936 if (template .getDataStreamTemplate () == null ) {
936937 throw new IllegalArgumentException (
@@ -971,18 +972,18 @@ private static void validateDataStreamsStillReferenced(
971972 .map (Map .Entry ::getKey )
972973 .collect (Collectors .toSet ());
973974
974- Function <ProjectMetadata , Set <String >> findUnreferencedDataStreams = meta -> {
975+ Function <Map < String , ComposableIndexTemplate >, Set <String >> findUnreferencedDataStreams = composableTemplates -> {
975976 final Set <String > unreferenced = new HashSet <>();
976977 // For each data stream that we have, see whether it's covered by a different
977978 // template (which is great), or whether it's now uncovered by any template
978979 for (String dataStream : dataStreams ) {
979- final String matchingTemplate = findV2Template (meta , dataStream , false );
980+ final String matchingTemplate = findV2Template (project , composableTemplates . entrySet (), dataStream , false , false );
980981 if (matchingTemplate == null ) {
981982 unreferenced .add (dataStream );
982983 } else {
983984 // We found a template that still matches, great! Buuuuttt... check whether it
984985 // is a data stream template, as it's only useful if it has a data stream definition
985- if (meta . templatesV2 () .get (matchingTemplate ).getDataStreamTemplate () == null ) {
986+ if (composableTemplates .get (matchingTemplate ).getDataStreamTemplate () == null ) {
986987 unreferenced .add (dataStream );
987988 }
988989 }
@@ -991,12 +992,13 @@ private static void validateDataStreamsStillReferenced(
991992 };
992993
993994 // Find data streams that are currently unreferenced
994- final Set <String > currentlyUnreferenced = findUnreferencedDataStreams .apply (project );
995+ final Set <String > currentlyUnreferenced = findUnreferencedDataStreams .apply (project . templatesV2 () );
995996
996- // Generate a metadata as if the new template were actually in the cluster state
997- final ProjectMetadata updatedMetadata = ProjectMetadata .builder (project ).put (templateName , newTemplate ).build ();
997+ // Generate a map as if the new template were actually in the cluster state
998+ final var updatedTemplatesMap = new HashMap <>(project .templatesV2 ());
999+ updatedTemplatesMap .put (templateName , newTemplate );
9981000 // Find the data streams that would be unreferenced now that the template is updated/added
999- final Set <String > newlyUnreferenced = findUnreferencedDataStreams .apply (updatedMetadata );
1001+ final Set <String > newlyUnreferenced = findUnreferencedDataStreams .apply (updatedTemplatesMap );
10001002
10011003 // If we found any data streams that used to be covered, but will no longer be covered by
10021004 // changing this template, then blow up with as much helpful information as we can muster
@@ -1226,7 +1228,7 @@ static Set<String> dataStreamsExclusivelyUsingTemplates(final ProjectMetadata pr
12261228 return candidates .stream ()
12271229 .noneMatch (
12281230 template -> templateNames .contains (template .v1 ()) == false
1229- && isGlobalAndHasIndexHiddenSetting (projectMetadata , template .v2 (), template . v1 ()) == false
1231+ && isGlobalAndHasIndexHiddenSetting (template .v2 (), projectMetadata . componentTemplates ()) == false
12301232 );
12311233 })
12321234 .map (DataStream ::getName )
@@ -1514,7 +1516,7 @@ private static String findV2Template(
15141516 // a restored index cluster state that modified a component template used by this global template such that it has this setting)
15151517 // we will fail and the user will have to update the index template and remove this setting or update the corresponding component
15161518 // template that contributes to the index template resolved settings
1517- if (isGlobalAndHasIndexHiddenSetting (projectMetadata , winner , winnerName )) {
1519+ if (isGlobalAndHasIndexHiddenSetting (winner , projectMetadata . componentTemplates () )) {
15181520 throw new IllegalStateException (
15191521 "global index template ["
15201522 + winnerName
@@ -1586,12 +1588,11 @@ private static boolean areTemplatesSorted(Collection<Map.Entry<String, Composabl
15861588 // Checks if a global template specifies the `index.hidden` setting. This check is important because a global
15871589 // template shouldn't specify the `index.hidden` setting, we leave it up to the caller to handle this situation.
15881590 private static boolean isGlobalAndHasIndexHiddenSetting (
1589- ProjectMetadata projectMetadata ,
15901591 ComposableIndexTemplate template ,
1591- String templateName
1592+ Map < String , ComponentTemplate > componentTemplates
15921593 ) {
15931594 return anyMatch (template .indexPatterns (), Regex ::isMatchAllPattern )
1594- && IndexMetadata .INDEX_HIDDEN_SETTING .exists (resolveSettings (projectMetadata , templateName ));
1595+ && IndexMetadata .INDEX_HIDDEN_SETTING .exists (resolveSettings (template , componentTemplates ));
15951596 }
15961597
15971598 /**
@@ -1962,10 +1963,8 @@ private static void validateCompositeTemplate(
19621963 final NamedXContentRegistry xContentRegistry ,
19631964 final SystemIndices systemIndices
19641965 ) throws Exception {
1965- final ProjectMetadata projectMetadataWithTemplate = ProjectMetadata .builder (project ).put (templateName , template ).build ();
1966-
19671966 final String temporaryIndexName = "validate-template-" + UUIDs .randomBase64UUID ().toLowerCase (Locale .ROOT );
1968- Settings resolvedSettings = resolveSettings (projectMetadataWithTemplate , templateName );
1967+ Settings resolvedSettings = resolveSettings (template , project . componentTemplates () );
19691968
19701969 // use the provided values, otherwise just pick valid dummy values
19711970 int dummyPartitionSize = IndexMetadata .INDEX_ROUTING_PARTITION_SIZE_SETTING .get (resolvedSettings );
@@ -1985,23 +1984,17 @@ private static void validateCompositeTemplate(
19851984 .build ();
19861985
19871986 // Validate index metadata (settings)
1988- final ProjectMetadata projectMetadataWithIndex = ProjectMetadata .builder (projectMetadataWithTemplate )
1989- .put (
1990- IndexMetadata .builder (temporaryIndexName )
1991- // necessary to pass asserts in ClusterState constructor
1992- .eventIngestedRange (IndexLongFieldRange .UNKNOWN )
1993- .settings (finalResolvedSettings )
1994- .putCustom (customMetadata )
1995- )
1987+ final IndexMetadata tmpIndexMetadata = IndexMetadata .builder (temporaryIndexName )
1988+ .settings (finalResolvedSettings )
1989+ .putCustom (customMetadata )
19961990 .build ();
1997- final IndexMetadata tmpIndexMetadata = projectMetadataWithIndex .index (temporaryIndexName );
19981991 indicesService .withTempIndexService (tmpIndexMetadata , tempIndexService -> {
19991992 // Validate aliases
20001993 MetadataCreateIndexService .resolveAndValidateAliases (
20011994 temporaryIndexName ,
20021995 Collections .emptySet (),
2003- MetadataIndexTemplateService .resolveAliases (projectMetadataWithIndex , templateName ),
2004- projectMetadataWithIndex ,
1996+ MetadataIndexTemplateService .resolveAliases (project , template ),
1997+ project ,
20051998 // the context is only used for validation so it's fine to pass fake values for the
20061999 // shard id and the current timestamp
20072000 xContentRegistry ,
@@ -2014,7 +2007,7 @@ private static void validateCompositeTemplate(
20142007 String indexName = DataStream .BACKING_INDEX_PREFIX + temporaryIndexName ;
20152008 // Parse mappings to ensure they are valid after being composed
20162009
2017- List <CompressedXContent > mappings = collectMappings (projectMetadataWithIndex , templateName , indexName );
2010+ List <CompressedXContent > mappings = collectMappings (template , project . componentTemplates () , indexName );
20182011 try {
20192012 MapperService mapperService = tempIndexService .mapperService ();
20202013 mapperService .merge (MapperService .SINGLE_MAPPING_NAME , mappings , MapperService .MergeReason .INDEX_TEMPLATE );
@@ -2061,10 +2054,6 @@ public static void validateTemplate(Settings validateSettings, CompressedXConten
20612054 });
20622055 }
20632056
2064- public void validate (String name , ComponentTemplate template ) {
2065- validate (name , template .template (), Collections .emptyList (), null );
2066- }
2067-
20682057 private void validate (String name , ComposableIndexTemplate template , @ Nullable Settings systemProvided ) {
20692058 validate (name , template .template (), template .indexPatterns (), systemProvided );
20702059 }
0 commit comments