+ * @param request the request to delete the job
+ * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return action acknowledgement
+ * @throws IOException when there is a serialization issue sending the request or receiving the response
+ */
+ public DeleteJobResponse deleteJob(DeleteJobRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request,
+ RequestConverters::deleteMachineLearningJob,
+ options,
+ DeleteJobResponse::fromXContent,
+ Collections.emptySet());
+ }
+
+ /**
+ * Deletes the given Machine Learning Job asynchronously and notifies the listener on completion
+ *
+ * @param request the request to delete the job
+ * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener Listener to be notified upon request completion
+ */
+ public void deleteJobAsync(DeleteJobRequest request, RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request,
+ RequestConverters::deleteMachineLearningJob,
+ options,
+ DeleteJobResponse::fromXContent,
+ listener,
+ Collections.emptySet());
+ }
+
+ /**
+ * Opens a Machine Learning Job.
+ * When you open a new job, it starts with an empty model.
+ *
+ * When you open an existing job, the most recent model state is automatically loaded.
+ * The job is ready to resume its analysis from where it left off, once new data is received.
+ *
+ *
+ * For additional info
+ * see
+ *
+ * @param request request containing job_id and additional optional options
+ * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return response containing if the job was successfully opened or not.
+ * @throws IOException when there is a serialization issue sending the request or receiving the response
+ */
+ public OpenJobResponse openJob(OpenJobRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request,
+ RequestConverters::machineLearningOpenJob,
+ options,
+ OpenJobResponse::fromXContent,
+ Collections.emptySet());
+ }
+
+ /**
+ * Opens a Machine Learning Job asynchronously, notifies listener on completion.
+ * When you open a new job, it starts with an empty model.
+ *
+ * When you open an existing job, the most recent model state is automatically loaded.
+ * The job is ready to resume its analysis from where it left off, once new data is received.
+ *
+ * For additional info
+ * see
+ *
+ * @param request request containing job_id and additional optional options
+ * @param options Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener Listener to be notified upon request completion
+ */
+ public void openJobAsync(OpenJobRequest request, RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request,
+ RequestConverters::machineLearningOpenJob,
+ options,
+ OpenJobResponse::fromXContent,
+ listener,
+ Collections.emptySet());
+ }
}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java
index 45c70593fe826..c40b4893e0146 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java
@@ -112,6 +112,8 @@
import org.elasticsearch.protocol.xpack.license.GetLicenseRequest;
import org.elasticsearch.protocol.xpack.license.PutLicenseRequest;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest;
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
@@ -1210,6 +1212,34 @@ static Request putMachineLearningJob(PutJobRequest putJobRequest) throws IOExcep
return request;
}
+ static Request deleteMachineLearningJob(DeleteJobRequest deleteJobRequest) {
+ String endpoint = new EndpointBuilder()
+ .addPathPartAsIs("_xpack")
+ .addPathPartAsIs("ml")
+ .addPathPartAsIs("anomaly_detectors")
+ .addPathPart(deleteJobRequest.getJobId())
+ .build();
+ Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
+
+ Params params = new Params(request);
+ params.putParam("force", Boolean.toString(deleteJobRequest.isForce()));
+
+ return request;
+ }
+
+ static Request machineLearningOpenJob(OpenJobRequest openJobRequest) throws IOException {
+ String endpoint = new EndpointBuilder()
+ .addPathPartAsIs("_xpack")
+ .addPathPartAsIs("ml")
+ .addPathPartAsIs("anomaly_detectors")
+ .addPathPart(openJobRequest.getJobId())
+ .addPathPartAsIs("_open")
+ .build();
+ Request request = new Request(HttpPost.METHOD_NAME, endpoint);
+ request.setJsonEntity(openJobRequest.toString());
+ return request;
+ }
+
static Request getMigrationAssistance(IndexUpgradeInfoRequest indexUpgradeInfoRequest) {
EndpointBuilder endpointBuilder = new EndpointBuilder()
.addPathPartAsIs("_xpack/migration/assistance")
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java
index f86eb5b5dca87..0037460150f1a 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java
@@ -20,6 +20,10 @@
import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator;
import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
+import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
+import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
import org.elasticsearch.protocol.xpack.ml.PutJobResponse;
import org.elasticsearch.protocol.xpack.ml.job.config.AnalysisConfig;
@@ -46,12 +50,37 @@ public void testPutJob() throws Exception {
assertThat(createdJob.getJobType(), is(Job.ANOMALY_DETECTOR_JOB_TYPE));
}
+ public void testDeleteJob() throws Exception {
+ String jobId = randomValidJobId();
+ Job job = buildJob(jobId);
+ MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
+ machineLearningClient.putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ DeleteJobResponse response = execute(new DeleteJobRequest(jobId),
+ machineLearningClient::deleteJob,
+ machineLearningClient::deleteJobAsync);
+
+ assertTrue(response.isAcknowledged());
+ }
+
+ public void testOpenJob() throws Exception {
+ String jobId = randomValidJobId();
+ Job job = buildJob(jobId);
+ MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
+
+ machineLearningClient.putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ OpenJobResponse response = execute(new OpenJobRequest(jobId), machineLearningClient::openJob, machineLearningClient::openJobAsync);
+
+ assertTrue(response.isOpened());
+ }
+
public static String randomValidJobId() {
CodepointSetGenerator generator = new CodepointSetGenerator("abcdefghijklmnopqrstuvwxyz0123456789".toCharArray());
return generator.ofCodePointsLength(random(), 10, 10);
}
- private static Job buildJob(String jobId) {
+ public static Job buildJob(String jobId) {
Job.Builder builder = new Job.Builder(jobId);
builder.setDescription(randomAlphaOfLength(10));
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
index 47195f0bb2aba..786cb94f8926d 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java
@@ -127,6 +127,8 @@
import org.elasticsearch.index.rankeval.RestRankEvalAction;
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest;
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
import org.elasticsearch.repositories.fs.FsRepository;
@@ -2610,6 +2612,33 @@ public void testXPackDeleteWatch() {
assertThat(request.getEntity(), nullValue());
}
+ public void testDeleteMachineLearningJob() {
+ String jobId = randomAlphaOfLength(10);
+ DeleteJobRequest deleteJobRequest = new DeleteJobRequest(jobId);
+
+ Request request = RequestConverters.deleteMachineLearningJob(deleteJobRequest);
+ assertEquals(HttpDelete.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/ml/anomaly_detectors/" + jobId, request.getEndpoint());
+ assertEquals(Boolean.toString(false), request.getParameters().get("force"));
+
+ deleteJobRequest.setForce(true);
+ request = RequestConverters.deleteMachineLearningJob(deleteJobRequest);
+ assertEquals(Boolean.toString(true), request.getParameters().get("force"));
+ }
+
+ public void testPostMachineLearningOpenJob() throws Exception {
+ String jobId = "some-job-id";
+ OpenJobRequest openJobRequest = new OpenJobRequest(jobId);
+ openJobRequest.setTimeout(TimeValue.timeValueMinutes(10));
+
+ Request request = RequestConverters.machineLearningOpenJob(openJobRequest);
+ assertEquals(HttpPost.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/ml/anomaly_detectors/" + jobId + "/_open", request.getEndpoint());
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ request.getEntity().writeTo(bos);
+ assertEquals(bos.toString("UTF-8"), "{\"job_id\":\""+ jobId +"\",\"timeout\":\"10m\"}");
+ }
+
/**
* Randomize the {@link FetchSourceContext} request parameters.
*/
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java
index 97bee81393864..a77d8b43e5737 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java
@@ -21,9 +21,14 @@
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.LatchedActionListener;
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
+import org.elasticsearch.client.MachineLearningIT;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobRequest;
+import org.elasticsearch.protocol.xpack.ml.DeleteJobResponse;
+import org.elasticsearch.protocol.xpack.ml.OpenJobRequest;
+import org.elasticsearch.protocol.xpack.ml.OpenJobResponse;
import org.elasticsearch.protocol.xpack.ml.PutJobRequest;
import org.elasticsearch.protocol.xpack.ml.PutJobResponse;
import org.elasticsearch.protocol.xpack.ml.job.config.AnalysisConfig;
@@ -118,4 +123,102 @@ public void onFailure(Exception e) {
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}
+
+ public void testDeleteJob() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ String jobId = "my-first-machine-learning-job";
+
+ Job job = MachineLearningIT.buildJob(jobId);
+ client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ Job secondJob = MachineLearningIT.buildJob("my-second-machine-learning-job");
+ client.machineLearning().putJob(new PutJobRequest(secondJob), RequestOptions.DEFAULT);
+
+ {
+ //tag::x-pack-delete-ml-job-request
+ DeleteJobRequest deleteJobRequest = new DeleteJobRequest("my-first-machine-learning-job");
+ deleteJobRequest.setForce(false); //<1>
+ DeleteJobResponse deleteJobResponse = client.machineLearning().deleteJob(deleteJobRequest, RequestOptions.DEFAULT);
+ //end::x-pack-delete-ml-job-request
+
+ //tag::x-pack-delete-ml-job-response
+ boolean isAcknowledged = deleteJobResponse.isAcknowledged(); //<1>
+ //end::x-pack-delete-ml-job-response
+ }
+ {
+ //tag::x-pack-delete-ml-job-request-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(DeleteJobResponse deleteJobResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ //end::x-pack-delete-ml-job-request-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ //tag::x-pack-delete-ml-job-request-async
+ DeleteJobRequest deleteJobRequest = new DeleteJobRequest("my-second-machine-learning-job");
+ client.machineLearning().deleteJobAsync(deleteJobRequest, RequestOptions.DEFAULT, listener); // <1>
+ //end::x-pack-delete-ml-job-request-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+
+ public void testOpenJob() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ Job job = MachineLearningIT.buildJob("opening-my-first-machine-learning-job");
+ client.machineLearning().putJob(new PutJobRequest(job), RequestOptions.DEFAULT);
+
+ Job secondJob = MachineLearningIT.buildJob("opening-my-second-machine-learning-job");
+ client.machineLearning().putJob(new PutJobRequest(secondJob), RequestOptions.DEFAULT);
+
+ {
+ //tag::x-pack-ml-open-job-request
+ OpenJobRequest openJobRequest = new OpenJobRequest("opening-my-first-machine-learning-job"); //<1>
+ openJobRequest.setTimeout(TimeValue.timeValueMinutes(10)); //<2>
+ //end::x-pack-ml-open-job-request
+
+ //tag::x-pack-ml-open-job-execute
+ OpenJobResponse openJobResponse = client.machineLearning().openJob(openJobRequest, RequestOptions.DEFAULT);
+ boolean isOpened = openJobResponse.isOpened(); //<1>
+ //end::x-pack-ml-open-job-execute
+
+ }
+ {
+ //tag::x-pack-ml-open-job-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(OpenJobResponse openJobResponse) {
+ //<1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ //end::x-pack-ml-open-job-listener
+ OpenJobRequest openJobRequest = new OpenJobRequest("opening-my-second-machine-learning-job");
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::x-pack-ml-open-job-execute-async
+ client.machineLearning().openJobAsync(openJobRequest, RequestOptions.DEFAULT, listener); //<1>
+ // end::x-pack-ml-open-job-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
}
diff --git a/docs/java-rest/high-level/ml/delete-job.asciidoc b/docs/java-rest/high-level/ml/delete-job.asciidoc
new file mode 100644
index 0000000000000..44a6a47940955
--- /dev/null
+++ b/docs/java-rest/high-level/ml/delete-job.asciidoc
@@ -0,0 +1,49 @@
+[[java-rest-high-x-pack-ml-delete-job]]
+=== Delete Job API
+
+[[java-rest-high-x-pack-machine-learning-delete-job-request]]
+==== Delete Job Request
+
+A `DeleteJobRequest` object requires a non-null `jobId` and can optionally set `force`.
+Can be executed as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-request]
+---------------------------------------------------
+<1> Use to forcefully delete an opened job;
+this method is quicker than closing and deleting the job.
+Defaults to `false`
+
+[[java-rest-high-x-pack-machine-learning-delete-job-response]]
+==== Delete Job Response
+
+The returned `DeleteJobResponse` object indicates the acknowledgement of the request:
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-response]
+---------------------------------------------------
+<1> `isAcknowledged` was the deletion request acknowledged or not
+
+[[java-rest-high-x-pack-machine-learning-delete-job-async]]
+==== Delete Job Asynchronously
+
+This request can also be made asynchronously.
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-request-async]
+---------------------------------------------------
+<1> The `DeleteJobRequest` to execute and the `ActionListener` to alert on completion or error.
+
+The deletion request returns immediately. Once the request is completed, the `ActionListener` is
+called back using the `onResponse` or `onFailure`. The latter indicates some failure occurred when
+making the request.
+
+A typical listener for a `DeleteJobRequest` could be defined as follows:
+
+["source","java",subs="attributes,callouts,macros"]
+---------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-delete-ml-job-request-listener]
+---------------------------------------------------
+<1> The action to be taken when it is completed
+<2> What to do when a failure occurs
diff --git a/docs/java-rest/high-level/ml/open-job.asciidoc b/docs/java-rest/high-level/ml/open-job.asciidoc
new file mode 100644
index 0000000000000..ad575121818bc
--- /dev/null
+++ b/docs/java-rest/high-level/ml/open-job.asciidoc
@@ -0,0 +1,55 @@
+[[java-rest-high-x-pack-ml-open-job]]
+=== Open Job API
+
+The Open Job API provides the ability to open {ml} jobs in the cluster.
+It accepts a `OpenJobRequest` object and responds
+with a `OpenJobResponse` object.
+
+[[java-rest-high-x-pack-ml-open-job-request]]
+==== Open Job Request
+
+An `OpenJobRequest` object gets created with an existing non-null `jobId`.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-request]
+--------------------------------------------------
+<1> Constructing a new request referencing an existing `jobId`
+<2> Optionally setting the `timeout` value for how long the
+execution should wait for the job to be opened.
+
+[[java-rest-high-x-pack-ml-open-job-execution]]
+==== Execution
+
+The request can be executed through the `MachineLearningClient` contained
+in the `RestHighLevelClient` object, accessed via the `machineLearningClient()` method.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-execute]
+--------------------------------------------------
+<1> `isOpened()` from the `OpenJobResponse` indicates if the job was successfully
+opened or not.
+
+[[java-rest-high-x-pack-ml-open-job-execution-async]]
+==== Asynchronous Execution
+
+The request can also be executed asynchronously:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-execute-async]
+--------------------------------------------------
+<1> The `OpenJobRequest` to execute and the `ActionListener` to use when
+the execution completes
+
+The method does not block and returns immediately. The passed `ActionListener` is used
+to notify the caller of completion. A typical `ActionListner` for `OpenJobResponse` may
+look like
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/MlClientDocumentationIT.java[x-pack-ml-open-job-listener]
+--------------------------------------------------
+<1> `onResponse` is called back when the action is completed successfully
+<2> `onFailure` is called back when some unexpected error occurs
diff --git a/docs/java-rest/high-level/ml/put_job.asciidoc b/docs/java-rest/high-level/ml/put-job.asciidoc
similarity index 100%
rename from docs/java-rest/high-level/ml/put_job.asciidoc
rename to docs/java-rest/high-level/ml/put-job.asciidoc
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index 808546f2c279c..6bcb736243a7c 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -205,8 +205,12 @@ include::licensing/delete-license.asciidoc[]
The Java High Level REST Client supports the following Machine Learning APIs:
* <>
+* <>
+* <>
-include::ml/put_job.asciidoc[]
+include::ml/put-job.asciidoc[]
+include::ml/delete-job.asciidoc[]
+include::ml/open-job.asciidoc[]
== Migration APIs
diff --git a/docs/plugins/integrations.asciidoc b/docs/plugins/integrations.asciidoc
index 90f2c685fdaeb..8bffe5193ed7b 100644
--- a/docs/plugins/integrations.asciidoc
+++ b/docs/plugins/integrations.asciidoc
@@ -17,14 +17,11 @@ Integrations are not plugins, but are external tools or modules that make it eas
* https://drupal.org/project/elasticsearch_connector[Drupal]:
Drupal Elasticsearch integration.
-* https://wordpress.org/plugins/wpsolr-search-engine/[WPSOLR]:
- Elasticsearch (and Apache Solr) WordPress Plugin
-
-* http://searchbox-io.github.com/wp-elasticsearch/[Wp-Elasticsearch]:
+* https://wordpress.org/plugins/elasticpress/[ElasticPress]:
Elasticsearch WordPress Plugin
-* https://github.com/wallmanderco/elasticsearch-indexer[Elasticsearch Indexer]:
- Elasticsearch WordPress Plugin
+* https://wordpress.org/plugins/wpsolr-search-engine/[WPSOLR]:
+ Elasticsearch (and Apache Solr) WordPress Plugin
* https://doc.tiki.org/Elasticsearch[Tiki Wiki CMS Groupware]:
Tiki has native support for Elasticsearch. This provides faster & better
diff --git a/docs/reference/search/request-body.asciidoc b/docs/reference/search/request-body.asciidoc
index 2a51d705d83ec..e7c9b593af372 100644
--- a/docs/reference/search/request-body.asciidoc
+++ b/docs/reference/search/request-body.asciidoc
@@ -90,7 +90,8 @@ And here is a sample response:
Set to `false` to return an overall failure if the request would produce partial
results. Defaults to true, which will allow partial results in the case of timeouts
- or partial failures.
+ or partial failures. This default can be controlled using the cluster-level setting
+ `search.default_allow_partial_results`.
`terminate_after`::
diff --git a/docs/reference/search/uri-request.asciidoc b/docs/reference/search/uri-request.asciidoc
index a90f32bb3cd36..279bc0c0384c1 100644
--- a/docs/reference/search/uri-request.asciidoc
+++ b/docs/reference/search/uri-request.asciidoc
@@ -125,5 +125,6 @@ more details on the different types of search that can be performed.
|`allow_partial_search_results` |Set to `false` to return an overall failure if the request would produce
partial results. Defaults to true, which will allow partial results in the case of timeouts
-or partial failures..
+or partial failures. This default can be controlled using the cluster-level setting
+`search.default_allow_partial_results`.
|=======================================================================
diff --git a/docs/reference/setup/important-settings/heap-dump-path.asciidoc b/docs/reference/setup/important-settings/heap-dump-path.asciidoc
index b0d301b21d0b8..fb8c7ff35f0d0 100644
--- a/docs/reference/setup/important-settings/heap-dump-path.asciidoc
+++ b/docs/reference/setup/important-settings/heap-dump-path.asciidoc
@@ -8,8 +8,8 @@ distributions, and the `data` directory under the root of the
Elasticsearch installation for the <> archive
distributions). If this path is not suitable for receiving heap dumps,
you should modify the entry `-XX:HeapDumpPath=...` in
-<>. If you specify a fixed filename instead
-of a directory, the JVM will repeatedly use the same file; this is one
-mechanism for preventing heap dumps from accumulating in the heap dump
-path. Alternatively, you can configure a scheduled task via your OS to
-remove heap dumps that are older than a configured age.
+<>. If you specify a directory, the JVM
+will generate a filename for the heap dump based on the PID of the running
+instance. If you specify a fixed filename instead of a directory, the file must
+not exist when the JVM needs to perform a heap dump on an out of memory
+exception, otherwise the heap dump will fail.
diff --git a/docs/reference/setup/important-settings/network-host.asciidoc b/docs/reference/setup/important-settings/network-host.asciidoc
index 7e29e73123d8d..1788bfebc66b5 100644
--- a/docs/reference/setup/important-settings/network-host.asciidoc
+++ b/docs/reference/setup/important-settings/network-host.asciidoc
@@ -9,7 +9,7 @@ location on a single node. This can be useful for testing Elasticsearch's
ability to form clusters, but it is not a configuration recommended for
production.
-In order to communicate and to form a cluster with nodes on other servers, your
+In order to form a cluster with nodes on other servers, your
node will need to bind to a non-loopback address. While there are many
<>, usually all you need to configure is
`network.host`:
diff --git a/libs/core/src/main/java/org/elasticsearch/common/CharArrays.java b/libs/core/src/main/java/org/elasticsearch/common/CharArrays.java
new file mode 100644
index 0000000000000..907874ca5735b
--- /dev/null
+++ b/libs/core/src/main/java/org/elasticsearch/common/CharArrays.java
@@ -0,0 +1,150 @@
+/*
+ * 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.common;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Helper class similar to Arrays to handle conversions for Char arrays
+ */
+public final class CharArrays {
+
+ private CharArrays() {}
+
+ /**
+ * Decodes the provided byte[] to a UTF-8 char[]. This is done while avoiding
+ * conversions to String. The provided byte[] is not modified by this method, so
+ * the caller needs to take care of clearing the value if it is sensitive.
+ */
+ public static char[] utf8BytesToChars(byte[] utf8Bytes) {
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(utf8Bytes);
+ final CharBuffer charBuffer = StandardCharsets.UTF_8.decode(byteBuffer);
+ final char[] chars;
+ if (charBuffer.hasArray()) {
+ // there is no guarantee that the char buffers backing array is the right size
+ // so we need to make a copy
+ chars = Arrays.copyOfRange(charBuffer.array(), charBuffer.position(), charBuffer.limit());
+ Arrays.fill(charBuffer.array(), (char) 0); // clear sensitive data
+ } else {
+ final int length = charBuffer.limit() - charBuffer.position();
+ chars = new char[length];
+ charBuffer.get(chars);
+ // if the buffer is not read only we can reset and fill with 0's
+ if (charBuffer.isReadOnly() == false) {
+ charBuffer.clear(); // reset
+ for (int i = 0; i < charBuffer.limit(); i++) {
+ charBuffer.put((char) 0);
+ }
+ }
+ }
+ return chars;
+ }
+
+ /**
+ * Encodes the provided char[] to a UTF-8 byte[]. This is done while avoiding
+ * conversions to String. The provided char[] is not modified by this method, so
+ * the caller needs to take care of clearing the value if it is sensitive.
+ */
+ public static byte[] toUtf8Bytes(char[] chars) {
+ final CharBuffer charBuffer = CharBuffer.wrap(chars);
+ final ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer);
+ final byte[] bytes;
+ if (byteBuffer.hasArray()) {
+ // there is no guarantee that the byte buffers backing array is the right size
+ // so we need to make a copy
+ bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
+ Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
+ } else {
+ final int length = byteBuffer.limit() - byteBuffer.position();
+ bytes = new byte[length];
+ byteBuffer.get(bytes);
+ // if the buffer is not read only we can reset and fill with 0's
+ if (byteBuffer.isReadOnly() == false) {
+ byteBuffer.clear(); // reset
+ for (int i = 0; i < byteBuffer.limit(); i++) {
+ byteBuffer.put((byte) 0);
+ }
+ }
+ }
+ return bytes;
+ }
+
+ /**
+ * Tests if a char[] contains a sequence of characters that match the prefix. This is like
+ * {@link String#startsWith(String)} but does not require conversion of the char[] to a string.
+ */
+ public static boolean charsBeginsWith(String prefix, char[] chars) {
+ if (chars == null || prefix == null) {
+ return false;
+ }
+
+ if (prefix.length() > chars.length) {
+ return false;
+ }
+
+ for (int i = 0; i < prefix.length(); i++) {
+ if (chars[i] != prefix.charAt(i)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Constant time equality check of char arrays to avoid potential timing attacks.
+ */
+ public static boolean constantTimeEquals(char[] a, char[] b) {
+ Objects.requireNonNull(a, "char arrays must not be null for constantTimeEquals");
+ Objects.requireNonNull(b, "char arrays must not be null for constantTimeEquals");
+ if (a.length != b.length) {
+ return false;
+ }
+
+ int equals = 0;
+ for (int i = 0; i < a.length; i++) {
+ equals |= a[i] ^ b[i];
+ }
+
+ return equals == 0;
+ }
+
+ /**
+ * Constant time equality check of strings to avoid potential timing attacks.
+ */
+ public static boolean constantTimeEquals(String a, String b) {
+ Objects.requireNonNull(a, "strings must not be null for constantTimeEquals");
+ Objects.requireNonNull(b, "strings must not be null for constantTimeEquals");
+ if (a.length() != b.length()) {
+ return false;
+ }
+
+ int equals = 0;
+ for (int i = 0; i < a.length(); i++) {
+ equals |= a.charAt(i) ^ b.charAt(i);
+ }
+
+ return equals == 0;
+ }
+}
diff --git a/libs/core/src/test/java/org/elasticsearch/common/CharArraysTests.java b/libs/core/src/test/java/org/elasticsearch/common/CharArraysTests.java
new file mode 100644
index 0000000000000..9283283ab0861
--- /dev/null
+++ b/libs/core/src/test/java/org/elasticsearch/common/CharArraysTests.java
@@ -0,0 +1,75 @@
+/*
+ * 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.common;
+
+import org.elasticsearch.test.ESTestCase;
+
+import java.nio.charset.StandardCharsets;
+
+public class CharArraysTests extends ESTestCase {
+
+ public void testCharsToBytes() {
+ final String originalValue = randomUnicodeOfCodepointLengthBetween(0, 32);
+ final byte[] expectedBytes = originalValue.getBytes(StandardCharsets.UTF_8);
+ final char[] valueChars = originalValue.toCharArray();
+
+ final byte[] convertedBytes = CharArrays.toUtf8Bytes(valueChars);
+ assertArrayEquals(expectedBytes, convertedBytes);
+ }
+
+ public void testBytesToUtf8Chars() {
+ final String originalValue = randomUnicodeOfCodepointLengthBetween(0, 32);
+ final byte[] bytes = originalValue.getBytes(StandardCharsets.UTF_8);
+ final char[] expectedChars = originalValue.toCharArray();
+
+ final char[] convertedChars = CharArrays.utf8BytesToChars(bytes);
+ assertArrayEquals(expectedChars, convertedChars);
+ }
+
+ public void testCharsBeginsWith() {
+ assertFalse(CharArrays.charsBeginsWith(randomAlphaOfLength(4), null));
+ assertFalse(CharArrays.charsBeginsWith(null, null));
+ assertFalse(CharArrays.charsBeginsWith(null, randomAlphaOfLength(4).toCharArray()));
+ assertFalse(CharArrays.charsBeginsWith(randomAlphaOfLength(2), randomAlphaOfLengthBetween(3, 8).toCharArray()));
+
+ final String prefix = randomAlphaOfLengthBetween(2, 4);
+ assertTrue(CharArrays.charsBeginsWith(prefix, prefix.toCharArray()));
+ final char[] prefixedValue = prefix.concat(randomAlphaOfLengthBetween(1, 12)).toCharArray();
+ assertTrue(CharArrays.charsBeginsWith(prefix, prefixedValue));
+
+ final String modifiedPrefix = randomBoolean() ? prefix.substring(1) : prefix.substring(0, prefix.length() - 1);
+ char[] nonMatchingValue;
+ do {
+ nonMatchingValue = modifiedPrefix.concat(randomAlphaOfLengthBetween(0, 12)).toCharArray();
+ } while (new String(nonMatchingValue).startsWith(prefix));
+ assertFalse(CharArrays.charsBeginsWith(prefix, nonMatchingValue));
+ assertTrue(CharArrays.charsBeginsWith(modifiedPrefix, nonMatchingValue));
+ }
+
+ public void testConstantTimeEquals() {
+ final String value = randomAlphaOfLengthBetween(0, 32);
+ assertTrue(CharArrays.constantTimeEquals(value, value));
+ assertTrue(CharArrays.constantTimeEquals(value.toCharArray(), value.toCharArray()));
+
+ final String other = randomAlphaOfLengthBetween(1, 32);
+ assertFalse(CharArrays.constantTimeEquals(value, other));
+ assertFalse(CharArrays.constantTimeEquals(value.toCharArray(), other.toCharArray()));
+ }
+}
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorFactoryTests.java
index 39a7bfd9a20b2..d51cb368e4317 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/AppendProcessorFactoryTests.java
@@ -100,6 +100,6 @@ public void testInvalidMustacheTemplate() throws Exception {
String processorTag = randomAlphaOfLength(10);
ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> factory.create(null, processorTag, config));
assertThat(exception.getMessage(), equalTo("java.lang.RuntimeException: could not compile script"));
- assertThat(exception.getHeader("processor_tag").get(0), equalTo(processorTag));
+ assertThat(exception.getMetadata("es.processor_tag").get(0), equalTo(processorTag));
}
}
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorFactoryTests.java
index 9e4acd7b17f83..f3396da64eb5f 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ConvertProcessorFactoryTests.java
@@ -58,9 +58,9 @@ public void testCreateUnsupportedType() throws Exception {
fail("factory create should have failed");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), Matchers.equalTo("[type] type [" + type + "] not supported, cannot convert field."));
- assertThat(e.getHeader("processor_type").get(0), equalTo(ConvertProcessor.TYPE));
- assertThat(e.getHeader("property_name").get(0), equalTo("type"));
- assertThat(e.getHeader("processor_tag"), nullValue());
+ assertThat(e.getMetadata("es.processor_type").get(0), equalTo(ConvertProcessor.TYPE));
+ assertThat(e.getMetadata("es.property_name").get(0), equalTo("type"));
+ assertThat(e.getMetadata("es.processor_tag"), nullValue());
}
}
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/FailProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/FailProcessorFactoryTests.java
index 801441407a7f7..3c89778f0e825 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/FailProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/FailProcessorFactoryTests.java
@@ -66,6 +66,6 @@ public void testInvalidMustacheTemplate() throws Exception {
String processorTag = randomAlphaOfLength(10);
ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> factory.create(null, processorTag, config));
assertThat(exception.getMessage(), equalTo("java.lang.RuntimeException: could not compile script"));
- assertThat(exception.getHeader("processor_tag").get(0), equalTo(processorTag));
+ assertThat(exception.getMetadata("es.processor_tag").get(0), equalTo(processorTag));
}
}
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RemoveProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RemoveProcessorFactoryTests.java
index c439a9662f202..bebe780276208 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RemoveProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RemoveProcessorFactoryTests.java
@@ -79,6 +79,6 @@ public void testInvalidMustacheTemplate() throws Exception {
String processorTag = randomAlphaOfLength(10);
ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> factory.create(null, processorTag, config));
assertThat(exception.getMessage(), equalTo("java.lang.RuntimeException: could not compile script"));
- assertThat(exception.getHeader("processor_tag").get(0), equalTo(processorTag));
+ assertThat(exception.getMetadata("es.processor_tag").get(0), equalTo(processorTag));
}
}
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/SetProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/SetProcessorFactoryTests.java
index 59a99b8f995d8..9602f34f698f7 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/SetProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/SetProcessorFactoryTests.java
@@ -108,7 +108,7 @@ public void testInvalidMustacheTemplate() throws Exception {
String processorTag = randomAlphaOfLength(10);
ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> factory.create(null, processorTag, config));
assertThat(exception.getMessage(), equalTo("java.lang.RuntimeException: could not compile script"));
- assertThat(exception.getHeader("processor_tag").get(0), equalTo(processorTag));
+ assertThat(exception.getMetadata("es.processor_tag").get(0), equalTo(processorTag));
}
}
diff --git a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/20_crud.yml b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/20_crud.yml
index 0e348bbd7265d..bd6a3e6ca14fd 100644
--- a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/20_crud.yml
+++ b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/20_crud.yml
@@ -158,9 +158,9 @@ teardown:
}
- match: { error.root_cause.0.type: "parse_exception" }
- match: { error.root_cause.0.reason: "[field] required property is missing" }
- - match: { error.root_cause.0.header.processor_tag: "fritag" }
- - match: { error.root_cause.0.header.processor_type: "set" }
- - match: { error.root_cause.0.header.property_name: "field" }
+ - match: { error.root_cause.0.processor_tag: "fritag" }
+ - match: { error.root_cause.0.processor_type: "set" }
+ - match: { error.root_cause.0.property_name: "field" }
---
"Test basic pipeline with on_failure in processor":
diff --git a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/50_on_failure.yml b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/50_on_failure.yml
index 4b40d9f670bfe..718b91ac1c111 100644
--- a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/50_on_failure.yml
+++ b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/50_on_failure.yml
@@ -148,9 +148,9 @@ teardown:
}
- match: { error.root_cause.0.type: "parse_exception" }
- match: { error.root_cause.0.reason: "[on_failure] processors list cannot be empty" }
- - match: { error.root_cause.0.header.processor_type: "fail" }
- - match: { error.root_cause.0.header.processor_tag: "emptyfail" }
- - match: { error.root_cause.0.header.property_name: "on_failure" }
+ - match: { error.root_cause.0.processor_type: "fail" }
+ - match: { error.root_cause.0.processor_tag: "emptyfail" }
+ - match: { error.root_cause.0.property_name: "on_failure" }
---
"Test pipeline with empty on_failure in pipeline":
diff --git a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/90_simulate.yml b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/90_simulate.yml
index 8b3ed313314bb..776a8af0c2420 100644
--- a/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/90_simulate.yml
+++ b/modules/ingest-common/src/test/resources/rest-api-spec/test/ingest/90_simulate.yml
@@ -107,9 +107,9 @@ teardown:
}
- match: { error.root_cause.0.type: "parse_exception" }
- match: { error.root_cause.0.reason: "[field] required property is missing" }
- - match: { error.root_cause.0.header.processor_tag: "fails" }
- - match: { error.root_cause.0.header.processor_type: "set" }
- - match: { error.root_cause.0.header.property_name: "field" }
+ - match: { error.root_cause.0.processor_tag: "fails" }
+ - match: { error.root_cause.0.processor_type: "set" }
+ - match: { error.root_cause.0.property_name: "field" }
---
"Test simulate without index type and id":
@@ -198,9 +198,9 @@ teardown:
}
]
}
- - is_false: error.root_cause.0.header.processor_type
- - is_false: error.root_cause.0.header.processor_tag
- - match: { error.root_cause.0.header.property_name: "pipeline" }
+ - is_false: error.root_cause.0.processor_type
+ - is_false: error.root_cause.0.processor_tag
+ - match: { error.root_cause.0.property_name: "pipeline" }
- match: { error.reason: "[pipeline] required property is missing" }
---
@@ -233,9 +233,9 @@ teardown:
}
- match: { error.root_cause.0.type: "parse_exception" }
- match: { error.root_cause.0.reason: "[value] required property is missing" }
- - match: { error.root_cause.0.header.processor_type: "set" }
- - match: { error.root_cause.0.header.property_name: "value" }
- - is_false: error.root_cause.0.header.processor_tag
+ - match: { error.root_cause.0.processor_type: "set" }
+ - match: { error.root_cause.0.property_name: "value" }
+ - is_false: error.root_cause.0.processor_tag
---
"Test simulate with verbose flag":
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java
index 345db46f8875f..7de8353194dda 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java
@@ -21,6 +21,7 @@
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
+import org.elasticsearch.painless.lookup.def;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
@@ -190,7 +191,7 @@ private static Class> definitionTypeForClass(PainlessLookup painlessLookup, Cl
componentType = componentType.getComponentType();
}
- if (painlessLookup.lookupPainlessClass(componentType) == null) {
+ if (componentType != def.class && painlessLookup.lookupPainlessClass(componentType) == null) {
throw new IllegalArgumentException(unknownErrorMessageSource.apply(componentType));
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java
index 16b8ac14f14f2..55855a3cb1efb 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java
@@ -26,6 +26,7 @@
import java.util.Set;
import java.util.function.Function;
+import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_CLASS_NAME;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessConstructorKey;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessFieldKey;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessMethodKey;
@@ -47,7 +48,7 @@ public final class PainlessLookup {
public boolean isValidCanonicalClassName(String canonicalClassName) {
Objects.requireNonNull(canonicalClassName);
- return canonicalClassNamesToClasses.containsKey(canonicalClassName);
+ return DEF_CLASS_NAME.equals(canonicalClassName) || canonicalClassNamesToClasses.containsKey(canonicalClassName);
}
public Class> canonicalTypeNameToType(String canonicalTypeName) {
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java
index e644453a4c1ba..c8353b54c9f44 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java
@@ -211,9 +211,6 @@ public static PainlessLookup buildFromWhitelists(List whitelists) {
public PainlessLookupBuilder() {
canonicalClassNamesToClasses = new HashMap<>();
classesToPainlessClassBuilders = new HashMap<>();
-
- canonicalClassNamesToClasses.put(DEF_CLASS_NAME, def.class);
- classesToPainlessClassBuilders.put(def.class, new PainlessClassBuilder());
}
private Class> canonicalTypeNameToType(String canonicalTypeName) {
@@ -225,7 +222,7 @@ private boolean isValidType(Class> type) {
type = type.getComponentType();
}
- return classesToPainlessClassBuilders.containsKey(type);
+ return type == def.class || classesToPainlessClassBuilders.containsKey(type);
}
public void addPainlessClass(ClassLoader classLoader, String javaClassName, boolean importClassName) {
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java
index f2eb434516961..71cacab9eba9d 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java
@@ -82,7 +82,7 @@ public static Class> canonicalTypeNameToType(String canonicalTypeName, Map type = canonicalClassNamesToClasses.get(canonicalTypeName);
+ Class> type = DEF_CLASS_NAME.equals(canonicalTypeName) ? def.class : canonicalClassNamesToClasses.get(canonicalTypeName);
if (type != null) {
return type;
@@ -105,7 +105,7 @@ public static Class> canonicalTypeNameToType(String canonicalTypeName, Map {
- /**
- * The password which is broadcasted to all nodes, but is never stored on
- * persistent storage. The password is used to reread and decrypt the contents
- * of the node's keystore (backing the implementation of
- * {@code SecureSettings}).
- */
- private SecureString secureSettingsPassword;
-
public NodesReloadSecureSettingsRequest() {
}
/**
- * Reload secure settings only on certain nodes, based on the nodes ids
- * specified. If none are passed, secure settings will be reloaded on all the
- * nodes.
+ * Reload secure settings only on certain nodes, based on the nodes IDs specified. If none are passed, secure settings will be reloaded
+ * on all the nodes.
*/
- public NodesReloadSecureSettingsRequest(String... nodesIds) {
+ public NodesReloadSecureSettingsRequest(final String... nodesIds) {
super(nodesIds);
}
- @Override
- public ActionRequestValidationException validate() {
- ActionRequestValidationException validationException = null;
- if (secureSettingsPassword == null) {
- validationException = addValidationError("secure settings password cannot be null (use empty string instead)",
- validationException);
- }
- return validationException;
- }
-
- public SecureString secureSettingsPassword() {
- return secureSettingsPassword;
- }
-
- public NodesReloadSecureSettingsRequest secureStorePassword(SecureString secureStorePassword) {
- this.secureSettingsPassword = secureStorePassword;
- return this;
- }
-
- @Override
- public void readFrom(StreamInput in) throws IOException {
- super.readFrom(in);
- final byte[] passwordBytes = in.readByteArray();
- try {
- this.secureSettingsPassword = new SecureString(utf8BytesToChars(passwordBytes));
- } finally {
- Arrays.fill(passwordBytes, (byte) 0);
- }
- }
-
- @Override
- public void writeTo(StreamOutput out) throws IOException {
- super.writeTo(out);
- final byte[] passwordBytes = charsToUtf8Bytes(this.secureSettingsPassword.getChars());
- try {
- out.writeByteArray(passwordBytes);
- } finally {
- Arrays.fill(passwordBytes, (byte) 0);
- }
- }
-
- /**
- * Encodes the provided char[] to a UTF-8 byte[]. This is done while avoiding
- * conversions to String. The provided char[] is not modified by this method, so
- * the caller needs to take care of clearing the value if it is sensitive.
- */
- private static byte[] charsToUtf8Bytes(char[] chars) {
- final CharBuffer charBuffer = CharBuffer.wrap(chars);
- final ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer);
- final byte[] bytes;
- if (byteBuffer.hasArray()) {
- // there is no guarantee that the byte buffers backing array is the right size
- // so we need to make a copy
- bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
- Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
- } else {
- final int length = byteBuffer.limit() - byteBuffer.position();
- bytes = new byte[length];
- byteBuffer.get(bytes);
- // if the buffer is not read only we can reset and fill with 0's
- if (byteBuffer.isReadOnly() == false) {
- byteBuffer.clear(); // reset
- for (int i = 0; i < byteBuffer.limit(); i++) {
- byteBuffer.put((byte) 0);
- }
- }
- }
- return bytes;
- }
-
- /**
- * Decodes the provided byte[] to a UTF-8 char[]. This is done while avoiding
- * conversions to String. The provided byte[] is not modified by this method, so
- * the caller needs to take care of clearing the value if it is sensitive.
- */
- public static char[] utf8BytesToChars(byte[] utf8Bytes) {
- final ByteBuffer byteBuffer = ByteBuffer.wrap(utf8Bytes);
- final CharBuffer charBuffer = StandardCharsets.UTF_8.decode(byteBuffer);
- final char[] chars;
- if (charBuffer.hasArray()) {
- // there is no guarantee that the char buffers backing array is the right size
- // so we need to make a copy
- chars = Arrays.copyOfRange(charBuffer.array(), charBuffer.position(), charBuffer.limit());
- Arrays.fill(charBuffer.array(), (char) 0); // clear sensitive data
- } else {
- final int length = charBuffer.limit() - charBuffer.position();
- chars = new char[length];
- charBuffer.get(chars);
- // if the buffer is not read only we can reset and fill with 0's
- if (charBuffer.isReadOnly() == false) {
- charBuffer.clear(); // reset
- for (int i = 0; i < charBuffer.limit(); i++) {
- charBuffer.put((char) 0);
- }
- }
- }
- return chars;
- }
}
diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsRequestBuilder.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsRequestBuilder.java
index b5f2f73e56f51..c8250455e6ba3 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsRequestBuilder.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/NodesReloadSecureSettingsRequestBuilder.java
@@ -19,19 +19,8 @@
package org.elasticsearch.action.admin.cluster.node.reload;
-import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.support.nodes.NodesOperationRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
-import org.elasticsearch.common.bytes.BytesReference;
-import org.elasticsearch.common.settings.SecureString;
-import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
-import org.elasticsearch.common.xcontent.NamedXContentRegistry;
-import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.common.xcontent.XContentType;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Objects;
/**
* Builder for the reload secure settings nodes request
@@ -39,46 +28,8 @@
public class NodesReloadSecureSettingsRequestBuilder extends NodesOperationRequestBuilder {
- public static final String SECURE_SETTINGS_PASSWORD_FIELD_NAME = "secure_settings_password";
-
public NodesReloadSecureSettingsRequestBuilder(ElasticsearchClient client, NodesReloadSecureSettingsAction action) {
super(client, action, new NodesReloadSecureSettingsRequest());
}
- public NodesReloadSecureSettingsRequestBuilder setSecureStorePassword(SecureString secureStorePassword) {
- request.secureStorePassword(secureStorePassword);
- return this;
- }
-
- public NodesReloadSecureSettingsRequestBuilder source(BytesReference source, XContentType xContentType) throws IOException {
- Objects.requireNonNull(xContentType);
- // EMPTY is ok here because we never call namedObject
- try (InputStream stream = source.streamInput();
- XContentParser parser = xContentType.xContent().createParser(NamedXContentRegistry.EMPTY,
- LoggingDeprecationHandler.INSTANCE, stream)) {
- XContentParser.Token token;
- token = parser.nextToken();
- if (token != XContentParser.Token.START_OBJECT) {
- throw new ElasticsearchParseException("expected an object, but found token [{}]", token);
- }
- token = parser.nextToken();
- if (token != XContentParser.Token.FIELD_NAME || false == SECURE_SETTINGS_PASSWORD_FIELD_NAME.equals(parser.currentName())) {
- throw new ElasticsearchParseException("expected a field named [{}], but found [{}]", SECURE_SETTINGS_PASSWORD_FIELD_NAME,
- token);
- }
- token = parser.nextToken();
- if (token != XContentParser.Token.VALUE_STRING) {
- throw new ElasticsearchParseException("expected field [{}] to be of type string, but found [{}] instead",
- SECURE_SETTINGS_PASSWORD_FIELD_NAME, token);
- }
- final String password = parser.text();
- setSecureStorePassword(new SecureString(password.toCharArray()));
- token = parser.nextToken();
- if (token != XContentParser.Token.END_OBJECT) {
- throw new ElasticsearchParseException("expected end of object, but found token [{}]", token);
- }
- }
- return this;
- }
-
}
diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/TransportNodesReloadSecureSettingsAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/TransportNodesReloadSecureSettingsAction.java
index 0f44170fa603b..b8a36bac68d61 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/TransportNodesReloadSecureSettingsAction.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/reload/TransportNodesReloadSecureSettingsAction.java
@@ -31,7 +31,6 @@
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.KeyStoreWrapper;
-import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.PluginsService;
@@ -82,16 +81,13 @@ protected NodesReloadSecureSettingsResponse.NodeResponse newNodeResponse() {
@Override
protected NodesReloadSecureSettingsResponse.NodeResponse nodeOperation(NodeRequest nodeReloadRequest) {
- final NodesReloadSecureSettingsRequest request = nodeReloadRequest.request;
- final SecureString secureSettingsPassword = request.secureSettingsPassword();
try (KeyStoreWrapper keystore = KeyStoreWrapper.load(environment.configFile())) {
// reread keystore from config file
if (keystore == null) {
return new NodesReloadSecureSettingsResponse.NodeResponse(clusterService.localNode(),
new IllegalStateException("Keystore is missing"));
}
- // decrypt the keystore using the password from the request
- keystore.decrypt(secureSettingsPassword.getChars());
+ keystore.decrypt(new char[0]);
// add the keystore to the original node settings object
final Settings settingsWithKeystore = Settings.builder()
.put(environment.settings(), false)
diff --git a/server/src/main/java/org/elasticsearch/ingest/ConfigurationUtils.java b/server/src/main/java/org/elasticsearch/ingest/ConfigurationUtils.java
index 2853842c646bc..54d06d116552f 100644
--- a/server/src/main/java/org/elasticsearch/ingest/ConfigurationUtils.java
+++ b/server/src/main/java/org/elasticsearch/ingest/ConfigurationUtils.java
@@ -284,14 +284,14 @@ public static ElasticsearchException newConfigurationException(String processorT
msg = "[" + propertyName + "] " + reason;
}
ElasticsearchParseException exception = new ElasticsearchParseException(msg);
- addHeadersToException(exception, processorType, processorTag, propertyName);
+ addMetadataToException(exception, processorType, processorTag, propertyName);
return exception;
}
public static ElasticsearchException newConfigurationException(String processorType, String processorTag,
String propertyName, Exception cause) {
ElasticsearchException exception = ExceptionsHelper.convertToElastic(cause);
- addHeadersToException(exception, processorType, processorTag, propertyName);
+ addMetadataToException(exception, processorType, processorTag, propertyName);
return exception;
}
@@ -341,16 +341,16 @@ public String execute() {
}
}
- private static void addHeadersToException(ElasticsearchException exception, String processorType,
- String processorTag, String propertyName) {
+ private static void addMetadataToException(ElasticsearchException exception, String processorType,
+ String processorTag, String propertyName) {
if (processorType != null) {
- exception.addHeader("processor_type", processorType);
+ exception.addMetadata("es.processor_type", processorType);
}
if (processorTag != null) {
- exception.addHeader("processor_tag", processorTag);
+ exception.addMetadata("es.processor_tag", processorTag);
}
if (propertyName != null) {
- exception.addHeader("property_name", propertyName);
+ exception.addMetadata("es.property_name", propertyName);
}
}
diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java
index 0697871ea5d1c..2251615d678fb 100644
--- a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java
+++ b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestReloadSecureSettingsAction.java
@@ -59,7 +59,6 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client
.cluster()
.prepareReloadSecureSettings()
.setTimeout(request.param("timeout"))
- .source(request.requiredContent(), request.getXContentType())
.setNodesIds(nodesIds);
final NodesReloadSecureSettingsRequest nodesRequest = nodesRequestBuilder.request();
return channel -> nodesRequestBuilder
@@ -68,12 +67,12 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client
public RestResponse buildResponse(NodesReloadSecureSettingsResponse response, XContentBuilder builder)
throws Exception {
builder.startObject();
- RestActions.buildNodesHeader(builder, channel.request(), response);
- builder.field("cluster_name", response.getClusterName().value());
- response.toXContent(builder, channel.request());
+ {
+ RestActions.buildNodesHeader(builder, channel.request(), response);
+ builder.field("cluster_name", response.getClusterName().value());
+ response.toXContent(builder, channel.request());
+ }
builder.endObject();
- // clear password for the original request
- nodesRequest.secureSettingsPassword().close();
return new BytesRestResponse(RestStatus.OK, builder);
}
});
diff --git a/server/src/test/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java b/server/src/test/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
index 7952758240544..3f9e258ffec1c 100644
--- a/server/src/test/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
+++ b/server/src/test/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
@@ -20,11 +20,9 @@
package org.elasticsearch.action.admin;
import org.elasticsearch.action.ActionListener;
-import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.admin.cluster.node.reload.NodesReloadSecureSettingsResponse;
import org.elasticsearch.common.settings.KeyStoreWrapper;
import org.elasticsearch.common.settings.SecureSettings;
-import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin;
@@ -44,11 +42,11 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.containsString;
public class ReloadSecureSettingsIT extends ESIntegTestCase {
@@ -62,7 +60,7 @@ public void testMissingKeystoreFile() throws Exception {
Files.deleteIfExists(KeyStoreWrapper.keystorePath(environment.configFile()));
final int initialReloadCount = mockReloadablePlugin.getReloadCount();
final CountDownLatch latch = new CountDownLatch(1);
- client().admin().cluster().prepareReloadSecureSettings().setSecureStorePassword(new SecureString(new char[0])).execute(
+ client().admin().cluster().prepareReloadSecureSettings().execute(
new ActionListener() {
@Override
public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
@@ -96,44 +94,6 @@ public void onFailure(Exception e) {
assertThat(mockReloadablePlugin.getReloadCount(), equalTo(initialReloadCount));
}
- public void testNullKeystorePassword() throws Exception {
- final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
- final MockReloadablePlugin mockReloadablePlugin = pluginsService.filterPlugins(MockReloadablePlugin.class)
- .stream().findFirst().get();
- final AtomicReference reloadSettingsError = new AtomicReference<>();
- final int initialReloadCount = mockReloadablePlugin.getReloadCount();
- final CountDownLatch latch = new CountDownLatch(1);
- client().admin().cluster().prepareReloadSecureSettings().execute(
- new ActionListener() {
- @Override
- public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
- try {
- reloadSettingsError.set(new AssertionError("Null keystore password should fail"));
- } finally {
- latch.countDown();
- }
- }
-
- @Override
- public void onFailure(Exception e) {
- try {
- assertThat(e, instanceOf(ActionRequestValidationException.class));
- assertThat(e.getMessage(), containsString("secure settings password cannot be null"));
- } catch (final AssertionError ae) {
- reloadSettingsError.set(ae);
- } finally {
- latch.countDown();
- }
- }
- });
- latch.await();
- if (reloadSettingsError.get() != null) {
- throw reloadSettingsError.get();
- }
- // in the null password case no reload should be triggered
- assertThat(mockReloadablePlugin.getReloadCount(), equalTo(initialReloadCount));
- }
-
public void testInvalidKeystoreFile() throws Exception {
final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
final MockReloadablePlugin mockReloadablePlugin = pluginsService.filterPlugins(MockReloadablePlugin.class)
@@ -149,7 +109,7 @@ public void testInvalidKeystoreFile() throws Exception {
Files.copy(keystore, KeyStoreWrapper.keystorePath(environment.configFile()), StandardCopyOption.REPLACE_EXISTING);
}
final CountDownLatch latch = new CountDownLatch(1);
- client().admin().cluster().prepareReloadSecureSettings().setSecureStorePassword(new SecureString(new char[0])).execute(
+ client().admin().cluster().prepareReloadSecureSettings().execute(
new ActionListener() {
@Override
public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
@@ -181,52 +141,6 @@ public void onFailure(Exception e) {
assertThat(mockReloadablePlugin.getReloadCount(), equalTo(initialReloadCount));
}
- public void testWrongKeystorePassword() throws Exception {
- final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
- final MockReloadablePlugin mockReloadablePlugin = pluginsService.filterPlugins(MockReloadablePlugin.class)
- .stream().findFirst().get();
- final Environment environment = internalCluster().getInstance(Environment.class);
- final AtomicReference reloadSettingsError = new AtomicReference<>();
- final int initialReloadCount = mockReloadablePlugin.getReloadCount();
- // "some" keystore should be present in this case
- writeEmptyKeystore(environment, new char[0]);
- final CountDownLatch latch = new CountDownLatch(1);
- client().admin()
- .cluster()
- .prepareReloadSecureSettings()
- .setSecureStorePassword(new SecureString(new char[] { 'W', 'r', 'o', 'n', 'g' }))
- .execute(new ActionListener() {
- @Override
- public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
- try {
- assertThat(nodesReloadResponse, notNullValue());
- final Map nodesMap = nodesReloadResponse.getNodesMap();
- assertThat(nodesMap.size(), equalTo(cluster().size()));
- for (final NodesReloadSecureSettingsResponse.NodeResponse nodeResponse : nodesReloadResponse.getNodes()) {
- assertThat(nodeResponse.reloadException(), notNullValue());
- assertThat(nodeResponse.reloadException(), instanceOf(SecurityException.class));
- }
- } catch (final AssertionError e) {
- reloadSettingsError.set(e);
- } finally {
- latch.countDown();
- }
- }
-
- @Override
- public void onFailure(Exception e) {
- reloadSettingsError.set(new AssertionError("Nodes request failed", e));
- latch.countDown();
- }
- });
- latch.await();
- if (reloadSettingsError.get() != null) {
- throw reloadSettingsError.get();
- }
- // in the wrong password case no reload should be triggered
- assertThat(mockReloadablePlugin.getReloadCount(), equalTo(initialReloadCount));
- }
-
public void testMisbehavingPlugin() throws Exception {
final Environment environment = internalCluster().getInstance(Environment.class);
final PluginsService pluginsService = internalCluster().getInstance(PluginsService.class);
@@ -247,7 +161,7 @@ public void testMisbehavingPlugin() throws Exception {
.get(Settings.builder().put(environment.settings()).setSecureSettings(secureSettings).build())
.toString();
final CountDownLatch latch = new CountDownLatch(1);
- client().admin().cluster().prepareReloadSecureSettings().setSecureStorePassword(new SecureString(new char[0])).execute(
+ client().admin().cluster().prepareReloadSecureSettings().execute(
new ActionListener() {
@Override
public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
@@ -314,7 +228,7 @@ protected Collection> nodePlugins() {
private void successfulReloadCall() throws InterruptedException {
final AtomicReference reloadSettingsError = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);
- client().admin().cluster().prepareReloadSecureSettings().setSecureStorePassword(new SecureString(new char[0])).execute(
+ client().admin().cluster().prepareReloadSecureSettings().execute(
new ActionListener() {
@Override
public void onResponse(NodesReloadSecureSettingsResponse nodesReloadResponse) {
diff --git a/server/src/test/java/org/elasticsearch/cluster/ack/AckIT.java b/server/src/test/java/org/elasticsearch/cluster/ack/AckIT.java
index 2cd8a2c27c714..df97854cc35b0 100644
--- a/server/src/test/java/org/elasticsearch/cluster/ack/AckIT.java
+++ b/server/src/test/java/org/elasticsearch/cluster/ack/AckIT.java
@@ -19,6 +19,7 @@
package org.elasticsearch.cluster.ack;
+import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteResponse;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
@@ -50,6 +51,7 @@
import static org.hamcrest.Matchers.notNullValue;
@ClusterScope(minNumDataNodes = 2)
+@AwaitsFix(bugUrl="https://github.com/elastic/elasticsearch/issues/32767")
public class AckIT extends ESIntegTestCase {
@Override
diff --git a/server/src/test/java/org/elasticsearch/index/shard/GlobalCheckpointListenersTests.java b/server/src/test/java/org/elasticsearch/index/shard/GlobalCheckpointListenersTests.java
index d9240602d8519..43b16c6ecc78f 100644
--- a/server/src/test/java/org/elasticsearch/index/shard/GlobalCheckpointListenersTests.java
+++ b/server/src/test/java/org/elasticsearch/index/shard/GlobalCheckpointListenersTests.java
@@ -341,7 +341,7 @@ public void testNotificationUsesExecutor() {
globalCheckpointListeners.add(NO_OPS_PERFORMED, (g, e) -> {});
}
globalCheckpointListeners.globalCheckpointUpdated(randomLongBetween(NO_OPS_PERFORMED, Long.MAX_VALUE));
- assertThat(count.get(), equalTo(1));
+ assertThat(count.get(), equalTo(numberOfListeners == 0 ? 0 : 1));
}
public void testConcurrency() throws BrokenBarrierException, InterruptedException {
diff --git a/server/src/test/java/org/elasticsearch/ingest/ConfigurationUtilsTests.java b/server/src/test/java/org/elasticsearch/ingest/ConfigurationUtilsTests.java
index af863410f9f35..61afd9ce2a473 100644
--- a/server/src/test/java/org/elasticsearch/ingest/ConfigurationUtilsTests.java
+++ b/server/src/test/java/org/elasticsearch/ingest/ConfigurationUtilsTests.java
@@ -131,9 +131,9 @@ public void testReadProcessors() throws Exception {
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
() -> ConfigurationUtils.readProcessorConfigs(config, registry));
assertThat(e.getMessage(), equalTo("No processor type exists with name [unknown_processor]"));
- assertThat(e.getHeader("processor_tag"), equalTo(Collections.singletonList("my_unknown")));
- assertThat(e.getHeader("processor_type"), equalTo(Collections.singletonList("unknown_processor")));
- assertThat(e.getHeader("property_name"), is(nullValue()));
+ assertThat(e.getMetadata("es.processor_tag"), equalTo(Collections.singletonList("my_unknown")));
+ assertThat(e.getMetadata("es.processor_type"), equalTo(Collections.singletonList("unknown_processor")));
+ assertThat(e.getMetadata("es.property_name"), is(nullValue()));
List