Skip to content

Commit b6fd1bb

Browse files
authored
Add _meta field to ilm policy (#73515)
Relates to #70755. The main changes of this PR are: Add an optional _meta field to ILM policy. Add some test code about the change. Update the doc of Create or update lifecycle policy API.
1 parent 5180f75 commit b6fd1bb

File tree

6 files changed

+87
-18
lines changed

6 files changed

+87
-18
lines changed

docs/reference/ilm/apis/put-lifecycle.asciidoc

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,23 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=timeoutparms]
4747
[[ilm-put-lifecycle-example]]
4848
==== {api-examples-title}
4949

50-
The following example creates a new policy named `my_policy`:
50+
The following example creates a new policy named `my_policy`. In addition, you can use the
51+
`_meta` parameter to add arbitrary metadata to the policy, the `_meta` parameter is optional
52+
and not automatically generated or used by Elasticsearch. To unset `_meta`, replace the policy
53+
without specifying one. To check the `_meta`, you can use the <<ilm-get-lifecycle,Get lifecycle policy>> API.
5154

5255
[source,console]
5356
--------------------------------------------------
5457
PUT _ilm/policy/my_policy
5558
{
5659
"policy": {
60+
"_meta": {
61+
"description": "used for nginx log",
62+
"project": {
63+
"name": "myProject",
64+
"department": "myDepartment"
65+
}
66+
},
5767
"phases": {
5868
"warm": {
5969
"min_age": "10d",

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

+47-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
*/
77
package org.elasticsearch.xpack.core.ilm;
88

9+
import org.elasticsearch.Version;
910
import org.elasticsearch.client.Client;
1011
import org.elasticsearch.cluster.AbstractDiffable;
1112
import org.elasticsearch.cluster.Diffable;
13+
import org.elasticsearch.common.Nullable;
1214
import org.elasticsearch.common.ParseField;
1315
import org.elasticsearch.common.Strings;
1416
import org.elasticsearch.common.io.stream.StreamInput;
@@ -43,33 +45,51 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
4345
private static final int MAX_INDEX_NAME_BYTES = 255;
4446

4547
public static final ParseField PHASES_FIELD = new ParseField("phases");
48+
private static final ParseField METADATA = new ParseField("_meta");
4649

4750
@SuppressWarnings("unchecked")
4851
public static final ConstructingObjectParser<LifecyclePolicy, String> PARSER = new ConstructingObjectParser<>("lifecycle_policy", false,
4952
(a, name) -> {
5053
List<Phase> phases = (List<Phase>) a[0];
5154
Map<String, Phase> phaseMap = phases.stream().collect(Collectors.toMap(Phase::getName, Function.identity()));
52-
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phaseMap);
55+
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phaseMap, (Map<String, Object>) a[1]);
5356
});
5457
static {
5558
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> Phase.parse(p, n), v -> {
5659
throw new IllegalArgumentException("ordered " + PHASES_FIELD.getPreferredName() + " are not supported");
5760
}, PHASES_FIELD);
61+
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.map(), METADATA);
5862
}
5963

6064
private final String name;
6165
private final LifecycleType type;
6266
private final Map<String, Phase> phases;
67+
@Nullable
68+
private final Map<String, Object> metadata;
6369

6470
/**
6571
* @param name
6672
* the name of this {@link LifecyclePolicy}
6773
* @param phases
6874
* a {@link Map} of {@link Phase}s which make up this
6975
* {@link LifecyclePolicy}.
76+
*
7077
*/
7178
public LifecyclePolicy(String name, Map<String, Phase> phases) {
72-
this(TimeseriesLifecycleType.INSTANCE, name, phases);
79+
this(TimeseriesLifecycleType.INSTANCE, name, phases, null);
80+
}
81+
82+
/**
83+
* @param name
84+
* the name of this {@link LifecyclePolicy}
85+
* @param phases
86+
* a {@link Map} of {@link Phase}s which make up this
87+
* {@link LifecyclePolicy}.
88+
* @param metadata
89+
* the custom metadata of this {@link LifecyclePolicy}
90+
*/
91+
public LifecyclePolicy(String name, Map<String, Phase> phases, @Nullable Map<String, Object> metadata) {
92+
this(TimeseriesLifecycleType.INSTANCE, name, phases, metadata);
7393
}
7494

