add phase execution info to ILM Explain API (#33488)

adds a section for phase execution to the Explain API.

This contains

- phase definition
- policy name
- policy version
- modified date
This commit is contained in:
Tal Levy 2018-09-17 17:00:00 -07:00 committed by GitHub
parent 7ff11b4ae1
commit 94a66c556d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 760 additions and 301 deletions

View File

@ -19,18 +19,14 @@
package org.elasticsearch.client.indexlifecycle;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -43,9 +39,9 @@ import java.util.stream.Collectors;
* Since the API can be run over multiple indices the response provides a map of
* index to the explanation of the lifecycle status for that index.
*/
public class ExplainLifecycleResponse extends ActionResponse implements ToXContentObject {
public class ExplainLifecycleResponse implements ToXContentObject {
public static final ParseField INDICES_FIELD = new ParseField("indices");
private static final ParseField INDICES_FIELD = new ParseField("indices");
private Map<String, IndexLifecycleExplainResponse> indexResponses;
@ -62,9 +58,6 @@ public class ExplainLifecycleResponse extends ActionResponse implements ToXConte
return PARSER.apply(parser, null);
}
public ExplainLifecycleResponse() {
}
public ExplainLifecycleResponse(Map<String, IndexLifecycleExplainResponse> indexResponses) {
this.indexResponses = indexResponses;
}
@ -91,25 +84,6 @@ public class ExplainLifecycleResponse extends ActionResponse implements ToXConte
return builder;
}
@Override
public void readFrom(StreamInput in) throws IOException {
int size = in.readVInt();
Map<String, IndexLifecycleExplainResponse> indexResponses = new HashMap<>(size);
for (int i = 0; i < size; i++) {
IndexLifecycleExplainResponse indexResponse = new IndexLifecycleExplainResponse(in);
indexResponses.put(indexResponse.getIndex(), indexResponse);
}
this.indexResponses = indexResponses;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(indexResponses.size());
for (IndexLifecycleExplainResponse e : indexResponses.values()) {
e.writeTo(out);
}
}
@Override
public int hashCode() {
return Objects.hash(indexResponses);

View File

@ -23,9 +23,6 @@ import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
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.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -37,7 +34,7 @@ import org.joda.time.chrono.ISOChronology;
import java.io.IOException;
import java.util.Objects;
public class IndexLifecycleExplainResponse implements ToXContentObject, Writeable {
public class IndexLifecycleExplainResponse implements ToXContentObject {
private static final ParseField INDEX_FIELD = new ParseField("index");
private static final ParseField MANAGED_BY_ILM_FIELD = new ParseField("managed");
@ -52,23 +49,25 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
private static final ParseField ACTION_TIME_FIELD = new ParseField("action_time");
private static final ParseField STEP_TIME_FIELD = new ParseField("step_time");
private static final ParseField STEP_INFO_FIELD = new ParseField("step_info");
private static final ParseField PHASE_EXECUTION_INFO = new ParseField("phase_execution");
public static final ConstructingObjectParser<IndexLifecycleExplainResponse, Void> PARSER = new ConstructingObjectParser<>(
"index_lifecycle_explain_response",
a -> new IndexLifecycleExplainResponse(
(String) a[0],
(boolean) a[1],
(String) a[2],
(boolean) (a[3] == null ? false: a[3]),
(long) (a[4] == null ? -1L: a[4]),
(String) a[5],
(String) a[6],
(String) a[7],
(String) a[8],
(long) (a[9] == null ? -1L: a[9]),
(long) (a[10] == null ? -1L: a[10]),
(long) (a[11] == null ? -1L: a[11]),
(BytesReference) a[12]));
"index_lifecycle_explain_response",
a -> new IndexLifecycleExplainResponse(
(String) a[0],
(boolean) a[1],
(String) a[2],
(boolean) (a[3] == null ? false: a[3]),
(long) (a[4] == null ? -1L: a[4]),
(String) a[5],
(String) a[6],
(String) a[7],
(String) a[8],
(long) (a[9] == null ? -1L: a[9]),
(long) (a[10] == null ? -1L: a[10]),
(long) (a[11] == null ? -1L: a[11]),
(BytesReference) a[12],
(PhaseExecutionInfo) a[13]));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), INDEX_FIELD);
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), MANAGED_BY_ILM_FIELD);
@ -87,6 +86,8 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
builder.copyCurrentStructure(p);
return BytesArray.bytes(builder);
}, STEP_INFO_FIELD);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> PhaseExecutionInfo.parse(p, ""),
PHASE_EXECUTION_INFO);
}
private final String index;
@ -102,30 +103,32 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
private final boolean skip;
private final boolean managedByILM;
private final BytesReference stepInfo;
private final PhaseExecutionInfo phaseExecutionInfo;
public static IndexLifecycleExplainResponse newManagedIndexResponse(String index, String policyName, boolean skip, long lifecycleDate,
String phase, String action, String step, String failedStep, long phaseTime, long actionTime, long stepTime,
BytesReference stepInfo) {
String phase, String action, String step, String failedStep,
long phaseTime, long actionTime, long stepTime,
BytesReference stepInfo, PhaseExecutionInfo phaseExecutionInfo) {
return new IndexLifecycleExplainResponse(index, true, policyName, skip, lifecycleDate, phase, action, step, failedStep, phaseTime,
actionTime, stepTime, stepInfo);
actionTime, stepTime, stepInfo, phaseExecutionInfo);
}
public static IndexLifecycleExplainResponse newUnmanagedIndexResponse(String index) {
return new IndexLifecycleExplainResponse(index, false, null, false, -1L, null, null, null, null, -1L, -1L, -1L, null);
return new IndexLifecycleExplainResponse(index, false, null, false, -1L, null, null, null, null, -1L, -1L, -1L, null, null);
}
private IndexLifecycleExplainResponse(String index, boolean managedByILM, String policyName, boolean skip, long lifecycleDate,
String phase, String action, String step, String failedStep, long phaseTime, long actionTime, long stepTime,
BytesReference stepInfo) {
String phase, String action, String step, String failedStep, long phaseTime, long actionTime,
long stepTime, BytesReference stepInfo, PhaseExecutionInfo phaseExecutionInfo) {
if (managedByILM) {
if (policyName == null) {
throw new IllegalArgumentException("[" + POLICY_NAME_FIELD.getPreferredName() + "] cannot be null for managed index");
}
} else {
if (policyName != null || lifecycleDate >= 0 || phase != null || action != null || step != null || failedStep != null
|| phaseTime >= 0 || actionTime >= 0 || stepTime >= 0 || stepInfo != null) {
|| phaseTime >= 0 || actionTime >= 0 || stepTime >= 0 || stepInfo != null || phaseExecutionInfo != null) {
throw new IllegalArgumentException(
"Unmanaged index response must only contain fields: [" + MANAGED_BY_ILM_FIELD + ", " + INDEX_FIELD + "]");
"Unmanaged index response must only contain fields: [" + MANAGED_BY_ILM_FIELD + ", " + INDEX_FIELD + "]");
}
}
this.index = index;
@ -141,56 +144,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
this.stepTime = stepTime;
this.failedStep = failedStep;
this.stepInfo = stepInfo;
}
public IndexLifecycleExplainResponse(StreamInput in) throws IOException {
index = in.readString();
managedByILM = in.readBoolean();
if (managedByILM) {
policyName = in.readString();
skip = in.readBoolean();
lifecycleDate = in.readZLong();
phase = in.readString();
action = in.readString();
step = in.readString();
failedStep = in.readOptionalString();
phaseTime = in.readZLong();
actionTime = in.readZLong();
stepTime = in.readZLong();
stepInfo = in.readOptionalBytesReference();
} else {
policyName = null;
skip = false;
lifecycleDate = -1L;
phase = null;
action = null;
step = null;
failedStep = null;
phaseTime = -1L;
actionTime = -1L;
stepTime = -1L;
stepInfo = null;
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(index);
out.writeBoolean(managedByILM);
if (managedByILM) {
out.writeString(policyName);
out.writeBoolean(skip);
out.writeZLong(lifecycleDate);
out.writeString(phase);
out.writeString(action);
out.writeString(step);
out.writeOptionalString(failedStep);
out.writeZLong(phaseTime);
out.writeZLong(actionTime);
out.writeZLong(stepTime);
out.writeOptionalBytesReference(stepInfo);
}
this.phaseExecutionInfo = phaseExecutionInfo;
}
public String getIndex() {
@ -245,6 +199,10 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
return stepInfo;
}
public PhaseExecutionInfo getPhaseExecutionInfo() {
return phaseExecutionInfo;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
@ -282,6 +240,9 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
if (stepInfo != null && stepInfo.length() > 0) {
builder.rawField(STEP_INFO_FIELD.getPreferredName(), stepInfo.streamInput(), XContentType.JSON);
}
if (phaseExecutionInfo != null) {
builder.field(PHASE_EXECUTION_INFO.getPreferredName(), phaseExecutionInfo);
}
}
builder.endObject();
return builder;
@ -290,7 +251,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
@Override
public int hashCode() {
return Objects.hash(index, managedByILM, policyName, skip, lifecycleDate, phase, action, step, failedStep, phaseTime, actionTime,
stepTime, stepInfo);
stepTime, stepInfo, phaseExecutionInfo);
}
@Override
@ -303,18 +264,19 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
}
IndexLifecycleExplainResponse other = (IndexLifecycleExplainResponse) obj;
return Objects.equals(index, other.index) &&
Objects.equals(managedByILM, other.managedByILM) &&
Objects.equals(policyName, other.policyName) &&
Objects.equals(skip, other.skip) &&
Objects.equals(lifecycleDate, other.lifecycleDate) &&
Objects.equals(phase, other.phase) &&
Objects.equals(action, other.action) &&
Objects.equals(step, other.step) &&
Objects.equals(failedStep, other.failedStep) &&
Objects.equals(phaseTime, other.phaseTime) &&
Objects.equals(actionTime, other.actionTime) &&
Objects.equals(stepTime, other.stepTime) &&
Objects.equals(stepInfo, other.stepInfo);
Objects.equals(managedByILM, other.managedByILM) &&
Objects.equals(policyName, other.policyName) &&
Objects.equals(skip, other.skip) &&
Objects.equals(lifecycleDate, other.lifecycleDate) &&
Objects.equals(phase, other.phase) &&
Objects.equals(action, other.action) &&
Objects.equals(step, other.step) &&
Objects.equals(failedStep, other.failedStep) &&
Objects.equals(phaseTime, other.phaseTime) &&
Objects.equals(actionTime, other.actionTime) &&
Objects.equals(stepTime, other.stepTime) &&
Objects.equals(stepInfo, other.stepInfo) &&
Objects.equals(phaseExecutionInfo, other.phaseExecutionInfo);
}
@Override
@ -323,3 +285,4 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
}
}

