Add Get Settings API support to java high-level rest client (#29229)

This PR adds support for the Get Settings API to the java high-level rest client.
Furthermore, logic related to the retrieval of default settings has been moved from the rest layer into the transport layer and now default settings may be retrieved consistency via both the rest API and the transport API.
This commit is contained in:
tomcallahan 2018-05-04 11:14:28 -04:00 committed by GitHub
parent bf51a21b6c
commit 0a93956194
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1046 additions and 42 deletions

View File

@ -43,6 +43,8 @@ import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
@ -265,6 +267,28 @@ public final class IndicesClient {
listener, emptySet(), headers);
}
/**
* Retrieve the settings of one or more indices
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-settings.html">
* Indices Get Settings API on elastic.co</a>
*/
public GetSettingsResponse getSettings(GetSettingsRequest getSettingsRequest, Header... headers) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(getSettingsRequest, RequestConverters::getSettings,
GetSettingsResponse::fromXContent, emptySet(), headers);
}
/**
* Asynchronously retrieve the settings of one or more indices
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-settings.html">
* Indices Get Settings API on elastic.co</a>
*/
public void getSettingsAsync(GetSettingsRequest getSettingsRequest, ActionListener<GetSettingsResponse> listener, Header... headers) {
restHighLevelClient.performRequestAsyncAndParseEntity(getSettingsRequest, RequestConverters::getSettings,
GetSettingsResponse::fromXContent, listener, emptySet(), headers);
}
/**
* Force merge one or more indices using the Force Merge API
* <p>

View File

@ -44,6 +44,7 @@ import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.bulk.BulkRequest;
@ -600,6 +601,22 @@ final class RequestConverters {
return request;
}
static Request getSettings(GetSettingsRequest getSettingsRequest) throws IOException {
String[] indices = getSettingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getSettingsRequest.indices();
String[] names = getSettingsRequest.names() == null ? Strings.EMPTY_ARRAY : getSettingsRequest.names();
String endpoint = endpoint(indices, "_settings", names);
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
Params params = new Params(request);
params.withIndicesOptions(getSettingsRequest.indicesOptions());
params.withLocal(getSettingsRequest.local());
params.withIncludeDefaults(getSettingsRequest.includeDefaults());
params.withMasterTimeout(getSettingsRequest.masterNodeTimeout());
return request;
}
static Request indicesExist(GetIndexRequest getIndexRequest) {
// this can be called with no indices as argument by transport client, not via REST though
if (getIndexRequest.indices() == null || getIndexRequest.indices().length == 0) {

View File

@ -51,6 +51,8 @@ import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsResponse;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
@ -189,6 +191,108 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
}
}
public void testGetSettings() throws IOException {
String indexName = "get_settings_index";
Settings basicSettings = Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
.build();
createIndex(indexName, basicSettings);
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices(indexName);
GetSettingsResponse getSettingsResponse = execute(getSettingsRequest, highLevelClient().indices()::getSettings,
highLevelClient().indices()::getSettingsAsync);
assertNull(getSettingsResponse.getSetting(indexName, "index.refresh_interval"));
assertEquals("1", getSettingsResponse.getSetting(indexName, "index.number_of_shards"));
updateIndexSettings(indexName, Settings.builder().put("refresh_interval", "30s"));
GetSettingsResponse updatedResponse = execute(getSettingsRequest, highLevelClient().indices()::getSettings,
highLevelClient().indices()::getSettingsAsync);
assertEquals("30s", updatedResponse.getSetting(indexName, "index.refresh_interval"));
}
public void testGetSettingsNonExistentIndex() throws IOException {
String nonExistentIndex = "index_that_doesnt_exist";
assertFalse(indexExists(nonExistentIndex));
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices(nonExistentIndex);
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(getSettingsRequest, highLevelClient().indices()::getSettings, highLevelClient().indices()::getSettingsAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
}
public void testGetSettingsFromMultipleIndices() throws IOException {
String indexName1 = "get_multiple_settings_one";
createIndex(indexName1, Settings.builder().put("number_of_shards", 2).build());
String indexName2 = "get_multiple_settings_two";
createIndex(indexName2, Settings.builder().put("number_of_shards", 3).build());
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices("get_multiple_settings*");
GetSettingsResponse getSettingsResponse = execute(getSettingsRequest, highLevelClient().indices()::getSettings,
highLevelClient().indices()::getSettingsAsync);
assertEquals("2", getSettingsResponse.getSetting(indexName1, "index.number_of_shards"));
assertEquals("3", getSettingsResponse.getSetting(indexName2, "index.number_of_shards"));
}
public void testGetSettingsFiltered() throws IOException {
String indexName = "get_settings_index";
Settings basicSettings = Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
.build();
createIndex(indexName, basicSettings);
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices(indexName).names("index.number_of_shards");
GetSettingsResponse getSettingsResponse = execute(getSettingsRequest, highLevelClient().indices()::getSettings,
highLevelClient().indices()::getSettingsAsync);
assertNull(getSettingsResponse.getSetting(indexName, "index.number_of_replicas"));
assertEquals("1", getSettingsResponse.getSetting(indexName, "index.number_of_shards"));
assertEquals(1, getSettingsResponse.getIndexToSettings().get("get_settings_index").size());
}
public void testGetSettingsWithDefaults() throws IOException {
String indexName = "get_settings_index";
Settings basicSettings = Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
.build();
createIndex(indexName, basicSettings);
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices(indexName).includeDefaults(true);
GetSettingsResponse getSettingsResponse = execute(getSettingsRequest, highLevelClient().indices()::getSettings,
highLevelClient().indices()::getSettingsAsync);
assertNotNull(getSettingsResponse.getSetting(indexName, "index.refresh_interval"));
assertEquals(IndexSettings.DEFAULT_REFRESH_INTERVAL,
getSettingsResponse.getIndexToDefaultSettings().get("get_settings_index").getAsTime("index.refresh_interval", null));
assertEquals("1", getSettingsResponse.getSetting(indexName, "index.number_of_shards"));
}
public void testGetSettingsWithDefaultsFiltered() throws IOException {
String indexName = "get_settings_index";
Settings basicSettings = Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
.build();
createIndex(indexName, basicSettings);
GetSettingsRequest getSettingsRequest = new GetSettingsRequest()
.indices(indexName)
.names("index.refresh_interval")
.includeDefaults(true);
GetSettingsResponse getSettingsResponse = execute(getSettingsRequest, highLevelClient().indices()::getSettings,
highLevelClient().indices()::getSettingsAsync);
assertNull(getSettingsResponse.getSetting(indexName, "index.number_of_replicas"));
assertNull(getSettingsResponse.getSetting(indexName, "index.number_of_shards"));
assertEquals(0, getSettingsResponse.getIndexToSettings().get("get_settings_index").size());
assertEquals(1, getSettingsResponse.getIndexToDefaultSettings().get("get_settings_index").size());
}
public void testPutMapping() throws IOException {
{
// Add mappings to index

View File

@ -47,6 +47,7 @@ import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.bulk.BulkRequest;
@ -76,6 +77,7 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -405,6 +407,52 @@ public class RequestConvertersTests extends ESTestCase {
assertNull(request.getEntity());
}
public void testGetSettings() throws IOException {
String[] indicesUnderTest = randomBoolean() ? null : randomIndicesNames(0, 5);
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices(indicesUnderTest);
Map<String, String> expectedParams = new HashMap<>();
setRandomMasterTimeout(getSettingsRequest, expectedParams);
setRandomIndicesOptions(getSettingsRequest::indicesOptions, getSettingsRequest::indicesOptions, expectedParams);
setRandomLocal(getSettingsRequest, expectedParams);
if (randomBoolean()) {
//the request object will not have include_defaults present unless it is set to true
getSettingsRequest.includeDefaults(randomBoolean());
if (getSettingsRequest.includeDefaults()) {
expectedParams.put("include_defaults", Boolean.toString(true));
}
}
StringJoiner endpoint = new StringJoiner("/", "/", "");
if (indicesUnderTest != null && indicesUnderTest.length > 0) {
endpoint.add(String.join(",", indicesUnderTest));
}
endpoint.add("_settings");
if (randomBoolean()) {
String[] names = randomBoolean() ? null : new String[randomIntBetween(0, 3)];
if (names != null) {
for (int x = 0; x < names.length; x++) {
names[x] = randomAlphaOfLengthBetween(3, 10);
}
}
getSettingsRequest.names(names);
if (names != null && names.length > 0) {
endpoint.add(String.join(",", names));
}
}
Request request = RequestConverters.getSettings(getSettingsRequest);
assertThat(endpoint.toString(), equalTo(request.getEndpoint()));
assertThat(request.getParameters(), equalTo(expectedParams));
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
assertThat(request.getEntity(), nullValue());
}
public void testDeleteIndexEmptyIndices() {
String[] indices = randomBoolean() ? null : Strings.EMPTY_ARRAY;
ActionRequestValidationException validationException = new DeleteIndexRequest(indices).validate();

View File

@ -50,6 +50,8 @@ import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsResponse;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
@ -775,6 +777,119 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
}
}
public void testGetSettings() throws Exception {
RestHighLevelClient client = highLevelClient();
{
Settings settings = Settings.builder().put("number_of_shards", 3).build();
CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("index", settings));
assertTrue(createIndexResponse.isAcknowledged());
}
// tag::get-settings-request
GetSettingsRequest request = new GetSettingsRequest().indices("index");
// end::get-settings-request
// tag::get-settings-request-names
request.names("index.number_of_shards"); // <1>
// end::get-settings-request-names
// tag::get-settings-request-indicesOptions
request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
// end::get-settings-request-indicesOptions
// tag::get-settings-execute
GetSettingsResponse getSettingsResponse = client.indices().getSettings(request);
// end::get-settings-execute
// tag::get-settings-response
String numberOfShardsString = getSettingsResponse.getSetting("index", "index.number_of_shards"); // <1>
Settings indexSettings = getSettingsResponse.getIndexToSettings().get("index"); // <2>
Integer numberOfShards = indexSettings.getAsInt("index.number_of_shards", null); // <3>
// end::get-settings-response
assertEquals("3", numberOfShardsString);
assertEquals(Integer.valueOf(3), numberOfShards);
assertNull("refresh_interval returned but was never set!",
getSettingsResponse.getSetting("index", "index.refresh_interval"));
// tag::get-settings-execute-listener
ActionListener<GetSettingsResponse> listener =
new ActionListener<GetSettingsResponse>() {
@Override
public void onResponse(GetSettingsResponse GetSettingsResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::get-settings-execute-listener
// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);
// tag::get-settings-execute-async
client.indices().getSettingsAsync(request, listener); // <1>
// end::get-settings-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
public void testGetSettingsWithDefaults() throws Exception {
RestHighLevelClient client = highLevelClient();
{
Settings settings = Settings.builder().put("number_of_shards", 3).build();
CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("index", settings));
assertTrue(createIndexResponse.isAcknowledged());
}
GetSettingsRequest request = new GetSettingsRequest().indices("index");
request.indicesOptions(IndicesOptions.lenientExpandOpen());
// tag::get-settings-request-include-defaults
request.includeDefaults(true); // <1>
// end::get-settings-request-include-defaults
GetSettingsResponse getSettingsResponse = client.indices().getSettings(request);
String numberOfShardsString = getSettingsResponse.getSetting("index", "index.number_of_shards");
Settings indexSettings = getSettingsResponse.getIndexToSettings().get("index");
Integer numberOfShards = indexSettings.getAsInt("index.number_of_shards", null);
// tag::get-settings-defaults-response
String refreshInterval = getSettingsResponse.getSetting("index", "index.refresh_interval"); // <1>
Settings indexDefaultSettings = getSettingsResponse.getIndexToDefaultSettings().get("index"); // <2>
// end::get-settings-defaults-response
assertEquals("3", numberOfShardsString);
assertEquals(Integer.valueOf(3), numberOfShards);
assertNotNull("with defaults enabled we should get a value for refresh_interval!", refreshInterval);
assertEquals(refreshInterval, indexDefaultSettings.get("index.refresh_interval"));
ActionListener<GetSettingsResponse> listener =
new ActionListener<GetSettingsResponse>() {
@Override
public void onResponse(GetSettingsResponse GetSettingsResponse) {
}
@Override
public void onFailure(Exception e) {
}
};
// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);
client.indices().getSettingsAsync(request, listener);
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
public void testForceMergeIndex() throws Exception {
RestHighLevelClient client = highLevelClient();

View File

@ -0,0 +1,96 @@
[[java-rest-high-get-settings]]
=== Get Settings API
[[java-rest-high-get-settings-request]]
==== Get Settings Request
A `GetSettingsRequest` requires one or more `index` arguments:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-request]
--------------------------------------------------
<1> The index whose settings we should retrieve
==== Optional arguments
The following arguments can optionally be provided:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-request-names]
--------------------------------------------------
<1> One or more settings that be the only settings retrieved. If unset, all settings will be retrieved
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-request-include-defaults]
--------------------------------------------------
<1> If true, defaults will be returned for settings not explicitly set on the index
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-request-indicesOptions]
--------------------------------------------------
<1> Setting `IndicesOptions` controls how unavailable indices are resolved and
how wildcard expressions are expanded
[[java-rest-high-get-settings-sync]]
==== Synchronous Execution
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-execute]
--------------------------------------------------
[[java-rest-high-get-settings-async]]
==== Asynchronous Execution
The asynchronous execution of a Get Settings request requires both the `GetSettingsRequest`
instance and an `ActionListener` instance to be passed to the asynchronous
method:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-execute-async]
--------------------------------------------------
<1> The `GetSettingsRequest` to execute and the `ActionListener` to use when
the execution completes
The asynchronous method does not block and returns immediately. Once it is
completed the `ActionListener` is called back using the `onResponse` method
if the execution successfully completed or using the `onFailure` method if
it failed.
A typical listener for `GetSettingsResponse` looks like:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-execute-listener]
--------------------------------------------------
<1> Called when the execution is successfully completed. The response is
provided as an argument
<2> Called in case of failure. The raised exception is provided as an argument
[[java-rest-high-get-settings-response]]
==== Get Settings Response
The returned `GetSettingsResponse` allows to retrieve information about the
executed operation as follows:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-response]
--------------------------------------------------
<1> We can retrieve the setting value for a particular index directly from the response as a string
<2> We can also retrieve the Settings object for a particular index for further examination
<3> The returned Settings object provides convenience methods for non String types
If the `includeDefaults` flag was set to true in the `GetSettingsRequest`, the
behavior of `GetSettingsResponse` will differ somewhat.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-settings-defaults-response]
--------------------------------------------------
<1> Individual default setting values may be retrieved directly from the `GetSettingsResponse`
<2> We may retrieve a Settings object for an index that contains those settings with default values

View File

@ -69,6 +69,7 @@ Index Management::
* <<java-rest-high-force-merge>>
* <<java-rest-high-rollover-index>>
* <<java-rest-high-indices-put-settings>>
* <<java-rest-high-get-settings>>
Mapping Management::
* <<java-rest-high-put-mapping>>
@ -93,6 +94,7 @@ include::indices/put_mapping.asciidoc[]
include::indices/update_aliases.asciidoc[]
include::indices/exists_alias.asciidoc[]
include::indices/put_settings.asciidoc[]
include::indices/get_settings.asciidoc[]
== Cluster APIs

View File

@ -16,6 +16,10 @@
}
},
"params": {
"master_timeout": {
"type": "time",
"description": "Specify timeout for connection to master"
},
"ignore_unavailable": {
"type" : "boolean",
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"

View File

@ -576,7 +576,7 @@ public class ActionModule extends AbstractModule {
registerHandler.accept(new RestOpenIndexAction(settings, restController));
registerHandler.accept(new RestUpdateSettingsAction(settings, restController));
registerHandler.accept(new RestGetSettingsAction(settings, restController, indexScopedSettings, settingsFilter));
registerHandler.accept(new RestGetSettingsAction(settings, restController));
registerHandler.accept(new RestAnalyzeAction(settings, restController));
registerHandler.accept(new RestGetIndexTemplateAction(settings, restController));

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.admin.indices.settings.get;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.ValidateActions;
@ -29,6 +30,8 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest> implements IndicesRequest.Replaceable {
@ -36,6 +39,7 @@ public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest
private IndicesOptions indicesOptions = IndicesOptions.fromOptions(false, true, true, true);
private String[] names = Strings.EMPTY_ARRAY;
private boolean humanReadable = false;
private boolean includeDefaults = false;
@Override
public GetSettingsRequest indices(String... indices) {
@ -48,6 +52,16 @@ public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest
return this;
}
/**
* When include_defaults is set, return default values which are normally suppressed.
* This flag is specific to the rest client.
*/
public GetSettingsRequest includeDefaults(boolean includeDefaults) {
this.includeDefaults = includeDefaults;
return this;
}
public GetSettingsRequest() {
}
@ -57,6 +71,9 @@ public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest
indicesOptions = IndicesOptions.readIndicesOptions(in);
names = in.readStringArray();
humanReadable = in.readBoolean();
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
includeDefaults = in.readBoolean();
}
}
@Override
@ -66,6 +83,9 @@ public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest
indicesOptions.writeIndicesOptions(out);
out.writeStringArray(names);
out.writeBoolean(humanReadable);
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeBoolean(includeDefaults);
}
}
@Override
@ -96,6 +116,10 @@ public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest
return this;
}
public boolean includeDefaults() {
return includeDefaults;
}
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
@ -109,4 +133,24 @@ public class GetSettingsRequest extends MasterNodeReadRequest<GetSettingsRequest
public void readFrom(StreamInput in) throws IOException {
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetSettingsRequest that = (GetSettingsRequest) o;
return humanReadable == that.humanReadable &&
includeDefaults == that.includeDefaults &&
Arrays.equals(indices, that.indices) &&
Objects.equals(indicesOptions, that.indicesOptions) &&
Arrays.equals(names, that.names);
}
@Override
public int hashCode() {
int result = Objects.hash(indicesOptions, humanReadable, includeDefaults);
result = 31 * result + Arrays.hashCode(indices);
result = 31 * result + Arrays.hashCode(names);
return result;
}
}

