瀏覽代碼

rest-high-level: added get cluster settings (#31706)

Relates to #27205
Sohaib Iftikhar 7 年之前
父節點
當前提交
c55d11f8b5

+ 31 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java

@@ -22,6 +22,8 @@ package org.elasticsearch.client;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
 import org.elasticsearch.rest.RestStatus;
@@ -72,6 +74,35 @@ public final class ClusterClient {
                 options, ClusterUpdateSettingsResponse::fromXContent, listener, emptySet());
     }
 
+    /**
+     * Get the cluster wide settings using the Cluster Get Settings API.
+     * See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-get-settings.html"> Cluster Get Settings
+     * API on elastic.co</a>
+     * @param clusterGetSettingsRequest the request
+     * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+     * @return the response
+     * @throws IOException in case there is a problem sending the request or parsing back the response
+     */
+    public ClusterGetSettingsResponse getSettings(ClusterGetSettingsRequest clusterGetSettingsRequest, RequestOptions options)
+        throws IOException {
+        return restHighLevelClient.performRequestAndParseEntity(clusterGetSettingsRequest, RequestConverters::clusterGetSettings,
+            options, ClusterGetSettingsResponse::fromXContent, emptySet());
+    }
+
+    /**
+     * Asynchronously get the cluster wide settings using the Cluster Get Settings API.
+     * See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-get-settings.html"> Cluster Get Settings
+     * API on elastic.co</a>
+     * @param clusterGetSettingsRequest the request
+     * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+     * @param listener the listener to be notified upon request completion
+     */
+    public void getSettingsAsync(ClusterGetSettingsRequest clusterGetSettingsRequest, RequestOptions options,
+                                 ActionListener<ClusterGetSettingsResponse> listener) {
+        restHighLevelClient.performRequestAsyncAndParseEntity(clusterGetSettingsRequest, RequestConverters::clusterGetSettings,
+            options, ClusterGetSettingsResponse::fromXContent, listener, emptySet());
+    }
+
     /**
      * Get cluster health using the Cluster Health API.
      * See

+ 14 - 2
client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

@@ -36,6 +36,7 @@ import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteReposito
 import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
 import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
 import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
 import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
@@ -605,7 +606,7 @@ final class RequestConverters {
         request.setEntity(createEntity(searchTemplateRequest, REQUEST_BODY_CONTENT_TYPE));
         return request;
     }
-    
+
     static Request multiSearchTemplate(MultiSearchTemplateRequest multiSearchTemplateRequest) throws IOException {
         Request request = new Request(HttpPost.METHOD_NAME, "/_msearch/template");
 
@@ -619,7 +620,7 @@ final class RequestConverters {
         byte[] source = MultiSearchTemplateRequest.writeMultiLineFormat(multiSearchTemplateRequest, xContent);
         request.setEntity(new ByteArrayEntity(source, createContentType(xContent.type())));
         return request;
-    }    
+    }
 
     static Request existsAlias(GetAliasesRequest getAliasesRequest) {
         if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) &&
@@ -709,6 +710,17 @@ final class RequestConverters {
         return request;
     }
 
+    static Request clusterGetSettings(ClusterGetSettingsRequest clusterGetSettingsRequest) throws IOException {
+        Request request = new Request(HttpGet.METHOD_NAME, "/_cluster/settings");
+
+        Params parameters = new Params(request);
+        parameters.withLocal(clusterGetSettingsRequest.local());
+        parameters.withIncludeDefaults(clusterGetSettingsRequest.includeDefaults());
+        parameters.withMasterTimeout(clusterGetSettingsRequest.masterNodeTimeout());
+
+        return request;
+    }
+
     static Request getPipeline(GetPipelineRequest getPipelineRequest) {
         String endpoint = new EndpointBuilder()
             .addPathPartAsIs("_ingest/pipeline")

+ 43 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java

@@ -22,6 +22,8 @@ package org.elasticsearch.client;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
 import org.elasticsearch.cluster.health.ClusterHealthStatus;
@@ -42,6 +44,7 @@ import java.util.Map;
 import static java.util.Collections.emptyMap;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
 
@@ -112,6 +115,46 @@ public class ClusterClientIT extends ESRestHighLevelClientTestCase {
                 "Elasticsearch exception [type=illegal_argument_exception, reason=transient setting [" + setting + "], not recognized]"));
     }
 
+    public void testClusterGetSettings() 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();
+        Settings persistentSettings = Settings.builder().put(persistentSettingKey, persistentSettingValue).build();
+        clusterUpdateSettings(persistentSettings, transientSettings);
+
+        ClusterGetSettingsRequest request = new ClusterGetSettingsRequest();
+        ClusterGetSettingsResponse response = execute(
+            request, highLevelClient().cluster()::getSettings, highLevelClient().cluster()::getSettingsAsync);
+        assertEquals(persistentSettings, response.getPersistentSettings());
+        assertEquals(transientSettings, response.getTransientSettings());
+        assertEquals(0, response.getDefaultSettings().size());
+    }
+
+    public void testClusterGetSettingsWithDefault() 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();
+        Settings persistentSettings = Settings.builder().put(persistentSettingKey, persistentSettingValue).build();
+        clusterUpdateSettings(persistentSettings, transientSettings);
+
+        ClusterGetSettingsRequest request = new ClusterGetSettingsRequest().includeDefaults(true);
+        ClusterGetSettingsResponse response = execute(
+            request, highLevelClient().cluster()::getSettings, highLevelClient().cluster()::getSettingsAsync);
+        assertEquals(persistentSettings, response.getPersistentSettings());
+        assertEquals(transientSettings, response.getTransientSettings());
+        assertThat(response.getDefaultSettings().size(), greaterThan(0));
+    }
+
     public void testClusterHealthGreen() throws IOException {
         ClusterHealthRequest request = new ClusterHealthRequest();
         request.timeout("5s");

+ 10 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java

@@ -20,9 +20,11 @@
 package org.elasticsearch.client;
 
 import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.ingest.PutPipelineRequest;
 import org.elasticsearch.action.support.PlainActionFuture;
 import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.ingest.Pipeline;
@@ -126,4 +128,12 @@ public abstract class ESRestHighLevelClientTestCase extends ESRestTestCase {
     protected static void createPipeline(PutPipelineRequest putPipelineRequest) throws IOException {
         assertOK(client().performRequest(RequestConverters.putPipeline(putPipelineRequest)));
     }
+
+    protected static void clusterUpdateSettings(Settings persistentSettings,
+                                                Settings transientSettings) throws IOException {
+        ClusterUpdateSettingsRequest request = new ClusterUpdateSettingsRequest();
+        request.persistentSettings(persistentSettings);
+        request.transientSettings(transientSettings);
+        assertOK(client().performRequest(RequestConverters.clusterPutSettings(request)));
+    }
 }

+ 29 - 13
client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java

@@ -36,6 +36,7 @@ import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteReposito
 import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
 import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
 import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
 import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
@@ -1374,42 +1375,42 @@ public class RequestConvertersTests extends ESTestCase {
         assertEquals(Collections.emptyMap(), request.getParameters());
         assertToXContentBody(searchTemplateRequest, request.getEntity());
     }
-    
+
     public void testMultiSearchTemplate() throws Exception {
         final int numSearchRequests = randomIntBetween(1, 10);
         MultiSearchTemplateRequest multiSearchTemplateRequest = new MultiSearchTemplateRequest();
-        
+
         for (int i = 0; i < numSearchRequests; i++) {
             // Create a random request.
             String[] indices = randomIndicesNames(0, 5);
             SearchRequest searchRequest = new SearchRequest(indices);
-            
+
             Map<String, String> expectedParams = new HashMap<>();
             setRandomSearchParams(searchRequest, expectedParams);
-    
+
             // scroll is not supported in the current msearch or msearchtemplate api, so unset it:
             searchRequest.scroll((Scroll) null);
             // batched reduce size is currently not set-able on a per-request basis as it is a query string parameter only
             searchRequest.setBatchedReduceSize(SearchRequest.DEFAULT_BATCHED_REDUCE_SIZE);
-            
+
             setRandomIndicesOptions(searchRequest::indicesOptions, searchRequest::indicesOptions, expectedParams);
-            
+
             SearchTemplateRequest searchTemplateRequest = new SearchTemplateRequest(searchRequest);
-    
+
             searchTemplateRequest.setScript("{\"query\": { \"match\" : { \"{{field}}\" : \"{{value}}\" }}}");
             searchTemplateRequest.setScriptType(ScriptType.INLINE);
             searchTemplateRequest.setProfile(randomBoolean());
-    
+
             Map<String, Object> scriptParams = new HashMap<>();
             scriptParams.put("field", "name");
             scriptParams.put("value", randomAlphaOfLengthBetween(2, 5));
             searchTemplateRequest.setScriptParams(scriptParams);
-    
-            multiSearchTemplateRequest.add(searchTemplateRequest);            
+
+            multiSearchTemplateRequest.add(searchTemplateRequest);
         }
 
         Request multiRequest = RequestConverters.multiSearchTemplate(multiSearchTemplateRequest);
-        
+
         assertEquals(HttpPost.METHOD_NAME, multiRequest.getMethod());
         assertEquals("/_msearch/template", multiRequest.getEndpoint());
         List<SearchTemplateRequest> searchRequests = multiSearchTemplateRequest.requests();
@@ -1418,9 +1419,9 @@ public class RequestConvertersTests extends ESTestCase {
         HttpEntity actualEntity = multiRequest.getEntity();
         byte[] expectedBytes = MultiSearchTemplateRequest.writeMultiLineFormat(multiSearchTemplateRequest, XContentType.JSON.xContent());
         assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue());
-        assertEquals(new BytesArray(expectedBytes), new BytesArray(EntityUtils.toByteArray(actualEntity)));        
+        assertEquals(new BytesArray(expectedBytes), new BytesArray(EntityUtils.toByteArray(actualEntity)));
     }
-    
+
     public void testExistsAlias() {
         GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
         String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
@@ -1636,6 +1637,21 @@ public class RequestConvertersTests extends ESTestCase {
         assertEquals(expectedParams, expectedRequest.getParameters());
     }
 
+    public void testClusterGetSettings() throws IOException {
+        ClusterGetSettingsRequest request = new ClusterGetSettingsRequest();
+        Map<String, String> expectedParams = new HashMap<>();
+        setRandomMasterTimeout(request, expectedParams);
+        request.includeDefaults(randomBoolean());
+        if (request.includeDefaults()) {
+            expectedParams.put("include_defaults", String.valueOf(true));
+        }
+
+        Request expectedRequest = RequestConverters.clusterGetSettings(request);
+        assertEquals("/_cluster/settings", expectedRequest.getEndpoint());
+        assertEquals(HttpGet.METHOD_NAME, expectedRequest.getMethod());
+        assertEquals(expectedParams, expectedRequest.getParameters());
+    }
+
     public void testPutPipeline() throws IOException {
         String pipelineId = "some_pipeline_id";
         PutPipelineRequest request = new PutPipelineRequest(

+ 68 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java

@@ -23,6 +23,8 @@ import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.LatchedActionListener;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest;
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
 import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@@ -49,6 +51,7 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.notNullValue;
 
 /**
@@ -189,6 +192,71 @@ public class ClusterClientDocumentationIT extends ESRestHighLevelClientTestCase
         }
     }
 
+    public void testClusterGetSettings() throws IOException {
+        RestHighLevelClient client = highLevelClient();
+
+        // tag::get-settings-request
+        ClusterGetSettingsRequest request = new ClusterGetSettingsRequest();
+        // end::get-settings-request
+
+        // tag::get-settings-request-includeDefaults
+        request.includeDefaults(true); // <1>
+        // end::get-settings-request-includeDefaults
+
+        // tag::get-settings-request-local
+        request.local(true); // <1>
+        // end::get-settings-request-local
+
+        // tag::get-settings-request-masterTimeout
+        request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
+        request.masterNodeTimeout("1m"); // <2>
+        // end::get-settings-request-masterTimeout
+
+        // tag::get-settings-execute
+        ClusterGetSettingsResponse response = client.cluster().getSettings(request, RequestOptions.DEFAULT); // <1>
+        // end::get-settings-execute
+
+        // tag::get-settings-response
+        Settings persistentSettings = response.getPersistentSettings(); // <1>
+        Settings transientSettings = response.getTransientSettings(); // <2>
+        Settings defaultSettings = response.getDefaultSettings(); // <3>
+        String settingValue = response.getSetting("cluster.routing.allocation.enable"); // <4>
+        // end::get-settings-response
+
+        assertThat(defaultSettings.size(), greaterThan(0));
+    }
+
+    public void testClusterGetSettingsAsync() throws InterruptedException {
+        RestHighLevelClient client = highLevelClient();
+
+        ClusterGetSettingsRequest request = new ClusterGetSettingsRequest();
+
+        // tag::get-settings-execute-listener
+        ActionListener<ClusterGetSettingsResponse> listener =
+            new ActionListener<ClusterGetSettingsResponse>() {
+                @Override
+                public void onResponse(ClusterGetSettingsResponse response) {
+                    // <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.cluster().getSettingsAsync(request, RequestOptions.DEFAULT, listener); // <1>
+        // end::get-settings-execute-async
+
+        assertTrue(latch.await(30L, TimeUnit.SECONDS));
+    }
+
     public void testClusterHealth() throws IOException {
         RestHighLevelClient client = highLevelClient();
         client.indices().create(new CreateIndexRequest("index"), RequestOptions.DEFAULT);

+ 92 - 0
docs/java-rest/high-level/cluster/get_settings.asciidoc

@@ -0,0 +1,92 @@
+[[java-rest-high-cluster-get-settings]]
+=== Cluster Get Settings API
+
+The Cluster Get Settings API allows to get the cluster wide settings.
+
+[[java-rest-high-cluster-get-settings-request]]
+==== Cluster Get Settings Request
+
+A `ClusterGetSettingsRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-settings-request]
+--------------------------------------------------
+
+==== Optional arguments
+The following arguments can optionally be provided:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-settings-request-includeDefaults]
+--------------------------------------------------
+<1> By default only those settings that were explicitly set are returned. Setting this to true also returns
+the default settings.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-settings-request-local]
+--------------------------------------------------
+<1> By default the request goes to the master of the cluster to get the latest results. If local is specified it gets
+the results from whichever node the request goes to.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-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-get-settings-sync]]
+==== Synchronous Execution
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-settings-execute]
+--------------------------------------------------
+<1> Execute the request and get back the response in a `ClusterGetSettingsResponse` object.
+
+[[java-rest-high-cluster-get-settings-async]]
+==== Asynchronous Execution
+
+The asynchronous execution of a cluster get settings requires both the
+`ClusterGetSettingsRequest` instance and an `ActionListener` instance to be
+passed to the asynchronous method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-settings-execute-async]
+--------------------------------------------------
+<1> The `ClusterGetSettingsRequest` 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 `ClusterGetSettingsResponse` looks like:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.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 a failure. The raised exception is provided as an argument
+
+[[java-rest-high-cluster-get-settings-response]]
+==== Cluster Get Settings Response
+
+The returned `ClusterGetSettingsResponse` allows to retrieve information about the
+executed operation as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-settings-response]
+--------------------------------------------------
+<1> Get the persistent settings.
+<2> Get the transient settings.
+<3> Get the default settings (returns empty settings if `includeDefaults` was not set to `true`).
+<4> Get the value as a `String` for a particular setting. The order of searching is first in `persistentSettings` then in
+`transientSettings` and finally, if not found in either, in `defaultSettings`.

+ 2 - 0
docs/java-rest/high-level/supported-apis.asciidoc

@@ -118,9 +118,11 @@ include::indices/get_templates.asciidoc[]
 The Java High Level REST Client supports the following Cluster APIs:
 
 * <<java-rest-high-cluster-put-settings>>
+* <<java-rest-high-cluster-get-settings>>
 * <<java-rest-high-cluster-health>>
 
 include::cluster/put_settings.asciidoc[]
+include::cluster/get_settings.asciidoc[]
 include::cluster/health.asciidoc[]
 
 == Ingest APIs

+ 2 - 0
docs/reference/cluster.asciidoc

@@ -42,6 +42,8 @@ include::cluster/reroute.asciidoc[]
 
 include::cluster/update-settings.asciidoc[]
 
+include::cluster/get-settings.asciidoc[]
+
 include::cluster/nodes-stats.asciidoc[]
 
 include::cluster/nodes-info.asciidoc[]

+ 20 - 0
docs/reference/cluster/get-settings.asciidoc

@@ -0,0 +1,20 @@
+[[cluster-get-settings]]
+== Cluster Get Settings
+
+The cluster get settings API allows to retrieve the cluster wide settings.
+
+[source,js]
+--------------------------------------------------
+GET /_cluster/settings
+--------------------------------------------------
+// CONSOLE
+
+Or
+[source,js]
+--------------------------------------------------
+GET /_cluster/settings?include_defaults=true
+--------------------------------------------------
+// CONSOLE
+
+In the second example above, the parameter `include_defaults` ensures that the settings which were not set explicitly
+are also returned. By default `include_defaults` is set to false.

+ 48 - 0
server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsRequest.java

@@ -0,0 +1,48 @@
+/*
+ * 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.action.ActionRequestValidationException;
+import org.elasticsearch.action.support.master.MasterNodeReadRequest;
+
+/**
+ * This request is specific to the REST client. {@link org.elasticsearch.action.admin.cluster.state.ClusterStateRequest}
+ * is used on the transport layer.
+ */
+public class ClusterGetSettingsRequest extends MasterNodeReadRequest<ClusterGetSettingsRequest> {
+    private boolean includeDefaults = false;
+
+    @Override
+    public ActionRequestValidationException validate() {
+        return null;
+    }
+
+    /**
+     * When include_defaults is set, return default settings which are normally suppressed.
+     */
+    public ClusterGetSettingsRequest includeDefaults(boolean includeDefaults) {
+        this.includeDefaults = includeDefaults;
+        return this;
+    }
+
+    public boolean includeDefaults() {
+        return includeDefaults;
+    }
+}