7595
/**
@@ -79,6 +99,11 @@ public LifecyclePolicy(StreamInput in) throws IOException {
7999
type = in.readNamedWriteable(LifecycleType.class);
80100
name = in.readString();
81101
phases = Collections.unmodifiableMap(in.readMap(StreamInput::readString, Phase::new));
102+
if (in.getVersion().onOrAfter(Version.V_8_0_0)) {
103+
this.metadata = in.readMap();
104+
} else {
105+
this.metadata = null;
106+
}
82107
}
83108

84109
/**
@@ -89,11 +114,14 @@ public LifecyclePolicy(StreamInput in) throws IOException {
89114
* @param phases
90115
* a {@link Map} of {@link Phase}s which make up this
91116
* {@link LifecyclePolicy}.
117+
* @param metadata
118+
* the custom metadata of this {@link LifecyclePolicy}
92119
*/
93-
public LifecyclePolicy(LifecycleType type, String name, Map<String, Phase> phases) {
120+
public LifecyclePolicy(LifecycleType type, String name, Map<String, Phase> phases, @Nullable Map<String, Object> metadata) {
94121
this.name = name;
95122
this.phases = phases;
96123
this.type = type;
124+
this.metadata = metadata;
97125
this.type.validate(phases.values());
98126
}
99127

@@ -106,6 +134,9 @@ public void writeTo(StreamOutput out) throws IOException {
106134
out.writeNamedWriteable(type);
107135
out.writeString(name);
108136
out.writeMap(phases, StreamOutput::writeString, (o, val) -> val.writeTo(o));
137+
if (out.getVersion().onOrAfter(Version.V_8_0_0)) {
138+
out.writeMap(this.metadata);
139+
}
109140
}
110141

111142
/**
@@ -130,6 +161,13 @@ public Map<String, Phase> getPhases() {
130161
return phases;
131162
}
132163

164+
/**
165+
* @return the custom metadata of this {@link LifecyclePolicy}
166+
*/
167+
public Map<String, Object> getMetadata() {
168+
return metadata;
169+
}
170+
133171
@Override
134172
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
135173
builder.startObject();
@@ -138,6 +176,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
138176
builder.field(phase.getName(), phase);
139177
}
140178
builder.endObject();
179+
if (this.metadata != null) {
180+
builder.field(METADATA.getPreferredName(), this.metadata);
181+
}
141182
builder.endObject();
142183
return builder;
143184
}
@@ -264,7 +305,7 @@ public static void validatePolicyName(String policy) {
264305

265306
@Override
266307
public int hashCode() {
267-
return Objects.hash(name, phases);
308+
return Objects.hash(name, phases, metadata);
268309
}
269310

270311
@Override
@@ -277,7 +318,8 @@ public boolean equals(Object obj) {
277318
}
278319
LifecyclePolicy other = (LifecyclePolicy) obj;
279320
return Objects.equals(name, other.name) &&
280-
Objects.equals(phases, other.phases);
321+
Objects.equals(phases, other.phases) &&
322+
Objects.equals(metadata, other.metadata);
281323
}
282324

283325
@Override

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecyclePolicyMetadataTests.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.List;
2424
import java.util.Map;
2525

26+
import static org.elasticsearch.xpack.core.ilm.LifecyclePolicyTests.randomMeta;
27+
2628
public class LifecyclePolicyMetadataTests extends AbstractSerializingTestCase<LifecyclePolicyMetadata> {
2729

2830
private String lifecycleName;
@@ -110,7 +112,7 @@ protected LifecyclePolicyMetadata mutateInstance(LifecyclePolicyMetadata instanc
110112
switch (between(0, 3)) {
111113
case 0:
112114
policy = new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, policy.getName() + randomAlphaOfLengthBetween(1, 5),
113-
policy.getPhases());
115+
policy.getPhases(), randomMeta());
114116
break;
115117
case 1:
116118
headers = new HashMap<>(headers);

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

+21-8
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public static LifecyclePolicy randomTimeseriesLifecyclePolicyWithAllPhases(@Null
123123
}
124124
phases.put(phase, new Phase(phase, after, actions));
125125
}
126-
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases);
126+
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
127127
}
128128

129129
public static LifecyclePolicy randomTimeseriesLifecyclePolicy(@Nullable String lifecycleName) {
@@ -203,7 +203,7 @@ public static LifecyclePolicy randomTimeseriesLifecyclePolicy(@Nullable String l
203203
} else {
204204
phases.remove(TimeseriesLifecycleType.FROZEN_PHASE);
205205
}
206-
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases);
206+
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
207207
}
208208

209209
private static Function<String, Set<String>> getPhaseToValidActions() {
@@ -271,7 +271,7 @@ public static LifecyclePolicy randomTestLifecyclePolicy(@Nullable String lifecyc
271271
String phaseName = randomAlphaOfLength(10);
272272
phases.put(phaseName, new Phase(phaseName, after, actions));
273273
}
274-
return new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
274+
return new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
275275
}
276276

277277
@Override
@@ -299,7 +299,7 @@ protected LifecyclePolicy mutateInstance(LifecyclePolicy instance) throws IOExce
299299
default:
300300
throw new AssertionError("Illegal randomisation branch");
301301
}
302-
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phases);
302+
return new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, name, phases, randomMeta());
303303
}
304304

