Rest: Adding support of multi-index query parameters for _cluster/state
Adding missing support for the multi-index query parameters 'ignore_unavailable', 'allow_no_indices' and 'expand_wildcards' to '_cluster/state' API. These parameters are supposed to be supported for APIs that work across multiple indices. So far overwriting the default settings per REST call was not possible which is fixed here. Closes #5229 Closes #9295
This commit is contained in:
parent
d3e10f9111
commit
eeb96db76b
|
@ -32,6 +32,18 @@
|
|||
"flat_settings": {
|
||||
"type": "boolean",
|
||||
"description": "Return settings in flat format (default: false)"
|
||||
},
|
||||
"ignore_unavailable": {
|
||||
"type" : "boolean",
|
||||
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"
|
||||
},
|
||||
"allow_no_indices": {
|
||||
"type" : "boolean",
|
||||
"description" : "Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)"
|
||||
},
|
||||
"expand_wildcards":{
|
||||
"type":"list",
|
||||
"description":"Whether wildcard expressions should get expanded to open or closed indices (default: open)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
setup:
|
||||
|
||||
- do:
|
||||
indices.create:
|
||||
index: test_close_index
|
||||
body:
|
||||
settings:
|
||||
number_of_shards: "1"
|
||||
number_of_replicas: "0"
|
||||
|
||||
- do:
|
||||
indices.create:
|
||||
index: test_open_index
|
||||
body:
|
||||
settings:
|
||||
number_of_shards: "1"
|
||||
number_of_replicas: "0"
|
||||
|
||||
- do:
|
||||
cluster.health:
|
||||
wait_for_status: green
|
||||
|
||||
# close one index, keep other open for later test
|
||||
|
||||
- do:
|
||||
indices.close:
|
||||
index: test_close_index
|
||||
|
||||
---
|
||||
"Test expand_wildcards parameter on closed, open indices and both":
|
||||
|
||||
- do:
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: test*
|
||||
expand_wildcards: [ closed ]
|
||||
|
||||
- is_false: metadata.indices.test_open_index
|
||||
- match: {metadata.indices.test_close_index.state: "close"}
|
||||
|
||||
- do:
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: test*
|
||||
expand_wildcards: [ open ]
|
||||
|
||||
- match: {metadata.indices.test_open_index.state: "open"}
|
||||
- is_false: metadata.indices.test_close_index
|
||||
|
||||
- do:
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: test*
|
||||
expand_wildcards: [ open,closed ]
|
||||
|
||||
- match: {metadata.indices.test_open_index.state: "open"}
|
||||
- match: {metadata.indices.test_close_index.state: "close"}
|
||||
|
||||
---
|
||||
"Test ignore_unavailable parameter":
|
||||
|
||||
- do:
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: foobla
|
||||
ignore_unavailable: true
|
||||
|
||||
- match: {metadata.indices: {}}
|
||||
|
||||
- do:
|
||||
catch: missing
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: foobla
|
||||
ignore_unavailable: false
|
||||
|
||||
---
|
||||
"Test allow_no_indices parameter":
|
||||
|
||||
- do:
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: not_there*
|
||||
|
||||
- match: {metadata.indices: {}}
|
||||
|
||||
- do:
|
||||
catch: missing
|
||||
cluster.state:
|
||||
metric: [ metadata ]
|
||||
index: not_there*
|
||||
allow_no_indices: false
|
|
@ -40,6 +40,7 @@ public class ClusterStateRequest extends MasterNodeReadOperationRequest<ClusterS
|
|||
private boolean metaData = true;
|
||||
private boolean blocks = true;
|
||||
private String[] indices = Strings.EMPTY_ARRAY;
|
||||
private IndicesOptions indicesOptions = IndicesOptions.lenientExpandOpen();
|
||||
|
||||
public ClusterStateRequest() {
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ public class ClusterStateRequest extends MasterNodeReadOperationRequest<ClusterS
|
|||
indices = Strings.EMPTY_ARRAY;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ClusterStateRequest clear() {
|
||||
routingTable = false;
|
||||
nodes = false;
|
||||
|
@ -116,7 +117,12 @@ public class ClusterStateRequest extends MasterNodeReadOperationRequest<ClusterS
|
|||
|
||||
@Override
|
||||
public IndicesOptions indicesOptions() {
|
||||
return IndicesOptions.lenientExpandOpen();
|
||||
return this.indicesOptions;
|
||||
}
|
||||
|
||||
public final ClusterStateRequest indicesOptions(IndicesOptions indicesOptions) {
|
||||
this.indicesOptions = indicesOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,6 +133,7 @@ public class ClusterStateRequest extends MasterNodeReadOperationRequest<ClusterS
|
|||
metaData = in.readBoolean();
|
||||
blocks = in.readBoolean();
|
||||
indices = in.readStringArray();
|
||||
indicesOptions = IndicesOptions.readIndicesOptions(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,5 +144,6 @@ public class ClusterStateRequest extends MasterNodeReadOperationRequest<ClusterS
|
|||
out.writeBoolean(metaData);
|
||||
out.writeBoolean(blocks);
|
||||
out.writeStringArray(indices);
|
||||
indicesOptions.writeIndicesOptions(out);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.elasticsearch.action.admin.cluster.state;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
||||
import org.elasticsearch.client.ClusterAdminClient;
|
||||
|
||||
|
@ -89,6 +90,11 @@ public class ClusterStateRequestBuilder extends MasterNodeReadOperationRequestBu
|
|||
return this;
|
||||
}
|
||||
|
||||
public ClusterStateRequestBuilder setIndicesOptions(IndicesOptions indicesOptions) {
|
||||
request.indicesOptions(indicesOptions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(ActionListener<ClusterStateResponse> listener) {
|
||||
client.state(request, listener);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.rest.action.admin.cluster.state;
|
|||
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
|
@ -57,6 +58,7 @@ public class RestClusterStateAction extends BaseRestHandler {
|
|||
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) {
|
||||
final ClusterStateRequest clusterStateRequest = Requests.clusterStateRequest();
|
||||
clusterStateRequest.listenerThreaded(false);
|
||||
clusterStateRequest.indicesOptions(IndicesOptions.fromRequest(request, clusterStateRequest.indicesOptions()));
|
||||
clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
|
||||
clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.action.admin.cluster.state;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamInput;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link ClusterStateRequest}.
|
||||
*/
|
||||
public class ClusterStateRequestTest extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testSerialization() throws Exception {
|
||||
int iterations = randomIntBetween(5, 20);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
|
||||
IndicesOptions indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
|
||||
ClusterStateRequest clusterStateRequest = new ClusterStateRequest().routingTable(randomBoolean()).metaData(randomBoolean())
|
||||
.nodes(randomBoolean()).blocks(randomBoolean()).indices("testindex", "testindex2").indicesOptions(indicesOptions);
|
||||
|
||||
Version testVersion = randomVersionBetween(Version.CURRENT.minimumCompatibilityVersion(), Version.CURRENT);
|
||||
BytesStreamOutput output = new BytesStreamOutput();
|
||||
output.setVersion(testVersion);
|
||||
clusterStateRequest.writeTo(output);
|
||||
|
||||
BytesStreamInput bytesStreamInput = new BytesStreamInput(output.bytes());
|
||||
bytesStreamInput.setVersion(testVersion);
|
||||
ClusterStateRequest deserializedCSRequest = new ClusterStateRequest();
|
||||
deserializedCSRequest.readFrom(bytesStreamInput);
|
||||
|
||||
assertThat(deserializedCSRequest.routingTable(), equalTo(clusterStateRequest.routingTable()));
|
||||
assertThat(deserializedCSRequest.metaData(), equalTo(clusterStateRequest.metaData()));
|
||||
assertThat(deserializedCSRequest.nodes(), equalTo(clusterStateRequest.nodes()));
|
||||
assertThat(deserializedCSRequest.blocks(), equalTo(clusterStateRequest.blocks()));
|
||||
assertThat(deserializedCSRequest.indices(), equalTo(clusterStateRequest.indices()));
|
||||
|
||||
if (testVersion.onOrAfter(Version.V_1_5_0)) {
|
||||
assertOptionsMatch(deserializedCSRequest.indicesOptions(), clusterStateRequest.indicesOptions());
|
||||
} else {
|
||||
// versions before V_1_5_0 use IndicesOptions.lenientExpandOpen()
|
||||
assertOptionsMatch(deserializedCSRequest.indicesOptions(), IndicesOptions.lenientExpandOpen());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertOptionsMatch(IndicesOptions in, IndicesOptions out) {
|
||||
assertThat(in.ignoreUnavailable(), equalTo(out.ignoreUnavailable()));
|
||||
assertThat(in.expandWildcardsClosed(), equalTo(out.expandWildcardsClosed()));
|
||||
assertThat(in.expandWildcardsOpen(), equalTo(out.expandWildcardsOpen()));
|
||||
assertThat(in.allowNoIndices(), equalTo(out.allowNoIndices()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.bwcompat;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ElasticsearchBackwardsCompatIntegrationTest;
|
||||
import org.junit.Test;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class ClusterStateBackwardsCompat extends ElasticsearchBackwardsCompatIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testClusterState() throws Exception {
|
||||
createIndex("test");
|
||||
|
||||
NodesInfoResponse nodesInfo = client().admin().cluster().prepareNodesInfo().execute().actionGet();
|
||||
Settings settings = ImmutableSettings.settingsBuilder().put("client.transport.ignore_cluster_name", true)
|
||||
.put("node.name", "transport_client_" + getTestName()).build();
|
||||
|
||||
// connect to each node with a custom TransportClient, issue a ClusterStateRequest to test serialization
|
||||
for (NodeInfo n : nodesInfo.getNodes()) {
|
||||
try (TransportClient tc = new TransportClient(settings)) {
|
||||
tc.addTransportAddress(n.getNode().address());
|
||||
ClusterStateResponse response = tc.admin().cluster().prepareState().execute().actionGet();
|
||||
|
||||
assertThat(response.getState().status(), equalTo(ClusterState.ClusterStateStatus.UNKNOWN));
|
||||
assertNotNull(response.getClusterName());
|
||||
assertTrue(response.getState().getMetaData().hasIndex("test"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,13 +21,16 @@ package org.elasticsearch.cluster;
|
|||
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.indices.IndexMissingException;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.hamcrest.CollectionAssertions;
|
||||
import org.junit.Before;
|
||||
|
@ -157,4 +160,51 @@ public class SimpleClusterStateTests extends ElasticsearchIntegrationTest {
|
|||
assertThat(mappingMetadata, equalTo(masterMappingMetaData));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndicesOptions() throws Exception {
|
||||
ClusterStateResponse clusterStateResponse = client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("f*")
|
||||
.get();
|
||||
assertThat(clusterStateResponse.getState().metaData().indices().size(), is(2));
|
||||
|
||||
// close one index
|
||||
client().admin().indices().close(Requests.closeIndexRequest("fuu")).get();
|
||||
clusterStateResponse = client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("f*").get();
|
||||
assertThat(clusterStateResponse.getState().metaData().indices().size(), is(1));
|
||||
assertThat(clusterStateResponse.getState().metaData().index("foo").state(), equalTo(IndexMetaData.State.OPEN));
|
||||
|
||||
// expand_wildcards_closed should toggle return only closed index fuu
|
||||
IndicesOptions expandCloseOptions = IndicesOptions.fromOptions(false, true, false, true);
|
||||
clusterStateResponse = client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("f*")
|
||||
.setIndicesOptions(expandCloseOptions).get();
|
||||
assertThat(clusterStateResponse.getState().metaData().indices().size(), is(1));
|
||||
assertThat(clusterStateResponse.getState().metaData().index("fuu").state(), equalTo(IndexMetaData.State.CLOSE));
|
||||
|
||||
// ignore_unavailable set to true should not raise exception on fzzbzz
|
||||
IndicesOptions ignoreUnavailabe = IndicesOptions.fromOptions(true, true, true, false);
|
||||
clusterStateResponse = client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("fzzbzz")
|
||||
.setIndicesOptions(ignoreUnavailabe).get();
|
||||
assertThat(clusterStateResponse.getState().metaData().indices().isEmpty(), is(true));
|
||||
|
||||
// empty wildcard expansion result should work when allowNoIndices is
|
||||
// turned on
|
||||
IndicesOptions allowNoIndices = IndicesOptions.fromOptions(false, true, true, false);
|
||||
clusterStateResponse = client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("a*")
|
||||
.setIndicesOptions(allowNoIndices).get();
|
||||
assertThat(clusterStateResponse.getState().metaData().indices().isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test(expected=IndexMissingException.class)
|
||||
public void testIndicesOptionsOnAllowNoIndicesFalse() throws Exception {
|
||||
// empty wildcard expansion throws exception when allowNoIndices is turned off
|
||||
IndicesOptions allowNoIndices = IndicesOptions.fromOptions(false, false, true, false);
|
||||
client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("a*").setIndicesOptions(allowNoIndices).get();
|
||||
}
|
||||
|
||||
@Test(expected=IndexMissingException.class)
|
||||
public void testIndicesIgnoreUnavailableFalse() throws Exception {
|
||||
// ignore_unavailable set to false throws exception when allowNoIndices is turned off
|
||||
IndicesOptions allowNoIndices = IndicesOptions.fromOptions(false, true, true, false);
|
||||
client().admin().cluster().prepareState().clear().setMetaData(true).setIndices("fzzbzz").setIndicesOptions(allowNoIndices).get();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue