diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadata.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadata.java index ca2c5f1a53571..bfb2bee1edaac 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadata.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadata.java @@ -18,23 +18,33 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.Map; import java.util.Objects; public class LifecyclePolicyMetadata extends AbstractDiffable implements ToXContentObject, Diffable { - public static final ParseField POLICY = new ParseField("policy"); - public static final ParseField HEADERS = new ParseField("headers"); + static final ParseField POLICY = new ParseField("policy"); + static final ParseField HEADERS = new ParseField("headers"); + static final ParseField VERSION = new ParseField("version"); + static final ParseField MODIFIED_DATE = new ParseField("modified_date"); + static final ParseField MODIFIED_DATE_STRING = new ParseField("modified_date_string"); + @SuppressWarnings("unchecked") public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("policy_metadata", a -> { LifecyclePolicy policy = (LifecyclePolicy) a[0]; - return new LifecyclePolicyMetadata(policy, (Map) a[1]); + return new LifecyclePolicyMetadata(policy, (Map) a[1], (long) a[2], (long) a[3]); }); static { PARSER.declareObject(ConstructingObjectParser.constructorArg(), LifecyclePolicy::parse, POLICY); PARSER.declareField(ConstructingObjectParser.constructorArg(), XContentParser::mapStrings, HEADERS, ValueType.OBJECT); + PARSER.declareLong(ConstructingObjectParser.constructorArg(), VERSION); + PARSER.declareLong(ConstructingObjectParser.constructorArg(), MODIFIED_DATE); + PARSER.declareString(ConstructingObjectParser.constructorArg(), MODIFIED_DATE_STRING); } public static LifecyclePolicyMetadata parse(XContentParser parser, String name) { @@ -43,16 +53,22 @@ public static LifecyclePolicyMetadata parse(XContentParser parser, String name) private final LifecyclePolicy policy; private final Map headers; + private final long version; + private final long modifiedDate; - public LifecyclePolicyMetadata(LifecyclePolicy policy, Map headers) { + public LifecyclePolicyMetadata(LifecyclePolicy policy, Map headers, long version, long modifiedDate) { this.policy = policy; this.headers = headers; + this.version = version; + this.modifiedDate = modifiedDate; } @SuppressWarnings("unchecked") public LifecyclePolicyMetadata(StreamInput in) throws IOException { this.policy = new LifecyclePolicy(in); this.headers = (Map) in.readGenericValue(); + this.version = in.readVLong(); + this.modifiedDate = in.readVLong(); } public Map getHeaders() { @@ -67,11 +83,27 @@ public String getName() { return policy.getName(); } + public long getVersion() { + return version; + } + + public long getModifiedDate() { + return modifiedDate; + } + + public String getModifiedDateString() { + ZonedDateTime modifiedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(modifiedDate), ZoneOffset.UTC); + return modifiedDateTime.toString(); + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); builder.field(POLICY.getPreferredName(), policy); builder.field(HEADERS.getPreferredName(), headers); + builder.field(VERSION.getPreferredName(), version); + builder.field(MODIFIED_DATE.getPreferredName(), modifiedDate); + builder.field(MODIFIED_DATE_STRING.getPreferredName(), getModifiedDateString()); builder.endObject(); return builder; } @@ -80,11 +112,13 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws public void writeTo(StreamOutput out) throws IOException { policy.writeTo(out); out.writeGenericValue(headers); + out.writeVLong(version); + out.writeVLong(modifiedDate); } @Override public int hashCode() { - return Objects.hash(policy, headers); + return Objects.hash(policy, headers, version, modifiedDate); } @Override @@ -97,7 +131,9 @@ public boolean equals(Object obj) { } LifecyclePolicyMetadata other = (LifecyclePolicyMetadata) obj; return Objects.equals(policy, other.policy) && - Objects.equals(headers, other.headers); + Objects.equals(headers, other.headers) && + Objects.equals(version, other.version) && + Objects.equals(modifiedDate, other.modifiedDate); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleAction.java index de3002994581e..aaa295354a850 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleAction.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; @@ -37,24 +38,28 @@ public Response newResponse() { public static class Response extends ActionResponse implements ToXContentObject { - private List policies; + private List policies; public Response() { } - public Response(List policies) { + public Response(List policies) { this.policies = policies; } - public List getPolicies() { + public List getPolicies() { return policies; } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - for (LifecyclePolicy policy : policies) { - builder.field(policy.getName(), policy); + for (LifecyclePolicyResponseItem item : policies) { + builder.startObject(item.getLifecyclePolicy().getName()); + builder.field("version", item.getVersion()); + builder.field("modified_date", item.getModifiedDate()); + builder.field("policy", item.getLifecyclePolicy()); + builder.endObject(); } builder.endObject(); return builder; @@ -62,7 +67,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws @Override public void readFrom(StreamInput in) throws IOException { - policies = in.readList(LifecyclePolicy::new); + this.policies = in.readList(LifecyclePolicyResponseItem::new); } @Override @@ -148,4 +153,61 @@ public boolean equals(Object obj) { } + public static class LifecyclePolicyResponseItem implements Writeable { + private final LifecyclePolicy lifecyclePolicy; + private final long version; + private final String modifiedDate; + + public LifecyclePolicyResponseItem(LifecyclePolicy lifecyclePolicy, long version, String modifiedDate) { + this.lifecyclePolicy = lifecyclePolicy; + this.version = version; + this.modifiedDate = modifiedDate; + } + + LifecyclePolicyResponseItem(StreamInput in) throws IOException { + this.lifecyclePolicy = new LifecyclePolicy(in); + this.version = in.readVLong(); + this.modifiedDate = in.readString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + lifecyclePolicy.writeTo(out); + out.writeVLong(version); + out.writeString(modifiedDate); + } + + public LifecyclePolicy getLifecyclePolicy() { + return lifecyclePolicy; + } + + public long getVersion() { + return version; + } + + public String getModifiedDate() { + return modifiedDate; + } + + @Override + public int hashCode() { + return Objects.hash(lifecyclePolicy, version, modifiedDate); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + LifecyclePolicyResponseItem other = (LifecyclePolicyResponseItem) obj; + return Objects.equals(lifecyclePolicy, other.lifecyclePolicy) && + Objects.equals(version, other.version) && + Objects.equals(modifiedDate, other.modifiedDate); + } + + } + } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadataTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadataTests.java index 71118c625498a..5cb75e132ce92 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadataTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyMetadataTests.java @@ -75,7 +75,8 @@ protected LifecyclePolicyMetadata createTestInstance() { for (int i = 0; i < numberHeaders; i++) { headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10)); } - return new LifecyclePolicyMetadata(LifecyclePolicyTests.randomTimeseriesLifecyclePolicy(lifecycleName), headers); + return new LifecyclePolicyMetadata(LifecyclePolicyTests.randomTimeseriesLifecyclePolicy(lifecycleName), headers, + randomNonNegativeLong(), randomNonNegativeLong()); } @Override @@ -87,7 +88,9 @@ protected Reader instanceReader() { protected LifecyclePolicyMetadata mutateInstance(LifecyclePolicyMetadata instance) throws IOException { LifecyclePolicy policy = instance.getPolicy(); Map headers = instance.getHeaders(); - switch (between(0, 1)) { + long version = instance.getVersion(); + long creationDate = instance.getModifiedDate(); + switch (between(0, 3)) { case 0: policy = new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, policy.getName() + randomAlphaOfLengthBetween(1, 5), policy.getPhases()); @@ -96,10 +99,16 @@ protected LifecyclePolicyMetadata mutateInstance(LifecyclePolicyMetadata instanc headers = new HashMap<>(headers); headers.put(randomAlphaOfLength(11), randomAlphaOfLength(11)); break; + case 2: + version++; + break; + case 3: + creationDate++; + break; default: throw new AssertionError("Illegal randomisation branch"); } - return new LifecyclePolicyMetadata(policy, headers); + return new LifecyclePolicyMetadata(policy, headers, version, creationDate); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleResponseTests.java index 63d963d59da21..08688407b3db6 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleResponseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetLifecycleResponseTests.java @@ -8,10 +8,10 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.test.AbstractStreamableTestCase; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction; -import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleType; import org.elasticsearch.xpack.core.indexlifecycle.MockAction; import org.elasticsearch.xpack.core.indexlifecycle.TestLifecycleType; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction.LifecyclePolicyResponseItem; import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction.Response; import java.util.ArrayList; @@ -25,11 +25,12 @@ public class GetLifecycleResponseTests extends AbstractStreamableTestCase policies = new ArrayList<>(); + List responseItems = new ArrayList<>(); for (int i = 0; i < randomIntBetween(0, 2); i++) { - policies.add(randomTestLifecyclePolicy(randomPrefix + i)); + responseItems.add(new LifecyclePolicyResponseItem(randomTestLifecyclePolicy(randomPrefix + i), + randomNonNegativeLong(), randomAlphaOfLength(8))); } - return new Response(policies); + return new Response(responseItems); } @Override @@ -45,16 +46,18 @@ protected NamedWriteableRegistry getNamedWriteableRegistry() { @Override protected Response mutateInstance(Response response) { - List policies = new ArrayList<>(response.getPolicies()); - if (policies.size() > 0) { + List responseItems = new ArrayList<>(response.getPolicies()); + if (responseItems.size() > 0) { if (randomBoolean()) { - policies.add(randomTestLifecyclePolicy(randomAlphaOfLength(5))); + responseItems.add(new LifecyclePolicyResponseItem(randomTestLifecyclePolicy(randomAlphaOfLength(5)), + randomNonNegativeLong(), randomAlphaOfLength(4))); } else { - policies.remove(policies.size() - 1); + responseItems.remove(0); } } else { - policies.add(randomTestLifecyclePolicy(randomAlphaOfLength(2))); + responseItems.add(new LifecyclePolicyResponseItem(randomTestLifecyclePolicy(randomAlphaOfLength(2)), + randomNonNegativeLong(), randomAlphaOfLength(4))); } - return new Response(policies); + return new Response(responseItems); } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetLifecycleAction.java index 27cc82d0c0e82..638bc82400047 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetLifecycleAction.java @@ -20,8 +20,9 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; -import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; +import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata; import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction.LifecyclePolicyResponseItem; import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction.Request; import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction.Response; @@ -49,24 +50,29 @@ protected Response newResponse() { } @Override - protected void masterOperation(Request request, ClusterState state, ActionListener listener) throws Exception { + protected void masterOperation(Request request, ClusterState state, ActionListener listener) { IndexLifecycleMetadata metadata = clusterService.state().metaData().custom(IndexLifecycleMetadata.TYPE); if (metadata == null) { listener.onFailure(new ResourceNotFoundException("Lifecycle policy not found: {}", Arrays.toString(request.getPolicyNames()))); } else { - List requestedPolicies; + List requestedPolicies; // if no policies explicitly provided, behave as if `*` was specified if (request.getPolicyNames().length == 0) { - requestedPolicies = new ArrayList<>(metadata.getPolicies().values()); + requestedPolicies = new ArrayList<>(metadata.getPolicyMetadatas().size()); + for (LifecyclePolicyMetadata policyMetadata : metadata.getPolicyMetadatas().values()) { + requestedPolicies.add(new LifecyclePolicyResponseItem(policyMetadata.getPolicy(), + policyMetadata.getVersion(), policyMetadata.getModifiedDateString())); + } } else { requestedPolicies = new ArrayList<>(request.getPolicyNames().length); for (String name : request.getPolicyNames()) { - LifecyclePolicy policy = metadata.getPolicies().get(name); - if (policy == null) { + LifecyclePolicyMetadata policyMetadata = metadata.getPolicyMetadatas().get(name); + if (policyMetadata == null) { listener.onFailure(new ResourceNotFoundException("Lifecycle policy not found: {}", name)); return; } - requestedPolicies.add(policy); + requestedPolicies.add(new LifecyclePolicyResponseItem(policyMetadata.getPolicy(), + policyMetadata.getVersion(), policyMetadata.getModifiedDateString())); } } listener.onResponse(new Response(requestedPolicies)); @@ -77,4 +83,4 @@ protected void masterOperation(Request request, ClusterState state, ActionListen protected ClusterBlockException checkBlock(Request request, ClusterState state) { return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); } -} \ No newline at end of file +} diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java index 61640fdac21f6..2a56f179f39a5 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java @@ -28,6 +28,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction.Request; import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction.Response; +import java.time.Instant; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; @@ -79,9 +80,12 @@ public ClusterState execute(ClusterState currentState) throws Exception { if (currentMetadata == null) { // first time using index-lifecycle feature, bootstrap metadata currentMetadata = IndexLifecycleMetadata.EMPTY; } - // NORELEASE Check if current step exists in new policy and if not move to next available step + LifecyclePolicyMetadata existingPolicyMetadata = currentMetadata.getPolicyMetadatas() + .get(request.getPolicy().getName()); + long nextVersion = (existingPolicyMetadata == null) ? 1L : existingPolicyMetadata.getVersion() + 1L; SortedMap newPolicies = new TreeMap<>(currentMetadata.getPolicyMetadatas()); - LifecyclePolicyMetadata lifecyclePolicyMetadata = new LifecyclePolicyMetadata(request.getPolicy(), filteredHeaders); + LifecyclePolicyMetadata lifecyclePolicyMetadata = new LifecyclePolicyMetadata(request.getPolicy(), filteredHeaders, + nextVersion, Instant.now().toEpochMilli()); newPolicies.put(lifecyclePolicyMetadata.getName(), lifecyclePolicyMetadata); IndexLifecycleMetadata newMetadata = new IndexLifecycleMetadata(newPolicies, OperationMode.RUNNING); newState.metaData(MetaData.builder(currentState.getMetaData()) diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java index 2e3e39d8f8345..35a907e06bd2c 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java @@ -94,9 +94,12 @@ public void prepareState() throws IOException { LifecyclePolicy invalidPolicy = newTestLifecyclePolicy(invalidPolicyName, Collections.singletonMap(invalidPhase.getName(), invalidPhase)); Map policyMap = new HashMap<>(); - policyMap.put(mixedPolicyName, new LifecyclePolicyMetadata(mixedPolicy, Collections.emptyMap())); - policyMap.put(allClusterPolicyName, new LifecyclePolicyMetadata(allClusterPolicy, Collections.emptyMap())); - policyMap.put(invalidPolicyName, new LifecyclePolicyMetadata(invalidPolicy, Collections.emptyMap())); + policyMap.put(mixedPolicyName, new LifecyclePolicyMetadata(mixedPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); + policyMap.put(allClusterPolicyName, new LifecyclePolicyMetadata(allClusterPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); + policyMap.put(invalidPolicyName, new LifecyclePolicyMetadata(invalidPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); policyStepsRegistry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY); indexName = randomAlphaOfLength(5); diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInitialisationIT.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInitialisationIT.java index 77d0bd84ce8f4..376e3d2175042 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInitialisationIT.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInitialisationIT.java @@ -36,10 +36,12 @@ import org.elasticsearch.xpack.core.indexlifecycle.Phase; import org.elasticsearch.xpack.core.indexlifecycle.Step; import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction; import org.junit.Before; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -57,6 +59,10 @@ import static org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyTestsUtils.newLockableLifecyclePolicy; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.core.CombinableMatcher.both; +import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; @ESIntegTestCase.ClusterScope(scope = Scope.TEST, numDataNodes = 0) @@ -133,8 +139,22 @@ public void testSingleNodeCluster() throws Exception { final String node1 = getLocalNodeId(server_1); logger.info("Creating lifecycle [test_lifecycle]"); PutLifecycleAction.Request putLifecycleRequest = new PutLifecycleAction.Request(lifecyclePolicy); + long lowerBoundModifiedDate = Instant.now().toEpochMilli(); PutLifecycleAction.Response putLifecycleResponse = client().execute(PutLifecycleAction.INSTANCE, putLifecycleRequest).get(); assertAcked(putLifecycleResponse); + long upperBoundModifiedDate = Instant.now().toEpochMilli(); + + // assert version and modified_date + GetLifecycleAction.Response getLifecycleResponse = client().execute(GetLifecycleAction.INSTANCE, + new GetLifecycleAction.Request()).get(); + assertThat(getLifecycleResponse.getPolicies().size(), equalTo(1)); + GetLifecycleAction.LifecyclePolicyResponseItem responseItem = getLifecycleResponse.getPolicies().get(0); + assertThat(responseItem.getLifecyclePolicy(), equalTo(lifecyclePolicy)); + assertThat(responseItem.getVersion(), equalTo(1L)); + long actualModifiedDate = Instant.parse(responseItem.getModifiedDate()).toEpochMilli(); + assertThat(actualModifiedDate, + is(both(greaterThanOrEqualTo(lowerBoundModifiedDate)).and(lessThanOrEqualTo(upperBoundModifiedDate)))); + logger.info("Creating index [test]"); CreateIndexResponse createIndexResponse = client().admin().indices().create(createIndexRequest("test").settings(settings)) .actionGet(); diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java index 60d4c3a829f11..97f78c89dc9ea 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java @@ -54,7 +54,8 @@ protected IndexLifecycleMetadata createTestInstance() { Map policies = new HashMap<>(numPolicies); for (int i = 0; i < numPolicies; i++) { LifecyclePolicy policy = randomTimeseriesLifecyclePolicy(randomAlphaOfLength(4) + i); - policies.put(policy.getName(), new LifecyclePolicyMetadata(policy, Collections.emptyMap())); + policies.put(policy.getName(), new LifecyclePolicyMetadata(policy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); } return new IndexLifecycleMetadata(policies, randomFrom(OperationMode.values())); } @@ -108,7 +109,8 @@ protected MetaData.Custom mutateInstance(MetaData.Custom instance) { OperationMode mode = metadata.getOperationMode(); if (randomBoolean()) { String policyName = randomAlphaOfLength(10); - policies.put(policyName, new LifecyclePolicyMetadata(randomTimeseriesLifecyclePolicy(policyName), Collections.emptyMap())); + policies.put(policyName, new LifecyclePolicyMetadata(randomTimeseriesLifecyclePolicy(policyName), Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); } else { mode = randomValueOtherThan(metadata.getOperationMode(), () -> randomFrom(OperationMode.values())); } @@ -148,7 +150,8 @@ public static IndexLifecycleMetadata createTestInstance(int numPolicies, Operati phases.put(phaseName, new Phase(phaseName, after, actions)); } String policyName = randomAlphaOfLength(10); - policies.put(policyName, new LifecyclePolicyMetadata(newTestLifecyclePolicy(policyName, phases), Collections.emptyMap())); + policies.put(policyName, new LifecyclePolicyMetadata(newTestLifecyclePolicy(policyName, phases), Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); } return new IndexLifecycleMetadata(policies, mode); } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java index 432a1229170cc..ff846b2553c36 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java @@ -560,7 +560,7 @@ public void testMoveClusterStateToNextStep() { () -> LifecyclePolicyTests.randomTestLifecyclePolicy("policy")); Phase nextPhase = policy.getPhases().values().stream().findFirst().get(); List policyMetadatas = Collections.singletonList( - new LifecyclePolicyMetadata(policy, Collections.emptyMap())); + new LifecyclePolicyMetadata(policy, Collections.emptyMap(), randomNonNegativeLong(), randomNonNegativeLong())); StepKey currentStep = new StepKey("current_phase", "current_action", "current_step"); StepKey nextStep = new StepKey(nextPhase.getName(), "next_action", "next_step"); long now = randomNonNegativeLong(); @@ -645,7 +645,7 @@ public void testSuccessfulValidatedMoveClusterStateToNextStep() { () -> LifecyclePolicyTests.randomTestLifecyclePolicy(policyName)); Phase nextPhase = policy.getPhases().values().stream().findFirst().get(); List policyMetadatas = Collections.singletonList( - new LifecyclePolicyMetadata(policy, Collections.emptyMap())); + new LifecyclePolicyMetadata(policy, Collections.emptyMap(), randomNonNegativeLong(), randomNonNegativeLong())); StepKey currentStepKey = new StepKey("current_phase", "current_action", "current_step"); StepKey nextStepKey = new StepKey(nextPhase.getName(), "next_action", "next_step"); long now = randomNonNegativeLong(); @@ -894,8 +894,10 @@ public void testSetPolicyForIndex() { .put(LifecycleSettings.LIFECYCLE_ACTION, currentStep.getAction()) .put(LifecycleSettings.LIFECYCLE_STEP, currentStep.getName()).put(LifecycleSettings.LIFECYCLE_SKIP, true); List policyMetadatas = new ArrayList<>(); - policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap())); - policyMetadatas.add(new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap())); + policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); + policyMetadatas.add(new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, policyMetadatas); Index index = clusterState.metaData().index(indexName).getIndex(); Index[] indices = new Index[] { index }; @@ -940,7 +942,8 @@ public void testSetPolicyForIndexIndexDoesntExist() { .put(LifecycleSettings.LIFECYCLE_ACTION, currentStep.getAction()) .put(LifecycleSettings.LIFECYCLE_STEP, currentStep.getName()).put(LifecycleSettings.LIFECYCLE_SKIP, true); List policyMetadatas = new ArrayList<>(); - policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap())); + policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, policyMetadatas); Index index = new Index("doesnt_exist", "im_not_here"); Index[] indices = new Index[] { index }; @@ -989,7 +992,8 @@ public void testRemovePolicyForIndex() { .put(LifecycleSettings.LIFECYCLE_ACTION, currentStep.getAction()) .put(LifecycleSettings.LIFECYCLE_STEP, currentStep.getName()).put(LifecycleSettings.LIFECYCLE_SKIP, true); List policyMetadatas = new ArrayList<>(); - policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap())); + policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, policyMetadatas); Index index = clusterState.metaData().index(indexName).getIndex(); Index[] indices = new Index[] { index }; @@ -1025,7 +1029,8 @@ public void testRemovePolicyForIndexIndexDoesntExist() { .put(LifecycleSettings.LIFECYCLE_ACTION, currentStep.getAction()) .put(LifecycleSettings.LIFECYCLE_STEP, currentStep.getName()).put(LifecycleSettings.LIFECYCLE_SKIP, true); List policyMetadatas = new ArrayList<>(); - policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap())); + policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, policyMetadatas); Index index = new Index("doesnt_exist", "im_not_here"); Index[] indices = new Index[] { index }; @@ -1048,7 +1053,8 @@ public void testRemovePolicyForIndexIndexInUnsafe() { .put(LifecycleSettings.LIFECYCLE_ACTION, currentStep.getAction()) .put(LifecycleSettings.LIFECYCLE_STEP, currentStep.getName()).put(LifecycleSettings.LIFECYCLE_SKIP, true); List policyMetadatas = new ArrayList<>(); - policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap())); + policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, policyMetadatas); Index index = clusterState.metaData().index(indexName).getIndex(); Index[] indices = new Index[] { index }; @@ -1066,7 +1072,8 @@ public void testIsReadyToTransition() { MockAsyncActionStep step = new MockAsyncActionStep(stepKey, null); step.setWillComplete(true); SortedMap lifecyclePolicyMap = new TreeMap<>(Collections.singletonMap(policyName, - new LifecyclePolicyMetadata(createPolicy(policyName, null, step.getKey()), new HashMap<>()))); + new LifecyclePolicyMetadata(createPolicy(policyName, null, step.getKey()), new HashMap<>(), + randomNonNegativeLong(), randomNonNegativeLong()))); Index index = new Index("my_index", "uuid"); Map firstStepMap = Collections.singletonMap(policyName, step); Map policySteps = Collections.singletonMap(step.getKey(), step); diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java index 0444e14079192..d7296ffc81622 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java @@ -113,7 +113,8 @@ public void testStoppedModeSkip() { Phase phase = new Phase("phase", TimeValue.ZERO, Collections.singletonMap("action", mockAction)); LifecyclePolicy policy = newTestLifecyclePolicy(policyName, Collections.singletonMap(phase.getName(), phase)); SortedMap policyMap = new TreeMap<>(); - policyMap.put(policyName, new LifecyclePolicyMetadata(policy, Collections.emptyMap())); + policyMap.put(policyName, new LifecyclePolicyMetadata(policy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()) .settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey(), policyName)) @@ -144,7 +145,8 @@ public void testRequestedStopOnShrink() { Phase phase = new Phase("phase", TimeValue.ZERO, Collections.singletonMap("action", mockAction)); LifecyclePolicy policy = newTestLifecyclePolicy(policyName, Collections.singletonMap(phase.getName(), phase)); SortedMap policyMap = new TreeMap<>(); - policyMap.put(policyName, new LifecyclePolicyMetadata(policy, Collections.emptyMap())); + policyMap.put(policyName, new LifecyclePolicyMetadata(policy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()) .settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey(), policyName) @@ -184,7 +186,8 @@ public void testRequestedStopOnSafeAction() { Phase phase = new Phase("phase", TimeValue.ZERO, Collections.singletonMap("action", mockAction)); LifecyclePolicy policy = newTestLifecyclePolicy(policyName, Collections.singletonMap(phase.getName(), phase)); SortedMap policyMap = new TreeMap<>(); - policyMap.put(policyName, new LifecyclePolicyMetadata(policy, Collections.emptyMap())); + policyMap.put(policyName, new LifecyclePolicyMetadata(policy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())); Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()) .settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey(), policyName) diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToErrorStepUpdateTaskTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToErrorStepUpdateTaskTests.java index bbc31eb9aeeda..40844d0f93d19 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToErrorStepUpdateTaskTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToErrorStepUpdateTaskTests.java @@ -50,7 +50,8 @@ public void setupClusterState() { .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); index = indexMetadata.getIndex(); IndexLifecycleMetadata ilmMeta = new IndexLifecycleMetadata( - Collections.singletonMap(policy, new LifecyclePolicyMetadata(lifecyclePolicy, Collections.emptyMap())), + Collections.singletonMap(policy, new LifecyclePolicyMetadata(lifecyclePolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())), OperationMode.RUNNING); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToNextStepUpdateTaskTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToNextStepUpdateTaskTests.java index 1c4ea47cb6186..cee1148d1bff5 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToNextStepUpdateTaskTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/MoveToNextStepUpdateTaskTests.java @@ -47,7 +47,8 @@ public void setupClusterState() { index = indexMetadata.getIndex(); lifecyclePolicy = LifecyclePolicyTests.randomTestLifecyclePolicy(policy); IndexLifecycleMetadata ilmMeta = new IndexLifecycleMetadata( - Collections.singletonMap(policy, new LifecyclePolicyMetadata(lifecyclePolicy, Collections.emptyMap())), + Collections.singletonMap(policy, new LifecyclePolicyMetadata(lifecyclePolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())), OperationMode.RUNNING); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java index 92914ed6ecbaa..1ea81001ef147 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java @@ -116,7 +116,7 @@ public void testUpdateFromNothingToSomethingToNothing() throws Exception { headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10)); } Map policyMap = Collections.singletonMap(newPolicy.getName(), - new LifecyclePolicyMetadata(newPolicy, headers)); + new LifecyclePolicyMetadata(newPolicy, headers, randomNonNegativeLong(), randomNonNegativeLong())); IndexLifecycleMetadata lifecycleMetadata = new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) @@ -203,7 +203,7 @@ public void testUpdateChangedPolicy() throws Exception { headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10)); } Map policyMap = Collections.singletonMap(newPolicy.getName(), - new LifecyclePolicyMetadata(newPolicy, headers)); + new LifecyclePolicyMetadata(newPolicy, headers, randomNonNegativeLong(), randomNonNegativeLong())); IndexLifecycleMetadata lifecycleMetadata = new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) @@ -224,7 +224,8 @@ public void testUpdateChangedPolicy() throws Exception { // swap out policy newPolicy = LifecyclePolicyTests.randomTestLifecyclePolicy(policyName); lifecycleMetadata = new IndexLifecycleMetadata(Collections.singletonMap(policyName, - new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap())), OperationMode.RUNNING); + new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap(), + randomNonNegativeLong(), randomNonNegativeLong())), OperationMode.RUNNING); currentState = ClusterState.builder(currentState) .metaData(MetaData.builder(metaData).putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata)).build(); registry.update(currentState, client); @@ -256,7 +257,7 @@ public void testUpdatePolicyButNoPhaseChangeIndexStepsDontChange() throws Except headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10)); } Map policyMap = Collections.singletonMap(newPolicy.getName(), - new LifecyclePolicyMetadata(newPolicy, headers)); + new LifecyclePolicyMetadata(newPolicy, headers, randomNonNegativeLong(), randomNonNegativeLong())); IndexLifecycleMetadata lifecycleMetadata = new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) @@ -300,7 +301,8 @@ public void testUpdatePolicyButNoPhaseChangeIndexStepsDontChange() throws Except assertThat(((ShrinkStep) gotStep).getNumberOfShards(), equalTo(1)); // Update the policy with the new policy, but keep the phase the same - policyMap = Collections.singletonMap(updatedPolicy.getName(), new LifecyclePolicyMetadata(updatedPolicy, headers)); + policyMap = Collections.singletonMap(updatedPolicy.getName(), new LifecyclePolicyMetadata(updatedPolicy, headers, + randomNonNegativeLong(), randomNonNegativeLong())); lifecycleMetadata = new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING); metaData = MetaData.builder(metaData) .putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata) diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/ilm/10_basic.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/ilm/10_basic.yml index 85f44549d80c2..eb004d2afa0ed 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/ilm/10_basic.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/ilm/10_basic.yml @@ -46,8 +46,10 @@ setup: acknowledge: true ilm.get_lifecycle: lifecycle: "my_timeseries_lifecycle" - - match: { my_timeseries_lifecycle.phases.warm.after: "10s" } - - match: { my_timeseries_lifecycle.phases.delete.after: "30s" } + - match: { my_timeseries_lifecycle.version: 1 } + - is_true: my_timeseries_lifecycle.modified_date + - match: { my_timeseries_lifecycle.policy.phases.warm.after: "10s" } + - match: { my_timeseries_lifecycle.policy.phases.delete.after: "30s" } - do: acknowledge: true @@ -91,8 +93,10 @@ setup: acknowledge: true ilm.get_lifecycle: lifecycle: "my_timeseries_lifecycle" - - match: { my_timeseries_lifecycle.phases.warm.after: "10s" } - - match: { my_timeseries_lifecycle.phases.delete.after: "30s" } + - match: { my_timeseries_lifecycle.version: 1 } + - is_true: my_timeseries_lifecycle.modified_date + - match: { my_timeseries_lifecycle.policy.phases.warm.after: "10s" } + - match: { my_timeseries_lifecycle.policy.phases.delete.after: "30s" } - do: @@ -139,8 +143,10 @@ setup: acknowledge: true ilm.get_lifecycle: lifecycle: "my_timeseries_lifecycle" - - match: { my_timeseries_lifecycle.phases.warm.after: "300s" } - - match: { my_timeseries_lifecycle.phases.delete.after: "600s" } + - match: { my_timeseries_lifecycle.version: 2 } + - is_true: my_timeseries_lifecycle.modified_date + - match: { my_timeseries_lifecycle.policy.phases.warm.after: "300s" } + - match: { my_timeseries_lifecycle.policy.phases.delete.after: "600s" } - do: acknowledge: true @@ -193,8 +199,8 @@ setup: acknowledge: true ilm.get_lifecycle: lifecycle: "my_timeseries_lifecycle" - - match: { my_timeseries_lifecycle.phases.warm.after: "10s" } - - match: { my_timeseries_lifecycle.phases.delete.after: "30s" } + - match: { my_timeseries_lifecycle.policy.phases.warm.after: "10s" } + - match: { my_timeseries_lifecycle.policy.phases.delete.after: "30s" } - do: indices.create: