LLClient: Support host selection (#30523)

Allows users of the Low Level REST client to specify which hosts a
request should be run on. They implement the  `NodeSelector` interface
or reuse a built in selector like `NOT_MASTER_ONLY` to chose which nodes
are valid. Using it looks like:
```
Request request = new Request("POST", "/foo/_search");
RequestOptions options = request.getOptions().toBuilder();
options.setNodeSelector(NodeSelector.NOT_MASTER_ONLY);
request.setOptions(options);
...
```

This introduces a new `Node` object which contains a `HttpHost` and the
metadata about the host. At this point that metadata is just `version`
and `roles` but I plan to add node attributes in a followup. The
canonical way to **get** this metadata is to use the `Sniffer` to pull
the information from the Elasticsearch cluster.

I've marked this as "breaking-java" because it breaks custom
implementations of `HostsSniffer` by renaming the interface to
`NodesSniffer` and by changing it from returning a `List<HttpHost>` to a
`List<Node>`. It *shouldn't* break anyone else though.

Because we expect to find it useful, this also implements `host_selector`
support to `do` statements in the yaml tests. Using it looks a little
like:

```
---
"example test":
  - skip:
      features: host_selector
  - do:
      host_selector:
        version: " - 7.0.0" # same syntax as skip
      apiname:
        something: true
```

The `do` section parses the `version` string into a host selector that
uses the same version comparison logic as the `skip` section. When the
`do` section is executed it passed the off to the `RestClient`, using
the `ElasticsearchHostsSniffer` to sniff the required metadata.

The idea is to use this in mixed version tests to target a specific
version of Elasticsearch so we can be sure about the deprecation
logging though we don't currently have any examples that need it. We do,
however, have at least one open pull request that requires something
like this to properly test it.

Closes #21888
This commit is contained in:
Nik Everett 2018-06-11 17:07:27 -04:00 committed by GitHub
parent 563141c6c9
commit 0d9b78834f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 2434 additions and 467 deletions

View file

@ -144,3 +144,13 @@ include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[rest-high-level-cl
In the rest of this documentation about the Java High Level Client, the `RestHighLevelClient` instance
will be referenced as `client`.
[[java-rest-hight-getting-started-request-options]]
=== RequestOptions
All APIs in the `RestHighLevelClient` accept a `RequestOptions` which you can
use to customize the request in ways that won't change how Elasticsearch
executes the request. For example, this is the place where you'd specify a
`NodeSelector` to control which node receives the request. See the
<<java-rest-low-usage-request-options,low level client documentation>> for
more examples of customizing the options.

View file

@ -55,7 +55,7 @@ dependencies {
Once a `RestClient` instance has been created as shown in <<java-rest-low-usage-initialization>>,
a `Sniffer` can be associated to it. The `Sniffer` will make use of the provided `RestClient`
to periodically (every 5 minutes by default) fetch the list of current nodes from the cluster
and update them by calling `RestClient#setHosts`.
and update them by calling `RestClient#setNodes`.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
@ -105,7 +105,7 @@ on failure is not enabled like explained above.
The Elasticsearch Nodes Info api doesn't return the protocol to use when
connecting to the nodes but only their `host:port` key-pair, hence `http`
is used by default. In case `https` should be used instead, the
`ElasticsearchHostsSniffer` instance has to be manually created and provided
`ElasticsearchNodesSniffer` instance has to be manually created and provided
as follows:
["source","java",subs="attributes,callouts,macros"]
@ -125,12 +125,12 @@ cluster, the ones that have responded until then.
include-tagged::{doc-tests}/SnifferDocumentation.java[sniff-request-timeout]
--------------------------------------------------
Also, a custom `HostsSniffer` implementation can be provided for advanced
use-cases that may require fetching the hosts from external sources rather
Also, a custom `NodesSniffer` implementation can be provided for advanced
use-cases that may require fetching the `Node`s from external sources rather
than from Elasticsearch:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/SnifferDocumentation.java[custom-hosts-sniffer]
include-tagged::{doc-tests}/SnifferDocumentation.java[custom-nodes-sniffer]
--------------------------------------------------
<1> Fetch the hosts from the external source

View file

@ -271,24 +271,51 @@ a `ContentType` of `application/json`.
include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-body-shorter]
--------------------------------------------------
And you can add one or more headers to send with the request:
[[java-rest-low-usage-request-options]]
==== RequestOptions
The `RequestOptions` class holds parts of the request that should be shared
between many requests in the same application. You can make a singleton
instance and share it between all requests:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-headers]
include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-options-singleton]
--------------------------------------------------
<1> Add any headers needed by all requests.
<2> Set a `NodeSelector`.
<3> Customize the response consumer.
`addHeader` is for headers that are required for authorization or to work with
a proxy in front of Elasticsearch. There is no need to set the `Content-Type`
header because the client will automatically set that from the `HttpEntity`
attached to the request.
You can set the `NodeSelector` which controls which nodes will receive
requests. `NodeSelector.NOT_MASTER_ONLY` is a good choice.
You can also customize the response consumer used to buffer the asynchronous
responses. The default consumer will buffer up to 100MB of response on the
JVM heap. If the response is larger then the request will fail. You could,
for example, lower the maximum size which might be useful if you are running
in a heap constrained environment:
in a heap constrained environment like the exmaple above.
Once you've created the singleton you can use it when making requests:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-response-consumer]
include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-options-set-singleton]
--------------------------------------------------
You can also customize these options on a per request basis. For example, this
adds an extra header:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-options-customize]
--------------------------------------------------
==== Multiple parallel asynchronous actions
The client is quite happy to execute many actions in parallel. The following