From 02fc16f10e00ad8bd997b47d16879cfe5b8da4ba Mon Sep 17 00:00:00 2001
From: olcbean <26058559+olcbean@users.noreply.github.com>
Date: Thu, 15 Feb 2018 17:21:45 +0100
Subject: [PATCH] Add Cluster Put Settings API to the high level REST client
(#28633)
Relates to #27205
---
.../elasticsearch/client/ClusterClient.java | 66 +++++++
.../org/elasticsearch/client/Request.java | 12 ++
.../client/RestHighLevelClient.java | 10 +
.../elasticsearch/client/ClusterClientIT.java | 108 +++++++++++
.../elasticsearch/client/IndicesClientIT.java | 1 -
.../elasticsearch/client/RequestTests.java | 44 +++--
.../ClusterClientDocumentationIT.java | 180 ++++++++++++++++++
.../IndicesClientDocumentationIT.java | 6 +-
.../high-level/cluster/put_settings.asciidoc | 129 +++++++++++++
.../high-level/indices/put_mapping.asciidoc | 2 +-
.../high-level/supported-apis.asciidoc | 7 +
.../ClusterUpdateSettingsRequest.java | 64 ++++++-
.../ClusterUpdateSettingsResponse.java | 40 +++-
.../admin/indices/get/GetIndexRequest.java | 10 +-
.../RestClusterUpdateSettingsAction.java | 31 ++-
.../ClusterUpdateSettingsRequestTests.java | 74 +++++++
.../ClusterUpdateSettingsResponseTests.java | 83 ++++++++
.../org/elasticsearch/test/ESTestCase.java | 1 +
.../elasticsearch/test/XContentTestUtils.java | 2 +-
19 files changed, 821 insertions(+), 49 deletions(-)
create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java
create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java
create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java
create mode 100644 docs/java-rest/high-level/cluster/put_settings.asciidoc
create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java
create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsResponseTests.java
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java
new file mode 100644
index 000000000000..177e33d72701
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client;
+
+import org.apache.http.Header;
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
+
+import java.io.IOException;
+
+import static java.util.Collections.emptySet;
+
+/**
+ * A wrapper for the {@link RestHighLevelClient} that provides methods for accessing the Cluster API.
+ *
+ * See Cluster API on elastic.co
+ */
+public final class ClusterClient {
+ private final RestHighLevelClient restHighLevelClient;
+
+ ClusterClient(RestHighLevelClient restHighLevelClient) {
+ this.restHighLevelClient = restHighLevelClient;
+ }
+
+ /**
+ * Updates cluster wide specific settings using the Cluster Update Settings API
+ *
+ * See Cluster Update Settings
+ * API on elastic.co
+ */
+ public ClusterUpdateSettingsResponse putSettings(ClusterUpdateSettingsRequest clusterUpdateSettingsRequest, Header... headers)
+ throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(clusterUpdateSettingsRequest, Request::clusterPutSettings,
+ ClusterUpdateSettingsResponse::fromXContent, emptySet(), headers);
+ }
+
+ /**
+ * Asynchronously updates cluster wide specific settings using the Cluster Update Settings API
+ *
+ * See Cluster Update Settings
+ * API on elastic.co
+ */
+ public void putSettingsAsync(ClusterUpdateSettingsRequest clusterUpdateSettingsRequest,
+ ActionListener listener, Header... headers) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(clusterUpdateSettingsRequest, Request::clusterPutSettings,
+ ClusterUpdateSettingsResponse::fromXContent, listener, emptySet(), headers);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java
index 4ec7315b73b5..f46248c2f5b8 100755
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java
@@ -29,6 +29,7 @@ import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.action.DocWriteRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
@@ -528,6 +529,17 @@ public final class Request {
return new Request(HttpPut.METHOD_NAME, endpoint, params.getParams(), entity);
}
+ static Request clusterPutSettings(ClusterUpdateSettingsRequest clusterUpdateSettingsRequest) throws IOException {
+ Params parameters = Params.builder();
+ parameters.withFlatSettings(clusterUpdateSettingsRequest.flatSettings());
+ parameters.withTimeout(clusterUpdateSettingsRequest.timeout());
+ parameters.withMasterTimeout(clusterUpdateSettingsRequest.masterNodeTimeout());
+
+ String endpoint = buildEndpoint("_cluster/settings");
+ HttpEntity entity = createEntity(clusterUpdateSettingsRequest, REQUEST_BODY_CONTENT_TYPE);
+ return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity);
+ }
+
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
index 51c6f40c6e37..bf80aa772074 100755
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
@@ -186,6 +186,7 @@ public class RestHighLevelClient implements Closeable {
private final CheckedConsumer doClose;
private final IndicesClient indicesClient = new IndicesClient(this);
+ private final ClusterClient clusterClient = new ClusterClient(this);
/**
* Creates a {@link RestHighLevelClient} given the low level {@link RestClientBuilder} that allows to build the
@@ -240,6 +241,15 @@ public class RestHighLevelClient implements Closeable {
return indicesClient;
}
+ /**
+ * Provides a {@link ClusterClient} which can be used to access the Cluster API.
+ *
+ * See Cluster API on elastic.co
+ */
+ public final ClusterClient cluster() {
+ return clusterClient;
+ }
+
/**
* Executes a bulk request using the Bulk API
*
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java
new file mode 100644
index 000000000000..9314bb2e36ce
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
+import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeUnit;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.common.xcontent.support.XContentMapValues;
+import org.elasticsearch.indices.recovery.RecoverySettings;
+import org.elasticsearch.rest.RestStatus;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+public class ClusterClientIT extends ESRestHighLevelClientTestCase {
+
+ public void testClusterPutSettings() throws IOException {
+ final String transientSettingKey = RecoverySettings.INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey();
+ final int transientSettingValue = 10;
+
+ final String persistentSettingKey = EnableAllocationDecider.CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING.getKey();
+ final String persistentSettingValue = EnableAllocationDecider.Allocation.NONE.name();
+
+ Settings transientSettings = Settings.builder().put(transientSettingKey, transientSettingValue, ByteSizeUnit.BYTES).build();
+ Map map = new HashMap<>();
+ map.put(persistentSettingKey, persistentSettingValue);
+
+ ClusterUpdateSettingsRequest setRequest = new ClusterUpdateSettingsRequest();
+ setRequest.transientSettings(transientSettings);
+ setRequest.persistentSettings(map);
+
+ ClusterUpdateSettingsResponse setResponse = execute(setRequest, highLevelClient().cluster()::putSettings,
+ highLevelClient().cluster()::putSettingsAsync);
+
+ assertAcked(setResponse);
+ assertThat(setResponse.getTransientSettings().get(transientSettingKey), notNullValue());
+ assertThat(setResponse.getTransientSettings().get(persistentSettingKey), nullValue());
+ assertThat(setResponse.getTransientSettings().get(transientSettingKey),
+ equalTo(transientSettingValue + ByteSizeUnit.BYTES.getSuffix()));
+ assertThat(setResponse.getPersistentSettings().get(transientSettingKey), nullValue());
+ assertThat(setResponse.getPersistentSettings().get(persistentSettingKey), notNullValue());
+ assertThat(setResponse.getPersistentSettings().get(persistentSettingKey), equalTo(persistentSettingValue));
+
+ Map setMap = getAsMap("/_cluster/settings");
+ String transientSetValue = (String) XContentMapValues.extractValue("transient." + transientSettingKey, setMap);
+ assertThat(transientSetValue, equalTo(transientSettingValue + ByteSizeUnit.BYTES.getSuffix()));
+ String persistentSetValue = (String) XContentMapValues.extractValue("persistent." + persistentSettingKey, setMap);
+ assertThat(persistentSetValue, equalTo(persistentSettingValue));
+
+ ClusterUpdateSettingsRequest resetRequest = new ClusterUpdateSettingsRequest();
+ resetRequest.transientSettings(Settings.builder().putNull(transientSettingKey));
+ resetRequest.persistentSettings("{\"" + persistentSettingKey + "\": null }", XContentType.JSON);
+
+ ClusterUpdateSettingsResponse resetResponse = execute(resetRequest, highLevelClient().cluster()::putSettings,
+ highLevelClient().cluster()::putSettingsAsync);
+
+ assertThat(resetResponse.getTransientSettings().get(transientSettingKey), equalTo(null));
+ assertThat(resetResponse.getPersistentSettings().get(persistentSettingKey), equalTo(null));
+ assertThat(resetResponse.getTransientSettings(), equalTo(Settings.EMPTY));
+ assertThat(resetResponse.getPersistentSettings(), equalTo(Settings.EMPTY));
+
+ Map resetMap = getAsMap("/_cluster/settings");
+ String transientResetValue = (String) XContentMapValues.extractValue("transient." + transientSettingKey, resetMap);
+ assertThat(transientResetValue, equalTo(null));
+ String persistentResetValue = (String) XContentMapValues.extractValue("persistent." + persistentSettingKey, resetMap);
+ assertThat(persistentResetValue, equalTo(null));
+ }
+
+ public void testClusterUpdateSettingNonExistent() {
+ String setting = "no_idea_what_you_are_talking_about";
+ int value = 10;
+ ClusterUpdateSettingsRequest clusterUpdateSettingsRequest = new ClusterUpdateSettingsRequest();
+ clusterUpdateSettingsRequest.transientSettings(Settings.builder().put(setting, value).build());
+
+ ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> execute(clusterUpdateSettingsRequest,
+ highLevelClient().cluster()::putSettings, highLevelClient().cluster()::putSettingsAsync));
+ assertThat(exception.status(), equalTo(RestStatus.BAD_REQUEST));
+ assertThat(exception.getMessage(), equalTo(
+ "Elasticsearch exception [type=illegal_argument_exception, reason=transient setting [" + setting + "], not recognized]"));
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
index 5baef93c0dee..b8c9f4e76c25 100755
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
@@ -167,7 +167,6 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
}
}
- @SuppressWarnings({"unchecked", "rawtypes"})
public void testPutMapping() throws IOException {
{
// Add mappings to index
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java
index 3e4add16707f..400a47ca47a7 100755
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java
@@ -30,6 +30,7 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.DocWriteRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
@@ -272,7 +273,7 @@ public class RequestTests extends ESTestCase {
Map expectedParams = new HashMap<>();
setRandomIndicesOptions(getIndexRequest::indicesOptions, getIndexRequest::indicesOptions, expectedParams);
setRandomLocal(getIndexRequest, expectedParams);
- setRandomFlatSettings(getIndexRequest, expectedParams);
+ setRandomFlatSettings(getIndexRequest::flatSettings, expectedParams);
setRandomHumanReadable(getIndexRequest, expectedParams);
setRandomIncludeDefaults(getIndexRequest, expectedParams);
@@ -1115,14 +1116,10 @@ public class RequestTests extends ESTestCase {
if (randomBoolean()) {
randomAliases(createIndexRequest);
}
- if (randomBoolean()) {
- setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, expectedParams);
- }
+ setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, expectedParams);
resizeRequest.setTargetIndex(createIndexRequest);
} else {
- if (randomBoolean()) {
- setRandomWaitForActiveShards(resizeRequest::setWaitForActiveShards, expectedParams);
- }
+ setRandomWaitForActiveShards(resizeRequest::setWaitForActiveShards, expectedParams);
}
Request request = function.apply(resizeRequest);
@@ -1133,6 +1130,19 @@ public class RequestTests extends ESTestCase {
assertEquals(expectedParams, request.getParameters());
assertToXContentBody(resizeRequest, request.getEntity());
}
+
+ public void testClusterPutSettings() throws IOException {
+ ClusterUpdateSettingsRequest request = new ClusterUpdateSettingsRequest();
+ Map expectedParams = new HashMap<>();
+ setRandomFlatSettings(request::flatSettings, expectedParams);
+ setRandomMasterTimeout(request, expectedParams);
+ setRandomTimeout(request::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams);
+
+ Request expectedRequest = Request.clusterPutSettings(request);
+ assertEquals("/_cluster/settings", expectedRequest.getEndpoint());
+ assertEquals(HttpPut.METHOD_NAME, expectedRequest.getMethod());
+ assertEquals(expectedParams, expectedRequest.getParameters());
+ }
private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException {
BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false);
@@ -1289,16 +1299,6 @@ public class RequestTests extends ESTestCase {
}
}
- private static void setRandomFlatSettings(GetIndexRequest request, Map expectedParams) {
- if (randomBoolean()) {
- boolean flatSettings = randomBoolean();
- request.flatSettings(flatSettings);
- if (flatSettings) {
- expectedParams.put("flat_settings", String.valueOf(flatSettings));
- }
- }
- }
-
private static void setRandomLocal(MasterNodeReadRequest> request, Map expectedParams) {
if (randomBoolean()) {
boolean local = randomBoolean();
@@ -1319,6 +1319,16 @@ public class RequestTests extends ESTestCase {
}
}
+ private static void setRandomFlatSettings(Consumer setter, Map expectedParams) {
+ if (randomBoolean()) {
+ boolean flatSettings = randomBoolean();
+ setter.accept(flatSettings);
+ if (flatSettings) {
+ expectedParams.put("flat_settings", String.valueOf(flatSettings));
+ }
+ }
+ }
+
private static void setRandomMasterTimeout(MasterNodeRequest> request, Map expectedParams) {
if (randomBoolean()) {
String masterTimeout = randomTimeValue();
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java
new file mode 100644
index 000000000000..e9fc4ec01ba9
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.documentation;
+
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.LatchedActionListener;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
+import org.elasticsearch.client.ESRestHighLevelClientTestCase;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeUnit;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.indices.recovery.RecoverySettings;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.Matchers.equalTo;
+
+/**
+ * This class is used to generate the Java Cluster API documentation.
+ * You need to wrap your code between two tags like:
+ * // tag::example[]
+ * // end::example[]
+ *
+ * Where example is your tag name.
+ *
+ * Then in the documentation, you can extract what is between tag and end tags with
+ * ["source","java",subs="attributes,callouts,macros"]
+ * --------------------------------------------------
+ * include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[example]
+ * --------------------------------------------------
+ */
+public class ClusterClientDocumentationIT extends ESRestHighLevelClientTestCase {
+
+ public void testClusterPutSettings() throws IOException {
+ RestHighLevelClient client = highLevelClient();
+
+ // tag::put-settings-request
+ ClusterUpdateSettingsRequest request = new ClusterUpdateSettingsRequest();
+ // end::put-settings-request
+
+ // tag::put-settings-create-settings
+ String transientSettingKey =
+ RecoverySettings.INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey();
+ int transientSettingValue = 10;
+ Settings transientSettings =
+ Settings.builder()
+ .put(transientSettingKey, transientSettingValue, ByteSizeUnit.BYTES)
+ .build(); // <1>
+
+ String persistentSettingKey =
+ EnableAllocationDecider.CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING.getKey();
+ String persistentSettingValue =
+ EnableAllocationDecider.Allocation.NONE.name();
+ Settings persistentSettings =
+ Settings.builder()
+ .put(persistentSettingKey, persistentSettingValue)
+ .build(); // <2>
+ // end::put-settings-create-settings
+
+ // tag::put-settings-request-cluster-settings
+ request.transientSettings(transientSettings); // <1>
+ request.persistentSettings(persistentSettings); // <2>
+ // end::put-settings-request-cluster-settings
+
+ {
+ // tag::put-settings-settings-builder
+ Settings.Builder transientSettingsBuilder =
+ Settings.builder()
+ .put(transientSettingKey, transientSettingValue, ByteSizeUnit.BYTES);
+ request.transientSettings(transientSettingsBuilder); // <1>
+ // end::put-settings-settings-builder
+ }
+ {
+ // tag::put-settings-settings-map
+ Map map = new HashMap<>();
+ map.put(transientSettingKey
+ , transientSettingValue + ByteSizeUnit.BYTES.getSuffix());
+ request.transientSettings(map); // <1>
+ // end::put-settings-settings-map
+ }
+ {
+ // tag::put-settings-settings-source
+ request.transientSettings(
+ "{\"indices.recovery.max_bytes_per_sec\": \"10b\"}"
+ , XContentType.JSON); // <1>
+ // end::put-settings-settings-source
+ }
+
+ // tag::put-settings-request-timeout
+ request.timeout(TimeValue.timeValueMinutes(2)); // <1>
+ request.timeout("2m"); // <2>
+ // end::put-settings-request-timeout
+ // tag::put-settings-request-masterTimeout
+ request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
+ request.masterNodeTimeout("1m"); // <2>
+ // end::put-settings-request-masterTimeout
+
+ // tag::put-settings-request-flat-settings
+ request.flatSettings(true); // <1>
+ // end::put-settings-request-flat-settings
+
+ // tag::put-settings-execute
+ ClusterUpdateSettingsResponse response = client.cluster().putSettings(request);
+ // end::put-settings-execute
+
+ // tag::put-settings-response
+ boolean acknowledged = response.isAcknowledged(); // <1>
+ Settings transientSettingsResponse = response.getTransientSettings(); // <2>
+ Settings persistentSettingsResponse = response.getPersistentSettings(); // <3>
+ // end::put-settings-response
+ assertTrue(acknowledged);
+ assertThat(transientSettingsResponse.get(transientSettingKey), equalTo(transientSettingValue + ByteSizeUnit.BYTES.getSuffix()));
+ assertThat(persistentSettingsResponse.get(persistentSettingKey), equalTo(persistentSettingValue));
+
+ // tag::put-settings-request-reset-transient
+ request.transientSettings(Settings.builder().putNull(transientSettingKey).build()); // <1>
+ // tag::put-settings-request-reset-transient
+ request.persistentSettings(Settings.builder().putNull(persistentSettingKey));
+ ClusterUpdateSettingsResponse resetResponse = client.cluster().putSettings(request);
+
+ assertTrue(resetResponse.isAcknowledged());
+ }
+
+ public void testClusterUpdateSettingsAsync() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+ {
+ ClusterUpdateSettingsRequest request = new ClusterUpdateSettingsRequest();
+
+ // tag::put-settings-execute-listener
+ ActionListener listener =
+ new ActionListener() {
+ @Override
+ public void onResponse(ClusterUpdateSettingsResponse response) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::put-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::put-settings-execute-async
+ client.cluster().putSettingsAsync(request, listener); // <1>
+ // end::put-settings-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
index 0462454f2982..e30018abd4ca 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
@@ -70,7 +70,7 @@ import java.util.concurrent.TimeUnit;
* Then in the documentation, you can extract what is between tag and end tags with
* ["source","java",subs="attributes,callouts,macros"]
* --------------------------------------------------
- * include-tagged::{doc-tests}/CRUDDocumentationIT.java[example]
+ * include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[example]
* --------------------------------------------------
*/
public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase {
@@ -105,7 +105,7 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
}
}
- public void testIndicesExistAsync() throws IOException {
+ public void testIndicesExistAsync() throws Exception {
RestHighLevelClient client = highLevelClient();
{
@@ -138,6 +138,8 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
// tag::indices-exists-async
client.indices().existsAsync(request, listener); // <1>
// end::indices-exists-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}
public void testDeleteIndex() throws IOException {
diff --git a/docs/java-rest/high-level/cluster/put_settings.asciidoc b/docs/java-rest/high-level/cluster/put_settings.asciidoc
new file mode 100644
index 000000000000..2d9f55c1e941
--- /dev/null
+++ b/docs/java-rest/high-level/cluster/put_settings.asciidoc
@@ -0,0 +1,129 @@
+[[java-rest-high-cluster-put-settings]]
+=== Cluster Update Settings API
+
+The Cluster Update Settings API allows to update cluster wide settings.
+
+[[java-rest-high-cluster-put-settings-request]]
+==== Cluster Update Settings Request
+
+A `ClusterUpdateSettingsRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-request]
+--------------------------------------------------
+
+==== Cluster Settings
+At least one setting to be updated must be provided:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-request-cluster-settings]
+--------------------------------------------------
+<1> Sets the transient settings to be applied
+<2> Sets the persistent setting to be applied
+
+==== Providing the Settings
+The settings to be applied can be provided in different ways:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-create-settings]
+--------------------------------------------------
+<1> Creates a transient setting as `Settings`
+<2> Creates a persistent setting as `Settings`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-settings-builder]
+--------------------------------------------------
+<1> Settings provided as `Settings.Builder`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-settings-source]
+--------------------------------------------------
+<1> Settings provided as `String`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-settings-map]
+--------------------------------------------------
+<1> Settings provided as a `Map`
+
+==== Optional Arguments
+The following arguments can optionally be provided:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-request-flat-settings]
+--------------------------------------------------
+<1> Wether the updated settings returned in the `ClusterUpdateSettings` should
+be in a flat format
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-request-timeout]
+--------------------------------------------------
+<1> Timeout to wait for the all the nodes to acknowledge the settings were applied
+as a `TimeValue`
+<2> Timeout to wait for the all the nodes to acknowledge the settings were applied
+as a `String`
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-request-masterTimeout]
+--------------------------------------------------
+<1> Timeout to connect to the master node as a `TimeValue`
+<2> Timeout to connect to the master node as a `String`
+
+[[java-rest-high-cluster-put-settings-sync]]
+==== Synchronous Execution
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-execute]
+--------------------------------------------------
+
+[[java-rest-high-cluster-put-settings-async]]
+==== Asynchronous Execution
+
+The asynchronous execution of a cluster update settings requires both the
+`ClusterUpdateSettingsRequest` instance and an `ActionListener` instance to be
+passed to the asynchronous method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-execute-async]
+--------------------------------------------------
+<1> The `ClusterUpdateSettingsRequest` 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 `ClusterUpdateSettingsResponse` looks like:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-execute-listener]
+--------------------------------------------------
+<1> Called when the execution is successfully completed. The response is
+provided as an argument
+<2> Called in case of a failure. The raised exception is provided as an argument
+
+[[java-rest-high-cluster-put-settings-response]]
+==== Cluster Update Settings Response
+
+The returned `ClusterUpdateSettings` allows to retrieve information about the
+executed operation as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-settings-response]
+--------------------------------------------------
+<1> Indicates whether all of the nodes have acknowledged the request
+<2> Indicates which transient settings have been applied
+<3> Indicates which persistent settings have been applied
\ No newline at end of file
diff --git a/docs/java-rest/high-level/indices/put_mapping.asciidoc b/docs/java-rest/high-level/indices/put_mapping.asciidoc
index 1f7d8c1d5e82..5fa985d02c16 100644
--- a/docs/java-rest/high-level/indices/put_mapping.asciidoc
+++ b/docs/java-rest/high-level/indices/put_mapping.asciidoc
@@ -20,7 +20,7 @@ A description of the fields to create on the mapping; if not defined, the mappin
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-source]
--------------------------------------------------
-<1> The mapping source provided as a `String`
+<1> Mapping source provided as a `String`
==== Providing the mapping source
The mapping source can be provided in different ways in addition to
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index 14e4351eb29b..295de7689f7c 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -71,3 +71,10 @@ include::indices/put_mapping.asciidoc[]
include::indices/update_aliases.asciidoc[]
include::indices/exists_alias.asciidoc[]
+== Cluster APIs
+
+The Java High Level REST Client supports the following Cluster APIs:
+
+* <>
+
+include::cluster/put_settings.asciidoc[]
diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java
index 2a8ed8bf11f4..f282cedff360 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java
@@ -22,26 +22,42 @@ package org.elasticsearch.action.admin.cluster.settings;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
+import org.elasticsearch.common.ParseField;
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.ObjectParser;
+import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.action.ValidateActions.addValidationError;
-import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
import static org.elasticsearch.common.settings.Settings.readSettingsFromStream;
import static org.elasticsearch.common.settings.Settings.writeSettingsToStream;
+import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
/**
* Request for an update cluster settings action
*/
-public class ClusterUpdateSettingsRequest extends AcknowledgedRequest {
+public class ClusterUpdateSettingsRequest extends AcknowledgedRequest implements ToXContentObject {
+ private static final ParseField PERSISTENT = new ParseField("persistent");
+ private static final ParseField TRANSIENT = new ParseField("transient");
+
+ private static final ObjectParser PARSER = new ObjectParser<>("cluster_update_settings_request",
+ false, ClusterUpdateSettingsRequest::new);
+
+ static {
+ PARSER.declareObject((r, p) -> r.persistentSettings = p, (p, c) -> Settings.fromXContent(p), PERSISTENT);
+ PARSER.declareObject((r, t) -> r.transientSettings = t, (p, c) -> Settings.fromXContent(p), TRANSIENT);
+ }
+
+ private boolean flatSettings = false;
private Settings transientSettings = EMPTY_SETTINGS;
private Settings persistentSettings = EMPTY_SETTINGS;
@@ -57,6 +73,29 @@ public class ClusterUpdateSettingsRequest extends AcknowledgedRequesttrue if settings need to be returned in flat format; false otherwise.
+ */
+ public boolean flatSettings() {
+ return flatSettings;
+ }
+
public Settings transientSettings() {
return transientSettings;
}
@@ -92,7 +131,7 @@ public class ClusterUpdateSettingsRequest extends AcknowledgedRequest PARSER = new ConstructingObjectParser<>(
+ "cluster_update_settings_response", true, a -> new ClusterUpdateSettingsResponse((boolean) a[0]));
+ static {
+ declareAcknowledgedField(PARSER);
+ PARSER.declareObject((r, p) -> r.persistentSettings = p, (p, c) -> Settings.fromXContent(p), PERSISTENT);
+ PARSER.declareObject((r, t) -> r.transientSettings = t, (p, c) -> Settings.fromXContent(p), TRANSIENT);
+ }
Settings transientSettings;
Settings persistentSettings;
@@ -39,6 +55,10 @@ public class ClusterUpdateSettingsResponse extends AcknowledgedResponse {
this.transientSettings = Settings.EMPTY;
}
+ ClusterUpdateSettingsResponse(boolean acknowledged) {
+ super(acknowledged);
+ }
+
ClusterUpdateSettingsResponse(boolean acknowledged, Settings transientSettings, Settings persistentSettings) {
super(acknowledged);
this.persistentSettings = persistentSettings;
@@ -68,4 +88,22 @@ public class ClusterUpdateSettingsResponse extends AcknowledgedResponse {
Settings.writeSettingsToStream(persistentSettings, out);
writeAcknowledged(out);
}
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
+ addAcknowledgedField(builder);
+ builder.startObject(PERSISTENT.getPreferredName());
+ persistentSettings.toXContent(builder, params);
+ builder.endObject();
+ builder.startObject(TRANSIENT.getPreferredName());
+ transientSettings.toXContent(builder, params);
+ builder.endObject();
+ builder.endObject();
+ return builder;
+ }
+
+ public static ClusterUpdateSettingsResponse fromXContent(XContentParser parser) throws IOException {
+ return PARSER.apply(parser, null);
+ }
}
diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java
index 477656d96cb5..2a70aa836454 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java
@@ -26,8 +26,6 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.ArrayUtils;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
/**
* A request to delete an index. Best created with {@link org.elasticsearch.client.Requests#deleteIndexRequest(String)}.
@@ -122,6 +120,8 @@ public class GetIndexRequest extends ClusterInfoRequest {
/**
* Sets the value of "flat_settings".
+ * Used only by the high-level REST client.
+ *
* @param flatSettings value of "flat_settings" flag to be set
* @return this request
*/
@@ -132,6 +132,8 @@ public class GetIndexRequest extends ClusterInfoRequest {
/**
* Return settings in flat format.
+ * Used only by the high-level REST client.
+ *
* @return true if settings need to be returned in flat format; false otherwise.
*/
public boolean flatSettings() {
@@ -140,6 +142,8 @@ public class GetIndexRequest extends ClusterInfoRequest {
/**
* Sets the value of "include_defaults".
+ * Used only by the high-level REST client.
+ *
* @param includeDefaults value of "include_defaults" to be set.
* @return this request
*/
@@ -150,6 +154,8 @@ public class GetIndexRequest extends ClusterInfoRequest {
/**
* Whether to return all default settings for each of the indices.
+ * Used only by the high-level REST client.
+ *
* @return true if defaults settings for each of the indices need to returned;
* false otherwise.
*/
diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterUpdateSettingsAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterUpdateSettingsAction.java
index 88e8ada55976..2901cdd2d9ba 100644
--- a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterUpdateSettingsAction.java
+++ b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterUpdateSettingsAction.java
@@ -20,22 +20,25 @@
package org.elasticsearch.rest.action.admin.cluster;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
-import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.node.NodeClient;
+import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
-import org.elasticsearch.rest.action.AcknowledgedRestListener;
+import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
public class RestClusterUpdateSettingsAction extends BaseRestHandler {
+
+ private static final String PERSISTENT = "persistent";
+ private static final String TRANSIENT = "transient";
+
public RestClusterUpdateSettingsAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.PUT, "/_cluster/settings", this);
@@ -56,26 +59,14 @@ public class RestClusterUpdateSettingsAction extends BaseRestHandler {
try (XContentParser parser = request.contentParser()) {
source = parser.map();
}
- if (source.containsKey("transient")) {
- clusterUpdateSettingsRequest.transientSettings((Map) source.get("transient"));
+ if (source.containsKey(TRANSIENT)) {
+ clusterUpdateSettingsRequest.transientSettings((Map) source.get(TRANSIENT));
}
- if (source.containsKey("persistent")) {
- clusterUpdateSettingsRequest.persistentSettings((Map) source.get("persistent"));
+ if (source.containsKey(PERSISTENT)) {
+ clusterUpdateSettingsRequest.persistentSettings((Map) source.get(PERSISTENT));
}
- return channel -> client.admin().cluster().updateSettings(clusterUpdateSettingsRequest,
- new AcknowledgedRestListener(channel) {
- @Override
- protected void addCustomFields(XContentBuilder builder, ClusterUpdateSettingsResponse response) throws IOException {
- builder.startObject("persistent");
- response.getPersistentSettings().toXContent(builder, request);
- builder.endObject();
-
- builder.startObject("transient");
- response.getTransientSettings().toXContent(builder, request);
- builder.endObject();
- }
- });
+ return channel -> client.admin().cluster().updateSettings(clusterUpdateSettingsRequest, new RestToXContentListener<>(channel));
}
@Override
diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java
new file mode 100644
index 000000000000..fdca03ebcda4
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java
@@ -0,0 +1,74 @@
+/*
+ * 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.settings;
+
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.XContentTestUtils;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+
+public class ClusterUpdateSettingsRequestTests extends ESTestCase {
+
+ public void testFromXContent() throws IOException {
+ doFromXContentTestWithRandomFields(false);
+ }
+
+ public void testFromXContentWithRandomFields() throws IOException {
+ doFromXContentTestWithRandomFields(true);
+ }
+
+ private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException {
+ final ClusterUpdateSettingsRequest request = createTestItem();
+ boolean humanReadable = randomBoolean();
+ final XContentType xContentType = XContentType.JSON;
+ BytesReference originalBytes = toShuffledXContent(request, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
+
+ if (addRandomFields) {
+ String unsupportedField = "unsupported_field";
+ BytesReference mutated = XContentTestUtils.insertIntoXContent(xContentType.xContent(), originalBytes,
+ Collections.singletonList(""), () -> unsupportedField, () -> randomAlphaOfLengthBetween(3, 10)).bytes();
+ IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
+ () -> ClusterUpdateSettingsRequest.fromXContent(createParser(xContentType.xContent(), mutated)));
+ assertThat(iae.getMessage(),
+ equalTo("[cluster_update_settings_request] unknown field [" + unsupportedField + "], parser not found"));
+ } else {
+ XContentParser parser = createParser(xContentType.xContent(), originalBytes);
+ ClusterUpdateSettingsRequest parsedRequest = ClusterUpdateSettingsRequest.fromXContent(parser);
+
+ assertNull(parser.nextToken());
+ assertThat(parsedRequest.transientSettings(), equalTo(request.transientSettings()));
+ assertThat(parsedRequest.persistentSettings(), equalTo(request.persistentSettings()));
+ }
+ }
+
+ private static ClusterUpdateSettingsRequest createTestItem() {
+ ClusterUpdateSettingsRequest request = new ClusterUpdateSettingsRequest();
+ request.persistentSettings(ClusterUpdateSettingsResponseTests.randomClusterSettings(0, 2));
+ request.transientSettings(ClusterUpdateSettingsResponseTests.randomClusterSettings(0, 2));
+ return request;
+ }
+}
diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsResponseTests.java
new file mode 100644
index 000000000000..77ccae5a96d3
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsResponseTests.java
@@ -0,0 +1,83 @@
+/*
+ * 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.settings;
+
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.settings.ClusterSettings;
+import org.elasticsearch.common.settings.Setting;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.settings.Settings.Builder;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.test.ESTestCase;
+
+import java.io.IOException;
+
+import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+public class ClusterUpdateSettingsResponseTests extends ESTestCase {
+
+ public void testFromXContent() throws IOException {
+ doFromXContentTestWithRandomFields(false);
+ }
+
+ public void testFromXContentWithRandomFields() throws IOException {
+ doFromXContentTestWithRandomFields(true);
+ }
+
+ private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException {
+ final ClusterUpdateSettingsResponse response = createTestItem();
+ boolean humanReadable = randomBoolean();
+ final XContentType xContentType = XContentType.JSON;
+
+ BytesReference originalBytes = toShuffledXContent(response, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
+ BytesReference mutated;
+ if (addRandomFields) {
+ mutated = insertRandomFields(xContentType, originalBytes, p -> p.startsWith("transient") || p.startsWith("persistent"),
+ random());
+ } else {
+ mutated = originalBytes;
+ }
+
+ XContentParser parser = createParser(xContentType.xContent(), mutated);
+ ClusterUpdateSettingsResponse parsedResponse = ClusterUpdateSettingsResponse.fromXContent(parser);
+
+ assertNull(parser.nextToken());
+ assertThat(parsedResponse.isAcknowledged(), equalTo(response.isAcknowledged()));
+ assertThat(response.transientSettings, equalTo(response.transientSettings));
+ assertThat(response.persistentSettings, equalTo(response.persistentSettings));
+ }
+
+ public static Settings randomClusterSettings(int min, int max) {
+ int num = randomIntBetween(min, max);
+ Builder builder = Settings.builder();
+ for (int i = 0; i < num; i++) {
+ Setting> setting = randomFrom(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
+ builder.put(setting.getKey(), randomAlphaOfLengthBetween(2, 10));
+ }
+ return builder.build();
+ }
+
+ private static ClusterUpdateSettingsResponse createTestItem() {
+ return new ClusterUpdateSettingsResponse(randomBoolean(), randomClusterSettings(0, 2), randomClusterSettings(0, 2));
+ }
+}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index aaed939c310c..ba8e67467481 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -29,6 +29,7 @@ import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter;
+
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
diff --git a/test/framework/src/main/java/org/elasticsearch/test/XContentTestUtils.java b/test/framework/src/main/java/org/elasticsearch/test/XContentTestUtils.java
index 063f05544431..cd556a9115ad 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/XContentTestUtils.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/XContentTestUtils.java
@@ -286,7 +286,7 @@ public final class XContentTestUtils {
* {@link ObjectPath}.
* The key/value arguments can suppliers that either return fixed or random values.
*/
- static XContentBuilder insertIntoXContent(XContent xContent, BytesReference original, List paths, Supplier key,
+ public static XContentBuilder insertIntoXContent(XContent xContent, BytesReference original, List paths, Supplier key,
Supplier