+ 165 - 0
server/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsResponse.java

@@ -0,0 +1,165 @@
+/*
+ * 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.action.ActionResponse;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
+
+/**
+ * This response is specific to the REST client. {@link org.elasticsearch.action.admin.cluster.state.ClusterStateResponse}
+ * is used on the transport layer.
+ */
+public class ClusterGetSettingsResponse extends ActionResponse implements ToXContentObject {
+
+    private Settings persistentSettings = Settings.EMPTY;
+    private Settings transientSettings = Settings.EMPTY;
+    private Settings defaultSettings = Settings.EMPTY;
+
+    static final String PERSISTENT_FIELD = "persistent";
+    static final String TRANSIENT_FIELD = "transient";
+    static final String DEFAULTS_FIELD = "defaults";
+
+    @SuppressWarnings("unchecked")
+    private static final ConstructingObjectParser<ClusterGetSettingsResponse, Void> PARSER =
+        new ConstructingObjectParser<>(
+            "cluster_get_settings_response",
+            true,
+            a -> {
+                Settings defaultSettings = a[2] == null ? Settings.EMPTY : (Settings) a[2];
+                return new ClusterGetSettingsResponse((Settings) a[0], (Settings) a[1], defaultSettings);
+            }
+        );
+    static {
+        PARSER.declareObject(constructorArg(), (p, c) -> Settings.fromXContent(p), new ParseField(PERSISTENT_FIELD));
+        PARSER.declareObject(constructorArg(), (p, c) -> Settings.fromXContent(p), new ParseField(TRANSIENT_FIELD));
+        PARSER.declareObject(optionalConstructorArg(), (p, c) -> Settings.fromXContent(p), new ParseField(DEFAULTS_FIELD));
+    }
+
+    public ClusterGetSettingsResponse(Settings persistentSettings, Settings transientSettings, Settings defaultSettings) {
+        if (persistentSettings != null) {
+            this.persistentSettings = persistentSettings;
+        }
+        if (transientSettings != null) {
+            this.transientSettings = transientSettings;
+        }
+        if (defaultSettings != null) {
+            this.defaultSettings = defaultSettings;
+        }
+    }
+
+    /**
+     * Returns the persistent settings for the cluster
+     * @return Settings
+     */
+    public Settings getPersistentSettings() {
+        return persistentSettings;
+    }
+
+    /**
+     * Returns the transient settings for the cluster
+     * @return Settings
+     */
+    public Settings getTransientSettings() {
+        return transientSettings;
+    }
+
+    /**
+     * Returns the default settings for the cluster (only if {@code include_defaults} was set to true in the request)
+     * @return Settings
+     */
+    public Settings getDefaultSettings() {
+        return defaultSettings;
+    }
+
+    /**
+     * Returns the string value of the setting for the specified index. The order of search is first
+     * in persistent settings the transient settings and finally the default settings.
+     * @param setting the name of the setting to get
+     * @return String
+     */
+    public String getSetting(String setting) {
+        if (persistentSettings.hasValue(setting)) {
+            return persistentSettings.get(setting);
+        } else if (transientSettings.hasValue(setting)) {
+            return transientSettings.get(setting);
+        } else if (defaultSettings.hasValue(setting)) {
+            return defaultSettings.get(setting);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+        builder.startObject();
+
+        builder.startObject(PERSISTENT_FIELD);
+        persistentSettings.toXContent(builder, params);
+        builder.endObject();
+
+        builder.startObject(TRANSIENT_FIELD);
+        transientSettings.toXContent(builder, params);
+        builder.endObject();
+
+        if (defaultSettings.isEmpty() == false) {
+            builder.startObject(DEFAULTS_FIELD);
+            defaultSettings.toXContent(builder, params);
+            builder.endObject();
+        }
+        builder.endObject();
+        return builder;
+    }
+
+    public static ClusterGetSettingsResponse fromXContent(XContentParser parser) {
+        return PARSER.apply(parser, null);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ClusterGetSettingsResponse that = (ClusterGetSettingsResponse) o;
+        return Objects.equals(transientSettings, that.transientSettings) &&
+            Objects.equals(persistentSettings, that.persistentSettings) &&
+            Objects.equals(defaultSettings, that.defaultSettings);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(transientSettings, persistentSettings, defaultSettings);
+    }
+
+    @Override
+    public String toString() {
+        return Strings.toString(this);
+    }
+}

+ 10 - 18
server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterGetSettingsAction.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.rest.action.admin.cluster;
 
+import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse;
 import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
 import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
 import org.elasticsearch.client.Requests;
@@ -65,6 +66,7 @@ public class RestClusterGetSettingsAction extends BaseRestHandler {
                 .nodes(false);
         final boolean renderDefaults = request.paramAsBoolean("include_defaults", false);
         clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
+        clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
         return channel -> client.admin().cluster().state(clusterStateRequest, new RestBuilderListener<ClusterStateResponse>(channel) {
             @Override
             public RestResponse buildResponse(ClusterStateResponse response, XContentBuilder builder) throws Exception {
@@ -85,23 +87,13 @@ public class RestClusterGetSettingsAction extends BaseRestHandler {
 
     private XContentBuilder renderResponse(ClusterState state, boolean renderDefaults, XContentBuilder builder, ToXContent.Params params)
             throws IOException {
-        builder.startObject();
-
-        builder.startObject("persistent");
-        state.metaData().persistentSettings().toXContent(builder, params);
-        builder.endObject();
-
-        builder.startObject("transient");
-        state.metaData().transientSettings().toXContent(builder, params);
-        builder.endObject();
-
-        if (renderDefaults) {
-            builder.startObject("defaults");
-            settingsFilter.filter(clusterSettings.diff(state.metaData().settings(), this.settings)).toXContent(builder, params);
-            builder.endObject();
-        }
-
-        builder.endObject();
-        return builder;
+        return
+            new ClusterGetSettingsResponse(
+                state.metaData().persistentSettings(),
+                state.metaData().transientSettings(),
+                renderDefaults ?
+                    settingsFilter.filter(clusterSettings.diff(state.metaData().settings(), this.settings)) :
+                    Settings.EMPTY
+            ).toXContent(builder, params);
     }
 }

+ 57 - 0
server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterGetSettingsResponseTests.java

@@ -0,0 +1,57 @@
+/*
+ * 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.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+import java.util.function.Predicate;
+
+public class ClusterGetSettingsResponseTests extends AbstractXContentTestCase<ClusterGetSettingsResponse> {
+
+    @Override
+    protected ClusterGetSettingsResponse doParseInstance(XContentParser parser) throws IOException {
+        return ClusterGetSettingsResponse.fromXContent(parser);
+    }
+
+    @Override
+    protected boolean supportsUnknownFields() {
+        return true;
+    }
+
+    @Override
+    protected ClusterGetSettingsResponse createTestInstance() {
+        Settings persistentSettings = ClusterUpdateSettingsResponseTests.randomClusterSettings(0, 2);
+        Settings transientSettings = ClusterUpdateSettingsResponseTests.randomClusterSettings(0, 2);
+        Settings defaultSettings = randomBoolean() ?
+            ClusterUpdateSettingsResponseTests.randomClusterSettings(0, 2): Settings.EMPTY;
+        return new ClusterGetSettingsResponse(persistentSettings, transientSettings, defaultSettings);
+    }
+
+    @Override
+    protected Predicate<String> getRandomFieldsExcludeFilter() {
+        return p ->
+            p.startsWith(ClusterGetSettingsResponse.TRANSIENT_FIELD) ||
+                p.startsWith(ClusterGetSettingsResponse.PERSISTENT_FIELD) ||
+                p.startsWith(ClusterGetSettingsResponse.DEFAULTS_FIELD);
+    }
+}