View File

@ -21,32 +21,83 @@ package org.elasticsearch.action.admin.indices.settings.get;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParserUtils;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
public class GetSettingsResponse extends ActionResponse {
public class GetSettingsResponse extends ActionResponse implements ToXContentObject {
private ImmutableOpenMap<String, Settings> indexToSettings = ImmutableOpenMap.of();
private ImmutableOpenMap<String, Settings> indexToDefaultSettings = ImmutableOpenMap.of();
public GetSettingsResponse(ImmutableOpenMap<String, Settings> indexToSettings) {
public GetSettingsResponse(ImmutableOpenMap<String, Settings> indexToSettings,
ImmutableOpenMap<String, Settings> indexToDefaultSettings) {
this.indexToSettings = indexToSettings;
this.indexToDefaultSettings = indexToDefaultSettings;
}
GetSettingsResponse() {
}
/**
* Returns a map of index name to {@link Settings} object. The returned {@link Settings}
* objects contain only those settings explicitly set on a given index. Any settings
* taking effect as defaults must be accessed via {@link #getIndexToDefaultSettings()}.
*/
public ImmutableOpenMap<String, Settings> getIndexToSettings() {
return indexToSettings;
}
/**
* If the originating {@link GetSettingsRequest} object was configured to include
* defaults, this will contain a mapping of index name to {@link Settings} objects.
* The returned {@link Settings} objects will contain only those settings taking
* effect as defaults. Any settings explicitly set on the index will be available
* via {@link #getIndexToSettings()}.
* See also {@link GetSettingsRequest#includeDefaults(boolean)}
*/
public ImmutableOpenMap<String, Settings> getIndexToDefaultSettings() {
return indexToDefaultSettings;
}
/**
* Returns the string value for the specified index and setting. If the includeDefaults
* flag was not set or set to false on the GetSettingsRequest, this method will only
* return a value where the setting was explicitly set on the index. If the includeDefaults
* flag was set to true on the GetSettingsRequest, this method will fall back to return the default
* value if the setting was not explicitly set.
*/
public String getSetting(String index, String setting) {
Settings settings = indexToSettings.get(index);
if (setting != null) {
return settings.get(setting);
if (settings != null && settings.hasValue(setting)) {
return settings.get(setting);
} else {
Settings defaultSettings = indexToDefaultSettings.get(index);
if (defaultSettings != null) {
return defaultSettings.get(setting);
} else {
return null;
}
}
} else {
return null;
}
@ -55,12 +106,22 @@ public class GetSettingsResponse extends ActionResponse {
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
int size = in.readVInt();
ImmutableOpenMap.Builder<String, Settings> builder = ImmutableOpenMap.builder();
for (int i = 0; i < size; i++) {
builder.put(in.readString(), Settings.readSettingsFromStream(in));
int settingsSize = in.readVInt();
ImmutableOpenMap.Builder<String, Settings> settingsBuilder = ImmutableOpenMap.builder();
for (int i = 0; i < settingsSize; i++) {
settingsBuilder.put(in.readString(), Settings.readSettingsFromStream(in));
}
indexToSettings = builder.build();
ImmutableOpenMap.Builder<String, Settings> defaultSettingsBuilder = ImmutableOpenMap.builder();
if (in.getVersion().onOrAfter(org.elasticsearch.Version.V_7_0_0_alpha1)) {
int defaultSettingsSize = in.readVInt();
for (int i = 0; i < defaultSettingsSize ; i++) {
defaultSettingsBuilder.put(in.readString(), Settings.readSettingsFromStream(in));
}
}
indexToSettings = settingsBuilder.build();
indexToDefaultSettings = defaultSettingsBuilder.build();
}
@Override
@ -71,5 +132,121 @@ public class GetSettingsResponse extends ActionResponse {
out.writeString(cursor.key);
Settings.writeSettingsToStream(cursor.value, out);
}
if (out.getVersion().onOrAfter(org.elasticsearch.Version.V_7_0_0_alpha1)) {
out.writeVInt(indexToDefaultSettings.size());
for (ObjectObjectCursor<String, Settings> cursor : indexToDefaultSettings) {
out.writeString(cursor.key);
Settings.writeSettingsToStream(cursor.value, out);
}
}
}
private static void parseSettingsField(XContentParser parser, String currentIndexName, Map<String, Settings> indexToSettings,
Map<String, Settings> indexToDefaultSettings) throws IOException {
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
switch (parser.currentName()) {
case "settings":
indexToSettings.put(currentIndexName, Settings.fromXContent(parser));
break;
case "defaults":
indexToDefaultSettings.put(currentIndexName, Settings.fromXContent(parser));
break;
default:
parser.skipChildren();
}
} else if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
parser.skipChildren();
}
parser.nextToken();
}
private static void parseIndexEntry(XContentParser parser, Map<String, Settings> indexToSettings,
Map<String, Settings> indexToDefaultSettings) throws IOException {
String indexName = parser.currentName();
parser.nextToken();
while (!parser.isClosed() && parser.currentToken() != XContentParser.Token.END_OBJECT) {
parseSettingsField(parser, indexName, indexToSettings, indexToDefaultSettings);
}
}
public static GetSettingsResponse fromXContent(XContentParser parser) throws IOException {
HashMap<String, Settings> indexToSettings = new HashMap<>();
HashMap<String, Settings> indexToDefaultSettings = new HashMap<>();
if (parser.currentToken() == null) {
parser.nextToken();
}
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser::getTokenLocation);
parser.nextToken();
while (!parser.isClosed()) {
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
//we must assume this is an index entry
parseIndexEntry(parser, indexToSettings, indexToDefaultSettings);
} else if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
parser.skipChildren();
} else {
parser.nextToken();
}
}
ImmutableOpenMap<String, Settings> settingsMap = ImmutableOpenMap.<String, Settings>builder().putAll(indexToSettings).build();
ImmutableOpenMap<String, Settings> defaultSettingsMap =
ImmutableOpenMap.<String, Settings>builder().putAll(indexToDefaultSettings).build();
return new GetSettingsResponse(settingsMap, defaultSettingsMap);
}
@Override
public String toString() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XContentBuilder builder = new XContentBuilder(JsonXContent.jsonXContent, baos);
toXContent(builder, ToXContent.EMPTY_PARAMS, false);
return Strings.toString(builder);
} catch (IOException e) {
throw new IllegalStateException(e); //should not be possible here
}
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return toXContent(builder, params, indexToDefaultSettings.isEmpty());
}
private XContentBuilder toXContent(XContentBuilder builder, Params params, boolean omitEmptySettings) throws IOException {
builder.startObject();
for (ObjectObjectCursor<String, Settings> cursor : getIndexToSettings()) {
// no settings, jump over it to shorten the response data
if (omitEmptySettings && cursor.value.isEmpty()) {
continue;
}
builder.startObject(cursor.key);
builder.startObject("settings");
cursor.value.toXContent(builder, params);
builder.endObject();
if (indexToDefaultSettings.isEmpty() == false) {
builder.startObject("defaults");
indexToDefaultSettings.get(cursor.key).toXContent(builder, params);
builder.endObject();
}
builder.endObject();
}
builder.endObject();
return builder;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetSettingsResponse that = (GetSettingsResponse) o;
return Objects.equals(indexToSettings, that.indexToSettings) &&
Objects.equals(indexToDefaultSettings, that.indexToDefaultSettings);
}
@Override
public int hashCode() {
return Objects.hash(indexToSettings, indexToDefaultSettings);
}
}

