Browse Source

Add support for marking component templates as deprecated (#101148)

Felix Barnsteiner 2 years ago
parent
commit
978a5469ce
23 changed files with 458 additions and 58 deletions
  1. 6 0
      docs/changelog/101148.yaml
  2. 6 0
      docs/reference/indices/put-component-template.asciidoc
  3. 6 0
      docs/reference/indices/put-index-template.asciidoc
  4. 6 0
      docs/reference/ingest/apis/put-pipeline.asciidoc
  5. 49 0
      rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.put_index_template/15_composition.yml
  6. 1 0
      server/src/main/java/org/elasticsearch/TransportVersions.java
  7. 6 1
      server/src/main/java/org/elasticsearch/action/admin/indices/template/put/TransportPutComponentTemplateAction.java
  8. 2 1
      server/src/main/java/org/elasticsearch/action/ingest/SimulateExecutionService.java
  9. 38 3
      server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplate.java
  10. 66 6
      server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java
  11. 66 3
      server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java
  12. 28 3
      server/src/main/java/org/elasticsearch/ingest/Pipeline.java
  13. 2 1
      server/src/main/java/org/elasticsearch/ingest/TrackingResultProcessor.java
  14. 30 8
      server/src/test/java/org/elasticsearch/cluster/metadata/ComponentTemplateTests.java
  15. 34 11
      server/src/test/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplateTests.java
  16. 28 4
      server/src/test/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateServiceTests.java
  17. 3 0
      server/src/test/java/org/elasticsearch/ingest/PipelineFactoryTests.java
  18. 12 3
      server/src/test/java/org/elasticsearch/ingest/PipelineProcessorTests.java
  19. 4 0
      test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
  20. 43 7
      x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicy.java
  21. 9 5
      x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyTests.java
  22. 2 1
      x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/cluster/metadata/MetadataMigrateToDataTiersRoutingService.java
  23. 11 1
      x-pack/plugin/profiling/src/test/java/org/elasticsearch/xpack/profiling/ProfilingIndexTemplateRegistryTests.java

+ 6 - 0
docs/changelog/101148.yaml

@@ -0,0 +1,6 @@
+pr: 101148
+summary: Add support for marking component templates as deprecated
+area: Indices APIs
+type: enhancement
+issues:
+ - 100992

+ 6 - 0
docs/reference/indices/put-component-template.asciidoc

@@ -169,6 +169,12 @@ created.
 Optional user metadata about the component template. May have any contents.
 This map is not automatically generated by {es}.
 
+`deprecated`::
+(Optional, boolean)
+Marks this component template as deprecated.
+When a deprecated component template is referenced when creating or updating a non-deprecated index template,
+{es} will emit a deprecation warning.
+
 [[put-component-template-api-example]]
 ==== {api-examples-title}
 

+ 6 - 0
docs/reference/indices/put-index-template.asciidoc

@@ -167,6 +167,12 @@ include::{docdir}/rest-api/common-parms.asciidoc[tag=settings]
 (Optional, integer)
 Version number used to manage index templates externally.
 This number is not automatically generated by {es}.
+
+`deprecated`::
+(Optional, boolean)
+Marks this index template as deprecated.
+When creating or updating a non-deprecated index template that uses deprecated components,
+{es} will emit a deprecation warning.
 // end::index-template-api-body[]
 
 [[put-index-template-api-example]]

+ 6 - 0
docs/reference/ingest/apis/put-pipeline.asciidoc

@@ -94,6 +94,12 @@ how the version attribute is used.
 (Optional, object)
 Optional metadata about the ingest pipeline. May have any contents. This
 map is not automatically generated by {es}.
+
+`deprecated`::
+(Optional, boolean)
+Marks this ingest pipeline as deprecated.
+When a deprecated ingest pipeline is referenced as the default or final pipeline when creating or updating a non-deprecated index template,
+{es} will emit a deprecation warning.
 // end::pipeline-object[]
 
 [[put-pipeline-api-example]]

+ 49 - 0
rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.put_index_template/15_composition.yml

@@ -492,3 +492,52 @@
         index: test-generic
   - match: { test-generic.mappings.properties.field.type: "keyword" }
   - match: { test-generic.mappings.properties.field.ignore_above: 1024 }
+---
+"Using deprecated component templates and pipelines in index template":
+  - skip:
+      version: ' - 8.11.99'
+      reason: 'The deprecated flags have been introduced in 8.12.0'
+      features: allowed_warnings
+
+  - do:
+      cluster.put_component_template:
+        name: mapping
+        body:
+          template:
+            mappings:
+              properties:
+                field:
+                  type: long
+          deprecated: true
+
+  - do:
+      ingest.put_pipeline:
+        id: "my_deprecated_pipeline"
+        body:
+          deprecated: true
+          processors: []
+  - match: { acknowledged: true }
+
+  - do:
+      cluster.put_component_template:
+        name: setting
+        body:
+          template:
+            settings:
+              index:
+                default_pipeline: my_deprecated_pipeline
+
+  - do:
+      allowed_warnings:
+        - "index template [test-composable-template] has index patterns [test-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [test-composable-template] will take precedence during new index creation"
+        - "index template [test-composable-template] uses deprecated component template [mapping]"
+        - "index template [test-composable-template] uses deprecated ingest pipeline [my_deprecated_pipeline]"
+      indices.put_index_template:
+        name: test-composable-template
+        body:
+          index_patterns:
+            - test-*
+          composed_of:
+            - mapping
+            - setting
+  - is_true: acknowledged

+ 1 - 0
server/src/main/java/org/elasticsearch/TransportVersions.java

@@ -160,6 +160,7 @@ public class TransportVersions {
     public static final TransportVersion KNN_AS_QUERY_ADDED = def(8_529_00_0);
     public static final TransportVersion UNDESIRED_SHARD_ALLOCATIONS_COUNT_ADDED = def(8_530_00_0);
     public static final TransportVersion ML_INFERENCE_TASK_SETTINGS_OPTIONAL_ADDED = def(8_531_00_0);
+    public static final TransportVersion DEPRECATED_COMPONENT_TEMPLATES_ADDED = def(8_532_00_0);
 
     /*
      * STOP! READ THIS FIRST! No, really,

+ 6 - 1
server/src/main/java/org/elasticsearch/action/admin/indices/template/put/TransportPutComponentTemplateAction.java

@@ -78,7 +78,12 @@ public class TransportPutComponentTemplateAction extends AcknowledgedTransportMa
             Settings settings = builder.build();
             indexScopedSettings.validate(settings, true);
             template = new Template(settings, template.mappings(), template.aliases(), template.lifecycle());
-            componentTemplate = new ComponentTemplate(template, componentTemplate.version(), componentTemplate.metadata());
+            componentTemplate = new ComponentTemplate(
+                template,
+                componentTemplate.version(),
+                componentTemplate.metadata(),
+                componentTemplate.deprecated()
+            );
         }
 
         return componentTemplate;

+ 2 - 1
server/src/main/java/org/elasticsearch/action/ingest/SimulateExecutionService.java

@@ -46,7 +46,8 @@ class SimulateExecutionService {
                 pipeline.getDescription(),
                 pipeline.getVersion(),
                 pipeline.getMetadata(),
-                verbosePipelineProcessor
+                verbosePipelineProcessor,
+                pipeline.getDeprecated()
             );
             ingestDocument.executePipeline(verbosePipeline, (result, e) -> {
                 handler.accept(new SimulateDocumentVerboseResult(processorResultList), e);

+ 38 - 3
server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplate.java

@@ -8,6 +8,7 @@
 
 package org.elasticsearch.cluster.metadata;
 
+import org.elasticsearch.TransportVersions;
 import org.elasticsearch.action.admin.indices.rollover.RolloverConfiguration;
 import org.elasticsearch.cluster.Diff;
 import org.elasticsearch.cluster.SimpleDiffable;
@@ -35,18 +36,20 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
     private static final ParseField TEMPLATE = new ParseField("template");
     private static final ParseField VERSION = new ParseField("version");
     private static final ParseField METADATA = new ParseField("_meta");
+    private static final ParseField DEPRECATED = new ParseField("deprecated");
 
     @SuppressWarnings("unchecked")
     public static final ConstructingObjectParser<ComponentTemplate, Void> PARSER = new ConstructingObjectParser<>(
         "component_template",
         false,
-        a -> new ComponentTemplate((Template) a[0], (Long) a[1], (Map<String, Object>) a[2])
+        a -> new ComponentTemplate((Template) a[0], (Long) a[1], (Map<String, Object>) a[2], (Boolean) a[3])
     );
 
     static {
         PARSER.declareObject(ConstructingObjectParser.constructorArg(), Template.PARSER, TEMPLATE);
         PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), VERSION);
         PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.map(), METADATA);
+        PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), DEPRECATED);
     }
 
     private final Template template;
@@ -54,6 +57,8 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
     private final Long version;
     @Nullable
     private final Map<String, Object> metadata;
+    @Nullable
+    private final Boolean deprecated;
 
     static Diff<ComponentTemplate> readComponentTemplateDiffFrom(StreamInput in) throws IOException {
         return SimpleDiffable.readDiffFrom(ComponentTemplate::new, in);
@@ -64,9 +69,19 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
     }
 
     public ComponentTemplate(Template template, @Nullable Long version, @Nullable Map<String, Object> metadata) {
+        this(template, version, metadata, null);
+    }
+
+    public ComponentTemplate(
+        Template template,
+        @Nullable Long version,
+        @Nullable Map<String, Object> metadata,
+        @Nullable Boolean deprecated
+    ) {
         this.template = template;
         this.version = version;
         this.metadata = metadata;
+        this.deprecated = deprecated;
     }
 
     public ComponentTemplate(StreamInput in) throws IOException {
@@ -77,6 +92,11 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
         } else {
             this.metadata = null;
         }
+        if (in.getTransportVersion().onOrAfter(TransportVersions.DEPRECATED_COMPONENT_TEMPLATES_ADDED)) {
+            this.deprecated = in.readOptionalBoolean();
+        } else {
+            deprecated = null;
+        }
     }
 
     public Template template() {
@@ -93,6 +113,14 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
         return metadata;
     }
 
+    public Boolean deprecated() {
+        return deprecated;
+    }
+
+    public boolean isDeprecated() {
+        return Boolean.TRUE.equals(deprecated);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         this.template.writeTo(out);
@@ -103,11 +131,14 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
             out.writeBoolean(true);
             out.writeGenericMap(this.metadata);
         }
+        if (out.getTransportVersion().onOrAfter(TransportVersions.DEPRECATED_COMPONENT_TEMPLATES_ADDED)) {
+            out.writeOptionalBoolean(this.deprecated);
+        }
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(template, version, metadata);
+        return Objects.hash(template, version, metadata, deprecated);
     }
 
     @Override
@@ -121,7 +152,8 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
         ComponentTemplate other = (ComponentTemplate) obj;
         return Objects.equals(template, other.template)
             && Objects.equals(version, other.version)
-            && Objects.equals(metadata, other.metadata);
+            && Objects.equals(metadata, other.metadata)
+            && Objects.equals(deprecated, other.deprecated);
     }
 
     @Override
@@ -148,6 +180,9 @@ public class ComponentTemplate implements SimpleDiffable<ComponentTemplate>, ToX
         if (this.metadata != null) {
             builder.field(METADATA.getPreferredName(), this.metadata);
         }
+        if (this.deprecated != null) {
+            builder.field(DEPRECATED.getPreferredName(), this.deprecated);
+        }
         builder.endObject();
         return builder;
     }

+ 66 - 6
server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java

@@ -46,6 +46,7 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
     private static final ParseField DATA_STREAM = new ParseField("data_stream");
     private static final ParseField ALLOW_AUTO_CREATE = new ParseField("allow_auto_create");
     private static final ParseField IGNORE_MISSING_COMPONENT_TEMPLATES = new ParseField("ignore_missing_component_templates");
+    private static final ParseField DEPRECATED = new ParseField("deprecated");
 
     @SuppressWarnings("unchecked")
     public static final ConstructingObjectParser<ComposableIndexTemplate, Void> PARSER = new ConstructingObjectParser<>(
@@ -60,7 +61,8 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
             (Map<String, Object>) a[5],
             (DataStreamTemplate) a[6],
             (Boolean) a[7],
-            (List<String>) a[8]
+            (List<String>) a[8],
+            (Boolean) a[9]
         )
     );
 
@@ -74,6 +76,7 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), DataStreamTemplate.PARSER, DATA_STREAM);
         PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), ALLOW_AUTO_CREATE);
         PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), IGNORE_MISSING_COMPONENT_TEMPLATES);
+        PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), DEPRECATED);
     }
 
     private final List<String> indexPatterns;
@@ -93,6 +96,8 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
     private final Boolean allowAutoCreate;
     @Nullable
     private final List<String> ignoreMissingComponentTemplates;
+    @Nullable
+    private final Boolean deprecated;
 
     static Diff<ComposableIndexTemplate> readITV2DiffFrom(StreamInput in) throws IOException {
         return SimpleDiffable.readDiffFrom(ComposableIndexTemplate::new, in);
@@ -135,10 +140,10 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         @Nullable DataStreamTemplate dataStreamTemplate,
         @Nullable Boolean allowAutoCreate
     ) {
-        this(indexPatterns, template, componentTemplates, priority, version, metadata, dataStreamTemplate, null, null);
+        this(indexPatterns, template, componentTemplates, priority, version, metadata, dataStreamTemplate, allowAutoCreate, null);
     }
 
-    public ComposableIndexTemplate(
+    ComposableIndexTemplate(
         List<String> indexPatterns,
         @Nullable Template template,
         @Nullable List<String> componentTemplates,
@@ -148,6 +153,32 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         @Nullable DataStreamTemplate dataStreamTemplate,
         @Nullable Boolean allowAutoCreate,
         @Nullable List<String> ignoreMissingComponentTemplates
+    ) {
+        this(
+            indexPatterns,
+            template,
+            componentTemplates,
+            priority,
+            version,
+            metadata,
+            dataStreamTemplate,
+            allowAutoCreate,
+            ignoreMissingComponentTemplates,
+            null
+        );
+    }
+
+    public ComposableIndexTemplate(
+        List<String> indexPatterns,
+        @Nullable Template template,
+        @Nullable List<String> componentTemplates,
+        @Nullable Long priority,
+        @Nullable Long version,
+        @Nullable Map<String, Object> metadata,
+        @Nullable DataStreamTemplate dataStreamTemplate,
+        @Nullable Boolean allowAutoCreate,
+        @Nullable List<String> ignoreMissingComponentTemplates,
+        @Nullable Boolean deprecated
     ) {
         this.indexPatterns = indexPatterns;
         this.template = template;
@@ -158,6 +189,7 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         this.dataStreamTemplate = dataStreamTemplate;
         this.allowAutoCreate = allowAutoCreate;
         this.ignoreMissingComponentTemplates = ignoreMissingComponentTemplates;
+        this.deprecated = deprecated;
     }
 
     public ComposableIndexTemplate(StreamInput in) throws IOException {
@@ -178,6 +210,11 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         } else {
             this.ignoreMissingComponentTemplates = null;
         }
+        if (in.getTransportVersion().onOrAfter(TransportVersions.DEPRECATED_COMPONENT_TEMPLATES_ADDED)) {
+            this.deprecated = in.readOptionalBoolean();
+        } else {
+            this.deprecated = null;
+        }
     }
 
     public List<String> indexPatterns() {
@@ -250,6 +287,14 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         return ignoreMissingComponentTemplates;
     }
 
+    public Boolean deprecated() {
+        return deprecated;
+    }
+
+    public boolean isDeprecated() {
+        return Boolean.TRUE.equals(deprecated);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeStringCollection(this.indexPatterns);
@@ -268,6 +313,9 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         if (out.getTransportVersion().onOrAfter(TransportVersions.V_8_7_0)) {
             out.writeOptionalStringCollection(ignoreMissingComponentTemplates);
         }
+        if (out.getTransportVersion().onOrAfter(TransportVersions.DEPRECATED_COMPONENT_TEMPLATES_ADDED)) {
+            out.writeOptionalBoolean(deprecated);
+        }
     }
 
     @Override
@@ -307,6 +355,9 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         if (this.ignoreMissingComponentTemplates != null) {
             builder.stringListField(IGNORE_MISSING_COMPONENT_TEMPLATES.getPreferredName(), ignoreMissingComponentTemplates);
         }
+        if (this.deprecated != null) {
+            builder.field(DEPRECATED.getPreferredName(), deprecated);
+        }
         builder.endObject();
         return builder;
     }
@@ -322,7 +373,8 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
             this.metadata,
             this.dataStreamTemplate,
             this.allowAutoCreate,
-            this.ignoreMissingComponentTemplates
+            this.ignoreMissingComponentTemplates,
+            this.deprecated
         );
     }
 
@@ -343,7 +395,8 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
             && Objects.equals(this.metadata, other.metadata)
             && Objects.equals(this.dataStreamTemplate, other.dataStreamTemplate)
             && Objects.equals(this.allowAutoCreate, other.allowAutoCreate)
-            && Objects.equals(this.ignoreMissingComponentTemplates, other.ignoreMissingComponentTemplates);
+            && Objects.equals(this.ignoreMissingComponentTemplates, other.ignoreMissingComponentTemplates)
+            && Objects.equals(deprecated, other.deprecated);
     }
 
     static boolean componentTemplatesEquals(List<String> c1, List<String> c2) {
@@ -480,6 +533,7 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
         private DataStreamTemplate dataStreamTemplate;
         private Boolean allowAutoCreate;
         private List<String> ignoreMissingComponentTemplates;
+        private Boolean deprecated;
 
         public Builder() {}
 
@@ -528,6 +582,11 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
             return this;
         }
 
+        public Builder deprecated(@Nullable Boolean deprecated) {
+            this.deprecated = deprecated;
+            return this;
+        }
+
         public ComposableIndexTemplate build() {
             return new ComposableIndexTemplate(
                 this.indexPatterns,
@@ -538,7 +597,8 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
                 this.metadata,
                 this.dataStreamTemplate,
                 this.allowAutoCreate,
-                this.ignoreMissingComponentTemplates
+                this.ignoreMissingComponentTemplates,
+                this.deprecated
             );
         }
     }

+ 66 - 3
server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java

@@ -28,6 +28,8 @@ import org.elasticsearch.common.UUIDs;
 import org.elasticsearch.common.ValidationException;
 import org.elasticsearch.common.compress.CompressedXContent;
 import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.logging.DeprecationCategory;
+import org.elasticsearch.common.logging.DeprecationLogger;
 import org.elasticsearch.common.logging.HeaderWarning;
 import org.elasticsearch.common.regex.Regex;
 import org.elasticsearch.common.settings.IndexScopedSettings;
@@ -50,6 +52,8 @@ import org.elasticsearch.indices.IndexTemplateMissingException;
 import org.elasticsearch.indices.IndicesService;
 import org.elasticsearch.indices.InvalidIndexTemplateException;
 import org.elasticsearch.indices.SystemIndices;
+import org.elasticsearch.ingest.IngestMetadata;
+import org.elasticsearch.ingest.PipelineConfiguration;
 import org.elasticsearch.xcontent.NamedXContentRegistry;
 
 import java.io.IOException;
@@ -122,6 +126,7 @@ public class MetadataIndexTemplateService {
     }
 
     private static final Logger logger = LogManager.getLogger(MetadataIndexTemplateService.class);
+    private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(MetadataIndexTemplateService.class);
 
     private final ClusterService clusterService;
     private final MasterServiceTaskQueue<TemplateClusterStateUpdateTask> taskQueue;
@@ -304,7 +309,12 @@ public class MetadataIndexTemplateService {
             template.template().aliases(),
             template.template().lifecycle()
         );
-        final ComponentTemplate finalComponentTemplate = new ComponentTemplate(finalTemplate, template.version(), template.metadata());
+        final ComponentTemplate finalComponentTemplate = new ComponentTemplate(
+            finalTemplate,
+            template.version(),
+            template.metadata(),
+            template.deprecated()
+        );
 
         if (finalComponentTemplate.equals(existing)) {
             return currentState;
@@ -614,7 +624,8 @@ public class MetadataIndexTemplateService {
                 template.metadata(),
                 template.getDataStreamTemplate(),
                 template.getAllowAutoCreate(),
-                template.getIgnoreMissingComponentTemplates()
+                template.getIgnoreMissingComponentTemplates(),
+                template.deprecated()
             );
         }
 
@@ -716,13 +727,21 @@ public class MetadataIndexTemplateService {
             indexTemplate.metadata(),
             indexTemplate.getDataStreamTemplate(),
             indexTemplate.getAllowAutoCreate(),
-            indexTemplate.getIgnoreMissingComponentTemplates()
+            indexTemplate.getIgnoreMissingComponentTemplates(),
+            indexTemplate.deprecated()
         );
 
         validate(name, templateToValidate);
         validateDataStreamsStillReferenced(currentState, name, templateToValidate);
         validateLifecycleIsOnlyAppliedOnDataStreams(currentState.metadata(), name, templateToValidate);
 
+        if (templateToValidate.isDeprecated() == false) {
+            validateUseOfDeprecatedComponentTemplates(name, templateToValidate, currentState.metadata().componentTemplates());
+            validateUseOfDeprecatedIngestPipelines(name, currentState.metadata().custom(IngestMetadata.TYPE), combinedSettings);
+            // TODO come up with a plan how to validate usage of deprecated ILM policies
+            // we don't have access to the core/main plugin here so we can't use the IndexLifecycleMetadata type
+        }
+
         // Finally, right before adding the template, we need to ensure that the composite settings,
         // mappings, and aliases are valid after it's been composed with the component templates
         try {
@@ -739,6 +758,50 @@ public class MetadataIndexTemplateService {
         }
     }
 
+    private void validateUseOfDeprecatedComponentTemplates(
+        String name,
+        ComposableIndexTemplate template,
+        Map<String, ComponentTemplate> componentTemplates
+    ) {
+        template.composedOf()
+            .stream()
+            .map(ct -> Tuple.tuple(ct, componentTemplates.get(ct)))
+            .filter(ct -> Objects.nonNull(ct.v2()))
+            .filter(ct -> ct.v2().isDeprecated())
+            .forEach(
+                ct -> deprecationLogger.warn(
+                    DeprecationCategory.TEMPLATES,
+                    "use_of_deprecated_component_template",
+                    "index template [{}] uses deprecated component template [{}]",
+                    name,
+                    ct.v1()
+                )
+            );
+    }
+
+    private void validateUseOfDeprecatedIngestPipelines(String name, IngestMetadata ingestMetadata, Settings combinedSettings) {
+        Map<String, PipelineConfiguration> pipelines = Optional.ofNullable(ingestMetadata)
+            .map(IngestMetadata::getPipelines)
+            .orElse(Map.of());
+        emitWarningIfPipelineIsDeprecated(name, pipelines, combinedSettings.get("index.default_pipeline"));
+        emitWarningIfPipelineIsDeprecated(name, pipelines, combinedSettings.get("index.final_pipeline"));
+    }
+
+    private void emitWarningIfPipelineIsDeprecated(String name, Map<String, PipelineConfiguration> pipelines, String pipelineName) {
+        Optional.ofNullable(pipelineName)
+            .map(pipelines::get)
+            .filter(p -> Boolean.TRUE.equals(p.getConfigAsMap().get("deprecated")))
+            .ifPresent(
+                p -> deprecationLogger.warn(
+                    DeprecationCategory.TEMPLATES,
+                    "use_of_deprecated_ingest_pipeline",
+                    "index template [{}] uses deprecated ingest pipeline [{}]",
+                    name,
+                    p.getId()
+                )
+            );
+    }
+
     private static void validateLifecycleIsOnlyAppliedOnDataStreams(
         Metadata metadata,
         String indexTemplateName,

+ 28 - 3
server/src/main/java/org/elasticsearch/ingest/Pipeline.java

@@ -28,6 +28,7 @@ public final class Pipeline {
     public static final String VERSION_KEY = "version";
     public static final String ON_FAILURE_KEY = "on_failure";
     public static final String META_KEY = "_meta";
+    public static final String DEPRECATED_KEY = "deprecated";
 
     private final String id;
     @Nullable
@@ -39,6 +40,8 @@ public final class Pipeline {
     private final CompoundProcessor compoundProcessor;
     private final IngestMetric metrics;
     private final LongSupplier relativeTimeProvider;
+    @Nullable
+    private final Boolean deprecated;
 
     public Pipeline(
         String id,
@@ -47,7 +50,18 @@ public final class Pipeline {
         @Nullable Map<String, Object> metadata,
         CompoundProcessor compoundProcessor
     ) {
-        this(id, description, version, metadata, compoundProcessor, System::nanoTime);
+        this(id, description, version, metadata, compoundProcessor, null);
+    }
+
+    public Pipeline(
+        String id,
+        @Nullable String description,
+        @Nullable Integer version,
+        @Nullable Map<String, Object> metadata,
+        CompoundProcessor compoundProcessor,
+        @Nullable Boolean deprecated
+    ) {
+        this(id, description, version, metadata, compoundProcessor, System::nanoTime, deprecated);
     }
 
     // package private for testing
@@ -57,7 +71,8 @@ public final class Pipeline {
         @Nullable Integer version,
         @Nullable Map<String, Object> metadata,
         CompoundProcessor compoundProcessor,
-        LongSupplier relativeTimeProvider
+        LongSupplier relativeTimeProvider,
+        @Nullable Boolean deprecated
     ) {
         this.id = id;
         this.description = description;
@@ -66,6 +81,7 @@ public final class Pipeline {
         this.version = version;
         this.metrics = new IngestMetric();
         this.relativeTimeProvider = relativeTimeProvider;
+        this.deprecated = deprecated;
     }
 
     public static Pipeline create(
@@ -77,6 +93,7 @@ public final class Pipeline {
         String description = ConfigurationUtils.readOptionalStringProperty(null, null, config, DESCRIPTION_KEY);
         Integer version = ConfigurationUtils.readIntProperty(null, null, config, VERSION_KEY, null);
         Map<String, Object> metadata = ConfigurationUtils.readOptionalMap(null, null, config, META_KEY);
+        Boolean deprecated = ConfigurationUtils.readOptionalBooleanProperty(null, null, config, DEPRECATED_KEY);
         List<Map<String, Object>> processorConfigs = ConfigurationUtils.readList(null, null, config, PROCESSORS_KEY);
         List<Processor> processors = ConfigurationUtils.readProcessorConfigs(processorConfigs, scriptService, processorFactories);
         List<Map<String, Object>> onFailureProcessorConfigs = ConfigurationUtils.readOptionalList(null, null, config, ON_FAILURE_KEY);
@@ -97,7 +114,7 @@ public final class Pipeline {
             throw new ElasticsearchParseException("pipeline [" + id + "] cannot have an empty on_failure option defined");
         }
         CompoundProcessor compoundProcessor = new CompoundProcessor(false, processors, onFailureProcessors);
-        return new Pipeline(id, description, version, metadata, compoundProcessor);
+        return new Pipeline(id, description, version, metadata, compoundProcessor, deprecated);
     }
 
     /**
@@ -185,4 +202,12 @@ public final class Pipeline {
     public IngestMetric getMetrics() {
         return metrics;
     }
+
+    public Boolean getDeprecated() {
+        return deprecated;
+    }
+
+    public boolean isDeprecated() {
+        return Boolean.TRUE.equals(deprecated);
+    }
 }

+ 2 - 1
server/src/main/java/org/elasticsearch/ingest/TrackingResultProcessor.java

@@ -132,7 +132,8 @@ public final class TrackingResultProcessor implements Processor {
                         pipeline.getDescription(),
                         pipeline.getVersion(),
                         pipeline.getMetadata(),
-                        verbosePipelineProcessor
+                        verbosePipelineProcessor,
+                        pipeline.getDeprecated()
                     );
                     ingestDocument.executePipeline(verbosePipeline, handler);
                 }

+ 30 - 8
server/src/test/java/org/elasticsearch/cluster/metadata/ComponentTemplateTests.java

@@ -65,7 +65,17 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
         return randomInstance(false);
     }
 
+    // Deprecated component templates may lead to deprecation warnings when used in non-deprecated index templates
+    // to avoid test failures due to unexpected deprecation warnings, returns a non-deprecated instance
+    public static ComponentTemplate randomNonDeprecatedInstance() {
+        return randomInstance(false, randomFrom(Boolean.FALSE, null));
+    }
+
     public static ComponentTemplate randomInstance(boolean lifecycleAllowed) {
+        return randomInstance(lifecycleAllowed, randomOptionalBoolean());
+    }
+
+    public static ComponentTemplate randomInstance(boolean lifecycleAllowed, Boolean deprecated) {
         Settings settings = null;
         CompressedXContent mappings = null;
         Map<String, AliasMetadata> aliases = null;
@@ -88,7 +98,7 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
         if (randomBoolean()) {
             meta = randomMeta();
         }
-        return new ComponentTemplate(template, randomBoolean() ? null : randomNonNegativeLong(), meta);
+        return new ComponentTemplate(template, randomBoolean() ? null : randomNonNegativeLong(), meta, deprecated);
     }
 
     public static Map<String, AliasMetadata> randomAliases() {
@@ -136,7 +146,7 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
     }
 
     public static ComponentTemplate mutateTemplate(ComponentTemplate orig) {
-        return switch (randomIntBetween(0, 2)) {
+        return switch (randomIntBetween(0, 3)) {
             case 0 -> {
                 Template ot = orig.template();
                 yield switch (randomIntBetween(0, 3)) {
@@ -148,7 +158,8 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
                             ot.lifecycle()
                         ),
                         orig.version(),
-                        orig.metadata()
+                        orig.metadata(),
+                        orig.deprecated()
                     );
                     case 1 -> new ComponentTemplate(
                         new Template(
@@ -158,7 +169,8 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
                             ot.lifecycle()
                         ),
                         orig.version(),
-                        orig.metadata()
+                        orig.metadata(),
+                        orig.deprecated()
                     );
                     case 2 -> new ComponentTemplate(
                         new Template(
@@ -168,7 +180,8 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
                             ot.lifecycle()
                         ),
                         orig.version(),
-                        orig.metadata()
+                        orig.metadata(),
+                        orig.deprecated()
                     );
                     case 3 -> new ComponentTemplate(
                         new Template(
@@ -178,7 +191,8 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
                             randomValueOtherThan(ot.lifecycle(), DataStreamLifecycleTests::randomLifecycle)
                         ),
                         orig.version(),
-                        orig.metadata()
+                        orig.metadata(),
+                        orig.deprecated()
                     );
                     default -> throw new IllegalStateException("illegal randomization branch");
                 };
@@ -186,12 +200,20 @@ public class ComponentTemplateTests extends SimpleDiffableSerializationTestCase<
             case 1 -> new ComponentTemplate(
                 orig.template(),
                 randomValueOtherThan(orig.version(), ESTestCase::randomNonNegativeLong),
-                orig.metadata()
+                orig.metadata(),
+                orig.deprecated()
             );
             case 2 -> new ComponentTemplate(
                 orig.template(),
                 orig.version(),
-                randomValueOtherThan(orig.metadata(), ComponentTemplateTests::randomMeta)
+                randomValueOtherThan(orig.metadata(), ComponentTemplateTests::randomMeta),
+                orig.deprecated()
+            );
+            case 3 -> new ComponentTemplate(
+                orig.template(),
+                orig.version(),
+                orig.metadata(),
+                orig.isDeprecated() ? randomFrom(false, null) : true
             );
             default -> throw new IllegalStateException("illegal randomization branch");
         };

+ 34 - 11
server/src/test/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplateTests.java

@@ -92,8 +92,9 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
             randomBoolean() ? null : randomNonNegativeLong(),
             meta,
             dataStreamTemplate,
-            randomBoolean() ? null : randomBoolean(),
-            ignoreMissingComponentTemplates
+            randomOptionalBoolean(),
+            ignoreMissingComponentTemplates,
+            randomOptionalBoolean()
         );
     }
 
@@ -158,7 +159,7 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
     }
 
     public static ComposableIndexTemplate mutateTemplate(ComposableIndexTemplate orig) {
-        switch (randomIntBetween(0, 7)) {
+        switch (randomIntBetween(0, 8)) {
             case 0:
                 List<String> newIndexPatterns = randomValueOtherThan(
                     orig.indexPatterns(),
@@ -172,7 +173,9 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.version(),
                     orig.metadata(),
                     orig.getDataStreamTemplate(),
-                    null
+                    null,
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 1:
                 return new ComposableIndexTemplate(
@@ -187,7 +190,8 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.metadata(),
                     orig.getDataStreamTemplate(),
                     orig.getAllowAutoCreate(),
-                    orig.getIgnoreMissingComponentTemplates()
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 2:
                 List<String> newComposedOf = randomValueOtherThan(orig.composedOf(), () -> randomList(0, 10, () -> randomAlphaOfLength(5)));
@@ -200,7 +204,8 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.metadata(),
                     orig.getDataStreamTemplate(),
                     orig.getAllowAutoCreate(),
-                    orig.getIgnoreMissingComponentTemplates()
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 3:
                 return new ComposableIndexTemplate(
@@ -212,7 +217,8 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.metadata(),
                     orig.getDataStreamTemplate(),
                     orig.getAllowAutoCreate(),
-                    orig.getIgnoreMissingComponentTemplates()
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 4:
                 return new ComposableIndexTemplate(
@@ -224,7 +230,8 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.metadata(),
                     orig.getDataStreamTemplate(),
                     orig.getAllowAutoCreate(),
-                    orig.getIgnoreMissingComponentTemplates()
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 5:
                 return new ComposableIndexTemplate(
@@ -236,7 +243,8 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     randomValueOtherThan(orig.metadata(), ComposableIndexTemplateTests::randomMeta),
                     orig.getDataStreamTemplate(),
                     orig.getAllowAutoCreate(),
-                    orig.getIgnoreMissingComponentTemplates()
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 6:
                 return new ComposableIndexTemplate(
@@ -248,7 +256,8 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.metadata(),
                     randomValueOtherThan(orig.getDataStreamTemplate(), ComposableIndexTemplateTests::randomDataStreamTemplate),
                     orig.getAllowAutoCreate(),
-                    orig.getIgnoreMissingComponentTemplates()
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.deprecated()
                 );
             case 7:
                 List<String> ignoreMissingComponentTemplates = randomValueOtherThan(
@@ -264,7 +273,21 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
                     orig.metadata(),
                     orig.getDataStreamTemplate(),
                     orig.getAllowAutoCreate(),
-                    ignoreMissingComponentTemplates
+                    ignoreMissingComponentTemplates,
+                    orig.deprecated()
+                );
+            case 8:
+                return new ComposableIndexTemplate(
+                    orig.indexPatterns(),
+                    orig.template(),
+                    orig.composedOf(),
+                    orig.priority(),
+                    orig.version(),
+                    orig.metadata(),
+                    orig.getDataStreamTemplate(),
+                    orig.getAllowAutoCreate(),
+                    orig.getIgnoreMissingComponentTemplates(),
+                    orig.isDeprecated() ? randomFrom(false, null) : true
                 );
             default:
                 throw new IllegalStateException("illegal randomization branch");

+ 28 - 4
server/src/test/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateServiceTests.java

@@ -1016,7 +1016,7 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
         ClusterState state = ClusterState.EMPTY_STATE;
         assertNull(MetadataIndexTemplateService.findV2Template(state.metadata(), "index", randomBoolean()));
 
-        ComponentTemplate ct = ComponentTemplateTests.randomInstance();
+        ComponentTemplate ct = ComponentTemplateTests.randomNonDeprecatedInstance();
         state = service.addComponentTemplate(state, true, "ct", ct);
         ComposableIndexTemplate it = new ComposableIndexTemplate(List.of("i*"), null, List.of("ct"), null, 1L, null, null, null);
         state = service.addIndexTemplateV2(state, true, "my-template", it);
@@ -1033,7 +1033,7 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
         ClusterState state = ClusterState.EMPTY_STATE;
         assertNull(MetadataIndexTemplateService.findV2Template(state.metadata(), "index", true));
 
-        ComponentTemplate ct = ComponentTemplateTests.randomInstance();
+        ComponentTemplate ct = ComponentTemplateTests.randomNonDeprecatedInstance();
         state = service.addComponentTemplate(state, true, "ct", ct);
         ComposableIndexTemplate it = new ComposableIndexTemplate(List.of("i*"), null, List.of("ct"), 0L, 1L, null, null, null);
         state = service.addIndexTemplateV2(state, true, "my-template", it);
@@ -1051,7 +1051,7 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
         ClusterState state = ClusterState.EMPTY_STATE;
         assertNull(MetadataIndexTemplateService.findV2Template(state.metadata(), indexName, true));
 
-        ComponentTemplate ct = ComponentTemplateTests.randomInstance();
+        ComponentTemplate ct = ComponentTemplateTests.randomNonDeprecatedInstance();
         state = service.addComponentTemplate(state, true, "ct", ct);
         ComposableIndexTemplate it = new ComposableIndexTemplate(List.of("index-*"), null, List.of("ct"), 0L, 1L, null, null, null);
         state = service.addIndexTemplateV2(state, true, "my-template", it);
@@ -2009,7 +2009,7 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
     public void testPutExistingComponentTemplateIsNoop() throws Exception {
         MetadataIndexTemplateService metadataIndexTemplateService = getMetadataIndexTemplateService();
         ClusterState state = ClusterState.EMPTY_STATE;
-        ComponentTemplate componentTemplate = ComponentTemplateTests.randomInstance();
+        ComponentTemplate componentTemplate = ComponentTemplateTests.randomNonDeprecatedInstance();
         state = metadataIndexTemplateService.addComponentTemplate(state, false, "foo", componentTemplate);
 
         assertNotNull(state.metadata().componentTemplates().get("foo"));
@@ -2597,6 +2597,30 @@ public class MetadataIndexTemplateServiceTests extends ESSingleNodeTestCase {
         );
     }
 
+    public void testAddIndexTemplateWithDeprecatedComponentTemplate() throws Exception {
+        ClusterState state = ClusterState.EMPTY_STATE;
+        final MetadataIndexTemplateService service = getMetadataIndexTemplateService();
+
+        ComponentTemplate ct = ComponentTemplateTests.randomInstance(false, true);
+        state = service.addComponentTemplate(state, true, "ct", ct);
+
+        ComposableIndexTemplate it = new ComposableIndexTemplate(
+            List.of("test*"),
+            null,
+            List.of("ct"),
+            null,
+            1L,
+            null,
+            null,
+            null,
+            null,
+            null
+        );
+        service.addIndexTemplateV2(state, false, "foo", it);
+
+        assertWarnings("index template [foo] uses deprecated component template [ct]");
+    }
+
     private static List<Throwable> putTemplate(NamedXContentRegistry xContentRegistry, PutRequest request) {
         ThreadPool testThreadPool = mock(ThreadPool.class);
         ClusterService clusterService = ClusterServiceUtils.createClusterService(testThreadPool);

+ 3 - 0
server/src/test/java/org/elasticsearch/ingest/PipelineFactoryTests.java

@@ -29,6 +29,7 @@ public class PipelineFactoryTests extends ESTestCase {
     private final String versionString = version != null ? Integer.toString(version) : null;
     private final ScriptService scriptService = mock(ScriptService.class);
     private final Map<String, Object> metadata = randomMapOfMaps();
+    private final Boolean deprecated = randomOptionalBoolean();
 
     public void testCreate() throws Exception {
         Map<String, Object> processorConfig0 = new HashMap<>();
@@ -40,12 +41,14 @@ public class PipelineFactoryTests extends ESTestCase {
         if (metadata != null) {
             pipelineConfig.put(Pipeline.META_KEY, metadata);
         }
+        pipelineConfig.put(Pipeline.DEPRECATED_KEY, deprecated);
         pipelineConfig.put(Pipeline.PROCESSORS_KEY, List.of(Map.of("test", processorConfig0), Map.of("test", processorConfig1)));
         Map<String, Processor.Factory> processorRegistry = Map.of("test", new TestProcessor.Factory());
         Pipeline pipeline = Pipeline.create("_id", pipelineConfig, processorRegistry, scriptService);
         assertThat(pipeline.getId(), equalTo("_id"));
         assertThat(pipeline.getDescription(), equalTo("_description"));
         assertThat(pipeline.getVersion(), equalTo(version));
+        assertThat(pipeline.getDeprecated(), equalTo(deprecated));
         assertThat(pipeline.getProcessors().size(), equalTo(2));
         assertThat(pipeline.getProcessors().get(0).getType(), equalTo("test-processor"));
         assertThat(pipeline.getProcessors().get(0).getTag(), equalTo("first-processor"));

+ 12 - 3
server/src/test/java/org/elasticsearch/ingest/PipelineProcessorTests.java

@@ -157,7 +157,15 @@ public class PipelineProcessorTests extends ESTestCase {
 
         LongSupplier relativeTimeProvider = mock(LongSupplier.class);
         when(relativeTimeProvider.getAsLong()).thenReturn(0L);
-        Pipeline pipeline1 = new Pipeline(pipeline1Id, null, null, null, new CompoundProcessor(pipeline1Processor), relativeTimeProvider);
+        Pipeline pipeline1 = new Pipeline(
+            pipeline1Id,
+            null,
+            null,
+            null,
+            new CompoundProcessor(pipeline1Processor),
+            relativeTimeProvider,
+            null
+        );
 
         String key1 = randomAlphaOfLength(10);
         relativeTimeProvider = mock(LongSupplier.class);
@@ -170,13 +178,14 @@ public class PipelineProcessorTests extends ESTestCase {
             new CompoundProcessor(true, List.of(new TestProcessor(ingestDocument -> {
                 ingestDocument.setFieldValue(key1, randomInt());
             }), pipeline2Processor), List.of()),
-            relativeTimeProvider
+            relativeTimeProvider,
+            null
         );
         relativeTimeProvider = mock(LongSupplier.class);
         when(relativeTimeProvider.getAsLong()).thenReturn(0L, TimeUnit.MILLISECONDS.toNanos(2));
         Pipeline pipeline3 = new Pipeline(pipeline3Id, null, null, null, new CompoundProcessor(new TestProcessor(ingestDocument -> {
             throw new RuntimeException("error");
-        })), relativeTimeProvider);
+        })), relativeTimeProvider, null);
         when(ingestService.getPipeline(pipeline1Id)).thenReturn(pipeline1);
         when(ingestService.getPipeline(pipeline2Id)).thenReturn(pipeline2);
         when(ingestService.getPipeline(pipeline3Id)).thenReturn(pipeline3);

+ 4 - 0
test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java

@@ -812,6 +812,10 @@ public abstract class ESTestCase extends LuceneTestCase {
         return random().nextBoolean();
     }
 
+    public static Boolean randomOptionalBoolean() {
+        return randomBoolean() ? Boolean.TRUE : randomFrom(Boolean.FALSE, null);
+    }
+
     public static byte randomByte() {
         return (byte) random().nextInt();
     }

+ 43 - 7
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicy.java

@@ -6,6 +6,7 @@
  */
 package org.elasticsearch.xpack.core.ilm;
 
+import org.elasticsearch.TransportVersions;
 import org.elasticsearch.client.internal.Client;
 import org.elasticsearch.cluster.SimpleDiffable;
 import org.elasticsearch.common.Strings;
@@ -44,6 +45,7 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
 
     public static final ParseField PHASES_FIELD = new ParseField("phases");
     private static final ParseField METADATA = new ParseField("_meta");
+    private static final ParseField DEPRECATED = new ParseField("deprecated");
 
     private static final StepKey NEW_STEP_KEY = new StepKey("new", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME);
 
@@ -54,7 +56,7 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
         (a, name) -> {
             List<Phase> phases = (List<Phase>) a[0];
             Map<String, Phase> phaseMap = phases.stream().collect(Collectors.toMap(Phase::getName, Function.identity()));
-            return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phaseMap, (Map<String, Object>) a[1]);
+            return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phaseMap, (Map<String, Object>) a[1], (Boolean) a[2]);
         }
     );
     static {
@@ -62,6 +64,7 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
             throw new IllegalArgumentException("ordered " + PHASES_FIELD.getPreferredName() + " are not supported");
         }, PHASES_FIELD);
         PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.map(), METADATA);