View File

@ -0,0 +1,130 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.indexlifecycle;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Objects;
/**
* This class contains information about the current phase being executed by Index
* Lifecycle Management on the specific index.
*/
public class PhaseExecutionInfo implements ToXContentObject {
private static final ParseField POLICY_NAME_FIELD = new ParseField("policy");
private static final ParseField PHASE_DEFINITION_FIELD = new ParseField("phase_definition");
private static final ParseField VERSION_FIELD = new ParseField("version");
private static final ParseField MODIFIED_DATE_IN_MILLIS_FIELD = new ParseField("modified_date_in_millis");
private static final ConstructingObjectParser<PhaseExecutionInfo, String> PARSER = new ConstructingObjectParser<>(
"phase_execution_info", false,
(a, name) -> new PhaseExecutionInfo((String) a[0], (Phase) a[1], (long) a[2], (long) a[3]));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), POLICY_NAME_FIELD);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), Phase::parse, PHASE_DEFINITION_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), VERSION_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), MODIFIED_DATE_IN_MILLIS_FIELD);
}
public static PhaseExecutionInfo parse(XContentParser parser, String name) {
return PARSER.apply(parser, name);
}
private final String policyName;
private final Phase phase;
private final long version;
private final long modifiedDate;
/**
* This class holds information about the current phase that is being executed
*
* @param policyName the name of the policy being executed, this may not be the current policy assigned to an index
* @param phase the current phase definition executed
* @param version the version of the <code>policyName</code> being executed
* @param modifiedDate the time the executing version of the phase was modified
*/
public PhaseExecutionInfo(String policyName, Phase phase, long version, long modifiedDate) {
this.policyName = policyName;
this.phase = phase;
this.version = version;
this.modifiedDate = modifiedDate;
}
public String getPolicyName() {
return policyName;
}
public Phase getPhase() {
return phase;
}
public long getVersion() {
return version;
}
public long getModifiedDate() {
return modifiedDate;
}
@Override
public int hashCode() {
return Objects.hash(policyName, phase, version, modifiedDate);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PhaseExecutionInfo other = (PhaseExecutionInfo) obj;
return Objects.equals(policyName, other.policyName) &&
Objects.equals(phase, other.phase) &&
Objects.equals(version, other.version) &&
Objects.equals(modifiedDate, other.modifiedDate);
}
@Override
public String toString() {
return Strings.toString(this, false, true);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(POLICY_NAME_FIELD.getPreferredName(), policyName);
if (phase != null) {
builder.field(PHASE_DEFINITION_FIELD.getPreferredName(), phase);
}
builder.field(VERSION_FIELD.getPreferredName(), version);
builder.timeField(MODIFIED_DATE_IN_MILLIS_FIELD.getPreferredName(), "modified_date", modifiedDate);
builder.endObject();
return builder;
}
}

View File