View File

@ -37,19 +37,23 @@ import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.index.Index;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.common.settings.IndexScopedSettings;
import java.util.Map;
import java.util.Arrays;
public class TransportGetSettingsAction extends TransportMasterNodeReadAction<GetSettingsRequest, GetSettingsResponse> {
private final SettingsFilter settingsFilter;
private final IndexScopedSettings indexScopedSettings;
@Inject
public TransportGetSettingsAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, SettingsFilter settingsFilter, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
IndexNameExpressionResolver indexNameExpressionResolver, IndexScopedSettings indexedScopedSettings) {
super(settings, GetSettingsAction.NAME, transportService, clusterService, threadPool, actionFilters, GetSettingsRequest::new, indexNameExpressionResolver);
this.settingsFilter = settingsFilter;
this.indexScopedSettings = indexedScopedSettings;
}
@Override
@ -69,25 +73,39 @@ public class TransportGetSettingsAction extends TransportMasterNodeReadAction<Ge
return new GetSettingsResponse();
}
private static boolean isFilteredRequest(GetSettingsRequest request) {
return CollectionUtils.isEmpty(request.names()) == false;
}
@Override
protected void masterOperation(GetSettingsRequest request, ClusterState state, ActionListener<GetSettingsResponse> listener) {
Index[] concreteIndices = indexNameExpressionResolver.concreteIndices(state, request);
ImmutableOpenMap.Builder<String, Settings> indexToSettingsBuilder = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, Settings> indexToDefaultSettingsBuilder = ImmutableOpenMap.builder();
for (Index concreteIndex : concreteIndices) {
IndexMetaData indexMetaData = state.getMetaData().index(concreteIndex);
if (indexMetaData == null) {
continue;
}
Settings settings = settingsFilter.filter(indexMetaData.getSettings());
Settings indexSettings = settingsFilter.filter(indexMetaData.getSettings());
if (request.humanReadable()) {
settings = IndexMetaData.addHumanReadableSettings(settings);
indexSettings = IndexMetaData.addHumanReadableSettings(indexSettings);
}
if (CollectionUtils.isEmpty(request.names()) == false) {
settings = settings.filter(k -> Regex.simpleMatch(request.names(), k));
if (isFilteredRequest(request)) {
indexSettings = indexSettings.filter(k -> Regex.simpleMatch(request.names(), k));
}
indexToSettingsBuilder.put(concreteIndex.getName(), indexSettings);
if (request.includeDefaults()) {
Settings defaultSettings = settingsFilter.filter(indexScopedSettings.diff(indexSettings, Settings.EMPTY));
if (isFilteredRequest(request)) {
defaultSettings = defaultSettings.filter(k -> Regex.simpleMatch(request.names(), k));
}
indexToDefaultSettingsBuilder.put(concreteIndex.getName(), defaultSettings);
}
indexToSettingsBuilder.put(concreteIndex.getName(), settings);
}
listener.onResponse(new GetSettingsResponse(indexToSettingsBuilder.build()));
listener.onResponse(new GetSettingsResponse(indexToSettingsBuilder.build(), indexToDefaultSettingsBuilder.build()));
}
}

