Add option to filter ILM explain response (#44777)

In order to make it easier to interpret the output of the ILM Explain
API, this commit adds two request parameters to that API:

- `only_managed`, which causes the response to only contain indices
  which have `index.lifecycle.name` set
- `only_errors`, which causes the response to contain only indices in an
  ILM error state

"Error state" is defined as either being in the `ERROR` step or having
`index.lifecycle.name` set to a policy that does not exist.
This commit is contained in:
Gordon Brown 2019-07-26 11:57:38 -04:00 committed by GitHub
parent 97177a3b4f
commit d4b2d21339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 227 additions and 32 deletions

View File

@ -26,6 +26,15 @@ about any failures.
==== Request Parameters ==== Request Parameters
`only_managed`::
(boolean) Filters the returned indices to only indices that are managed by
ILM.
`only_errors`::
(boolean) Filters the returned indices to only indices that are managed by
ILM and are in an error state, either due to an encountering an error while
executing the policy, or attempting to use a policy that does not exist.
include::{docdir}/rest-api/timeoutparms.asciidoc[] include::{docdir}/rest-api/timeoutparms.asciidoc[]
==== Authorization ==== Authorization

View File

@ -6,9 +6,11 @@
package org.elasticsearch.xpack.core.indexlifecycle; package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.info.ClusterInfoRequest; import org.elasticsearch.action.support.master.info.ClusterInfoRequest;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -21,6 +23,10 @@ import java.util.Objects;
* {@link #indices(String...)} method * {@link #indices(String...)} method
*/ */
public class ExplainLifecycleRequest extends ClusterInfoRequest<ExplainLifecycleRequest> { public class ExplainLifecycleRequest extends ClusterInfoRequest<ExplainLifecycleRequest> {
private static final Version FILTERS_INTRODUCED_VERSION = Version.V_7_4_0;
private boolean onlyErrors = false;
private boolean onlyManaged = false;
public ExplainLifecycleRequest() { public ExplainLifecycleRequest() {
super(); super();
@ -28,6 +34,37 @@ public class ExplainLifecycleRequest extends ClusterInfoRequest<ExplainLifecycle
public ExplainLifecycleRequest(StreamInput in) throws IOException { public ExplainLifecycleRequest(StreamInput in) throws IOException {
super(in); super(in);
if (in.getVersion().onOrAfter(FILTERS_INTRODUCED_VERSION)) {
onlyErrors = in.readBoolean();
onlyManaged = in.readBoolean();
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
if (out.getVersion().onOrAfter(FILTERS_INTRODUCED_VERSION)) {
out.writeBoolean(onlyErrors);
out.writeBoolean(onlyManaged);
}
}
public boolean onlyErrors() {
return onlyErrors;
}
public ExplainLifecycleRequest onlyErrors(boolean onlyErrors) {
this.onlyErrors = onlyErrors;
return this;
}
public boolean onlyManaged() {
return onlyManaged;
}
public ExplainLifecycleRequest onlyManaged(boolean onlyManaged) {
this.onlyManaged = onlyManaged;
return this;
} }
@Override @Override
@ -37,7 +74,7 @@ public class ExplainLifecycleRequest extends ClusterInfoRequest<ExplainLifecycle
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(Arrays.hashCode(indices()), indicesOptions()); return Objects.hash(Arrays.hashCode(indices()), indicesOptions(), onlyErrors, onlyManaged);
} }
@Override @Override
@ -50,12 +87,15 @@ public class ExplainLifecycleRequest extends ClusterInfoRequest<ExplainLifecycle
} }
ExplainLifecycleRequest other = (ExplainLifecycleRequest) obj; ExplainLifecycleRequest other = (ExplainLifecycleRequest) obj;
return Objects.deepEquals(indices(), other.indices()) && return Objects.deepEquals(indices(), other.indices()) &&
Objects.equals(indicesOptions(), other.indicesOptions()); Objects.equals(indicesOptions(), other.indicesOptions()) &&
Objects.equals(onlyErrors(), other.onlyErrors()) &&
Objects.equals(onlyManaged(), other.onlyManaged());
} }
@Override @Override
public String toString() { public String toString() {
return "ExplainLifecycleRequest [indices()=" + Arrays.toString(indices()) + ", indicesOptions()=" + indicesOptions() + "]"; return "ExplainLifecycleRequest [indices()=" + Arrays.toString(indices()) + ", indicesOptions()=" + indicesOptions() +
", onlyErrors()=" + onlyErrors() + ", onlyManaged()=" + onlyManaged() + "]";
} }
} }