@ -36,6 +36,7 @@ import org.elasticsearch.client.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.client.indexlifecycle.LifecyclePolicyMetadata;
import org.elasticsearch.client.indexlifecycle.OperationMode;
import org.elasticsearch.client.indexlifecycle.Phase;
import org.elasticsearch.client.indexlifecycle.PhaseExecutionInfo;
import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest;
import org.elasticsearch.client.indexlifecycle.RolloverAction;
import org.elasticsearch.client.indexlifecycle.ShrinkAction;
@ -132,7 +133,8 @@ public class IndexLifecycleIT extends ESRestHighLevelClientTestCase {
Map<String, LifecycleAction> hotActions = Collections.singletonMap(
RolloverAction.NAME,
new RolloverAction(null, TimeValue.timeValueHours(50 * 24), null));
lifecyclePhases.put("hot", new Phase("hot", randomFrom(TimeValue.ZERO, null), hotActions));
Phase hotPhase = new Phase("hot", randomFrom(TimeValue.ZERO, null), hotActions);
lifecyclePhases.put("hot", hotPhase);
Map<String, LifecycleAction> warmActions = new HashMap<>();
warmActions.put(AllocateAction.NAME, new AllocateAction(null, null, null, Collections.singletonMap("_name", "node-1")));
@ -152,6 +154,11 @@ public class IndexLifecycleIT extends ESRestHighLevelClientTestCase {
AcknowledgedResponse putResponse = execute(putRequest, highLevelClient().indexLifecycle()::putLifecyclePolicy,
highLevelClient().indexLifecycle()::putLifecyclePolicyAsync);
assertTrue(putResponse.isAcknowledged());
GetLifecyclePolicyRequest getRequest = new GetLifecyclePolicyRequest(policy.getName());
GetLifecyclePolicyResponse getResponse = execute(getRequest, highLevelClient().indexLifecycle()::getLifecyclePolicy,
highLevelClient().indexLifecycle()::getLifecyclePolicyAsync);
long expectedPolicyModifiedDate = getResponse.getPolicies().get(policy.getName()).getModifiedDate();
createIndex("foo-01", Settings.builder().put("index.lifecycle.name", policy.getName())
.put("index.lifecycle.rollover_alias", "foo-alias").build(), "", "\"foo-alias\" : {}");
@ -182,6 +189,8 @@ public class IndexLifecycleIT extends ESRestHighLevelClientTestCase {
assertEquals("hot", fooResponse.getPhase());
assertEquals("rollover", fooResponse.getAction());
assertEquals("attempt_rollover", fooResponse.getStep());
assertEquals(new PhaseExecutionInfo(policy.getName(), new Phase("", hotPhase.getMinimumAge(), hotPhase.getActions()),
1L, expectedPolicyModifiedDate), fooResponse.getPhaseExecutionInfo());
IndexLifecycleExplainResponse bazResponse = indexResponses.get("baz-01");
assertNotNull(bazResponse);
assertTrue(bazResponse.managedByILM());

View File

@ -18,14 +18,19 @@
*/
package org.elasticsearch.client.indexlifecycle;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
import org.elasticsearch.test.AbstractXContentTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ExplainLifecycleResponseTests extends AbstractStreamableXContentTestCase<ExplainLifecycleResponse> {
public class ExplainLifecycleResponseTests extends AbstractXContentTestCase<ExplainLifecycleResponse> {
@Override
protected ExplainLifecycleResponse createTestInstance() {
@ -37,19 +42,6 @@ public class ExplainLifecycleResponseTests extends AbstractStreamableXContentTes
return new ExplainLifecycleResponse(indexResponses);
}
@Override
protected ExplainLifecycleResponse createBlankInstance() {
return new ExplainLifecycleResponse();
}
@Override
protected ExplainLifecycleResponse mutateInstance(ExplainLifecycleResponse response) {
Map<String, IndexLifecycleExplainResponse> indexResponses = new HashMap<>(response.getIndexResponses());
IndexLifecycleExplainResponse indexResponse = IndexExplainResponseTests.randomIndexExplainResponse();
indexResponses.put(indexResponse.getIndex(), indexResponse);
return new ExplainLifecycleResponse(indexResponses);
}
@Override
protected ExplainLifecycleResponse doParseInstance(XContentParser parser) throws IOException {
return ExplainLifecycleResponse.fromXContent(parser);
@ -59,4 +51,11 @@ public class ExplainLifecycleResponseTests extends AbstractStreamableXContentTes
protected boolean supportsUnknownFields() {
return false;
}
@Override
protected NamedXContentRegistry xContentRegistry() {
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse));
return new NamedXContentRegistry(entries);
}
}

View File

@ -19,20 +19,23 @@
package org.elasticsearch.client.indexlifecycle;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractSerializingTestCase;
import org.elasticsearch.test.AbstractXContentTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
public class IndexExplainResponseTests extends AbstractSerializingTestCase<IndexLifecycleExplainResponse> {
public class IndexExplainResponseTests extends AbstractXContentTestCase<IndexLifecycleExplainResponse> {
static IndexLifecycleExplainResponse randomIndexExplainResponse() {
if (frequently()) {
@ -50,7 +53,8 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
return IndexLifecycleExplainResponse.newManagedIndexResponse(randomAlphaOfLength(10), randomAlphaOfLength(10), randomBoolean(),
randomNonNegativeLong(), randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10),
randomBoolean() ? null : randomAlphaOfLength(10), randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(),
randomBoolean() ? null : new BytesArray(new RandomStepInfo(() -> randomAlphaOfLength(10)).toString()));
randomBoolean() ? null : new BytesArray(new RandomStepInfo(() -> randomAlphaOfLength(10)).toString()),
randomBoolean() ? null : PhaseExecutionInfoTests.randomPhaseExecutionInfo(""));
}
@Override
@ -58,99 +62,14 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
return randomIndexExplainResponse();
}
@Override
protected Reader<IndexLifecycleExplainResponse> instanceReader() {
return IndexLifecycleExplainResponse::new;
}
@Override
protected IndexLifecycleExplainResponse doParseInstance(XContentParser parser) throws IOException {
return IndexLifecycleExplainResponse.PARSER.apply(parser, null);
}
@Override
protected IndexLifecycleExplainResponse mutateInstance(IndexLifecycleExplainResponse instance) throws IOException {
String index = instance.getIndex();
String policy = instance.getPolicyName();
String phase = instance.getPhase();
String action = instance.getAction();
String step = instance.getStep();
String failedStep = instance.getFailedStep();
long policyTime = instance.getLifecycleDate();
long phaseTime = instance.getPhaseTime();
long actionTime = instance.getActionTime();
long stepTime = instance.getStepTime();
boolean managed = instance.managedByILM();
boolean skip = instance.skip();
BytesReference stepInfo = instance.getStepInfo();
if (managed) {
switch (between(0, 12)) {
case 0:
index = index + randomAlphaOfLengthBetween(1, 5);
break;
case 1:
policy = policy + randomAlphaOfLengthBetween(1, 5);
break;
case 2:
phase = phase + randomAlphaOfLengthBetween(1, 5);
break;
case 3:
action = action + randomAlphaOfLengthBetween(1, 5);
break;
case 4:
step = step + randomAlphaOfLengthBetween(1, 5);
break;
case 5:
if (Strings.hasLength(failedStep) == false) {
failedStep = randomAlphaOfLength(10);
} else if (randomBoolean()) {
failedStep = failedStep + randomAlphaOfLengthBetween(1, 5);
} else {
failedStep = null;
}
break;
case 6:
policyTime += randomLongBetween(0, 100000);
break;
case 7:
phaseTime += randomLongBetween(0, 100000);
break;
case 8:
actionTime += randomLongBetween(0, 100000);
break;
case 9:
stepTime += randomLongBetween(0, 100000);
break;
case 10:
if (Strings.hasLength(stepInfo) == false) {
stepInfo = new BytesArray(randomByteArrayOfLength(100));
} else if (randomBoolean()) {
stepInfo = randomValueOtherThan(stepInfo,
() -> new BytesArray(new RandomStepInfo(() -> randomAlphaOfLength(10)).toString()));
} else {
stepInfo = null;
}
break;
case 11:
skip = skip == false;
break;
case 12:
return IndexLifecycleExplainResponse.newUnmanagedIndexResponse(index);
default:
throw new AssertionError("Illegal randomisation branch");
}
return IndexLifecycleExplainResponse.newManagedIndexResponse(index, policy, skip, policyTime, phase, action, step, failedStep,
phaseTime, actionTime, stepTime, stepInfo);
} else {
switch (between(0, 1)) {
case 0:
return IndexLifecycleExplainResponse.newUnmanagedIndexResponse(index + randomAlphaOfLengthBetween(1, 5));
case 1:
return randomManagedIndexExplainResponse();
default:
throw new AssertionError("Illegal randomisation branch");
}
}
protected boolean supportsUnknownFields() {
return false;
}
private static class RandomStepInfo implements ToXContentObject {
@ -194,4 +113,10 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
}
}
@Override
protected NamedXContentRegistry xContentRegistry() {
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse));
return new NamedXContentRegistry(entries);
}
}

