diff --git a/docs/reference/ilm/apis/put-lifecycle.asciidoc b/docs/reference/ilm/apis/put-lifecycle.asciidoc index cef74ac620473..cb8b449b49a28 100644 --- a/docs/reference/ilm/apis/put-lifecycle.asciidoc +++ b/docs/reference/ilm/apis/put-lifecycle.asciidoc @@ -47,13 +47,23 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=timeoutparms] [[ilm-put-lifecycle-example]] ==== {api-examples-title} -The following example creates a new policy named `my_policy`: +The following example creates a new policy named `my_policy`. In addition, you can use the +`_meta` parameter to add arbitrary metadata to the policy, the `_meta` parameter is optional +and not automatically generated or used by Elasticsearch. To unset `_meta`, replace the policy +without specifying one. To check the `_meta`, you can use the <> API. [source,console] -------------------------------------------------- PUT _ilm/policy/my_policy { "policy": { + "_meta": { + "description": "used for nginx log", + "project": { + "name": "myProject", + "department": "myDepartment" + } + }, "phases": { "warm": { "min_age": "10d", diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicy.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicy.java index 0791e6185248b..ccacde8ced349 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicy.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicy.java @@ -6,9 +6,11 @@ */ package org.elasticsearch.xpack.core.ilm; +import org.elasticsearch.Version; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.AbstractDiffable; import org.elasticsearch.cluster.Diffable; +import org.elasticsearch.common.Nullable; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; @@ -43,23 +45,27 @@ public class LifecyclePolicy extends AbstractDiffable private static final int MAX_INDEX_NAME_BYTES = 255; public static final ParseField PHASES_FIELD = new ParseField("phases"); + private static final ParseField METADATA = new ParseField("_meta"); @SuppressWarnings("unchecked") public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("lifecycle_policy", false, (a, name) -> { List phases = (List) a[0]; Map phaseMap = phases.stream().collect(Collectors.toMap(Phase::getName, Function.identity())); - return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phaseMap); + return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phaseMap, (Map) a[1]); }); static { PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> Phase.parse(p, n), v -> { throw new IllegalArgumentException("ordered " + PHASES_FIELD.getPreferredName() + " are not supported"); }, PHASES_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.map(), METADATA); } private final String name; private final LifecycleType type; private final Map phases; + @Nullable + private final Map metadata; /** * @param name @@ -67,9 +73,23 @@ public class LifecyclePolicy extends AbstractDiffable * @param phases * a {@link Map} of {@link Phase}s which make up this * {@link LifecyclePolicy}. + * */ public LifecyclePolicy(String name, Map phases) { - this(TimeseriesLifecycleType.INSTANCE, name, phases); + this(TimeseriesLifecycleType.INSTANCE, name, phases, null); + } + + /** + * @param name + * the name of this {@link LifecyclePolicy} + * @param phases + * a {@link Map} of {@link Phase}s which make up this + * {@link LifecyclePolicy}. + * @param metadata + * the custom metadata of this {@link LifecyclePolicy} + */ + public LifecyclePolicy(String name, Map phases, @Nullable Map metadata) { + this(TimeseriesLifecycleType.INSTANCE, name, phases, metadata); } /** @@ -79,6 +99,11 @@ public LifecyclePolicy(StreamInput in) throws IOException { type = in.readNamedWriteable(LifecycleType.class); name = in.readString(); phases = Collections.unmodifiableMap(in.readMap(StreamInput::readString, Phase::new)); + if (in.getVersion().onOrAfter(Version.V_8_0_0)) { + this.metadata = in.readMap(); + } else { + this.metadata = null; + } } /** @@ -89,11 +114,14 @@ public LifecyclePolicy(StreamInput in) throws IOException { * @param phases * a {@link Map} of {@link Phase}s which make up this * {@link LifecyclePolicy}. + * @param metadata + * the custom metadata of this {@link LifecyclePolicy} */ - public LifecyclePolicy(LifecycleType type, String name, Map phases) { + public LifecyclePolicy(LifecycleType type, String name, Map phases, @Nullable Map metadata) { this.name = name; this.phases = phases; this.type = type; + this.metadata = metadata; this.type.validate(phases.values()); } @@ -106,6 +134,9 @@ public void writeTo(StreamOutput out) throws IOException { out.writeNamedWriteable(type); out.writeString(name); out.writeMap(phases, StreamOutput::writeString, (o, val) -> val.writeTo(o)); + if (out.getVersion().onOrAfter(Version.V_8_0_0)) { + out.writeMap(this.metadata); + } } /** @@ -130,6 +161,13 @@ public Map getPhases() { return phases; } + /** + * @return the custom metadata of this {@link LifecyclePolicy} + */ + public Map getMetadata() { + return metadata; + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); @@ -138,6 +176,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(phase.getName(), phase); } builder.endObject(); + if (this.metadata != null) { + builder.field(METADATA.getPreferredName(), this.metadata); + } builder.endObject(); return builder; } @@ -264,7 +305,7 @@ public static void validatePolicyName(String policy) { @Override public int hashCode() { - return Objects.hash(name, phases); + return Objects.hash(name, phases, metadata); } @Override @@ -277,7 +318,8 @@ public boolean equals(Object obj) { } LifecyclePolicy other = (LifecyclePolicy) obj; return Objects.equals(name, other.name) && - Objects.equals(phases, other.phases); + Objects.equals(phases, other.phases) && + Objects.equals(metadata, other.metadata); } @Override diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyMetadataTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyMetadataTests.java index 73111fc5a9310..2d087eff45741 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyMetadataTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyMetadataTests.java @@ -23,6 +23,8 @@ import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.core.ilm.LifecyclePolicyTests.randomMeta; + public class LifecyclePolicyMetadataTests extends AbstractSerializingTestCase { private String lifecycleName; @@ -110,7 +112,7 @@ protected LifecyclePolicyMetadata mutateInstance(LifecyclePolicyMetadata instanc switch (between(0, 3)) { case 0: policy = new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, policy.getName() + randomAlphaOfLengthBetween(1, 5), - policy.getPhases()); + policy.getPhases(), randomMeta()); break; case 1: headers = new HashMap<>(headers); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyTests.java index 680926092f0fd..52dbabc3280cd 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyTests.java @@ -123,7 +123,7 @@ public static LifecyclePolicy randomTimeseriesLifecyclePolicyWithAllPhases(@Null } phases.put(phase, new Phase(phase, after, actions)); } - return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases); + return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); } public static LifecyclePolicy randomTimeseriesLifecyclePolicy(@Nullable String lifecycleName) { @@ -203,7 +203,7 @@ public static LifecyclePolicy randomTimeseriesLifecyclePolicy(@Nullable String l } else { phases.remove(TimeseriesLifecycleType.FROZEN_PHASE); } - return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases); + return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); } private static Function> getPhaseToValidActions() { @@ -271,7 +271,7 @@ public static LifecyclePolicy randomTestLifecyclePolicy(@Nullable String lifecyc String phaseName = randomAlphaOfLength(10); phases.put(phaseName, new Phase(phaseName, after, actions)); } - return new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); + return new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); } @Override @@ -299,7 +299,7 @@ protected LifecyclePolicy mutateInstance(LifecyclePolicy instance) throws IOExce default: throw new AssertionError("Illegal randomisation branch"); } - return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phases); + return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phases, randomMeta()); } @Override @@ -311,7 +311,7 @@ public void testFirstAndLastSteps() { Client client = mock(Client.class); lifecycleName = randomAlphaOfLengthBetween(1, 20); Map phases = new LinkedHashMap<>(); - LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); + LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); List steps = policy.toSteps(client); assertThat(steps.size(), equalTo(2)); assertThat(steps.get(0), instanceOf(InitializePolicyContextStep.class)); @@ -331,7 +331,7 @@ public void testToStepsWithOneStep() { Map actions = Collections.singletonMap(MockAction.NAME, firstAction); Phase firstPhase = new Phase("test", TimeValue.ZERO, actions); phases.put(firstPhase.getName(), firstPhase); - LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); + LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); StepKey firstStepKey = InitializePolicyContextStep.KEY; StepKey secondStepKey = PhaseCompleteStep.finalStep("new").getKey(); List steps = policy.toSteps(client); @@ -366,7 +366,7 @@ public void testToStepsWithTwoPhases() { Phase secondPhase = new Phase("second_phase", TimeValue.ZERO, secondActions); phases.put(firstPhase.getName(), firstPhase); phases.put(secondPhase.getName(), secondPhase); - LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); + LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); List steps = policy.toSteps(client); assertThat(steps.size(), equalTo(7)); @@ -395,7 +395,7 @@ public void testIsActionSafe() { Phase secondPhase = new Phase("second_phase", TimeValue.ZERO, secondActions); phases.put(firstPhase.getName(), firstPhase); phases.put(secondPhase.getName(), secondPhase); - LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); + LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta()); assertTrue(policy.isActionSafe(new StepKey("first_phase", MockAction.NAME, randomAlphaOfLength(10)))); @@ -428,4 +428,17 @@ public void testValidatePolicyName() { LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(1, 255)); } + + public static Map randomMeta() { + if (randomBoolean()) { + if (randomBoolean()) { + return Collections.singletonMap(randomAlphaOfLength(4), randomAlphaOfLength(4)); + } else { + return Collections.singletonMap(randomAlphaOfLength(5), + Collections.singletonMap(randomAlphaOfLength(4), randomAlphaOfLength(4))); + } + } else { + return null; + } + } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistry.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistry.java index 8d993eb606b9a..16360b256ab34 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistry.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistry.java @@ -162,7 +162,7 @@ private List parseStepsFromPhase(String policy, String currentPhase, Strin if (phaseExecutionInfo.getPhase() != null) { phaseMap.put(currentPhase, phaseExecutionInfo.getPhase()); } - policyToExecute = new LifecyclePolicy(currentPolicy.getType(), currentPolicy.getName(), phaseMap); + policyToExecute = new LifecyclePolicy(currentPolicy.getType(), currentPolicy.getName(), phaseMap, currentPolicy.getMetadata()); } LifecyclePolicySecurityClient policyClient = new LifecyclePolicySecurityClient(client, ClientHelper.INDEX_LIFECYCLE_ORIGIN, lifecyclePolicyMap.get(policy).getHeaders()); diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecyclePolicyTestsUtils.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecyclePolicyTestsUtils.java index 0205092447e7c..59356ebf32f60 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecyclePolicyTestsUtils.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecyclePolicyTestsUtils.java @@ -15,6 +15,8 @@ import java.util.Map; +import static org.elasticsearch.xpack.core.ilm.LifecyclePolicyTests.randomMeta; + /** * This class is here for constructing instances of {@link LifecyclePolicy} that differs from * the main {@link TimeseriesLifecycleType} one. Since the more generic constructor is package-private so @@ -24,11 +26,11 @@ public class LifecyclePolicyTestsUtils { public static LifecyclePolicy newTestLifecyclePolicy(String policyName, Map phases) { - return new LifecyclePolicy(TestLifecycleType.INSTANCE, policyName, phases); + return new LifecyclePolicy(TestLifecycleType.INSTANCE, policyName, phases, randomMeta()); } public static LifecyclePolicy newLockableLifecyclePolicy(String policyName, Map phases) { - return new LifecyclePolicy(LockableLifecycleType.INSTANCE, policyName, phases); + return new LifecyclePolicy(LockableLifecycleType.INSTANCE, policyName, phases, randomMeta()); } public static LifecyclePolicy randomTimeseriesLifecyclePolicy(String policyName) {