View File

@ -26,6 +26,12 @@ public class ExplainLifecycleRequestTests extends AbstractWireSerializingTestCas
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()); randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
request.indicesOptions(indicesOptions); request.indicesOptions(indicesOptions);
} }
if (randomBoolean()) {
request.onlyErrors(randomBoolean());
}
if (randomBoolean()) {
request.onlyManaged(randomBoolean());
}
return request; return request;
} }
@ -33,21 +39,31 @@ public class ExplainLifecycleRequestTests extends AbstractWireSerializingTestCas
protected ExplainLifecycleRequest mutateInstance(ExplainLifecycleRequest instance) throws IOException { protected ExplainLifecycleRequest mutateInstance(ExplainLifecycleRequest instance) throws IOException {
String[] indices = instance.indices(); String[] indices = instance.indices();
IndicesOptions indicesOptions = instance.indicesOptions(); IndicesOptions indicesOptions = instance.indicesOptions();
switch (between(0, 1)) { boolean onlyErrors = instance.onlyErrors();
case 0: boolean onlyManaged = instance.onlyManaged();
indices = randomValueOtherThanMany(i -> Arrays.equals(i, instance.indices()), switch (between(0, 3)) {
case 0:
indices = randomValueOtherThanMany(i -> Arrays.equals(i, instance.indices()),
() -> generateRandomStringArray(20, 10, false, false)); () -> generateRandomStringArray(20, 10, false, false));
break; break;
case 1: case 1:
indicesOptions = randomValueOtherThan(indicesOptions, () -> IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), indicesOptions = randomValueOtherThan(indicesOptions, () -> IndicesOptions.fromOptions(randomBoolean(), randomBoolean(),
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean())); randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()));
break; break;
default: case 2:
throw new AssertionError("Illegal randomisation branch"); onlyErrors = !onlyErrors;
break;
case 3:
onlyManaged = !onlyManaged;
break;
default:
throw new AssertionError("Illegal randomisation branch");
} }
ExplainLifecycleRequest newRequest = new ExplainLifecycleRequest(); ExplainLifecycleRequest newRequest = new ExplainLifecycleRequest();
newRequest.indices(indices); newRequest.indices(indices);
newRequest.indicesOptions(indicesOptions); newRequest.indicesOptions(indicesOptions);
newRequest.onlyErrors(onlyErrors);
newRequest.onlyManaged(onlyManaged);
return newRequest; return newRequest;
} }

View File