View File

@ -0,0 +1,67 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.indexlifecycle;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractXContentTestCase;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class PhaseExecutionInfoTests extends AbstractXContentTestCase<PhaseExecutionInfo> {
static PhaseExecutionInfo randomPhaseExecutionInfo(String phaseName) {
return new PhaseExecutionInfo(randomAlphaOfLength(5), PhaseTests.randomPhase(phaseName),
randomNonNegativeLong(), randomNonNegativeLong());
}
String phaseName;
@Before
public void setupPhaseName() {
phaseName = randomAlphaOfLength(7);
}
@Override
protected PhaseExecutionInfo createTestInstance() {
return randomPhaseExecutionInfo(phaseName);
}
@Override
protected PhaseExecutionInfo doParseInstance(XContentParser parser) throws IOException {
return PhaseExecutionInfo.parse(parser, phaseName);
}
@Override
protected boolean supportsUnknownFields() {
return false;
}
@Override
protected NamedXContentRegistry xContentRegistry() {
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse));
return new NamedXContentRegistry(entries);
}
}

View File

@ -41,6 +41,10 @@ public class PhaseTests extends AbstractXContentTestCase<Phase> {
@Override
protected Phase createTestInstance() {
return randomPhase(phaseName);
}
static Phase randomPhase(String phaseName) {
TimeValue after = null;
if (randomBoolean()) {
after = TimeValue.parseTimeValue(randomTimeValue(0, 1000000000, "s", "m", "h", "d"), "test_after");

View File

@ -39,23 +39,25 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
private static final ParseField ACTION_TIME_FIELD = new ParseField("action_time");
private static final ParseField STEP_TIME_FIELD = new ParseField("step_time");
private static final ParseField STEP_INFO_FIELD = new ParseField("step_info");
private static final ParseField PHASE_EXECUTION_INFO = new ParseField("phase_execution");
public static final ConstructingObjectParser<IndexLifecycleExplainResponse, Void> PARSER = new ConstructingObjectParser<>(
"index_lifecycle_explain_response",
a -> new IndexLifecycleExplainResponse(
(String) a[0],
(boolean) a[1],
(String) a[2],
(boolean) (a[3] == null ? false: a[3]),
(long) (a[4] == null ? -1L: a[4]),
(String) a[0],
(boolean) a[1],
(String) a[2],
(boolean) (a[3] == null ? false: a[3]),
(long) (a[4] == null ? -1L: a[4]),
(String) a[5],
(String) a[6],
(String) a[7],
(String) a[8],
(long) (a[9] == null ? -1L: a[9]),
(long) (a[10] == null ? -1L: a[10]),
(long) (a[11] == null ? -1L: a[11]),
(BytesReference) a[12]));
(String) a[6],
(String) a[7],
(String) a[8],
(long) (a[9] == null ? -1L: a[9]),
(long) (a[10] == null ? -1L: a[10]),
(long) (a[11] == null ? -1L: a[11]),
(BytesReference) a[12],
(PhaseExecutionInfo) a[13]));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), INDEX_FIELD);
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), MANAGED_BY_ILM_FIELD);
@ -74,6 +76,8 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
builder.copyCurrentStructure(p);
return BytesArray.bytes(builder);
}, STEP_INFO_FIELD);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> PhaseExecutionInfo.parse(p, ""),
PHASE_EXECUTION_INFO);
}
private final String index;
@ -89,28 +93,29 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
private final boolean skip;
private final boolean managedByILM;
private final BytesReference stepInfo;
private final PhaseExecutionInfo phaseExecutionInfo;
public static IndexLifecycleExplainResponse newManagedIndexResponse(String index, String policyName, boolean skip, long lifecycleDate,
String phase, String action, String step, String failedStep, long phaseTime, long actionTime, long stepTime,
BytesReference stepInfo) {
BytesReference stepInfo, PhaseExecutionInfo phaseExecutionInfo) {
return new IndexLifecycleExplainResponse(index, true, policyName, skip, lifecycleDate, phase, action, step, failedStep, phaseTime,
actionTime, stepTime, stepInfo);
actionTime, stepTime, stepInfo, phaseExecutionInfo);
}
public static IndexLifecycleExplainResponse newUnmanagedIndexResponse(String index) {
return new IndexLifecycleExplainResponse(index, false, null, false, -1L, null, null, null, null, -1L, -1L, -1L, null);
return new IndexLifecycleExplainResponse(index, false, null, false, -1L, null, null, null, null, -1L, -1L, -1L, null, null);
}
private IndexLifecycleExplainResponse(String index, boolean managedByILM, String policyName, boolean skip, long lifecycleDate,
String phase, String action, String step, String failedStep, long phaseTime, long actionTime,
long stepTime, BytesReference stepInfo) {
long stepTime, BytesReference stepInfo, PhaseExecutionInfo phaseExecutionInfo) {
if (managedByILM) {
if (policyName == null) {
throw new IllegalArgumentException("[" + POLICY_NAME_FIELD.getPreferredName() + "] cannot be null for managed index");
}
} else {
if (policyName != null || lifecycleDate >= 0 || phase != null || action != null || step != null || failedStep != null
|| phaseTime >= 0 || actionTime >= 0 || stepTime >= 0 || stepInfo != null) {
|| phaseTime >= 0 || actionTime >= 0 || stepTime >= 0 || stepInfo != null || phaseExecutionInfo != null) {
throw new IllegalArgumentException(
"Unmanaged index response must only contain fields: [" + MANAGED_BY_ILM_FIELD + ", " + INDEX_FIELD + "]");
}
@ -128,6 +133,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
this.stepTime = stepTime;
this.failedStep = failedStep;
this.stepInfo = stepInfo;
this.phaseExecutionInfo = phaseExecutionInfo;
}
public IndexLifecycleExplainResponse(StreamInput in) throws IOException {
@ -145,7 +151,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
actionTime = in.readZLong();
stepTime = in.readZLong();
stepInfo = in.readOptionalBytesReference();
phaseExecutionInfo = in.readOptionalWriteable(PhaseExecutionInfo::new);
} else {
policyName = null;
skip = false;
@ -158,6 +164,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
actionTime = -1L;
stepTime = -1L;
stepInfo = null;
phaseExecutionInfo = null;
}
}
@ -177,13 +184,14 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
out.writeZLong(actionTime);
out.writeZLong(stepTime);
out.writeOptionalBytesReference(stepInfo);
out.writeOptionalWriteable(phaseExecutionInfo);
}
}
public String getIndex() {
return index;
}
public boolean managedByILM() {
return managedByILM;
}
@ -191,7 +199,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
public String getPolicyName() {
return policyName;
}
public boolean skip() {
return skip;
}
@ -227,11 +235,15 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
public String getFailedStep() {
return failedStep;
}
public BytesReference getStepInfo() {
return stepInfo;
}
public PhaseExecutionInfo getPhaseExecutionInfo() {
return phaseExecutionInfo;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
@ -269,6 +281,9 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
if (stepInfo != null && stepInfo.length() > 0) {
builder.rawField(STEP_INFO_FIELD.getPreferredName(), stepInfo.streamInput(), XContentType.JSON);
}
if (phaseExecutionInfo != null) {
builder.field(PHASE_EXECUTION_INFO.getPreferredName(), phaseExecutionInfo);
}
}
builder.endObject();
return builder;
@ -277,7 +292,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
@Override
public int hashCode() {
return Objects.hash(index, managedByILM, policyName, skip, lifecycleDate, phase, action, step, failedStep, phaseTime, actionTime,
stepTime, stepInfo);
stepTime, stepInfo, phaseExecutionInfo);
}
@Override
@ -301,7 +316,8 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
Objects.equals(phaseTime, other.phaseTime) &&
Objects.equals(actionTime, other.actionTime) &&
Objects.equals(stepTime, other.stepTime) &&
Objects.equals(stepInfo, other.stepInfo);
Objects.equals(stepInfo, other.stepInfo) &&
Objects.equals(phaseExecutionInfo, other.phaseExecutionInfo);
}
@Override