View File

@ -44,18 +44,12 @@ import static org.elasticsearch.rest.RestStatus.OK;
public class RestGetSettingsAction extends BaseRestHandler {
private final IndexScopedSettings indexScopedSettings;
private final SettingsFilter settingsFilter;
public RestGetSettingsAction(Settings settings, RestController controller, IndexScopedSettings indexScopedSettings,
final SettingsFilter settingsFilter) {
public RestGetSettingsAction(Settings settings, RestController controller) {
super(settings);
this.indexScopedSettings = indexScopedSettings;
controller.registerHandler(GET, "/_settings/{name}", this);
controller.registerHandler(GET, "/{index}/_settings", this);
controller.registerHandler(GET, "/{index}/_settings/{name}", this);
controller.registerHandler(GET, "/{index}/_setting/{name}", this);
this.settingsFilter = settingsFilter;
}
@Override
@ -73,31 +67,16 @@ public class RestGetSettingsAction extends BaseRestHandler {
.indices(Strings.splitStringByCommaToArray(request.param("index")))
.indicesOptions(IndicesOptions.fromRequest(request, IndicesOptions.strictExpandOpen()))
.humanReadable(request.hasParam("human"))
.includeDefaults(renderDefaults)
.names(names);
getSettingsRequest.local(request.paramAsBoolean("local", getSettingsRequest.local()));
getSettingsRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getSettingsRequest.masterNodeTimeout()));
return channel -> client.admin().indices().getSettings(getSettingsRequest, new RestBuilderListener<GetSettingsResponse>(channel) {
@Override
public RestResponse buildResponse(GetSettingsResponse getSettingsResponse, XContentBuilder builder) throws Exception {
builder.startObject();
for (ObjectObjectCursor<String, Settings> cursor : getSettingsResponse.getIndexToSettings()) {
// no settings, jump over it to shorten the response data
if (cursor.value.isEmpty()) {
continue;
}
builder.startObject(cursor.key);
builder.startObject("settings");
cursor.value.toXContent(builder, request);
builder.endObject();
if (renderDefaults) {
builder.startObject("defaults");
settingsFilter.filter(indexScopedSettings.diff(cursor.value, settings)).toXContent(builder, request);
builder.endObject();
}
builder.endObject();
}
builder.endObject();
getSettingsResponse.toXContent(builder, request);
return new BytesRestResponse(OK, builder);
}
});

View File

@ -0,0 +1,148 @@
/*
* 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.indices.settings.get;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.replication.ClusterStateCreationUtils;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.index.Index;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.transport.CapturingTransport;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.junit.After;
import org.junit.Before;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.test.ClusterServiceUtils.createClusterService;
public class GetSettingsActionTests extends ESTestCase {
private TransportService transportService;
private ClusterService clusterService;
private ThreadPool threadPool;
private SettingsFilter settingsFilter;
private final String indexName = "test_index";
private TestTransportGetSettingsAction getSettingsAction;
class TestTransportGetSettingsAction extends TransportGetSettingsAction {
TestTransportGetSettingsAction() {
super(Settings.EMPTY, GetSettingsActionTests.this.transportService, GetSettingsActionTests.this.clusterService,
GetSettingsActionTests.this.threadPool, settingsFilter, new ActionFilters(Collections.emptySet()),
new Resolver(Settings.EMPTY), IndexScopedSettings.DEFAULT_SCOPED_SETTINGS);
}
@Override
protected void masterOperation(GetSettingsRequest request, ClusterState state, ActionListener<GetSettingsResponse> listener) {
ClusterState stateWithIndex = ClusterStateCreationUtils.state(indexName, 1, 1);
super.masterOperation(request, stateWithIndex, listener);
}
}
@Before
public void setUp() throws Exception {
super.setUp();
settingsFilter = new SettingsModule(Settings.EMPTY, Collections.emptyList(), Collections.emptyList()).getSettingsFilter();
threadPool = new TestThreadPool("GetSettingsActionTests");
clusterService = createClusterService(threadPool);
CapturingTransport capturingTransport = new CapturingTransport();
transportService = new TransportService(clusterService.getSettings(), capturingTransport, threadPool,
TransportService.NOOP_TRANSPORT_INTERCEPTOR,
boundAddress -> clusterService.localNode(), null, Collections.emptySet());
transportService.start();
transportService.acceptIncomingRequests();
getSettingsAction = new GetSettingsActionTests.TestTransportGetSettingsAction();
}
@After
public void tearDown() throws Exception {
ThreadPool.terminate(threadPool, 30, TimeUnit.SECONDS);
threadPool = null;
clusterService.close();
super.tearDown();
}
public void testIncludeDefaults() {
GetSettingsRequest noDefaultsRequest = new GetSettingsRequest().indices(indexName);
getSettingsAction.execute(null, noDefaultsRequest, ActionListener.wrap(noDefaultsResponse -> {
assertNull("index.refresh_interval should be null as it was never set", noDefaultsResponse.getSetting(indexName,
"index.refresh_interval"));
}, exception -> {
throw new AssertionError(exception);
}));
GetSettingsRequest defaultsRequest = new GetSettingsRequest().indices(indexName).includeDefaults(true);
getSettingsAction.execute(null, defaultsRequest, ActionListener.wrap(defaultsResponse -> {
assertNotNull("index.refresh_interval should be set as we are including defaults", defaultsResponse.getSetting(indexName,
"index.refresh_interval"));
}, exception -> {
throw new AssertionError(exception);
}));
}
public void testIncludeDefaultsWithFiltering() {
GetSettingsRequest defaultsRequest = new GetSettingsRequest().indices(indexName).includeDefaults(true)
.names("index.refresh_interval");
getSettingsAction.execute(null, defaultsRequest, ActionListener.wrap(defaultsResponse -> {
assertNotNull("index.refresh_interval should be set as we are including defaults", defaultsResponse.getSetting(indexName,
"index.refresh_interval"));
assertNull("index.number_of_shards should be null as this query is filtered",
defaultsResponse.getSetting(indexName, "index.number_of_shards"));
assertNull("index.warmer.enabled should be null as this query is filtered",
defaultsResponse.getSetting(indexName, "index.warmer.enabled"));
}, exception -> {
throw new AssertionError(exception);
}));
}
static class Resolver extends IndexNameExpressionResolver {
Resolver(Settings settings) {
super(settings);
}
@Override
public String[] concreteIndexNames(ClusterState state, IndicesRequest request) {
return request.indices();
}
@Override
public Index[] concreteIndices(ClusterState state, IndicesRequest request) {
Index[] out = new Index[request.indices().length];
for (int x = 0; x < out.length; x++) {
out[x] = new Index(request.indices()[x], "_na_");
}
return out;
}
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.indices.settings.get;
import org.elasticsearch.Version;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Base64;
public class GetSettingsRequestTests extends ESTestCase {
private static final String TEST_622_REQUEST_BYTES = "ADwDAAEKdGVzdF9pbmRleA4BEHRlc3Rfc2V0dGluZ19rZXkB";
private static final GetSettingsRequest TEST_622_REQUEST = new GetSettingsRequest()
.indices("test_index")
.names("test_setting_key")
.humanReadable(true);
private static final GetSettingsRequest TEST_700_REQUEST = new GetSettingsRequest()
.includeDefaults(true)
.humanReadable(true)
.indices("test_index")
.names("test_setting_key");
public void testSerdeRoundTrip() throws IOException {
BytesStreamOutput bso = new BytesStreamOutput();
TEST_700_REQUEST.writeTo(bso);
byte[] responseBytes = BytesReference.toBytes(bso.bytes());
StreamInput si = StreamInput.wrap(responseBytes);
GetSettingsRequest deserialized = new GetSettingsRequest(si);
assertEquals(TEST_700_REQUEST, deserialized);
}
public void testSerializeBackwardsCompatibility() throws IOException {
BytesStreamOutput bso = new BytesStreamOutput();
bso.setVersion(Version.V_6_2_2);
TEST_700_REQUEST.writeTo(bso);
byte[] responseBytes = BytesReference.toBytes(bso.bytes());
assertEquals(TEST_622_REQUEST_BYTES, Base64.getEncoder().encodeToString(responseBytes));
}
public void testDeserializeBackwardsCompatibility() throws IOException {
StreamInput si = StreamInput.wrap(Base64.getDecoder().decode(TEST_622_REQUEST_BYTES));
si.setVersion(Version.V_6_2_2);
GetSettingsRequest deserialized = new GetSettingsRequest(si);
assertEquals(TEST_622_REQUEST, deserialized);
}
}

View File

@ -0,0 +1,160 @@
/*
* 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.indices.settings.get;
import org.elasticsearch.Version;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
import org.junit.Assert;
import java.io.IOException;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
import static org.elasticsearch.index.IndexSettings.INDEX_REFRESH_INTERVAL_SETTING;
public class GetSettingsResponseTests extends AbstractStreamableXContentTestCase<GetSettingsResponse> {
/*
index.number_of_shards=2,index.number_of_replicas=1. The below base64'd bytes were generated by
code from the 6.2.2 tag.
*/
private static final String TEST_6_2_2_RESPONSE_BYTES =
"AQppbmRleF9uYW1lAhhpbmRleC5udW1iZXJfb2ZfcmVwbGljYXMAATEWaW5kZXgubnVtYmVyX29mX3NoYXJkcwABMg==";
/* This response object was generated using similar code to the code used to create the above bytes */
private static final GetSettingsResponse TEST_6_2_2_RESPONSE_INSTANCE = getExpectedTest622Response();
@Override
protected GetSettingsResponse createBlankInstance() {
return new GetSettingsResponse();
}
@Override
protected GetSettingsResponse createTestInstance() {
HashMap<String, Settings> indexToSettings = new HashMap<>();
HashMap<String, Settings> indexToDefaultSettings = new HashMap<>();
IndexScopedSettings indexScopedSettings = IndexScopedSettings.DEFAULT_SCOPED_SETTINGS;
Set<String> indexNames = new HashSet<String>();
int numIndices = randomIntBetween(1, 5);
for (int x=0;x<numIndices;x++) {
String indexName = randomAlphaOfLength(5);
indexNames.add(indexName);
}
for (String indexName : indexNames) {
Settings.Builder builder = Settings.builder();
builder.put(RandomCreateIndexGenerator.randomIndexSettings());
/*
We must ensure that *something* is in the settings response as we optimize away empty settings
blocks in x content responses
*/
builder.put("index.refresh_interval", "1s");
indexToSettings.put(indexName, builder.build());
}
ImmutableOpenMap<String, Settings> immutableIndexToSettings =
ImmutableOpenMap.<String, Settings>builder().putAll(indexToSettings).build();
if (randomBoolean()) {
for (String indexName : indexToSettings.keySet()) {
Settings defaultSettings = indexScopedSettings.diff(indexToSettings.get(indexName), Settings.EMPTY);
indexToDefaultSettings.put(indexName, defaultSettings);
}
}
ImmutableOpenMap<String, Settings> immutableIndexToDefaultSettings =
ImmutableOpenMap.<String, Settings>builder().putAll(indexToDefaultSettings).build();
return new GetSettingsResponse(immutableIndexToSettings, immutableIndexToDefaultSettings);
}
@Override
protected GetSettingsResponse doParseInstance(XContentParser parser) throws IOException {
return GetSettingsResponse.fromXContent(parser);
}
@Override
protected Predicate<String> getRandomFieldsExcludeFilter() {
//we do not want to add new fields at the root (index-level), or inside settings blocks
return f -> f.equals("") || f.contains(".settings") || f.contains(".defaults");
}
private static GetSettingsResponse getExpectedTest622Response() {
/* This is a fairly direct copy of the code used to generate the base64'd response above -- with the caveat that the constructor
has been modified so that the code compiles on this version of elasticsearch
*/
HashMap<String, Settings> indexToSettings = new HashMap<>();
Settings.Builder builder = Settings.builder();
builder.put(SETTING_NUMBER_OF_SHARDS, 2);
builder.put(SETTING_NUMBER_OF_REPLICAS, 1);
indexToSettings.put("index_name", builder.build());
GetSettingsResponse response = new GetSettingsResponse(ImmutableOpenMap.<String, Settings>builder().putAll(indexToSettings).build
(), ImmutableOpenMap.of());
return response;
}
private static GetSettingsResponse getResponseWithNewFields() {
HashMap<String, Settings> indexToDefaultSettings = new HashMap<>();
Settings.Builder builder = Settings.builder();
builder.put(INDEX_REFRESH_INTERVAL_SETTING.getKey(), "1s");
indexToDefaultSettings.put("index_name", builder.build());
ImmutableOpenMap<String, Settings> defaultsMap = ImmutableOpenMap.<String, Settings>builder().putAll(indexToDefaultSettings)
.build();
return new GetSettingsResponse(getExpectedTest622Response().getIndexToSettings(), defaultsMap);
}
public void testCanDecode622Response() throws IOException {
StreamInput si = StreamInput.wrap(Base64.getDecoder().decode(TEST_6_2_2_RESPONSE_BYTES));
si.setVersion(Version.V_6_2_2);
GetSettingsResponse response = new GetSettingsResponse();
response.readFrom(si);
Assert.assertEquals(TEST_6_2_2_RESPONSE_INSTANCE, response);
}
public void testCanOutput622Response() throws IOException {
GetSettingsResponse responseWithExtraFields = getResponseWithNewFields();
BytesStreamOutput bso = new BytesStreamOutput();
bso.setVersion(Version.V_6_2_2);
responseWithExtraFields.writeTo(bso);
String base64OfResponse = Base64.getEncoder().encodeToString(BytesReference.toBytes(bso.bytes()));
Assert.assertEquals(TEST_6_2_2_RESPONSE_BYTES, base64OfResponse);
}
}