@ -54,9 +54,11 @@ import java.util.function.Supplier;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
@ -838,6 +840,45 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase {
assertOK(client().performRequest(startILMReqest)); assertOK(client().performRequest(startILMReqest));
} }
public void testExplainFilters() throws Exception {
String goodIndex = index + "-good-000001";
String errorIndex = index + "-error";
String nonexistantPolicyIndex = index + "-nonexistant-policy";
String unmanagedIndex = index + "-unmanaged";
createFullPolicy(TimeValue.ZERO);
createIndexWithSettings(goodIndex, Settings.builder()
.put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, "alias")
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put(LifecycleSettings.LIFECYCLE_NAME, policy));
createIndexWithSettingsNoAlias(errorIndex, Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put(LifecycleSettings.LIFECYCLE_NAME, policy));
createIndexWithSettingsNoAlias(nonexistantPolicyIndex, Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put(LifecycleSettings.LIFECYCLE_NAME, randomValueOtherThan(policy, () -> randomAlphaOfLengthBetween(3,10))));
createIndexWithSettingsNoAlias(unmanagedIndex, Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));
assertBusy(() -> {
Map<String, Map<String, Object>> explainResponse = explain(index + "*", false, false);
assertNotNull(explainResponse);
assertThat(explainResponse,
allOf(hasKey(goodIndex), hasKey(errorIndex), hasKey(nonexistantPolicyIndex), hasKey(unmanagedIndex)));
Map<String, Map<String, Object>> onlyManagedResponse = explain(index + "*", false, true);
assertNotNull(onlyManagedResponse);
assertThat(onlyManagedResponse, allOf(hasKey(goodIndex), hasKey(errorIndex), hasKey(nonexistantPolicyIndex)));
assertThat(onlyManagedResponse, not(hasKey(unmanagedIndex)));
Map<String, Map<String, Object>> onlyErrorsResponse = explain(index + "*", true, randomBoolean());
assertNotNull(onlyErrorsResponse);
assertThat(onlyErrorsResponse, allOf(hasKey(errorIndex), hasKey(nonexistantPolicyIndex)));
assertThat(onlyErrorsResponse, allOf(not(hasKey(goodIndex)), not(hasKey(unmanagedIndex))));
});
}
private void createFullPolicy(TimeValue hotTime) throws IOException { private void createFullPolicy(TimeValue hotTime) throws IOException {
Map<String, LifecycleAction> hotActions = new HashMap<>(); Map<String, LifecycleAction> hotActions = new HashMap<>();
hotActions.put(SetPriorityAction.NAME, new SetPriorityAction(100)); hotActions.put(SetPriorityAction.NAME, new SetPriorityAction(100));
@ -957,15 +998,21 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase {
} }
private Map<String, Object> explainIndex(String indexName) throws IOException { private Map<String, Object> explainIndex(String indexName) throws IOException {
Request explainRequest = new Request("GET", indexName + "/_ilm/explain"); return explain(indexName, false, false).get(indexName);
}
private Map<String, Map<String, Object>> explain(String indexPattern, boolean onlyErrors, boolean onlyManaged) throws IOException {
Request explainRequest = new Request("GET", indexPattern + "/_ilm/explain");
explainRequest.addParameter("only_errors", Boolean.toString(onlyErrors));
explainRequest.addParameter("only_managed", Boolean.toString(onlyManaged));
Response response = client().performRequest(explainRequest); Response response = client().performRequest(explainRequest);
Map<String, Object> responseMap; Map<String, Object> responseMap;
try (InputStream is = response.getEntity().getContent()) { try (InputStream is = response.getEntity().getContent()) {
responseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true); responseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true);
} }
@SuppressWarnings("unchecked") Map<String, Object> indexResponse = ((Map<String, Map<String, Object>>) responseMap.get("indices")) @SuppressWarnings("unchecked") Map<String, Map<String, Object>> indexResponse =
.get(indexName); ((Map<String, Map<String, Object>>) responseMap.get("indices"));
return indexResponse; return indexResponse;
} }

View File

@ -60,6 +60,12 @@ setup:
- do: - do:
indices.create: indices.create:
index: my_index_no_policy index: my_index_no_policy
- do:
indices.create:
index: index_with_policy_that_doesnt_exist
body:
settings:
index.lifecycle.name: "a_policy_that_doesnt_exist"
--- ---
teardown: teardown:
@ -81,6 +87,10 @@ teardown:
indices.delete: indices.delete:
index: my_index_no_policy index: my_index_no_policy
- do:
indices.delete:
index: index_with_policy_that_doesnt_exist
- do: - do:
ilm.delete_lifecycle: ilm.delete_lifecycle:
policy: "my_moveable_timeseries_lifecycle" policy: "my_moveable_timeseries_lifecycle"
@ -112,6 +122,7 @@ teardown:
- is_false: indices.my_index2 - is_false: indices.my_index2
- is_false: indices.another_index - is_false: indices.another_index
- is_false: indices.unmanaged_index - is_false: indices.unmanaged_index
- is_false: indices.index_with_policy_that_doesnt_exist
--- ---
"Test Wildcard Index Lifecycle Explain": "Test Wildcard Index Lifecycle Explain":
@ -146,6 +157,7 @@ teardown:
- is_false: indices.another_index - is_false: indices.another_index
- is_false: indices.unmanaged_index - is_false: indices.unmanaged_index
- is_false: indices.index_with_policy_that_doesnt_exist
--- ---
@ -201,6 +213,16 @@ teardown:
- is_false: indices.another_index.failed_step - is_false: indices.another_index.failed_step
- is_false: indices.another_index.step_info - is_false: indices.another_index.step_info
- match: { indices.index_with_policy_that_doesnt_exist.index: "index_with_policy_that_doesnt_exist" }
- match: { indices.index_with_policy_that_doesnt_exist.policy: "a_policy_that_doesnt_exist" }
- match: { indices.index_with_policy_that_doesnt_exist.step_info.reason: "policy [a_policy_that_doesnt_exist] does not exist" }
- is_true: indices.index_with_policy_that_doesnt_exist.managed
- is_false: indices.index_with_policy_that_doesnt_exist.phase
- is_false: indices.index_with_policy_that_doesnt_exist.action
- is_false: indices.index_with_policy_that_doesnt_exist.step
- is_false: indices.index_with_policy_that_doesnt_exist.age
- is_false: indices.index_with_policy_that_doesnt_exist.failed_step
--- ---
"Test Unmanaged Index Lifecycle Explain": "Test Unmanaged Index Lifecycle Explain":
@ -221,3 +243,34 @@ teardown:
- is_false: indices.my_index - is_false: indices.my_index
- is_false: indices.my_index2 - is_false: indices.my_index2
- is_false: indices.another_index - is_false: indices.another_index
- is_false: indices.index_with_policy_that_doesnt_exist
---
"Test filter for only managed indices":
- do:
ilm.explain_lifecycle:
index: "*"
only_managed: true
- match: { indices.my_index.index: "my_index" }
- match: { indices.my_index2.index: "my_index2" }
- match: { indices.another_index.index: "another_index" }
- match: { indices.index_with_policy_that_doesnt_exist.index: "index_with_policy_that_doesnt_exist" }
- is_false: indices.unmanaged_index
- is_false: indices.my_index_no_policy
---
"Test filter for only error indices":
- do:
ilm.explain_lifecycle:
index: "*"
only_errors: true
- match: { indices.index_with_policy_that_doesnt_exist.index: "index_with_policy_that_doesnt_exist" }
- is_false: indices.unmanaged_index
- is_false: indices.my_index_no_policy
- is_false: indices.my_index
- is_false: indices.my_index2
- is_false: indices.another_index

View File