View File

@ -0,0 +1,135 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
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.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Objects;
/**
* This class contains information about the current phase being executed by Index
* Lifecycle Management on the specific index.
*/
public class PhaseExecutionInfo implements ToXContentObject, Writeable {
private static final ParseField POLICY_NAME_FIELD = new ParseField("policy");
private static final ParseField PHASE_DEFINITION_FIELD = new ParseField("phase_definition");
private static final ParseField VERSION_FIELD = new ParseField("version");
private static final ParseField MODIFIED_DATE_IN_MILLIS_FIELD = new ParseField("modified_date_in_millis");
private static final ConstructingObjectParser<PhaseExecutionInfo, String> PARSER = new ConstructingObjectParser<>(
"phase_execution_info", false,
(a, name) -> new PhaseExecutionInfo((String) a[0], (Phase) a[1], (long) a[2], (long) a[3]));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), POLICY_NAME_FIELD);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), Phase::parse, PHASE_DEFINITION_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), VERSION_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), MODIFIED_DATE_IN_MILLIS_FIELD);
}
public static PhaseExecutionInfo parse(XContentParser parser, String name) {
return PARSER.apply(parser, name);
}
private final String policyName;
private final Phase phase;
private final long version;
private final long modifiedDate;
/**
* This class holds information about the current phase that is being executed
*
* @param policyName the name of the policy being executed, this may not be the current policy assigned to an index
* @param phase the current phase definition executed
* @param version the version of the <code>policyName</code> being executed
* @param modifiedDate the time the executing version of the phase was modified
*/
public PhaseExecutionInfo(String policyName, @Nullable Phase phase, long version, long modifiedDate) {
this.policyName = policyName;
this.phase = phase;
this.version = version;
this.modifiedDate = modifiedDate;
}
PhaseExecutionInfo(StreamInput in) throws IOException {
this.policyName = in.readString();
this.phase = in.readOptionalWriteable(Phase::new);
this.version = in.readVLong();
this.modifiedDate = in.readVLong();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(policyName);
out.writeOptionalWriteable(phase);
out.writeVLong(version);
out.writeVLong(modifiedDate);
}
public String getPolicyName() {
return policyName;
}
public Phase getPhase() {
return phase;
}
public long getVersion() {
return version;
}
public long getModifiedDate() {
return modifiedDate;
}
@Override
public int hashCode() {
return Objects.hash(policyName, phase, version, modifiedDate);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PhaseExecutionInfo other = (PhaseExecutionInfo) obj;
return Objects.equals(policyName, other.policyName) &&
Objects.equals(phase, other.phase) &&
Objects.equals(version, other.version) &&
Objects.equals(modifiedDate, other.modifiedDate);
}
@Override
public String toString() {
return Strings.toString(this, false, true);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(POLICY_NAME_FIELD.getPreferredName(), policyName);
if (phase != null) {
builder.field(PHASE_DEFINITION_FIELD.getPreferredName(), phase);
}
builder.field(VERSION_FIELD.getPreferredName(), version);
builder.timeField(MODIFIED_DATE_IN_MILLIS_FIELD.getPreferredName(), "modified_date", modifiedDate);
builder.endObject();
return builder;
}
}

View File

@ -6,11 +6,18 @@
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ExplainLifecycleResponseTests extends AbstractStreamableXContentTestCase<ExplainLifecycleResponse> {
@ -47,4 +54,16 @@ public class ExplainLifecycleResponseTests extends AbstractStreamableXContentTes
protected boolean supportsUnknownFields() {
return false;
}
protected NamedWriteableRegistry getNamedWriteableRegistry() {
return new NamedWriteableRegistry(Arrays
.asList(new NamedWriteableRegistry.Entry(LifecycleAction.class, MockAction.NAME, MockAction::new)));
}
@Override
protected NamedXContentRegistry xContentRegistry() {
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(MockAction.NAME), MockAction::parse));
return new NamedXContentRegistry(entries);
}
}

View File

@ -6,16 +6,23 @@
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractSerializingTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
@ -35,9 +42,10 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
private static IndexLifecycleExplainResponse randomManagedIndexExplainResponse() {
return IndexLifecycleExplainResponse.newManagedIndexResponse(randomAlphaOfLength(10), randomAlphaOfLength(10), randomBoolean(),
randomNonNegativeLong(), randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10),
randomBoolean() ? null : randomAlphaOfLength(10), randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(),
randomBoolean() ? null : new BytesArray(new RandomStepInfo(() -> randomAlphaOfLength(10)).toString()));
randomNonNegativeLong(), randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10),
randomBoolean() ? null : randomAlphaOfLength(10), randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(),
randomBoolean() ? null : new BytesArray(new RandomStepInfo(() -> randomAlphaOfLength(10)).toString()),
randomBoolean() ? null : PhaseExecutionInfoTests.randomPhaseExecutionInfo(""));
}
@Override
@ -70,8 +78,9 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
boolean managed = instance.managedByILM();
boolean skip = instance.skip();
BytesReference stepInfo = instance.getStepInfo();
PhaseExecutionInfo phaseExecutionInfo = instance.getPhaseExecutionInfo();
if (managed) {
switch (between(0, 12)) {
switch (between(0, 13)) {
case 0:
index = index + randomAlphaOfLengthBetween(1, 5);
break;
@ -122,12 +131,15 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
skip = skip == false;
break;
case 12:
phaseExecutionInfo = randomValueOtherThan(phaseExecutionInfo, () -> PhaseExecutionInfoTests.randomPhaseExecutionInfo(""));
break;
case 13:
return IndexLifecycleExplainResponse.newUnmanagedIndexResponse(index);
default:
throw new AssertionError("Illegal randomisation branch");
}
return IndexLifecycleExplainResponse.newManagedIndexResponse(index, policy, skip, policyTime, phase, action, step, failedStep,
phaseTime, actionTime, stepTime, stepInfo);
phaseTime, actionTime, stepTime, stepInfo, phaseExecutionInfo);
} else {
switch (between(0, 1)) {
case 0:
@ -140,6 +152,18 @@ public class IndexExplainResponseTests extends AbstractSerializingTestCase<Index
}
}
protected NamedWriteableRegistry getNamedWriteableRegistry() {
return new NamedWriteableRegistry(Arrays
.asList(new NamedWriteableRegistry.Entry(LifecycleAction.class, MockAction.NAME, MockAction::new)));
}
@Override
protected NamedXContentRegistry xContentRegistry() {
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(MockAction.NAME), MockAction::parse));
return new NamedXContentRegistry(entries);
}
private static class RandomStepInfo implements ToXContentObject {
private final String key;

View File

@ -0,0 +1,88 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractSerializingTestCase;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PhaseExecutionInfoTests extends AbstractSerializingTestCase<PhaseExecutionInfo> {
static PhaseExecutionInfo randomPhaseExecutionInfo(String phaseName) {
return new PhaseExecutionInfo(randomAlphaOfLength(5), PhaseTests.randomTestPhase(phaseName),
randomNonNegativeLong(), randomNonNegativeLong());
}
String phaseName;
@Before
public void setupPhaseName() {
phaseName = randomAlphaOfLength(7);
}
@Override
protected PhaseExecutionInfo createTestInstance() {
return randomPhaseExecutionInfo(phaseName);
}
@Override
protected Reader<PhaseExecutionInfo> instanceReader() {
return PhaseExecutionInfo::new;
}
@Override
protected PhaseExecutionInfo doParseInstance(XContentParser parser) throws IOException {
return PhaseExecutionInfo.parse(parser, phaseName);
}
@Override
protected PhaseExecutionInfo mutateInstance(PhaseExecutionInfo instance) throws IOException {
String policyName = instance.getPolicyName();
Phase phase = instance.getPhase();
long version = instance.getVersion();
long modifiedDate = instance.getModifiedDate();
switch (between(0, 3)) {
case 0:
policyName = policyName + randomAlphaOfLengthBetween(1, 5);
break;
case 1:
phase = randomValueOtherThan(phase, () -> PhaseTests.randomTestPhase(randomAlphaOfLength(6)));
break;
case 2:
version++;
break;
case 3:
modifiedDate++;
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new PhaseExecutionInfo(policyName, phase, version, modifiedDate);
}
protected NamedWriteableRegistry getNamedWriteableRegistry() {
return new NamedWriteableRegistry(Arrays
.asList(new NamedWriteableRegistry.Entry(LifecycleAction.class, MockAction.NAME, MockAction::new)));
}
@Override
protected NamedXContentRegistry xContentRegistry() {
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(MockAction.NAME), MockAction::parse));
return new NamedXContentRegistry(entries);
}
}