305305
@Override
@@ -311,7 +311,7 @@ public void testFirstAndLastSteps() {
311311
Client client = mock(Client.class);
312312
lifecycleName = randomAlphaOfLengthBetween(1, 20);
313313
Map<String, Phase> phases = new LinkedHashMap<>();
314-
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
314+
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
315315
List<Step> steps = policy.toSteps(client);
316316
assertThat(steps.size(), equalTo(2));
317317
assertThat(steps.get(0), instanceOf(InitializePolicyContextStep.class));
@@ -331,7 +331,7 @@ public void testToStepsWithOneStep() {
331331
Map<String, LifecycleAction> actions = Collections.singletonMap(MockAction.NAME, firstAction);
332332
Phase firstPhase = new Phase("test", TimeValue.ZERO, actions);
333333
phases.put(firstPhase.getName(), firstPhase);
334-
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
334+
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
335335
StepKey firstStepKey = InitializePolicyContextStep.KEY;
336336
StepKey secondStepKey = PhaseCompleteStep.finalStep("new").getKey();
337337
List<Step> steps = policy.toSteps(client);
@@ -366,7 +366,7 @@ public void testToStepsWithTwoPhases() {
366366
Phase secondPhase = new Phase("second_phase", TimeValue.ZERO, secondActions);
367367
phases.put(firstPhase.getName(), firstPhase);
368368
phases.put(secondPhase.getName(), secondPhase);
369-
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
369+
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
370370

371371
List<Step> steps = policy.toSteps(client);
372372
assertThat(steps.size(), equalTo(7));
@@ -395,7 +395,7 @@ public void testIsActionSafe() {
395395
Phase secondPhase = new Phase("second_phase", TimeValue.ZERO, secondActions);
396396
phases.put(firstPhase.getName(), firstPhase);
397397
phases.put(secondPhase.getName(), secondPhase);
398-
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
398+
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases, randomMeta());
399399

400400
assertTrue(policy.isActionSafe(new StepKey("first_phase", MockAction.NAME, randomAlphaOfLength(10))));
401401

@@ -428,4 +428,17 @@ public void testValidatePolicyName() {
428428

429429
LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(1, 255));
430430
}
431+
432+
public static Map<String, Object> randomMeta() {
433+
if (randomBoolean()) {
434+
if (randomBoolean()) {
435+
return Collections.singletonMap(randomAlphaOfLength(4), randomAlphaOfLength(4));
436+
} else {
437+
return Collections.singletonMap(randomAlphaOfLength(5),
438+
Collections.singletonMap(randomAlphaOfLength(4), randomAlphaOfLength(4)));
439+
}
440+
} else {
441+
return null;
442+
}
443+
}
431444
}

x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistry.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private List<Step> parseStepsFromPhase(String policy, String currentPhase, Strin
162162
if (phaseExecutionInfo.getPhase() != null) {
163163
phaseMap.put(currentPhase, phaseExecutionInfo.getPhase());
164164
}
165-
policyToExecute = new LifecyclePolicy(currentPolicy.getType(), currentPolicy.getName(), phaseMap);
165+
policyToExecute = new LifecyclePolicy(currentPolicy.getType(), currentPolicy.getName(), phaseMap, currentPolicy.getMetadata());
166166
}
167167
LifecyclePolicySecurityClient policyClient = new LifecyclePolicySecurityClient(client,
168168
ClientHelper.INDEX_LIFECYCLE_ORIGIN, lifecyclePolicyMap.get(policy).getHeaders());

x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/LifecyclePolicyTestsUtils.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import java.util.Map;
1717

18+
import static org.elasticsearch.xpack.core.ilm.LifecyclePolicyTests.randomMeta;
19+
1820
/**
1921
* This class is here for constructing instances of {@link LifecyclePolicy} that differs from
2022
* the main {@link TimeseriesLifecycleType} one. Since the more generic constructor is package-private so
@@ -24,11 +26,11 @@
2426
public class LifecyclePolicyTestsUtils {
2527

2628
public static LifecyclePolicy newTestLifecyclePolicy(String policyName, Map<String, Phase> phases) {
27-
return new LifecyclePolicy(TestLifecycleType.INSTANCE, policyName, phases);
29+
return new LifecyclePolicy(TestLifecycleType.INSTANCE, policyName, phases, randomMeta());
2830
}
2931

3032
public static LifecyclePolicy newLockableLifecyclePolicy(String policyName, Map<String, Phase> phases) {
31-
return new LifecyclePolicy(LockableLifecycleType.INSTANCE, policyName, phases);
33+
return new LifecyclePolicy(LockableLifecycleType.INSTANCE, policyName, phases, randomMeta());
3234
}
3335

3436
public static LifecyclePolicy randomTimeseriesLifecyclePolicy(String policyName) {

0 commit comments

Comments
 (0)