+        PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), DEPRECATED);
     }
 
     private final String name;
@@ -69,6 +72,8 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
     private final Map<String, Phase> phases;
     @Nullable
     private final Map<String, Object> metadata;
+    @Nullable
+    private final Boolean deprecated;
 
     /**
      * @param name
@@ -79,10 +84,12 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
      *
      */
     public LifecyclePolicy(String name, Map<String, Phase> phases) {
-        this(TimeseriesLifecycleType.INSTANCE, name, phases, null);
+        this(TimeseriesLifecycleType.INSTANCE, name, phases, null, null);
     }
 
     /**
+     * @param type
+     *            the {@link LifecycleType} of the policy
      * @param name
      *            the name of this {@link LifecyclePolicy}
      * @param phases
@@ -91,8 +98,8 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
      * @param metadata
      *            the custom metadata of this {@link LifecyclePolicy}
      */
-    public LifecyclePolicy(String name, Map<String, Phase> phases, @Nullable Map<String, Object> metadata) {
-        this(TimeseriesLifecycleType.INSTANCE, name, phases, metadata);
+    public LifecyclePolicy(LifecycleType type, String name, Map<String, Phase> phases, @Nullable Map<String, Object> metadata) {
+        this(type, name, phases, metadata, null);
     }
 
     /**
@@ -103,6 +110,11 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
         name = in.readString();
         phases = in.readImmutableMap(Phase::new);
         this.metadata = in.readMap();
+        if (in.getTransportVersion().onOrAfter(TransportVersions.DEPRECATED_COMPONENT_TEMPLATES_ADDED)) {
+            this.deprecated = in.readOptionalBoolean();
+        } else {
+            this.deprecated = null;
+        }
     }
 
     /**
@@ -116,11 +128,18 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
      * @param metadata
      *            the custom metadata of this {@link LifecyclePolicy}
      */
-    public LifecyclePolicy(LifecycleType type, String name, Map<String, Phase> phases, @Nullable Map<String, Object> metadata) {
+    public LifecyclePolicy(
+        LifecycleType type,
+        String name,
+        Map<String, Phase> phases,
+        @Nullable Map<String, Object> metadata,
+        @Nullable Boolean deprecated
+    ) {
         this.name = name;
         this.phases = phases;
         this.type = type;
         this.metadata = metadata;
+        this.deprecated = deprecated;
     }
 
     public void validate() {
@@ -137,6 +156,9 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
         out.writeString(name);
         out.writeMap(phases, StreamOutput::writeWriteable);
         out.writeGenericMap(this.metadata);
+        if (out.getTransportVersion().onOrAfter(TransportVersions.DEPRECATED_COMPONENT_TEMPLATES_ADDED)) {
+            out.writeOptionalBoolean(deprecated);
+        }
     }
 
     /**
@@ -168,6 +190,14 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
         return metadata;
     }
 
+    public Boolean getDeprecated() {
+        return deprecated;
+    }
+
+    public boolean isDeprecated() {
+        return Boolean.TRUE.equals(deprecated);
+    }
+
     @Override
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject();
@@ -179,6 +209,9 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
         if (this.metadata != null) {
             builder.field(METADATA.getPreferredName(), this.metadata);
         }
+        if (this.deprecated != null) {
+            builder.field(DEPRECATED.getPreferredName(), this.deprecated);
+        }
         builder.endObject();
         return builder;
     }
@@ -310,7 +343,7 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
 
     @Override
     public int hashCode() {
-        return Objects.hash(name, phases, metadata);
+        return Objects.hash(name, phases, metadata, deprecated);
     }
 
     @Override
@@ -322,7 +355,10 @@ public class LifecyclePolicy implements SimpleDiffable<LifecyclePolicy>, ToXCont
             return false;
         }
         LifecyclePolicy other = (LifecyclePolicy) obj;
-        return Objects.equals(name, other.name) && Objects.equals(phases, other.phases) && Objects.equals(metadata, other.metadata);
+        return Objects.equals(name, other.name)
+            && Objects.equals(phases, other.phases)
+            && Objects.equals(metadata, other.metadata)
+            && Objects.equals(deprecated, other.deprecated);
     }
 
     @Override

+ 9 - 5
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyTests.java

@@ -139,7 +139,7 @@ public class LifecyclePolicyTests extends AbstractXContentSerializingTestCase<Li
             }
             phases.put(phase, new Phase(phase, after, actions));
         }
-        return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
+        return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta(), randomOptionalBoolean());
     }
 
     public static LifecyclePolicy randomTimeseriesLifecyclePolicy(@Nullable String lifecycleName) {
@@ -230,7 +230,7 @@ public class LifecyclePolicyTests extends AbstractXContentSerializingTestCase<Li
         } else {
             phases.remove(TimeseriesLifecycleType.FROZEN_PHASE);
         }
-        return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
+        return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta(), randomOptionalBoolean());
     }
 
     private static Function<String, Set<String>> getPhaseToValidActions() {
@@ -276,14 +276,16 @@ public class LifecyclePolicyTests extends AbstractXContentSerializingTestCase<Li
             String phaseName = randomAlphaOfLength(10);
             phases.put(phaseName, new Phase(phaseName, after, actions));
         }
-        return new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
+        return new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta(), randomOptionalBoolean());
     }
 
     @Override
     protected LifecyclePolicy mutateInstance(LifecyclePolicy instance) {
         String name = instance.getName();
         Map<String, Phase> phases = instance.getPhases();
-        switch (between(0, 1)) {
+        Map<String, Object> metadata = instance.getMetadata();
+        Boolean deprecated = instance.getDeprecated();
+        switch (between(0, 3)) {
             case 0 -> name = name + randomAlphaOfLengthBetween(1, 5);
             case 1 -> {
                 // Remove the frozen phase, because it makes a lot of invalid phases when randomly mutating an existing policy
@@ -303,9 +305,11 @@ public class LifecyclePolicyTests extends AbstractXContentSerializingTestCase<Li
                 phases = new LinkedHashMap<>(phases);
                 phases.put(phaseName, new Phase(phaseName, null, Collections.emptyMap()));
             }
+            case 2 -> metadata = randomValueOtherThan(metadata, LifecyclePolicyTests::randomMeta);
+            case 3 -> deprecated = instance.isDeprecated() ? randomFrom(false, null) : true;
             default -> throw new AssertionError("Illegal randomisation branch");
         }
-        return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phases, randomMeta());
+        return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phases, metadata, deprecated);
     }
 
     @Override

+ 2 - 1
x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/cluster/metadata/MetadataMigrateToDataTiersRoutingService.java

@@ -751,7 +751,8 @@ public final class MetadataMigrateToDataTiersRoutingService {
                     ComponentTemplate migratedComponentTemplate = new ComponentTemplate(
                         migratedInnerTemplate,
                         componentTemplate.version(),
-                        componentTemplate.metadata()
+                        componentTemplate.metadata(),
+                        componentTemplate.deprecated()
                     );
 
                     mb.put(componentEntry.getKey(), migratedComponentTemplate);

+ 11 - 1
x-pack/plugin/profiling/src/test/java/org/elasticsearch/xpack/profiling/ProfilingIndexTemplateRegistryTests.java

@@ -42,6 +42,7 @@ import org.elasticsearch.xpack.core.ilm.LifecycleAction;
 import org.elasticsearch.xpack.core.ilm.LifecyclePolicy;
 import org.elasticsearch.xpack.core.ilm.LifecyclePolicyMetadata;
 import org.elasticsearch.xpack.core.ilm.OperationMode;
+import org.elasticsearch.xpack.core.ilm.TimeseriesLifecycleType;
 import org.elasticsearch.xpack.core.ilm.action.PutLifecycleAction;
 import org.junit.After;
 import org.junit.Before;
@@ -328,7 +329,16 @@ public class ProfilingIndexTemplateRegistryTests extends ESTestCase {
             Map<String, Object> metadata = new HashMap<>(policy.getMetadata());
             // outdated version
             metadata.put("version", randomIntBetween(1, ProfilingIndexTemplateRegistry.INDEX_TEMPLATE_VERSION - 1));
-            policies.put(policy.getName(), new LifecyclePolicy(policy.getName(), policy.getPhases(), metadata));
+            policies.put(
+                policy.getName(),
+                new LifecyclePolicy(
+                    TimeseriesLifecycleType.INSTANCE,
+                    policy.getName(),
+                    policy.getPhases(),
+                    metadata,
+                    policy.getDeprecated()
+                )
+            );
         }
         ClusterState clusterState = createClusterState(Settings.EMPTY, componentTemplates, composableTemplates, policies, nodes);