View File

@ -33,6 +33,10 @@ public class PhaseTests extends AbstractSerializingTestCase<Phase> {
@Override
protected Phase createTestInstance() {
return randomTestPhase(phaseName);
}
static Phase randomTestPhase(String phaseName) {
TimeValue after = null;
if (randomBoolean()) {
after = TimeValue.parseTimeValue(randomTimeValue(0, 1000000000, "s", "m", "h", "d"), "test_after");

View File

@ -28,10 +28,11 @@ import org.elasticsearch.xpack.core.indexlifecycle.ClusterStateActionStep;
import org.elasticsearch.xpack.core.indexlifecycle.ClusterStateWaitStep;
import org.elasticsearch.xpack.core.indexlifecycle.ErrorStep;
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.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseCompleteStep;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
@ -250,8 +251,10 @@ public class IndexLifecycleRunner {
LongSupplier nowSupplier) {
IndexMetaData idxMeta = clusterState.getMetaData().index(index);
IndexLifecycleMetadata ilmMeta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicy policy = ilmMeta.getPolicies().get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
Settings.Builder indexSettings = moveIndexSettingsToNextStep(policy, idxMeta.getSettings(), currentStep, nextStep, nowSupplier);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
Settings.Builder indexSettings = moveIndexSettingsToNextStep(policyMetadata, idxMeta.getSettings(), currentStep,
nextStep, nowSupplier);
ClusterState.Builder newClusterStateBuilder = newClusterStateWithIndexSettings(index, clusterState, indexSettings);
return newClusterStateBuilder.build();
}
@ -260,12 +263,13 @@ public class IndexLifecycleRunner {
LongSupplier nowSupplier) throws IOException {
IndexMetaData idxMeta = clusterState.getMetaData().index(index);
IndexLifecycleMetadata ilmMeta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicy policy = ilmMeta.getPolicies().get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
XContentBuilder causeXContentBuilder = JsonXContent.contentBuilder();
causeXContentBuilder.startObject();
ElasticsearchException.generateThrowableXContent(causeXContentBuilder, ToXContent.EMPTY_PARAMS, cause);
causeXContentBuilder.endObject();
Settings.Builder indexSettings = moveIndexSettingsToNextStep(policy, idxMeta.getSettings(), currentStep,
Settings.Builder indexSettings = moveIndexSettingsToNextStep(policyMetadata, idxMeta.getSettings(), currentStep,
new StepKey(currentStep.getPhase(), currentStep.getAction(), ErrorStep.NAME), nowSupplier)
.put(LifecycleSettings.LIFECYCLE_FAILED_STEP, currentStep.getName())
.put(LifecycleSettings.LIFECYCLE_STEP_INFO, BytesReference.bytes(causeXContentBuilder).utf8ToString());
@ -294,7 +298,7 @@ public class IndexLifecycleRunner {
return newState;
}
private static Settings.Builder moveIndexSettingsToNextStep(LifecyclePolicy policy, Settings existingSettings,
private static Settings.Builder moveIndexSettingsToNextStep(LifecyclePolicyMetadata policyMetadata, Settings existingSettings,
StepKey currentStep, StepKey nextStep, LongSupplier nowSupplier) {
long nowAsMillis = nowSupplier.getAsLong();
Settings.Builder newSettings = Settings.builder().put(existingSettings).put(LifecycleSettings.LIFECYCLE_PHASE, nextStep.getPhase())
@ -305,16 +309,15 @@ public class IndexLifecycleRunner {
.put(LifecycleSettings.LIFECYCLE_STEP_INFO, (String) null);
if (currentStep.getPhase().equals(nextStep.getPhase()) == false) {
final String newPhaseDefinition;
final Phase nextPhase;
if ("new".equals(nextStep.getPhase()) || TerminalPolicyStep.KEY.equals(nextStep)) {
newPhaseDefinition = nextStep.getPhase();
nextPhase = null;
} else {
Phase nextPhase = policy.getPhases().get(nextStep.getPhase());
if (nextPhase == null) {
newPhaseDefinition = null;
} else {
newPhaseDefinition = Strings.toString(nextPhase, false, false);
}
nextPhase = policyMetadata.getPolicy().getPhases().get(nextStep.getPhase());
}
PhaseExecutionInfo phaseExecutionInfo = new PhaseExecutionInfo(policyMetadata.getName(), nextPhase,
policyMetadata.getVersion(), policyMetadata.getModifiedDate());
newPhaseDefinition = Strings.toString(phaseExecutionInfo, false, false);
newSettings.put(LifecycleSettings.LIFECYCLE_PHASE_DEFINITION, newPhaseDefinition);
newSettings.put(LifecycleSettings.LIFECYCLE_PHASE_TIME, nowAsMillis);
}
@ -378,7 +381,7 @@ public class IndexLifecycleRunner {
}
public static ClusterState setPolicyForIndexes(final String newPolicyName, final Index[] indices, ClusterState currentState,
LifecyclePolicy newPolicy, List<String> failedIndexes, LongSupplier nowSupplier) {
LifecyclePolicyMetadata newPolicyMetadata, List<String> failedIndexes, LongSupplier nowSupplier) {
MetaData.Builder newMetadata = MetaData.builder(currentState.getMetaData());
boolean clusterStateChanged = false;
for (Index index : indices) {
@ -388,7 +391,7 @@ public class IndexLifecycleRunner {
failedIndexes.add(index.getName());
} else {
IndexMetaData.Builder newIdxMetadata = IndexLifecycleRunner.setPolicyForIndex(newPolicyName,
newPolicy, indexMetadata, nowSupplier);
newPolicyMetadata, indexMetadata, nowSupplier);
if (newIdxMetadata != null) {
newMetadata.put(newIdxMetadata);
clusterStateChanged = true;
@ -404,7 +407,7 @@ public class IndexLifecycleRunner {
}
}
private static IndexMetaData.Builder setPolicyForIndex(final String newPolicyName, LifecyclePolicy newPolicy,
private static IndexMetaData.Builder setPolicyForIndex(final String newPolicyName, LifecyclePolicyMetadata newPolicyMetadata,
IndexMetaData indexMetadata, LongSupplier nowSupplier) {
Settings idxSettings = indexMetadata.getSettings();
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(idxSettings);
@ -413,9 +416,9 @@ public class IndexLifecycleRunner {
if (currentStepKey != null) {
// Check if current step exists in new policy and if not move to
// next available step
StepKey nextValidStepKey = newPolicy.getNextValidStep(currentStepKey);
StepKey nextValidStepKey = newPolicyMetadata.getPolicy().getNextValidStep(currentStepKey);
if (nextValidStepKey.equals(currentStepKey) == false) {
newSettings = moveIndexSettingsToNextStep(newPolicy, idxSettings, currentStepKey, nextValidStepKey, nowSupplier);
newSettings = moveIndexSettingsToNextStep(newPolicyMetadata, idxSettings, currentStepKey, nextValidStepKey, nowSupplier);
}
}
newSettings.put(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey(), newPolicyName);

View File

@ -30,6 +30,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep;
@ -170,7 +171,7 @@ public class PolicyStepsRegistry {
// parse existing phase steps from the phase definition in the index settings
String phaseDef = imd.value.getSettings().get(LifecycleSettings.LIFECYCLE_PHASE_DEFINITION,
InitializePolicyContextStep.INITIALIZATION_PHASE);
final Phase phase;
final PhaseExecutionInfo phaseExecutionInfo;
LifecyclePolicy currentPolicy = lifecyclePolicyMap.get(policy).getPolicy();
final LifecyclePolicy policyToExecute;
if (InitializePolicyContextStep.INITIALIZATION_PHASE.equals(phaseDef)
@ -181,15 +182,15 @@ public class PolicyStepsRegistry {
// if the current phase definition describes an internal step/phase, do not parse
try (XContentParser parser = JsonXContent.jsonXContent.createParser(xContentRegistry,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, phaseDef)) {
phase = Phase.parse(parser, currentPhase);
phaseExecutionInfo = PhaseExecutionInfo.parse(parser, currentPhase);
} catch (IOException e) {
logger.error("failed to configure phase [" + currentPhase + "] for index [" + index.getName() + "]", e);
indexPhaseSteps.remove(index);
continue;
}
Map<String, Phase> phaseMap = new HashMap<>(currentPolicy.getPhases());
if (phase != null) {
phaseMap.put(currentPhase, phase);
if (phaseExecutionInfo.getPhase() != null) {
phaseMap.put(currentPhase, phaseExecutionInfo.getPhase());
}
policyToExecute = new LifecyclePolicy(currentPolicy.getType(), currentPolicy.getName(), phaseMap);
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.indexlifecycle.action;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.info.TransportClusterInfoAction;
@ -19,25 +20,36 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleRequest;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleResponse;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleExplainResponse;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class TransportExplainLifecycleAction
extends TransportClusterInfoAction<ExplainLifecycleRequest, ExplainLifecycleResponse> {
private final NamedXContentRegistry xContentRegistry;
@Inject
public TransportExplainLifecycleAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver,
NamedXContentRegistry xContentRegistry) {
super(settings, ExplainLifecycleAction.NAME, transportService, clusterService, threadPool, actionFilters,
ExplainLifecycleRequest::new, indexNameExpressionResolver);
this.xContentRegistry = xContentRegistry;
}
@Override
@ -65,19 +77,34 @@ public class TransportExplainLifecycleAction
IndexMetaData idxMetadata = state.metaData().index(index);
Settings idxSettings = idxMetadata.getSettings();
String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxSettings);
String currentPhase = LifecycleSettings.LIFECYCLE_PHASE_SETTING.get(idxSettings);
// parse existing phase steps from the phase definition in the index settings
String phaseDef = idxSettings.get(LifecycleSettings.LIFECYCLE_PHASE_DEFINITION);
PhaseExecutionInfo phaseExecutionInfo = null;
if (Strings.isNullOrEmpty(phaseDef) == false) {
try (XContentParser parser = JsonXContent.jsonXContent.createParser(xContentRegistry,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, phaseDef)) {
phaseExecutionInfo = PhaseExecutionInfo.parse(parser, currentPhase);
} catch (IOException e) {
listener.onFailure(new ElasticsearchParseException(
"failed to parse [" + LifecycleSettings.LIFECYCLE_PHASE_DEFINITION + "] for index [" + index + "]", e));
return;
}
}
final IndexLifecycleExplainResponse indexResponse;
if (Strings.hasLength(policyName)) {
indexResponse = IndexLifecycleExplainResponse.newManagedIndexResponse(index, policyName,
LifecycleSettings.LIFECYCLE_SKIP_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_PHASE_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_ACTION_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_STEP_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_FAILED_STEP_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_PHASE_TIME_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_ACTION_TIME_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_STEP_TIME_SETTING.get(idxSettings),
new BytesArray(LifecycleSettings.LIFECYCLE_STEP_INFO_SETTING.get(idxSettings)));
LifecycleSettings.LIFECYCLE_SKIP_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_PHASE_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_ACTION_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_STEP_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_FAILED_STEP_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_PHASE_TIME_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_ACTION_TIME_SETTING.get(idxSettings),
LifecycleSettings.LIFECYCLE_STEP_TIME_SETTING.get(idxSettings),
new BytesArray(LifecycleSettings.LIFECYCLE_STEP_INFO_SETTING.get(idxSettings)),
phaseExecutionInfo);
} else {
indexResponse = IndexLifecycleExplainResponse.newUnmanagedIndexResponse(index);
}

View File

@ -19,12 +19,12 @@ import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.SetIndexLifecyclePolicyRequest;
import org.elasticsearch.xpack.core.indexlifecycle.SetIndexLifecyclePolicyResponse;
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.action.SetIndexLifecyclePolicyAction;
import org.elasticsearch.xpack.indexlifecycle.IndexLifecycleRunner;
@ -76,14 +76,14 @@ public class TransportSetIndexLifecyclePolicyAction
throw new ResourceNotFoundException("Policy does not exist [{}]", newPolicyName);
}
LifecyclePolicy newPolicy = ilmMetadata.getPolicies().get(newPolicyName);
LifecyclePolicyMetadata newPolicyMetadata = ilmMetadata.getPolicyMetadatas().get(newPolicyName);
if (newPolicy == null) {
if (newPolicyMetadata == null) {
throw new ResourceNotFoundException("Policy does not exist [{}]", newPolicyName);
}
return IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, currentState, newPolicy, failedIndexes,
() -> System.currentTimeMillis());
return IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, currentState, newPolicyMetadata,
failedIndexes, System::currentTimeMillis);
}
@Override

View File

@ -28,14 +28,19 @@ import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.indexlifecycle.ClusterStateWaitStep;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleRequest;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleResponse;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleExplainResponse;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleType;
import org.elasticsearch.xpack.core.indexlifecycle.MockAction;
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep;
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction;
import org.junit.Before;
@ -69,6 +74,7 @@ import static org.hamcrest.core.IsNull.nullValue;
public class IndexLifecycleInitialisationIT extends ESIntegTestCase {
private Settings settings;
private LifecyclePolicy lifecyclePolicy;
private Phase mockPhase;
private static final ObservableAction OBSERVABLE_ACTION;
static {
List<Step> steps = new ArrayList<>();
@ -127,7 +133,8 @@ public class IndexLifecycleInitialisationIT extends ESIntegTestCase {
Step.StepKey key = new Step.StepKey("mock", ObservableAction.NAME, ObservableClusterStateWaitStep.NAME);
steps.add(new ObservableClusterStateWaitStep(key, TerminalPolicyStep.KEY));
Map<String, LifecycleAction> actions = Collections.singletonMap(ObservableAction.NAME, OBSERVABLE_ACTION);
Map<String, Phase> phases = Collections.singletonMap("mock", new Phase("mock", TimeValue.timeValueSeconds(0), actions));
mockPhase = new Phase("mock", TimeValue.timeValueSeconds(0), actions);
Map<String, Phase> phases = Collections.singletonMap("mock", mockPhase);
lifecyclePolicy = newLockableLifecyclePolicy("test", phases);
}
@ -175,6 +182,58 @@ public class IndexLifecycleInitialisationIT extends ESIntegTestCase {
});
}
public void testExplainExecution() throws Exception {
// start node
logger.info("Starting server1");
final String server_1 = internalCluster().startNode();
logger.info("Creating lifecycle [test_lifecycle]");
PutLifecycleAction.Request putLifecycleRequest = new PutLifecycleAction.Request(lifecyclePolicy);
PutLifecycleAction.Response putLifecycleResponse = client().execute(PutLifecycleAction.INSTANCE, putLifecycleRequest).get();
assertAcked(putLifecycleResponse);
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();
logger.info("Creating index [test]");
CreateIndexResponse createIndexResponse = client().admin().indices().create(createIndexRequest("test").settings(settings))
.actionGet();
assertAcked(createIndexResponse);
{
PhaseExecutionInfo expectedExecutionInfo = new PhaseExecutionInfo(lifecyclePolicy.getName(), mockPhase, 1L, actualModifiedDate);
assertBusy(() -> {
ExplainLifecycleRequest explainRequest = new ExplainLifecycleRequest();
ExplainLifecycleResponse explainResponse = client().execute(ExplainLifecycleAction.INSTANCE, explainRequest).get();
assertThat(explainResponse.getIndexResponses().size(), equalTo(1));
IndexLifecycleExplainResponse indexResponse = explainResponse.getIndexResponses().get("test");
assertThat(indexResponse.getStep(), equalTo("observable_cluster_state_action"));
assertThat(indexResponse.getPhaseExecutionInfo(), equalTo(expectedExecutionInfo));
});
}
// complete the step
client().admin().indices().prepareUpdateSettings("test")
.setSettings(Collections.singletonMap("index.lifecycle.test.complete", true)).get();
{
PhaseExecutionInfo expectedExecutionInfo = new PhaseExecutionInfo(lifecyclePolicy.getName(), null, 1L, actualModifiedDate);
assertBusy(() -> {
ExplainLifecycleRequest explainRequest = new ExplainLifecycleRequest();
ExplainLifecycleResponse explainResponse = client().execute(ExplainLifecycleAction.INSTANCE, explainRequest).get();
assertThat(explainResponse.getIndexResponses().size(), equalTo(1));
IndexLifecycleExplainResponse indexResponse = explainResponse.getIndexResponses().get("test");
assertThat(indexResponse.getPhase(), equalTo(TerminalPolicyStep.COMPLETED_PHASE));
assertThat(indexResponse.getStep(), equalTo(TerminalPolicyStep.KEY.getName()));
assertThat(indexResponse.getPhaseExecutionInfo(), equalTo(expectedExecutionInfo));
});
}
}
public void testMasterDedicatedDataDedicated() throws Exception {
settings = Settings.builder().put(settings).put("index.lifecycle.test.complete", true).build();
// start master node

View File

@ -896,14 +896,15 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
List<LifecyclePolicyMetadata> policyMetadatas = new ArrayList<>();
policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong()));
policyMetadatas.add(new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong()));
LifecyclePolicyMetadata newPolicyMetadata = new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
policyMetadatas.add(newPolicyMetadata);
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, clusterState, newPolicy,
ClusterState newClusterState = IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, clusterState, newPolicyMetadata,
failedIndexes, () -> now);
assertTrue(failedIndexes.isEmpty());
@ -915,14 +916,16 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
String indexName = randomAlphaOfLength(10);
String newPolicyName = "new_policy";
LifecyclePolicy newPolicy = newTestLifecyclePolicy(newPolicyName, Collections.emptyMap());
LifecyclePolicyMetadata newPolicyMetadata = new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
StepKey currentStep = new StepKey("", "", "");
Settings.Builder indexSettingsBuilder = Settings.builder();
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, Collections.emptyList());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, Collections.singletonList(newPolicyMetadata));
Index index = clusterState.metaData().index(indexName).getIndex();
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, clusterState, newPolicy,
ClusterState newClusterState = IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, clusterState, newPolicyMetadata,
failedIndexes, () -> now);
assertTrue(failedIndexes.isEmpty());
@ -936,6 +939,8 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
String newPolicyName = "new_policy";
LifecyclePolicy oldPolicy = newTestLifecyclePolicy(oldPolicyName, Collections.emptyMap());
LifecyclePolicy newPolicy = newTestLifecyclePolicy(newPolicyName, Collections.emptyMap());
LifecyclePolicyMetadata newPolicyMetadata = new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
StepKey currentStep = AbstractStepTestCase.randomStepKey();
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, oldPolicyName)
.put(LifecycleSettings.LIFECYCLE_PHASE, currentStep.getPhase())
@ -949,7 +954,7 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, clusterState, newPolicy,
ClusterState newClusterState = IndexLifecycleRunner.setPolicyForIndexes(newPolicyName, indices, clusterState, newPolicyMetadata,
failedIndexes, () -> now);
assertEquals(1, failedIndexes.size());

View File

@ -114,6 +114,7 @@ teardown:
- match: { indices.my_index.step: "complete" }
- is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info
- is_false: indices.my_index.phase_execution
- is_false: indices.my_index2
- is_false: indices.another_index
@ -135,6 +136,7 @@ teardown:
- match: { indices.my_index.step: "complete" }
- is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info
- is_false: indices.my_index.phase_execution
- is_true: indices.my_index2.managed
- match: { indices.my_index2.index: "my_index2" }
@ -144,6 +146,7 @@ teardown:
- match: { indices.my_index2.step: "complete" }
- is_false: indices.my_index2.failed_step
- is_false: indices.my_index2.step_info
- is_false: indices.my_index2.phase_execution
- is_false: indices.another_index
- is_false: indices.unmanaged_index
@ -165,6 +168,7 @@ teardown:
- match: { indices.my_index.step: "complete" }
- is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info
- is_false: indices.my_index.phase_execution
- is_true: indices.my_index2.managed
- match: { indices.my_index2.index: "my_index2" }
@ -174,7 +178,8 @@ teardown:
- match: { indices.my_index2.step: "complete" }
- is_false: indices.my_index2.failed_step
- is_false: indices.my_index2.step_info
- is_false: indices.my_index2.phase_execution
- is_true: indices.another_index.managed
- match: { indices.another_index.index: "another_index" }
- match: { indices.another_index.policy: "my_moveable_timeseries_lifecycle" }
@ -183,7 +188,8 @@ teardown:
- match: { indices.another_index.step: "complete" }
- is_false: indices.another_index.failed_step
- is_false: indices.another_index.step_info
- is_false: indices.another_index.phase_execution
- match: { indices.unmanaged_index.index: "unmanaged_index" }
- is_false: indices.unmanaged_index.managed
- is_false: indices.unmanaged_index.policy
@ -207,6 +213,7 @@ teardown:
- is_false: indices.unmanaged_index.phase
- is_false: indices.unmanaged_index.action
- is_false: indices.unmanaged_index.step
- is_false: indices.unmanaged_index.phase_execution
- is_false: indices.another_index.failed_step
- is_false: indices.another_index.step_info
- is_false: indices.my_index