@ -214,6 +214,10 @@ public class IndexLifecycleService
} }
} }
public boolean policyExists(String policyId) {
return policyRegistry.policyExists(policyId);
}
/** /**
* executes the policy execution on the appropriate indices by running cluster-state tasks per index. * executes the policy execution on the appropriate indices by running cluster-state tasks per index.
* *

View File

@ -37,6 +37,8 @@ public class RestExplainLifecycleAction extends BaseRestHandler {
ExplainLifecycleRequest explainLifecycleRequest = new ExplainLifecycleRequest(); ExplainLifecycleRequest explainLifecycleRequest = new ExplainLifecycleRequest();
explainLifecycleRequest.indices(indexes); explainLifecycleRequest.indices(indexes);
explainLifecycleRequest.indicesOptions(IndicesOptions.fromRequest(restRequest, IndicesOptions.strictExpandOpen())); explainLifecycleRequest.indicesOptions(IndicesOptions.fromRequest(restRequest, IndicesOptions.strictExpandOpen()));
explainLifecycleRequest.onlyManaged(restRequest.paramAsBoolean("only_managed", false));
explainLifecycleRequest.onlyErrors(restRequest.paramAsBoolean("only_errors", false));
String masterNodeTimeout = restRequest.param("master_timeout"); String masterNodeTimeout = restRequest.param("master_timeout");
if (masterNodeTimeout != null) { if (masterNodeTimeout != null) {
explainLifecycleRequest.masterNodeTimeout(masterNodeTimeout); explainLifecycleRequest.masterNodeTimeout(masterNodeTimeout);

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.indexlifecycle.ErrorStep;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleRequest; import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleRequest;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleResponse; import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleResponse;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleExplainResponse; import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleExplainResponse;
@ -34,6 +35,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.LifecycleExecutionState;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseExecutionInfo; import org.elasticsearch.xpack.core.indexlifecycle.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
import org.elasticsearch.xpack.ilm.IndexLifecycleService;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -43,14 +45,16 @@ public class TransportExplainLifecycleAction
extends TransportClusterInfoAction<ExplainLifecycleRequest, ExplainLifecycleResponse> { extends TransportClusterInfoAction<ExplainLifecycleRequest, ExplainLifecycleResponse> {
private final NamedXContentRegistry xContentRegistry; private final NamedXContentRegistry xContentRegistry;
private final IndexLifecycleService indexLifecycleService;
@Inject @Inject
public TransportExplainLifecycleAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, public TransportExplainLifecycleAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool,
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
NamedXContentRegistry xContentRegistry) { NamedXContentRegistry xContentRegistry, IndexLifecycleService indexLifecycleService) {
super(ExplainLifecycleAction.NAME, transportService, clusterService, threadPool, actionFilters, super(ExplainLifecycleAction.NAME, transportService, clusterService, threadPool, actionFilters,
ExplainLifecycleRequest::new, indexNameExpressionResolver); ExplainLifecycleRequest::new, indexNameExpressionResolver);
this.xContentRegistry = xContentRegistry; this.xContentRegistry = xContentRegistry;
this.indexLifecycleService = indexLifecycleService;
} }
@Override @Override
@ -73,7 +77,7 @@ public class TransportExplainLifecycleAction
@Override @Override
protected void doMasterOperation(ExplainLifecycleRequest request, String[] concreteIndices, ClusterState state, protected void doMasterOperation(ExplainLifecycleRequest request, String[] concreteIndices, ClusterState state,
ActionListener<ExplainLifecycleResponse> listener) { ActionListener<ExplainLifecycleResponse> listener) {
Map<String, IndexLifecycleExplainResponse> indexReponses = new HashMap<>(); Map<String, IndexLifecycleExplainResponse> indexResponses = new HashMap<>();
for (String index : concreteIndices) { for (String index : concreteIndices) {
IndexMetaData idxMetadata = state.metaData().index(index); IndexMetaData idxMetadata = state.metaData().index(index);
Settings idxSettings = idxMetadata.getSettings(); Settings idxSettings = idxMetadata.getSettings();
@ -100,23 +104,34 @@ public class TransportExplainLifecycleAction
} }
final IndexLifecycleExplainResponse indexResponse; final IndexLifecycleExplainResponse indexResponse;
if (Strings.hasLength(policyName)) { if (Strings.hasLength(policyName)) {
indexResponse = IndexLifecycleExplainResponse.newManagedIndexResponse(index, policyName, // If this is requesting only errors, only include indices in the error step or which are using a nonexistent policy
lifecycleState.getLifecycleDate(), if (request.onlyErrors() == false
lifecycleState.getPhase(), || (ErrorStep.NAME.equals(lifecycleState.getStep()) || indexLifecycleService.policyExists(policyName) == false)) {
lifecycleState.getAction(), indexResponse = IndexLifecycleExplainResponse.newManagedIndexResponse(index, policyName,
lifecycleState.getStep(), lifecycleState.getLifecycleDate(),
lifecycleState.getFailedStep(), lifecycleState.getPhase(),
lifecycleState.getPhaseTime(), lifecycleState.getAction(),
lifecycleState.getActionTime(), lifecycleState.getStep(),
lifecycleState.getStepTime(), lifecycleState.getFailedStep(),
stepInfoBytes, lifecycleState.getPhaseTime(),
phaseExecutionInfo); lifecycleState.getActionTime(),
} else { lifecycleState.getStepTime(),
stepInfoBytes,
phaseExecutionInfo);
} else {
indexResponse = null;
}
} else if (request.onlyManaged() == false && request.onlyErrors() == false) {
indexResponse = IndexLifecycleExplainResponse.newUnmanagedIndexResponse(index); indexResponse = IndexLifecycleExplainResponse.newUnmanagedIndexResponse(index);
} else {
indexResponse = null;
}
if (indexResponse != null) {
indexResponses.put(indexResponse.getIndex(), indexResponse);
} }
indexReponses.put(indexResponse.getIndex(), indexResponse);
} }
listener.onResponse(new ExplainLifecycleResponse(indexReponses)); listener.onResponse(new ExplainLifecycleResponse(indexResponses));
} }
} }

View File

@ -11,7 +11,16 @@
"description" : "The name of the index to explain" "description" : "The name of the index to explain"
} }
}, },
"params": {} "params": {
"only_managed": {
"type": "boolean",
"description": "filters the indices included in the response to ones managed by ILM"
},
"only_errors": {
"type": "boolean",
"description": "filters the indices included in the response to ones in an ILM error state, implies only_managed"
}
}
}, },
"body": null "body": null
} }