Remove Migration Upgrade and Assistance APIs (#40075)

The Migration Assistance API has been functionally replaced by the
Deprecation Info API, and the Migration Upgrade API is not used for the
transition from ES 6.x to 7.x, and does not need to be kept around to
repair indices that were not properly upgraded before upgrading the
cluster, as was the case in 6.
This commit is contained in:
Gordon Brown 2019-03-18 13:46:56 -06:00 committed by GitHub
parent 38e9522218
commit c8a4a7fc9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 43 additions and 3034 deletions

View File

@ -19,15 +19,9 @@
package org.elasticsearch.client;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.DeprecationInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.tasks.TaskSubmissionResponse;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.client.migration.IndexUpgradeRequest;
import java.io.IOException;
import java.util.Collections;
@ -47,34 +41,6 @@ public final class MigrationClient {
this.restHighLevelClient = restHighLevelClient;
}
/**
* Get Migration Assistance for one or more indices
*
* @param request 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 IndexUpgradeInfoResponse getAssistance(IndexUpgradeInfoRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, MigrationRequestConverters::getMigrationAssistance, options,
IndexUpgradeInfoResponse::fromXContent, Collections.emptySet());
}
public BulkByScrollResponse upgrade(IndexUpgradeRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, MigrationRequestConverters::migrate, options,
BulkByScrollResponse::fromXContent, Collections.emptySet());
}
public TaskSubmissionResponse submitUpgradeTask(IndexUpgradeRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, MigrationRequestConverters::submitMigrateTask, options,
TaskSubmissionResponse::fromXContent, Collections.emptySet());
}
public void upgradeAsync(IndexUpgradeRequest request, RequestOptions options, ActionListener<BulkByScrollResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, MigrationRequestConverters::migrate, options,
BulkByScrollResponse::fromXContent, listener, Collections.emptySet());
}
/**
* Get deprecation info for one or more indices
* @param request the request

View File

@ -20,35 +20,13 @@
package org.elasticsearch.client;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeRequest;
final class MigrationRequestConverters {
private MigrationRequestConverters() {
}
static Request getMigrationAssistance(IndexUpgradeInfoRequest indexUpgradeInfoRequest) {
RequestConverters.EndpointBuilder endpointBuilder = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_migration", "assistance")
.addCommaSeparatedPathParts(indexUpgradeInfoRequest.indices());
String endpoint = endpointBuilder.build();
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
RequestConverters.Params parameters = new RequestConverters.Params(request);
parameters.withIndicesOptions(indexUpgradeInfoRequest.indicesOptions());
return request;
}
static Request migrate(IndexUpgradeRequest indexUpgradeRequest) {
return prepareMigrateRequest(indexUpgradeRequest, true);
}
static Request submitMigrateTask(IndexUpgradeRequest indexUpgradeRequest) {
return prepareMigrateRequest(indexUpgradeRequest, false);
}
static Request getDeprecationInfo(DeprecationInfoRequest deprecationInfoRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addCommaSeparatedPathParts(deprecationInfoRequest.getIndices())
@ -57,18 +35,4 @@ final class MigrationRequestConverters {
return new Request(HttpGet.METHOD_NAME, endpoint);
}
private static Request prepareMigrateRequest(IndexUpgradeRequest indexUpgradeRequest, boolean waitForCompletion) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_migration", "upgrade")
.addPathPart(indexUpgradeRequest.index())
.build();
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
RequestConverters.Params params = new RequestConverters.Params(request)
.withWaitForCompletion(waitForCompletion);
return request;
}
}

View File

@ -94,9 +94,9 @@ import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregationBui
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilter;
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilters;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoHashGridAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileGridAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.geogrid.ParsedGeoHashGrid;
import org.elasticsearch.search.aggregations.bucket.geogrid.ParsedGeoTileGrid;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileGridAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.global.GlobalAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.global.ParsedGlobal;
import org.elasticsearch.search.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder;
@ -428,7 +428,7 @@ public class RestHighLevelClient implements Closeable {
}
/**
* Provides methods for accessing the Elastic Licensed Licensing APIs that
* Provides methods for accessing the Elastic Licensed Migration APIs that
* are shipped with the default distribution of Elasticsearch. All of
* these APIs will 404 if run against the OSS distribution of Elasticsearch.
* <p>

View File

@ -1,75 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.migration;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.TimedRequest;
import org.elasticsearch.common.Strings;
import java.util.Arrays;
import java.util.Objects;
/**
* A request for retrieving upgrade information
* Part of Migration API
*/
public class IndexUpgradeInfoRequest extends TimedRequest implements IndicesRequest.Replaceable {
private String[] indices = Strings.EMPTY_ARRAY;
private IndicesOptions indicesOptions = IndicesOptions.fromOptions(false, true, true, true);
public IndexUpgradeInfoRequest(String... indices) {
indices(indices);
}
@Override
public String[] indices() {
return indices;
}
@Override
public IndexUpgradeInfoRequest indices(String... indices) {
this.indices = Objects.requireNonNull(indices, "indices cannot be null");
return this;
}
@Override
public IndicesOptions indicesOptions() {
return indicesOptions;
}
public void indicesOptions(IndicesOptions indicesOptions) {
this.indicesOptions = indicesOptions;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IndexUpgradeInfoRequest request = (IndexUpgradeInfoRequest) o;
return Arrays.equals(indices, request.indices) &&
Objects.equals(indicesOptions.toString(), request.indicesOptions.toString());
}
@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(indices), indicesOptions.toString());
}
}

View File

@ -1,96 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.migration;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
/**
* Response object that contains information about indices to be upgraded
*/
public class IndexUpgradeInfoResponse {
private static final ParseField INDICES = new ParseField("indices");
private static final ParseField ACTION_REQUIRED = new ParseField("action_required");
private static final ConstructingObjectParser<IndexUpgradeInfoResponse, String> PARSER =
new ConstructingObjectParser<>("IndexUpgradeInfoResponse",
true,
(a, c) -> {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>)a[0];
Map<String, UpgradeActionRequired> actionsRequired = map.entrySet().stream()
.filter(e -> {
if (e.getValue() instanceof Map == false) {
return false;
}
@SuppressWarnings("unchecked")
Map<String, Object> value =(Map<String, Object>)e.getValue();
return value.containsKey(ACTION_REQUIRED.getPreferredName());
})
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> {
@SuppressWarnings("unchecked")
Map<String, Object> value = (Map<String, Object>) e.getValue();
return UpgradeActionRequired.fromString((String)value.get(ACTION_REQUIRED.getPreferredName()));
}
));
return new IndexUpgradeInfoResponse(actionsRequired);
});
static {
PARSER.declareObject(constructorArg(), (p, c) -> p.map(), INDICES);
}
private final Map<String, UpgradeActionRequired> actions;
public IndexUpgradeInfoResponse(Map<String, UpgradeActionRequired> actions) {
this.actions = actions;
}
public Map<String, UpgradeActionRequired> getActions() {
return actions;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IndexUpgradeInfoResponse response = (IndexUpgradeInfoResponse) o;
return Objects.equals(actions, response.actions);
}
@Override
public int hashCode() {
return Objects.hash(actions);
}
public static IndexUpgradeInfoResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
}

View File

@ -1,53 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.migration;
import org.elasticsearch.client.Validatable;
import java.util.Objects;
/**
* A request for performing Upgrade on Index
* Part of Migration API
*/
public class IndexUpgradeRequest implements Validatable {
private String index;
public IndexUpgradeRequest(String index) {
this.index = index;
}
public String index() {
return index;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IndexUpgradeRequest request = (IndexUpgradeRequest) o;
return Objects.equals(index, request.index);
}
@Override
public int hashCode() {
return Objects.hash(index);
}
}

View File

@ -1,41 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.migration;
import java.util.Locale;
/**
* Indicates the type of the upgrade required for the index
*/
public enum UpgradeActionRequired {
NOT_APPLICABLE, // Indicates that the check is not applicable to this index type, the next check will be performed
UP_TO_DATE, // Indicates that the check finds this index to be up to date - no additional checks are required
REINDEX, // The index should be reindex
UPGRADE; // The index should go through the upgrade procedure
public static UpgradeActionRequired fromString(String value) {
return UpgradeActionRequired.valueOf(value.toUpperCase(Locale.ROOT));
}
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}

View File

@ -19,12 +19,8 @@
package org.elasticsearch.client;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.DeprecationInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeRequest;
import org.elasticsearch.client.tasks.TaskSubmissionResponse;
import org.elasticsearch.common.settings.Settings;
@ -32,51 +28,10 @@ import java.io.IOException;
import java.util.Collections;
import java.util.function.BooleanSupplier;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
public class MigrationIT extends ESRestHighLevelClientTestCase {
public void testGetAssistance() throws IOException {
{
IndexUpgradeInfoResponse response = highLevelClient().migration()
.getAssistance(new IndexUpgradeInfoRequest(), RequestOptions.DEFAULT);
assertEquals(0, response.getActions().size());
}
{
createIndex("test", Settings.EMPTY);
IndexUpgradeInfoResponse response = highLevelClient().migration().getAssistance(
new IndexUpgradeInfoRequest("test"), RequestOptions.DEFAULT);
assertEquals(0, response.getActions().size());
}
}
public void testUpgradeWhenIndexCannotBeUpgraded() throws IOException {
createIndex("test", Settings.EMPTY);
ThrowingRunnable execute = () -> execute(new IndexUpgradeRequest("test"),
highLevelClient().migration()::upgrade,
highLevelClient().migration()::upgradeAsync);
ElasticsearchStatusException responseException = expectThrows(ElasticsearchStatusException.class, execute);
assertThat(responseException.getDetailedMessage(), containsString("cannot be upgraded"));
}
public void testUpgradeWithTaskApi() throws IOException, InterruptedException {
createIndex("test", Settings.EMPTY);
IndexUpgradeRequest request = new IndexUpgradeRequest("test");
TaskSubmissionResponse upgrade = highLevelClient().migration()
.submitUpgradeTask(request, RequestOptions.DEFAULT);
assertNotNull(upgrade.getTask());
BooleanSupplier hasUpgradeCompleted = checkCompletionStatus(upgrade);
awaitBusy(hasUpgradeCompleted);
}
public void testGetDeprecationInfo() throws IOException {
createIndex("test", Settings.EMPTY);
DeprecationInfoRequest request = new DeprecationInfoRequest(Collections.singletonList("test"));

View File

@ -20,9 +20,7 @@
package org.elasticsearch.client;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeRequest;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.test.ESTestCase;
import java.util.HashMap;
@ -30,37 +28,16 @@ import java.util.Map;
public class MigrationRequestConvertersTests extends ESTestCase {
public void testGetMigrationAssistance() {
IndexUpgradeInfoRequest upgradeInfoRequest = new IndexUpgradeInfoRequest();
String expectedEndpoint = "/_migration/assistance";
if (randomBoolean()) {
String[] indices = RequestConvertersTests.randomIndicesNames(1, 5);
upgradeInfoRequest.indices(indices);
expectedEndpoint += "/" + String.join(",", indices);
}
public void testGetDeprecationInfo() {
DeprecationInfoRequest deprecationInfoRequest = new DeprecationInfoRequest();
String expectedEndpoint = "/_migration/deprecations";
Map<String, String> expectedParams = new HashMap<>();
RequestConvertersTests.setRandomIndicesOptions(upgradeInfoRequest::indicesOptions, upgradeInfoRequest::indicesOptions,
expectedParams);
Request request = MigrationRequestConverters.getMigrationAssistance(upgradeInfoRequest);
Request request = MigrationRequestConverters.getDeprecationInfo(deprecationInfoRequest);
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
assertEquals(expectedEndpoint, request.getEndpoint());
assertNull(request.getEntity());
assertEquals(expectedParams, request.getParameters());
}
public void testUpgradeRequest() {
String[] indices = RequestConvertersTests.randomIndicesNames(1, 1);
IndexUpgradeRequest upgradeInfoRequest = new IndexUpgradeRequest(indices[0]);
String expectedEndpoint = "/_migration/upgrade/" + indices[0];
Map<String, String> expectedParams = new HashMap<>();
expectedParams.put("wait_for_completion", Boolean.TRUE.toString());
Request request = MigrationRequestConverters.migrate(upgradeInfoRequest);
assertEquals(HttpPost.METHOD_NAME, request.getMethod());
assertEquals(expectedEndpoint, request.getEndpoint());
assertNull(request.getEntity());
assertEquals(expectedParams, request.getParameters());
}
}

View File

@ -19,23 +19,14 @@
package org.elasticsearch.client.documentation;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.LatchedActionListener;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.DeprecationInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeRequest;
import org.elasticsearch.client.migration.UpgradeActionRequired;
import org.elasticsearch.client.tasks.TaskSubmissionResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import java.io.IOException;
import java.util.ArrayList;
@ -44,10 +35,6 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
/**
* This class is used to generate the Java Migration API documentation.
* You need to wrap your code between two tags like:
@ -68,98 +55,6 @@ import static org.hamcrest.Matchers.not;
*/
public class MigrationClientDocumentationIT extends ESRestHighLevelClientTestCase {
public void testGetAssistance() throws IOException {
RestHighLevelClient client = highLevelClient();
// tag::get-assistance-request
IndexUpgradeInfoRequest request = new IndexUpgradeInfoRequest(); // <1>
// end::get-assistance-request
// tag::get-assistance-request-indices
request.indices("index1", "index2"); // <1>
// end::get-assistance-request-indices
request.indices(Strings.EMPTY_ARRAY);
// tag::get-assistance-request-indices-options
request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
// end::get-assistance-request-indices-options
// tag::get-assistance-execute
IndexUpgradeInfoResponse response = client.migration().getAssistance(request, RequestOptions.DEFAULT);
// end::get-assistance-execute
// tag::get-assistance-response
Map<String, UpgradeActionRequired> actions = response.getActions();
for (Map.Entry<String, UpgradeActionRequired> entry : actions.entrySet()) {
String index = entry.getKey(); // <1>
UpgradeActionRequired actionRequired = entry.getValue(); // <2>
}
// end::get-assistance-response
}
public void testUpgrade() throws IOException {
RestHighLevelClient client = highLevelClient();
createIndex("test", Settings.EMPTY);
// tag::upgrade-request
IndexUpgradeRequest request = new IndexUpgradeRequest("test"); // <1>
// end::upgrade-request
try {
// tag::upgrade-execute
BulkByScrollResponse response = client.migration().upgrade(request, RequestOptions.DEFAULT);
// end::upgrade-execute
} catch (ElasticsearchStatusException e) {
assertThat(e.getMessage(), containsString("cannot be upgraded"));
}
}
public void testUpgradeAsync() throws IOException, InterruptedException {
RestHighLevelClient client = highLevelClient();
createIndex("test", Settings.EMPTY);
final CountDownLatch latch = new CountDownLatch(1);
// tag::upgrade-async-listener
ActionListener<BulkByScrollResponse> listener = new ActionListener<BulkByScrollResponse>() {
@Override
public void onResponse(BulkByScrollResponse bulkResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::upgrade-async-listener
listener = new LatchedActionListener<>(listener, latch);
// tag::upgrade-async-execute
client.migration().upgradeAsync(new IndexUpgradeRequest("test"), RequestOptions.DEFAULT, listener); // <1>
// end::upgrade-async-execute
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
public void testUpgradeWithTaskApi() throws IOException {
createIndex("test", Settings.EMPTY);
RestHighLevelClient client = highLevelClient();
// tag::upgrade-task-api
IndexUpgradeRequest request = new IndexUpgradeRequest("test");
TaskSubmissionResponse response = client.migration()
.submitUpgradeTask(request, RequestOptions.DEFAULT);
String taskId = response.getTask();
// end::upgrade-task-api
assertThat(taskId, not(isEmptyOrNullString()));
}
public void testGetDeprecationInfo() throws IOException, InterruptedException {
RestHighLevelClient client = highLevelClient();
createIndex("test", Settings.EMPTY);

View File

@ -1,30 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.migration;
import org.elasticsearch.test.ESTestCase;
public class IndexUpgradeInfoRequestTests extends ESTestCase {
public void testNullIndices() {
expectThrows(NullPointerException.class, () -> new IndexUpgradeInfoRequest((String[])null));
expectThrows(NullPointerException.class, () -> new IndexUpgradeInfoRequest().indices((String[])null));
}
}

View File

@ -1,49 +0,0 @@
[[java-rest-high-migration-get-assistance]]
=== Migration Get Assistance
[[java-rest-high-migration-get-assistance-request]]
==== Index Upgrade Info Request
An `IndexUpgradeInfoRequest` does not require any argument:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MigrationClientDocumentationIT.java[get-assistance-request]
--------------------------------------------------
<1> Create a new request instance
==== Optional arguments
The following arguments can optionally be provided:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MigrationClientDocumentationIT.java[get-assistance-request-indices]
--------------------------------------------------
<1> Set the indices to the request
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MigrationClientDocumentationIT.java[get-assistance-request-indices-options]
--------------------------------------------------
<1> Set the `IndicesOptions` to control how unavailable indices are resolved and
how wildcard expressions are expanded
[[java-rest-high-migration-get-assistance-execution]]
==== Execution
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MigrationClientDocumentationIT.java[get-assistance-execute]
--------------------------------------------------
[[java-rest-high-migration-get-assistance-response]]
==== Response
The returned `IndexUpgradeInfoResponse` contains the actions required for each index.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/MigrationClientDocumentationIT.java[get-assistance-response]
--------------------------------------------------
<1> Retrieve the index
<2> Retrieve the action required for the migration of the current index

View File

@ -1,74 +0,0 @@
--
:api: upgrade
:request: IndexUpgradeRequest
:response: BulkByScrollResponse
:submit_response: IndexUpgradeSubmissionResponse
--
[[java-rest-high-migration-upgrade]]
=== Migration Upgrade
[[java-rest-high-migration-upgrade-request]]
==== Index Upgrade Request
An +{request}+ requires an index argument. Only one index at the time should be upgraded:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request]
--------------------------------------------------
<1> Create a new request instance
[[java-rest-high-migration-upgrade-execution]]
==== Execution
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-execute]
--------------------------------------------------
[[java-rest-high-migration-upgrade-response]]
==== Response
The returned +{response}+ contains information about the executed operation
[[java-rest-high-migration-async-upgrade-request]]
==== Asynchronous Execution
The asynchronous execution of an upgrade request requires both the +{request}+
instance and an `ActionListener` instance to be passed to the asynchronous
method:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-async-listener]
--------------------------------------------------
<1> Called when the execution is successfully completed. The response is
provided as an argument and contains a list of individual results for each
operation that was executed. Note that one or more operations might have
failed while the others have been successfully executed.
<2> Called when the whole +{request}+ fails. In this case the raised
exception is provided as an argument and no operation has been executed.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-async-execute]
--------------------------------------------------
<1> The +{request}+ 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.
=== Migration Upgrade with Task API
Submission of upgrade request task will requires the +{request}+ and will return
+{submit_response}+. The +{submit_response}+ can later be use to fetch
TaskId and query the Task API for results.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-task-api]
--------------------------------------------------

View File

@ -348,12 +348,8 @@ include::ml/set-upgrade-mode.asciidoc[]
The Java High Level REST Client supports the following Migration APIs:
* <<java-rest-high-migration-get-assistance>>
* <<{upid}-upgrade>>
* <<{upid}-get-deprecation-info>>
include::migration/get-assistance.asciidoc[]
include::migration/upgrade.asciidoc[]
include::migration/get-deprecation-info.asciidoc[]
== Rollup APIs

View File

@ -1,95 +0,0 @@
[role="xpack"]
[testenv="basic"]
[[migration-api-assistance]]
=== Migration assistance API
++++
<titleabbrev>Migration assistance</titleabbrev>
++++
The Migration Assistance API analyzes existing indices in the cluster and
returns the information about indices that require some changes before the
cluster can be upgraded to the next major version.
[float]
==== Request
`GET /_migration/assistance` +
`GET /_migration/assistance/<index_name>`
//==== Description
[float]
==== Path Parameters
`index_name`::
(string) Identifier for the index. It can be an index name or a wildcard
expression.
//==== Query Parameters
//==== Authorization
[float]
==== Examples
To see a list of indices that needs to be upgraded or reindexed, submit a GET
request to the `/_migration/assistance` endpoint:
[source,js]
--------------------------------------------------
GET /_migration/assistance
--------------------------------------------------
// CONSOLE
// TEST[skip:cannot create an old index in docs test]
A successful call returns a list of indices that need to be updated or reindexed:
[source,js]
--------------------------------------------------
{
"indices" : {
".watches" : {
"action_required" : "upgrade"
},
".security" : {
"action_required" : "upgrade"
},
"my_old_index": {
"action_required" : "reindex"
},
"my_other_old_index": {
"action_required" : "reindex"
}
}
}
--------------------------------------------------
// NOTCONSOLE
To check a particular index or set of indices, specify this index name or mask
as the last part of the `/_migration/assistance/index_name` endpoint:
[source,js]
--------------------------------------------------
GET /_migration/assistance/my_*
--------------------------------------------------
// CONSOLE
// TEST[skip:cannot create an old index in docs test]
A successful call returns a list of indices that needs to be updated or reindexed
and match the index specified on the endpoint:
[source,js]
--------------------------------------------------
{
"indices" : {
"my_old_index": {
"action_required" : "reindex"
},
"my_other_old_index": {
"action_required" : "reindex"
}
}
}
--------------------------------------------------
// NOTCONSOLE

View File

@ -1,142 +0,0 @@
[role="xpack"]
[testenv="basic"]
[[migration-api-upgrade]]
=== Migration upgrade API
++++
<titleabbrev>Migration upgrade</titleabbrev>
++++
The Migration Upgrade API performs the upgrade of internal indices to make them
compatible with the next major version.
[float]
==== Request
`POST /_migration/upgrade/<index_name>`
[float]
==== Description
Indices must be upgraded one at a time.
[float]
==== Path Parameters
`index_name`::
(string) Identifier for the index.
`wait_for_completion`::
(boolean) Defines whether the upgrade call blocks until the upgrade process is
finished. The default value is `true`. If set to `false`, the upgrade can be
performed asynchronously.
//==== Query Parameters
//==== Authorization
[float]
==== Examples
The following example submits a POST request to the
`/_migration/upgrade/<index_name>` endpoint:
[source,js]
--------------------------------------------------
POST /_migration/upgrade/.watches
--------------------------------------------------
// CONSOLE
// TEST[skip:cannot create an old index in docs test]
A successful call returns the statistics about the upgrade process:
[source,js]
--------------------------------------------------
{
"took" : 127,
"timed_out" : false,
"total" : 4,
"updated" : 0,
"created" : 4,
"deleted" : 0,
"batches" : 1,
"version_conflicts" : 0,
"noops" : 0,
"retries" : {
"bulk" : 0,
"search" : 0
},
"throttled_millis" : 0,
"failures" : [ ]
}
--------------------------------------------------
// NOTCONSOLE
The following example upgrades a large index asynchronously by specifying the
`wait_for_completion` parameter:
[source,js]
--------------------------------------------------
POST /_migration/upgrade/.watches?wait_for_completion=false
--------------------------------------------------
// CONSOLE
// TEST[skip:cannot create an old index in docs test]
This call should return the id of the upgrade process task:
[source,js]
--------------------------------------------------
{
"task" : "PFvgv7T6TGumRyFF3vqTFg:1137"
}
--------------------------------------------------
// NOTCONSOLE
The status of the running or finished upgrade requests can be obtained by using
the <<tasks,Task API>>:
[source,js]
--------------------------------------------------
GET _tasks/PFvgv7T6TGumRyFF3vqTFg:1137?detailed=true
--------------------------------------------------
// CONSOLE
// TEST[skip:cannot create an old index in docs test]
[source,js]
--------------------------------------------------
{
"completed" : true, <1>
"task" : {
"node" : "PFvgv7T6TGumRyFF3vqTFg",
"id" : 1137,
"type" : "transport",
"action" : "cluster:admin/xpack/upgrade",
"description" : "",
"start_time_in_millis" : 1500650625413,
"running_time_in_nanos" : 947456819,
"cancellable" : true
},
"response" : { <2>
"took" : 212,
"timed_out" : false,
"total" : 4,
"updated" : 0,
"created" : 4,
"deleted" : 0,
"batches" : 1,
"version_conflicts" : 0,
"noops" : 0,
"retries" : {
"bulk" : 0,
"search" : 0
},
"throttled_millis" : 0,
"failures" : [ ]
}
}
--------------------------------------------------
// NOTCONSOLE
<1> If the `completed` field value is `true`, the upgrade request has finished.
If it is `false`, the request is still running.
<2> The `response` field contains the status of the upgrade request.

View File

@ -5,10 +5,6 @@
The migration APIs simplify upgrading {xpack} indices from one version to another.
* <<migration-api-assistance>>
* <<migration-api-upgrade>>
* <<migration-api-deprecation>>
include::apis/assistance.asciidoc[]
include::apis/upgrade.asciidoc[]
include::apis/deprecation.asciidoc[]

View File

@ -16,6 +16,19 @@ command line option to <<setup-installation-daemon,write the PID to a file>>.
The `_upgrade` API is no longer useful and will be removed. Instead, see
<<reindex-upgrade>>.
[role="exclude",id="migration-api-assistance"]
=== Migration Assistance API
The Migration Assistance API has been replaced with the
<<migration-api-deprecation, Deprecation Info API>>.
[role="exclude",id="migration-api-upgrade"]
=== Migration Upgrade API
The Migration Upgrade API has been removed. Use the
{kibana-ref}/upgrade-assistant.html[{kib} Upgrade Assistant] or
<<reindex-upgrade,Reindex manually>> instead.
[role="exclude",id="docs-bulk-udp"]
=== Bulk UDP API

View File

@ -38,6 +38,5 @@ subprojects {
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-monitoring:${version}": xpackModule('monitoring')]
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-security:${version}": xpackModule('security')]
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-sql:${version}": xpackModule('sql')]
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-upgrade:${version}": xpackModule('upgrade')]
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-watcher:${version}": xpackModule('watcher')]
}

View File

@ -1,13 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.upgrade;
public final class IndexUpgradeCheckVersion {
public static final int UPGRADE_VERSION = 6;
private IndexUpgradeCheckVersion() {}
}

View File

@ -10,7 +10,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
public final class UpgradeField {
// this is the required index.format setting for 6.0 services (watcher and security) to start up
// this index setting is set by the upgrade API or automatically when a 6.0 index template is created
private static final int EXPECTED_INDEX_FORMAT_VERSION = 6;
public static final int EXPECTED_INDEX_FORMAT_VERSION = 6;
private UpgradeField() {}

View File

@ -1,36 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.protocol.xpack.migration;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
public class IndexUpgradeInfoRequestTests extends AbstractWireSerializingTestCase<IndexUpgradeInfoRequest> {
@Override
protected IndexUpgradeInfoRequest createTestInstance() {
int indexCount = randomInt(4);
String[] indices = new String[indexCount];
for (int i = 0; i < indexCount; i++) {
indices[i] = randomAlphaOfLength(10);
}
IndexUpgradeInfoRequest request = new IndexUpgradeInfoRequest(indices);
if (randomBoolean()) {
request.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()));
}
return request;
}
@Override
protected Writeable.Reader<IndexUpgradeInfoRequest> instanceReader() {
return IndexUpgradeInfoRequest::new;
}
public void testNullIndices() {
expectThrows(NullPointerException.class, () -> new IndexUpgradeInfoRequest((String[])null));
expectThrows(NullPointerException.class, () -> new IndexUpgradeInfoRequest().indices((String[])null));
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.protocol.xpack.migration;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
public class IndexUpgradeInfoResponseTests extends
AbstractHlrcStreamableXContentTestCase<IndexUpgradeInfoResponse, org.elasticsearch.client.migration.IndexUpgradeInfoResponse> {
@Override
public org.elasticsearch.client.migration.IndexUpgradeInfoResponse doHlrcParseInstance(XContentParser parser) {
return org.elasticsearch.client.migration.IndexUpgradeInfoResponse.fromXContent(parser);
}
@Override
public IndexUpgradeInfoResponse convertHlrcToInternal(org.elasticsearch.client.migration.IndexUpgradeInfoResponse instance) {
final Map<String, org.elasticsearch.client.migration.UpgradeActionRequired> actions = instance.getActions();
return new IndexUpgradeInfoResponse(actions.entrySet().stream().map(
e -> new AbstractMap.SimpleEntry<>(e.getKey(), UpgradeActionRequired.valueOf(e.getValue().name()))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
@Override
protected IndexUpgradeInfoResponse createBlankInstance() {
return new IndexUpgradeInfoResponse();
}
@Override
protected IndexUpgradeInfoResponse createTestInstance() {
return randomIndexUpgradeInfoResponse(randomIntBetween(0, 10));
}
private static IndexUpgradeInfoResponse randomIndexUpgradeInfoResponse(int numIndices) {
Map<String, UpgradeActionRequired> actions = new HashMap<>();
for (int i = 0; i < numIndices; i++) {
actions.put(randomAlphaOfLength(5), randomFrom(UpgradeActionRequired.values()));
}
return new IndexUpgradeInfoResponse(actions);
}
@Override
protected IndexUpgradeInfoResponse mutateInstance(IndexUpgradeInfoResponse instance) {
if (instance.getActions().size() == 0) {
return randomIndexUpgradeInfoResponse(1);
}
Map<String, UpgradeActionRequired> actions = new HashMap<>(instance.getActions());
if (randomBoolean()) {
Iterator<Map.Entry<String, UpgradeActionRequired>> iterator = actions.entrySet().iterator();
iterator.next();
iterator.remove();
} else {
actions.put(randomAlphaOfLength(5), randomFrom(UpgradeActionRequired.values()));
}
return new IndexUpgradeInfoResponse(actions);
}
}

View File

@ -1,35 +0,0 @@
{
"migration.get_assistance": {
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-assistance.html",
"methods": [ "GET" ],
"url": {
"path": "/_migration/assistance",
"paths": [
"/_migration/assistance",
"/_migration/assistance/{index}"
],
"parts": {
"index": {
"type" : "list",
"description" : "A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices"
}
},
"params": {
"allow_no_indices": {
"type" : "boolean",
"description" : "Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)"
},
"expand_wildcards": {
"type" : "enum",
"options" : ["open","closed","none","all"],
"default" : "open",
"description" : "Whether to expand wildcard expression to concrete indices that are open, closed or both."
},
"ignore_unavailable": {
"type" : "boolean",
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"
}
}
}
}
}

View File

@ -1,26 +0,0 @@
{
"migration.upgrade": {
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-upgrade.html",
"methods": [ "POST" ],
"url": {
"path": "/_migration/upgrade/{index}",
"paths": [
"/_migration/upgrade/{index}"
],
"parts": {
"index": {
"type" : "string",
"required" : true,
"description" : "The name of the index"
}
},
"params": {
"wait_for_completion": {
"type" : "boolean",
"default": true,
"description" : "Should the request block until the upgrade operation is completed"
}
}
}
}
}

View File

@ -1,60 +0,0 @@
---
setup:
- do:
license.post:
body: >
{
"license": {
"uid": "b8520184-985d-4b04-8a89-b52da6e0aad1",
"type": "platinum",
"issue_date_in_millis": 1494510840000,
"expiry_date_in_millis": 2756814840000,
"max_nodes": 1,
"issued_to": "upgrade_api_test",
"issuer": "elasticsearch",
"signature": "AAAAAwAAAA0hsB+mfk9EqWiY6e1KAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQA6NkNF3Z219ptzRwZwGzgIwaXn5rXvOWSB9KK86xBqeYQMlO1ahCd4eW3FHWTuginPuqMX8okzN+UEMANPE3l0QxvrgCcTzNYPGqCJDwBb0ghuQ4Y5Cezn806sBnXLVF35B1HU2C1PYc1mZvisD63NqasrAVYb3GS6vwq8a7PYfKpfZfFCqG2SZIkSHACPGBTUiPbVEVv1iiOC04x/pjF4Kn26MPbFD5jbQBSY2V8TxoapMHf11EDpOTlMYkXgerbMg7VWtVCypTMJJrhoVguCrZvM8U/+sSnbodtnZUeAImnFbYeV10Rcw62dtrpka0yuo7h6Qtrvy9YqVHZDtyrM",
"start_date_in_millis": -1
}
}
- do:
indices.create:
index: test1
- do:
indices.refresh: {}
---
"Upgrade info - all":
- do:
migration.get_assistance: { index: _all }
- length: { indices: 0 }
---
"Upgrade test - should fail as index is already up to date":
- do:
catch: /illegal_state_exception/
migration.upgrade: { index: test1 }
---
"Upgrade test - wait_for_completion:false":
- do:
migration.upgrade:
index: test1
wait_for_completion: false
- match: {task: '/.+:\d+/'}
- set: {task: task}
- do:
tasks.get:
wait_for_completion: true
task_id: $task
- is_false: node_failures
- is_true: task
- match: {completed: true}
- is_true: error
- match: {error.type: "illegal_state_exception"}
- match: {error.reason: "Index [test1] cannot be upgraded"}

View File

@ -24,5 +24,4 @@
- contains: { nodes.$master.modules: { name: x-pack-rollup } }
- contains: { nodes.$master.modules: { name: x-pack-security } }
- contains: { nodes.$master.modules: { name: x-pack-sql } }
- contains: { nodes.$master.modules: { name: x-pack-upgrade } }
- contains: { nodes.$master.modules: { name: x-pack-watcher } }

View File

@ -1,45 +0,0 @@
import com.carrotsearch.gradle.junit4.RandomizedTestingTask
evaluationDependsOn(xpackModule('core'))
apply plugin: 'elasticsearch.esplugin'
esplugin {
name 'x-pack-upgrade'
description 'Elasticsearch Expanded Pack Plugin - Upgrade'
classname 'org.elasticsearch.xpack.upgrade.Upgrade'
extendedPlugins = ['x-pack-core']
}
archivesBaseName = 'x-pack-upgrade'
dependencies {
// "org.elasticsearch.plugin:x-pack-core:${version}" doesn't work with idea because the testArtifacts are also here
compileOnly project(path: xpackModule('core'), configuration: 'default')
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
}
compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
run {
plugin xpackModule('core')
}
integTest.enabled = false
// Instead we create a separate task to run the
// tests based on ESIntegTestCase
task internalClusterTest(type: RandomizedTestingTask,
group: JavaBasePlugin.VERIFICATION_GROUP,
description: 'Multi-node tests',
dependsOn: unitTest.dependsOn) {
include '**/*IT.class'
systemProperty 'es.set.netty.runtime.available.processors', 'false'
}
check.dependsOn internalClusterTest
internalClusterTest.mustRunAfter test
// also add an "alias" task to make typing on the command line easier
task icTest {
dependsOn internalClusterTest
}

View File

@ -1,126 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider.Allocation;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.script.Script;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.xpack.core.upgrade.IndexUpgradeCheckVersion;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* Generic upgrade check applicable to all indices to be upgraded from the current version
* to the next major version
* <p>
* The upgrade is performed in the following way:
* <p>
* - preUpgrade method is called
* - reindex is performed
* - postUpgrade is called if reindex was successful
*/
public class IndexUpgradeCheck<T> {
private final String name;
private final Function<IndexMetaData, UpgradeActionRequired> actionRequired;
private final InternalIndexReindexer<T> reindexer;
/**
* Creates a new upgrade check
*
* @param name - the name of the check
* @param actionRequired - return true if they can work with the index with specified name
* @param client - client
* @param clusterService - cluster service
* @param types - a list of types that the reindexing should be limited to
* @param updateScript - the upgrade script that should be used during reindexing
*/
public IndexUpgradeCheck(String name,
Function<IndexMetaData, UpgradeActionRequired> actionRequired,
Client client, ClusterService clusterService, String[] types, Script updateScript) {
this(name, actionRequired, client, clusterService, types, updateScript,
(cs, listener) -> {
Allocation clusterRoutingAllocation = EnableAllocationDecider.CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING
.get(cs.getMetaData().settings());
if (Allocation.NONE == clusterRoutingAllocation) {
listener.onFailure(new ElasticsearchException(
"pre-upgrade check failed, please enable cluster routing allocation using setting [{}]",
EnableAllocationDecider.CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING.getKey()));
} else {
listener.onResponse(null);
}
}, (t, listener) -> listener.onResponse(TransportResponse.Empty.INSTANCE));
}
/**
* Creates a new upgrade check
*
* @param name - the name of the check
* @param actionRequired - return true if they can work with the index with specified name
* @param client - client
* @param clusterService - cluster service
* @param types - a list of types that the reindexing should be limited to
* @param updateScript - the upgrade script that should be used during reindexing
* @param preUpgrade - action that should be performed before upgrade
* @param postUpgrade - action that should be performed after upgrade
*/
public IndexUpgradeCheck(String name,
Function<IndexMetaData, UpgradeActionRequired> actionRequired,
Client client, ClusterService clusterService, String[] types, Script updateScript,
BiConsumer<ClusterState, ActionListener<T>> preUpgrade,
BiConsumer<T, ActionListener<TransportResponse.Empty>> postUpgrade) {
this.name = name;
this.actionRequired = actionRequired;
this.reindexer = new InternalIndexReindexer<>(client, clusterService, IndexUpgradeCheckVersion.UPGRADE_VERSION, updateScript,
types, preUpgrade, postUpgrade);
}
/**
* Returns the name of the check
*/
public String getName() {
return name;
}
/**
* This method is called by Upgrade API to verify if upgrade or reindex for this index is required
*
* @param indexMetaData index metadata
* @return required action or UpgradeActionRequired.NOT_APPLICABLE if this check cannot be performed on the index
*/
public UpgradeActionRequired actionRequired(IndexMetaData indexMetaData) {
return actionRequired.apply(indexMetaData);
}
/**
* Perform the index upgrade
*
* @param task the task that executes the upgrade operation
* @param indexMetaData index metadata
* @param state current cluster state
* @param listener the listener that should be called upon completion of the upgrade
*/
public void upgrade(TaskId task, IndexMetaData indexMetaData, ClusterState state,
ActionListener<BulkByScrollResponse> listener) {
reindexer.upgrade(task, indexMetaData.getIndex().getName(), state, listener);
}
// pkg scope for testing
InternalIndexReindexer getInternalIndexReindexer() {
return reindexer;
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.service.ClusterService;
import java.util.Collection;
import java.util.Collections;
/**
* Factory for index checks
*/
public interface IndexUpgradeCheckFactory {
/**
* Using this method the check can expose additional user parameter that can be specified by the user on upgrade api
*
* @return the list of supported parameters
*/
default Collection<String> supportedParams() {
return Collections.emptyList();
}
/**
* Creates an upgrade check
* <p>
* This method is called from {@link org.elasticsearch.plugins.Plugin#createComponents} method.
*/
IndexUpgradeCheck createCheck(Client client, ClusterService clusterService);
}

View File

@ -1,118 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.tasks.TaskId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class IndexUpgradeService {
private static final Logger logger = LogManager.getLogger(IndexUpgradeService.class);
private final List<IndexUpgradeCheck> upgradeChecks;
private final IndexNameExpressionResolver indexNameExpressionResolver;
public IndexUpgradeService(List<IndexUpgradeCheck> upgradeChecks) {
this.upgradeChecks = upgradeChecks;
this.indexNameExpressionResolver = new IndexNameExpressionResolver();
}
/**
* Returns the information about required upgrade action for the given indices
*
* @param indices list of indices to check, specify _all for all indices
* @param options wild card resolution option
* @param state the current cluster state
* @return a list of indices that should be upgraded/reindexed
*/
public Map<String, UpgradeActionRequired> upgradeInfo(String[] indices, IndicesOptions options, ClusterState state) {
Map<String, UpgradeActionRequired> results = new HashMap<>();
String[] concreteIndexNames = indexNameExpressionResolver.concreteIndexNames(state, options, indices);
MetaData metaData = state.getMetaData();
for (String index : concreteIndexNames) {
IndexMetaData indexMetaData = metaData.index(index);
UpgradeActionRequired upgradeActionRequired = upgradeInfo(indexMetaData, index);
if (upgradeActionRequired != null) {
results.put(index, upgradeActionRequired);
}
}
return results;
}
private UpgradeActionRequired upgradeInfo(IndexMetaData indexMetaData, String index) {
for (IndexUpgradeCheck check : upgradeChecks) {
UpgradeActionRequired upgradeActionRequired = check.actionRequired(indexMetaData);
logger.trace("[{}] check [{}] returned [{}]", index, check.getName(), upgradeActionRequired);
switch (upgradeActionRequired) {
case UPGRADE:
case REINDEX:
// this index needs to be upgraded or reindexed - skipping all other checks
return upgradeActionRequired;
case UP_TO_DATE:
// this index is good - skipping all other checks
return null;
case NOT_APPLICABLE:
// this action is not applicable to this index - skipping to the next one
break;
default:
throw new IllegalStateException("unknown upgrade action " + upgradeActionRequired + " for the index "
+ index);
}
}
// Catch all check for all indices that didn't match the specific checks
if (indexMetaData.getCreationVersion().before(Version.V_6_0_0)) {
return UpgradeActionRequired.REINDEX;
} else {
return null;
}
}
public void upgrade(TaskId task, String index, ClusterState state, ActionListener<BulkByScrollResponse> listener) {
IndexMetaData indexMetaData = state.metaData().index(index);
if (indexMetaData == null) {
throw new IndexNotFoundException(index);
}
for (IndexUpgradeCheck check : upgradeChecks) {
UpgradeActionRequired upgradeActionRequired = check.actionRequired(indexMetaData);
switch (upgradeActionRequired) {
case UPGRADE:
// this index needs to be upgraded - start the upgrade procedure
check.upgrade(task, indexMetaData, state, listener);
return;
case REINDEX:
// this index needs to be re-indexed
throw new IllegalStateException("Index [" + index + "] cannot be upgraded, it should be reindex instead");
case UP_TO_DATE:
throw new IllegalStateException("Index [" + index + "] cannot be upgraded, it is up to date");
case NOT_APPLICABLE:
// this action is not applicable to this index - skipping to the next one
break;
default:
throw new IllegalStateException("unknown upgrade action [" + upgradeActionRequired + "] for the index [" + index + "]");
}
}
throw new IllegalStateException("Index [" + index + "] cannot be upgraded");
}
}

View File

@ -1,210 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.ParentTaskAssigningClient;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.ReindexAction;
import org.elasticsearch.index.reindex.ReindexRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.transport.TransportResponse;
import java.util.function.BiConsumer;
import static org.elasticsearch.index.IndexSettings.same;
/**
* A component that performs the following upgrade procedure:
* <p>
* - Check that all data and master nodes are running running the same version
* - Create a new index .{name}-6
* - Make index .{name} read only
* - Reindex from .{name} to .{name}-6 with transform
* - Delete index .{name} and add alias .{name} to .{name}-6
*/
public class InternalIndexReindexer<T> {
private static final Logger logger = LogManager.getLogger(InternalIndexReindexer.class);
private final Client client;
private final ClusterService clusterService;
private final Script transformScript;
private final String[] types;
private final int version;
private final BiConsumer<ClusterState, ActionListener<T>> preUpgrade;
private final BiConsumer<T, ActionListener<TransportResponse.Empty>> postUpgrade;
public InternalIndexReindexer(Client client, ClusterService clusterService, int version, Script transformScript, String[] types,
BiConsumer<ClusterState,ActionListener<T>> preUpgrade,
BiConsumer<T, ActionListener<TransportResponse.Empty>> postUpgrade) {
this.client = client;
this.clusterService = clusterService;
this.transformScript = transformScript;
this.types = types;
this.version = version;
this.preUpgrade = preUpgrade;
this.postUpgrade = postUpgrade;
}
public void upgrade(TaskId task, String index, ClusterState clusterState, ActionListener<BulkByScrollResponse> listener) {
ParentTaskAssigningClient parentAwareClient = new ParentTaskAssigningClient(client, task);
preUpgrade.accept(clusterState, ActionListener.wrap(
t -> innerUpgrade(parentAwareClient, index, clusterState, ActionListener.wrap(
response -> postUpgrade.accept(t, ActionListener.wrap(
empty -> listener.onResponse(response),
listener::onFailure
)),
listener::onFailure
)),
listener::onFailure));
}
private void innerUpgrade(ParentTaskAssigningClient parentAwareClient, String index, ClusterState clusterState,
ActionListener<BulkByScrollResponse> listener) {
String newIndex = index + "-" + version;
logger.trace("upgrading index {} to new index {}", index, newIndex);
try {
checkMasterAndDataNodeVersion(clusterState);
parentAwareClient.admin().indices().prepareCreate(newIndex).execute(ActionListener.wrap(createIndexResponse -> {
setReadOnlyBlock(index, ActionListener.wrap(
setReadOnlyResponse -> reindex(parentAwareClient, index, newIndex, ActionListener.wrap(bulkByScrollResponse -> {
if ((bulkByScrollResponse.getBulkFailures() != null
&& bulkByScrollResponse.getBulkFailures().isEmpty() == false)
|| (bulkByScrollResponse.getSearchFailures() != null
&& bulkByScrollResponse.getSearchFailures().isEmpty() == false)) {
ElasticsearchException ex = logAndThrowExceptionForFailures(bulkByScrollResponse);
removeReadOnlyBlockOnReindexFailure(parentAwareClient, index, listener, ex);
} else {
// Successful completion of reindexing - remove read only and delete old index
removeReadOnlyBlock(parentAwareClient, index,
ActionListener.wrap(unsetReadOnlyResponse -> parentAwareClient.admin().indices().prepareAliases()
.removeIndex(index).addAlias(newIndex, index)
.execute(ActionListener.wrap(
deleteIndexResponse -> listener.onResponse(bulkByScrollResponse),
listener::onFailure)),
listener::onFailure));
}
}, e -> {
logger.error("error occurred while reindexing", e);
removeReadOnlyBlockOnReindexFailure(parentAwareClient, index, listener, e);
})), listener::onFailure));
}, listener::onFailure));
} catch (Exception ex) {
logger.error("error occurred while upgrading index", ex);
removeReadOnlyBlockOnReindexFailure(parentAwareClient, index, listener, ex);
listener.onFailure(ex);
}
}
private void removeReadOnlyBlockOnReindexFailure(ParentTaskAssigningClient parentAwareClient, String index,
ActionListener<BulkByScrollResponse> listener, Exception ex) {
removeReadOnlyBlock(parentAwareClient, index, ActionListener.wrap(unsetReadOnlyResponse -> {
listener.onFailure(ex);
}, e1 -> {
listener.onFailure(ex);
}));
}
private ElasticsearchException logAndThrowExceptionForFailures(BulkByScrollResponse bulkByScrollResponse) {
String bulkFailures = (bulkByScrollResponse.getBulkFailures() != null)
? Strings.collectionToCommaDelimitedString(bulkByScrollResponse.getBulkFailures())
: "";
String searchFailures = (bulkByScrollResponse.getSearchFailures() != null)
? Strings.collectionToCommaDelimitedString(bulkByScrollResponse.getSearchFailures())
: "";
logger.error("error occurred while reindexing, bulk failures [{}], search failures [{}]", bulkFailures, searchFailures);
return new ElasticsearchException("error occurred while reindexing, bulk failures [{}], search failures [{}]", bulkFailures,
searchFailures);
}
private void checkMasterAndDataNodeVersion(ClusterState clusterState) {
if (clusterState.nodes().getMinNodeVersion().before(Upgrade.UPGRADE_INTRODUCED)) {
throw new IllegalStateException("All nodes should have at least version [" + Upgrade.UPGRADE_INTRODUCED + "] to upgrade");
}
}
private void removeReadOnlyBlock(ParentTaskAssigningClient parentAwareClient, String index,
ActionListener<AcknowledgedResponse> listener) {
Settings settings = Settings.builder().put(IndexMetaData.INDEX_READ_ONLY_SETTING.getKey(), false).build();
parentAwareClient.admin().indices().prepareUpdateSettings(index).setSettings(settings).execute(listener);
}
private void reindex(ParentTaskAssigningClient parentAwareClient, String index, String newIndex,
ActionListener<BulkByScrollResponse> listener) {
ReindexRequest reindexRequest = new ReindexRequest();
reindexRequest.setSourceIndices(index);
reindexRequest.setSourceDocTypes(types);
reindexRequest.setDestIndex(newIndex);
reindexRequest.setRefresh(true);
reindexRequest.setScript(transformScript);
parentAwareClient.execute(ReindexAction.INSTANCE, reindexRequest, listener);
}
/**
* Makes the index readonly if it's not set as a readonly yet
*/
private void setReadOnlyBlock(String index, ActionListener<TransportResponse.Empty> listener) {
clusterService.submitStateUpdateTask("lock-index-for-upgrade", new ClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
final IndexMetaData indexMetaData = currentState.metaData().index(index);
if (indexMetaData == null) {
throw new IndexNotFoundException(index);
}
if (indexMetaData.getState() != IndexMetaData.State.OPEN) {
throw new IllegalStateException("unable to upgrade a closed index[" + index + "]");
}
if (currentState.blocks().hasIndexBlock(index, IndexMetaData.INDEX_READ_ONLY_BLOCK)) {
throw new IllegalStateException("unable to upgrade a read-only index[" + index + "]");
}
final Settings indexSettingsBuilder =
Settings.builder()
.put(indexMetaData.getSettings())
.put(IndexMetaData.INDEX_READ_ONLY_SETTING.getKey(), true)
.build();
final IndexMetaData.Builder builder = IndexMetaData.builder(indexMetaData).settings(indexSettingsBuilder);
assert same(indexMetaData.getSettings(), indexSettingsBuilder) == false;
builder.settingsVersion(1 + builder.settingsVersion());
MetaData.Builder metaDataBuilder = MetaData.builder(currentState.metaData()).put(builder);
ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(currentState.blocks())
.addIndexBlock(index, IndexMetaData.INDEX_READ_ONLY_BLOCK);
return ClusterState.builder(currentState).metaData(metaDataBuilder).blocks(blocks).build();
}
@Override
public void onFailure(String source, Exception e) {
listener.onFailure(e);
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
listener.onResponse(TransportResponse.Empty.INSTANCE);
}
});
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeInfoAction;
import org.elasticsearch.xpack.upgrade.actions.TransportIndexUpgradeAction;
import org.elasticsearch.xpack.upgrade.actions.TransportIndexUpgradeInfoAction;
import org.elasticsearch.xpack.upgrade.rest.RestIndexUpgradeAction;
import org.elasticsearch.xpack.upgrade.rest.RestIndexUpgradeInfoAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Supplier;
public class Upgrade extends Plugin implements ActionPlugin {
public static final Version UPGRADE_INTRODUCED = Version.CURRENT.minimumCompatibilityVersion();
private final List<BiFunction<Client, ClusterService, IndexUpgradeCheck>> upgradeCheckFactories;
public Upgrade() {
this.upgradeCheckFactories = new ArrayList<>();
}
@Override
public Collection<Object> createComponents(Client client, ClusterService clusterService, ThreadPool threadPool,
ResourceWatcherService resourceWatcherService, ScriptService scriptService,
NamedXContentRegistry xContentRegistry, Environment environment,
NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry) {
List<IndexUpgradeCheck> upgradeChecks = new ArrayList<>(upgradeCheckFactories.size());
for (BiFunction<Client, ClusterService, IndexUpgradeCheck> checkFactory : upgradeCheckFactories) {
upgradeChecks.add(checkFactory.apply(client, clusterService));
}
return Collections.singletonList(new IndexUpgradeService(Collections.unmodifiableList(upgradeChecks)));
}
@Override
public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
return Arrays.asList(
new ActionHandler<>(IndexUpgradeInfoAction.INSTANCE, TransportIndexUpgradeInfoAction.class),
new ActionHandler<>(IndexUpgradeAction.INSTANCE, TransportIndexUpgradeAction.class)
);
}
@Override
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<DiscoveryNodes> nodesInCluster) {
return Arrays.asList(
new RestIndexUpgradeInfoAction(settings, restController),
new RestIndexUpgradeAction(settings, restController)
);
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade.actions;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
import org.elasticsearch.xpack.upgrade.IndexUpgradeService;
public class TransportIndexUpgradeAction extends TransportMasterNodeAction<IndexUpgradeAction.Request, BulkByScrollResponse> {
private final IndexUpgradeService indexUpgradeService;
@Inject
public TransportIndexUpgradeAction(TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters,
IndexUpgradeService indexUpgradeService,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(IndexUpgradeAction.NAME, transportService, clusterService, threadPool, actionFilters,
IndexUpgradeAction.Request::new, indexNameExpressionResolver);
this.indexUpgradeService = indexUpgradeService;
}
@Override
protected String executor() {
return ThreadPool.Names.GENERIC;
}
@Override
protected BulkByScrollResponse newResponse() {
return new BulkByScrollResponse();
}
@Override
protected ClusterBlockException checkBlock(IndexUpgradeAction.Request request, ClusterState state) {
// Cluster is not affected but we look up repositories in metadata
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
}
@Override
protected final void masterOperation(Task task, IndexUpgradeAction.Request request, ClusterState state,
ActionListener<BulkByScrollResponse> listener) {
TaskId taskId = new TaskId(clusterService.localNode().getId(), task.getId());
indexUpgradeService.upgrade(taskId, request.index(), state, listener);
}
@Override
protected final void masterOperation(IndexUpgradeAction.Request request, ClusterState state,
ActionListener<BulkByScrollResponse> listener) {
throw new UnsupportedOperationException("the task parameter is required");
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade.actions;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.license.LicenseUtils;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeInfoAction;
import org.elasticsearch.xpack.upgrade.IndexUpgradeService;
import java.util.Map;
public class TransportIndexUpgradeInfoAction
extends TransportMasterNodeReadAction<IndexUpgradeInfoRequest, IndexUpgradeInfoResponse> {
private final IndexUpgradeService indexUpgradeService;
private final XPackLicenseState licenseState;
@Inject
public TransportIndexUpgradeInfoAction(TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters,
IndexUpgradeService indexUpgradeService,
IndexNameExpressionResolver indexNameExpressionResolver,
XPackLicenseState licenseState) {
super(IndexUpgradeInfoAction.NAME, transportService, clusterService, threadPool, actionFilters,
IndexUpgradeInfoRequest::new, indexNameExpressionResolver);
this.indexUpgradeService = indexUpgradeService;
this.licenseState = licenseState;
}
@Override
protected String executor() {
return ThreadPool.Names.GENERIC;
}
@Override
protected IndexUpgradeInfoResponse newResponse() {
return new IndexUpgradeInfoResponse();
}
@Override
protected ClusterBlockException checkBlock(IndexUpgradeInfoRequest request, ClusterState state) {
// Cluster is not affected but we look up repositories in metadata
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
}
@Override
protected final void masterOperation(final IndexUpgradeInfoRequest request, ClusterState state,
final ActionListener<IndexUpgradeInfoResponse> listener) {
if (licenseState.isUpgradeAllowed()) {
Map<String, UpgradeActionRequired> results =
indexUpgradeService.upgradeInfo(request.indices(), request.indicesOptions(), state);
listener.onResponse(new IndexUpgradeInfoResponse(results));
} else {
listener.onFailure(LicenseUtils.newComplianceException(XPackField.UPGRADE));
}
}
}

View File

@ -1,129 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade.rest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.BulkByScrollTask;
import org.elasticsearch.index.reindex.ScrollableHitSource;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.RestBuilderListener;
import org.elasticsearch.tasks.LoggingTaskListener;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction.Request;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.rest.RestRequest.Method.POST;
public class RestIndexUpgradeAction extends BaseRestHandler {
private static final Logger logger = LogManager.getLogger(RestIndexUpgradeAction.class);
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
public RestIndexUpgradeAction(Settings settings, RestController controller) {
super(settings);
controller.registerWithDeprecatedHandler(
POST, "_migration/upgrade/{index}", this,
POST, "_xpack/migration/upgrade/{index}", deprecationLogger);
}
@Override
public String getName() {
return "migration_upgrade";
}
@Override
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
if (request.method().equals(POST)) {
return handlePost(request, client);
} else {
throw new IllegalArgumentException("illegal method [" + request.method() + "] for request [" + request.path() + "]");
}
}
private RestChannelConsumer handlePost(final RestRequest request, NodeClient client) {
Request upgradeRequest = new Request(request.param("index"));
Map<String, String> params = new HashMap<>();
params.put(BulkByScrollTask.Status.INCLUDE_CREATED, Boolean.toString(true));
params.put(BulkByScrollTask.Status.INCLUDE_UPDATED, Boolean.toString(true));
if (request.paramAsBoolean("wait_for_completion", true)) {
return channel -> client.execute(IndexUpgradeAction.INSTANCE, upgradeRequest,
new RestBuilderListener<BulkByScrollResponse>(channel) {
@Override
public RestResponse buildResponse(BulkByScrollResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
response.toXContent(builder, new ToXContent.DelegatingMapParams(params, channel.request()));
builder.endObject();
return new BytesRestResponse(getStatus(response), builder);
}
private RestStatus getStatus(BulkByScrollResponse response) {
/*
* Return the highest numbered rest status under the assumption that higher numbered statuses are "more error"
* and thus more interesting to the user.
*/
RestStatus status = RestStatus.OK;
if (response.isTimedOut()) {
status = RestStatus.REQUEST_TIMEOUT;
}
for (BulkItemResponse.Failure failure : response.getBulkFailures()) {
if (failure.getStatus().getStatus() > status.getStatus()) {
status = failure.getStatus();
}
}
for (ScrollableHitSource.SearchFailure failure : response.getSearchFailures()) {
RestStatus failureStatus = ExceptionsHelper.status(failure.getReason());
if (failureStatus.getStatus() > status.getStatus()) {
status = failureStatus;
}
}
return status;
}
});
} else {
upgradeRequest.setShouldStoreResult(true);
/*
* Validating before forking to make sure we can catch the issues earlier
*/
ActionRequestValidationException validationException = upgradeRequest.validate();
if (validationException != null) {
throw validationException;
}
Task task = client.executeLocally(IndexUpgradeAction.INSTANCE, upgradeRequest, LoggingTaskListener.instance());
// Send task description id instead of waiting for the message
return channel -> {
try (XContentBuilder builder = channel.newBuilder()) {
builder.startObject();
builder.field("task", client.getLocalNodeId() + ":" + task.getId());
builder.endObject();
channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder));
}
};
}
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade.rest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeInfoAction;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
public class RestIndexUpgradeInfoAction extends BaseRestHandler {
private static final Logger logger = LogManager.getLogger(RestIndexUpgradeInfoAction.class);
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
public RestIndexUpgradeInfoAction(Settings settings, RestController controller) {
super(settings);
controller.registerWithDeprecatedHandler(
GET, "_migration/assistance", this,
GET, "/_xpack/migration/assistance", deprecationLogger);
controller.registerWithDeprecatedHandler(
GET, "_migration/assistance/{index}", this,
GET, "/_xpack/migration/assistance/{index}", deprecationLogger);
}
@Override
public String getName() {
return "migration_assistance";
}
@Override
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
if (request.method().equals(GET)) {
return handleGet(request, client);
} else {
throw new IllegalArgumentException("illegal method [" + request.method() + "] for request [" + request.path() + "]");
}
}
private RestChannelConsumer handleGet(final RestRequest request, NodeClient client) {
IndexUpgradeInfoRequest infoRequest = new IndexUpgradeInfoRequest(Strings.splitStringByCommaToArray(request.param("index")));
infoRequest.indicesOptions(IndicesOptions.fromRequest(request, infoRequest.indicesOptions()));
return channel -> client.execute(IndexUpgradeInfoAction.INSTANCE, infoRequest, new RestToXContentListener<>(channel));
}
}

View File

@ -1,25 +0,0 @@
grant {
// needed for multiple server implementations used in tests
permission java.net.SocketPermission "*", "accept,connect";
};
grant codeBase "${codebase.netty-common}" {
// for reading the system-wide configuration for the backlog of established sockets
permission java.io.FilePermission "/proc/sys/net/core/somaxconn", "read";
};
grant codeBase "${codebase.netty-transport}" {
// Netty NioEventLoop wants to change this, because of https://bugs.openjdk.java.net/browse/JDK-6427854
// the bug says it only happened rarely, and that its fixed, but apparently it still happens rarely!
permission java.util.PropertyPermission "sun.nio.ch.bugLevel", "write";
};
grant codeBase "${codebase.elasticsearch-rest-client}" {
// rest client uses system properties which gets the default proxy
permission java.net.NetPermission "getProxySelector";
};
grant codeBase "${codebase.httpasyncclient}" {
// rest client uses system properties which gets the default proxy
permission java.net.NetPermission "getProxySelector";
};

View File

@ -1,140 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.elasticsearch.Build;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeInfoAction;
import org.junit.Before;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.core.IsEqual.equalTo;
public class IndexUpgradeIT extends IndexUpgradeIntegTestCase {
@Before
public void resetLicensing() throws Exception {
enableLicensing();
}
public void testIndexUpgradeInfo() {
// Testing only negative case here, the positive test is done in bwcTests
assertAcked(client().admin().indices().prepareCreate("test").get());
ensureYellow("test");
IndexUpgradeInfoResponse response = new IndexUpgradeInfoAction.RequestBuilder(client()).setIndices("test").get();
assertThat(response.getActions().entrySet(), empty());
}
public void testIndexUpgradeInfoLicense() throws Exception {
// This test disables all licenses and generates a new one using dev private key
// in non-snapshot builds we are using production public key for license verification
// which makes this test to fail
assumeTrue("License is only valid when tested against snapshot/test keys", Build.CURRENT.isSnapshot());
assertAcked(client().admin().indices().prepareCreate("test").get());
ensureYellow("test");
disableLicensing();
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class,
() -> new IndexUpgradeInfoAction.RequestBuilder(client()).setIndices("test").get());
assertThat(e.getMessage(), equalTo("current license is non-compliant for [upgrade]"));
enableLicensing();
IndexUpgradeInfoResponse response = new IndexUpgradeInfoAction.RequestBuilder(client()).setIndices("test").get();
assertThat(response.getActions().entrySet(), empty());
}
public void testUpToDateIndexUpgrade() throws Exception {
// Testing only negative case here, the positive test is done in bwcTests
String testIndex = "test";
String testType = "doc";
assertAcked(client().admin().indices().prepareCreate(testIndex).get());
indexRandom(true,
client().prepareIndex(testIndex, testType, "1").setSource("{\"foo\":\"bar\"}", XContentType.JSON),
client().prepareIndex(testIndex, testType, "2").setSource("{\"foo\":\"baz\"}", XContentType.JSON)
);
ensureYellow(testIndex);
IllegalStateException ex = expectThrows(IllegalStateException.class,
() -> new IndexUpgradeAction.RequestBuilder(client()).setIndex(testIndex).get());
assertThat(ex.getMessage(), equalTo("Index [" + testIndex + "] cannot be upgraded"));
SearchResponse searchResponse = client().prepareSearch(testIndex).get();
assertEquals(2L, searchResponse.getHits().getTotalHits().value);
}
public void testInternalUpgradePrePostChecks() throws Exception {
String testIndex = "internal_index";
String testType = "test";
Long val = randomLong();
AtomicBoolean preUpgradeIsCalled = new AtomicBoolean();
AtomicBoolean postUpgradeIsCalled = new AtomicBoolean();
IndexUpgradeCheck check = new IndexUpgradeCheck<Long>(
"test",
indexMetaData -> {
if (indexMetaData.getIndex().getName().equals(testIndex)) {
return UpgradeActionRequired.UPGRADE;
} else {
return UpgradeActionRequired.NOT_APPLICABLE;
}
},
client(), internalCluster().clusterService(internalCluster().getMasterName()), Strings.EMPTY_ARRAY, null,
(cs, listener) -> {
assertFalse(preUpgradeIsCalled.getAndSet(true));
assertFalse(postUpgradeIsCalled.get());
listener.onResponse(val);
},
(aLong, listener) -> {
assertTrue(preUpgradeIsCalled.get());
assertFalse(postUpgradeIsCalled.getAndSet(true));
assertEquals(aLong, val);
listener.onResponse(TransportResponse.Empty.INSTANCE);
});
assertAcked(client().admin().indices().prepareCreate(testIndex).get());
indexRandom(true,
client().prepareIndex(testIndex, testType, "1").setSource("{\"foo\":\"bar\"}", XContentType.JSON),
client().prepareIndex(testIndex, testType, "2").setSource("{\"foo\":\"baz\"}", XContentType.JSON)
);
ensureYellow(testIndex);
IndexUpgradeService service = new IndexUpgradeService(Collections.singletonList(check));
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
service.upgrade(new TaskId("abc", 123), testIndex, clusterService().state(), future);
BulkByScrollResponse response = future.actionGet();
assertThat(response.getCreated(), equalTo(2L));
SearchResponse searchResponse = client().prepareSearch(testIndex).get();
assertEquals(2L, searchResponse.getHits().getTotalHits().value);
assertTrue(preUpgradeIsCalled.get());
assertTrue(postUpgradeIsCalled.get());
}
public void testIndexUpgradeInfoOnEmptyCluster() {
// On empty cluster asking for all indices shouldn't fail since no indices means nothing needs to be upgraded
IndexUpgradeInfoResponse response = new IndexUpgradeInfoAction.RequestBuilder(client()).setIndices("_all").get();
assertThat(response.getActions().entrySet(), empty());
// but calling on a particular index should fail
assertThrows(new IndexUpgradeInfoAction.RequestBuilder(client()).setIndices("test"), IndexNotFoundException.class);
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.elasticsearch.analysis.common.CommonAnalysisPlugin;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.reindex.ReindexPlugin;
import org.elasticsearch.license.AbstractLicensesIntegrationTestCase;
import org.elasticsearch.license.License;
import org.elasticsearch.license.TestUtils;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;
import org.elasticsearch.xpack.core.XPackClientPlugin;
import org.elasticsearch.xpack.core.monitoring.test.MockPainlessScriptEngine;
import java.util.Arrays;
import java.util.Collection;
public abstract class IndexUpgradeIntegTestCase extends AbstractLicensesIntegrationTestCase {
@Override
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(LocalStateCompositeXPackPlugin.class, Upgrade.class, ReindexPlugin.class,
MockPainlessScriptEngine.TestPlugin.class, CommonAnalysisPlugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return Arrays.asList(XPackClientPlugin.class, ReindexPlugin.class);
}
private static String randomValidLicenseType() {
return randomFrom("trial", "platinum", "gold", "standard", "basic");
}
private static String randomInvalidLicenseType() {
return "missing";
}
public void disableLicensing() throws Exception {
updateLicensing(randomInvalidLicenseType());
}
public void enableLicensing() throws Exception {
updateLicensing(randomValidLicenseType());
}
public void updateLicensing(String licenseType) throws Exception {
wipeAllLicenses();
if (licenseType.equals("missing")) {
putLicenseTombstone();
} else {
License license = TestUtils.generateSignedLicense(licenseType, TimeValue.timeValueMinutes(1));
putLicense(license);
}
}
}

View File

@ -1,183 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.elasticsearch.Version;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import static org.hamcrest.core.IsEqual.equalTo;
public class IndexUpgradeServiceTests extends ESTestCase {
private IndexUpgradeCheck upgradeBarCheck = new IndexUpgradeCheck("upgrade_bar",
(Function<IndexMetaData, UpgradeActionRequired>) indexMetaData -> {
if ("bar".equals(indexMetaData.getSettings().get("test.setting"))) {
return UpgradeActionRequired.UPGRADE;
} else {
return UpgradeActionRequired.NOT_APPLICABLE;
}
}, null, null, null, null);
private IndexUpgradeCheck reindexFooCheck = new IndexUpgradeCheck("reindex_foo",
(Function<IndexMetaData, UpgradeActionRequired>) indexMetaData -> {
if ("foo".equals(indexMetaData.getSettings().get("test.setting"))) {
return UpgradeActionRequired.REINDEX;
} else {
return UpgradeActionRequired.NOT_APPLICABLE;
}
}, null, null, null, null);
private IndexUpgradeCheck everythingIsFineCheck = new IndexUpgradeCheck("everything_is_fine",
indexMetaData -> UpgradeActionRequired.UP_TO_DATE, null, null, null, null);
private IndexUpgradeCheck unreachableCheck = new IndexUpgradeCheck("unreachable",
(Function<IndexMetaData, UpgradeActionRequired>) indexMetaData -> {
fail("Unreachable check is called");
return null;
}, null, null, null, null);
public void testIndexUpgradeServiceMultipleCheck() throws Exception {
IndexUpgradeService service;
if (randomBoolean()) {
service = new IndexUpgradeService(Arrays.asList(
upgradeBarCheck,
reindexFooCheck,
everythingIsFineCheck,
unreachableCheck // This one should never be called
));
} else {
service = new IndexUpgradeService(Arrays.asList(
reindexFooCheck,
upgradeBarCheck,
everythingIsFineCheck,
unreachableCheck // This one should never be called
));
}
IndexMetaData fooIndex = newTestIndexMeta("bar", Settings.builder().put("test.setting", "bar").build());
IndexMetaData barIndex = newTestIndexMeta("foo", Settings.builder().put("test.setting", "foo").build());
IndexMetaData bazIndex = newTestIndexMeta("baz", Settings.EMPTY);
ClusterState clusterState = mockClusterState(fooIndex, barIndex, bazIndex);
Map<String, UpgradeActionRequired> result = service.upgradeInfo(new String[]{"bar", "foo", "baz"},
IndicesOptions.lenientExpandOpen(), clusterState);
assertThat(result.size(), equalTo(2));
assertThat(result.get("bar"), equalTo(UpgradeActionRequired.UPGRADE));
assertThat(result.get("foo"), equalTo(UpgradeActionRequired.REINDEX));
result = service.upgradeInfo(new String[]{"b*"}, IndicesOptions.lenientExpandOpen(), clusterState);
assertThat(result.size(), equalTo(1));
assertThat(result.get("bar"), equalTo(UpgradeActionRequired.UPGRADE));
}
public void testNoMatchingChecks() throws Exception {
IndexUpgradeService service = new IndexUpgradeService(Arrays.asList(
upgradeBarCheck,
reindexFooCheck
));
IndexMetaData fooIndex = newTestIndexMeta("bar", Settings.builder().put("test.setting", "bar").build());
IndexMetaData barIndex = newTestIndexMeta("foo", Settings.builder().put("test.setting", "foo").build());
IndexMetaData bazIndex = newTestIndexMeta("baz", Settings.EMPTY);
ClusterState clusterState = mockClusterState(fooIndex, barIndex, bazIndex);
Map<String, UpgradeActionRequired> result = service.upgradeInfo(new String[]{"bar", "foo", "baz"},
IndicesOptions.lenientExpandOpen(), clusterState);
assertThat(result.size(), equalTo(2));
assertThat(result.get("bar"), equalTo(UpgradeActionRequired.UPGRADE));
assertThat(result.get("foo"), equalTo(UpgradeActionRequired.REINDEX));
}
public void testEarlierChecksWin() throws Exception {
IndexUpgradeService service = new IndexUpgradeService(Arrays.asList(
everythingIsFineCheck,
upgradeBarCheck,
reindexFooCheck
));
IndexMetaData fooIndex = newTestIndexMeta("bar", Settings.builder().put("test.setting", "bar").build());
IndexMetaData barIndex = newTestIndexMeta("foo", Settings.builder().put("test.setting", "foo").build());
IndexMetaData bazIndex = newTestIndexMeta("baz", Settings.EMPTY);
ClusterState clusterState = mockClusterState(fooIndex, barIndex, bazIndex);
Map<String, UpgradeActionRequired> result = service.upgradeInfo(new String[]{"bar", "foo", "baz"},
IndicesOptions.lenientExpandOpen(), clusterState);
assertThat(result.size(), equalTo(0)); // everything as the first checker should indicate that everything is fine
}
public void testGenericTest() throws Exception {
IndexUpgradeService service = new IndexUpgradeService(Arrays.asList(
upgradeBarCheck,
reindexFooCheck
));
IndexMetaData goodIndex = newTestIndexMeta("good", Settings.EMPTY);
IndexMetaData badIndex = newTestIndexMeta("bad",
Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.fromString("2.0.0")).build());
ClusterState clusterState = mockClusterState(goodIndex, badIndex);
Map<String, UpgradeActionRequired> result = service.upgradeInfo(new String[]{"good", "bad"},
IndicesOptions.lenientExpandOpen(), clusterState);
assertThat(result.size(), equalTo(1));
assertThat(result.get("bad"), equalTo(UpgradeActionRequired.REINDEX));
}
private ClusterState mockClusterState(IndexMetaData... indices) {
MetaData.Builder metaDataBuilder = MetaData.builder();
for (IndexMetaData indexMetaData : indices) {
metaDataBuilder.put(indexMetaData, false);
}
return ClusterState.builder(ClusterName.DEFAULT).metaData(metaDataBuilder).build();
}
public static IndexMetaData newTestIndexMeta(String name, String alias, Settings indexSettings) throws IOException {
Settings build = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_CREATION_DATE, 1)
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID())
.put(IndexMetaData.SETTING_VERSION_UPGRADED, Version.V_6_0_0)
.put(indexSettings)
.build();
IndexMetaData.Builder builder = IndexMetaData.builder(name).settings(build);
if (alias != null) {
// Create alias
builder.putAlias(AliasMetaData.newAliasMetaDataBuilder(alias).build());
}
return builder.build();
}
public static IndexMetaData newTestIndexMeta(String name, Settings indexSettings) throws IOException {
return newTestIndexMeta(name, null, indexSettings);
}
}

View File

@ -1,202 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.ReindexAction;
import org.elasticsearch.index.reindex.ReindexPlugin;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.protocol.xpack.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.upgrade.UpgradeField;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeInfoAction;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
@ESIntegTestCase.ClusterScope(scope = TEST, supportsDedicatedMasters = false, numClientNodes = 0, maxNumDataNodes = 1)
public class IndexUpgradeTasksIT extends ESIntegTestCase {
@Override
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(MockUpgradePlugin.class, ReindexPlugin.class);
}
public static class MockUpgradePlugin extends Plugin implements ScriptPlugin, ActionPlugin {
public static final String NAME = MockScriptEngine.NAME;
private Settings settings;
private Upgrade upgrade;
private CountDownLatch upgradeLatch = new CountDownLatch(1);
private CountDownLatch upgradeCalledLatch = new CountDownLatch(1);
@Override
public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
return new MockScriptEngine(pluginScriptLang(), pluginScripts(), Collections.emptyMap());
}
public String pluginScriptLang() {
return NAME;
}
public MockUpgradePlugin(Settings settings) {
this.settings = settings;
this.upgrade = new Upgrade();
LogManager.getLogger(IndexUpgradeTasksIT.class).info("MockUpgradePlugin is created");
}
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
scripts.put("block", map -> {
upgradeCalledLatch.countDown();
try {
assertThat(upgradeLatch.await(10, TimeUnit.SECONDS), equalTo(true));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return null;
});
return scripts;
}
@Override
public Collection<Object> createComponents(Client client, ClusterService clusterService, ThreadPool threadPool,
ResourceWatcherService resourceWatcherService, ScriptService scriptService,
NamedXContentRegistry xContentRegistry, Environment environment,
NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry) {
return Arrays.asList(new IndexUpgradeService(Collections.singletonList(
new IndexUpgradeCheck("test",
new Function<IndexMetaData, UpgradeActionRequired>() {
@Override
public UpgradeActionRequired apply(IndexMetaData indexMetaData) {
if ("test".equals(indexMetaData.getIndex().getName())) {
if (UpgradeField.checkInternalIndexFormat(indexMetaData)) {
return UpgradeActionRequired.UP_TO_DATE;
} else {
return UpgradeActionRequired.UPGRADE;
}
} else {
return UpgradeActionRequired.NOT_APPLICABLE;
}
}
},
client, clusterService, Strings.EMPTY_ARRAY,
new Script(ScriptType.INLINE, NAME, "block", Collections.emptyMap()))
)), new XPackLicenseState(settings));
}
@Override
public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
return upgrade.getActions();
}
@Override
public Collection<String> getRestHeaders() {
return upgrade.getRestHeaders();
}
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
public void testParentTasksDuringUpgrade() throws Exception {
logger.info("before getInstance");
PluginsService pluginsService = internalCluster().getDataNodeInstance(PluginsService.class);
MockUpgradePlugin mockUpgradePlugin = pluginsService.filterPlugins(MockUpgradePlugin.class).get(0);
assertThat(mockUpgradePlugin, notNullValue());
logger.info("after getInstance");
assertAcked(client().admin().indices().prepareCreate("test").get());
client().prepareIndex("test", "doc", "1").setSource("{\"foo\": \"bar\"}", XContentType.JSON)
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
ensureYellow("test");
IndexUpgradeInfoResponse infoResponse = new IndexUpgradeInfoAction.RequestBuilder(client()).setIndices("test").get();
assertThat(infoResponse.getActions().keySet(), contains("test"));
assertThat(infoResponse.getActions().get("test"), equalTo(UpgradeActionRequired.UPGRADE));
ActionFuture<BulkByScrollResponse> upgradeResponse = new IndexUpgradeAction.RequestBuilder(client()).setIndex("test").execute();
assertThat(mockUpgradePlugin.upgradeCalledLatch.await(10, TimeUnit.SECONDS), equalTo(true));
ListTasksResponse response = client().admin().cluster().prepareListTasks().get();
mockUpgradePlugin.upgradeLatch.countDown();
// Find the upgrade task group
TaskGroup upgradeGroup = null;
for (TaskGroup group : response.getTaskGroups()) {
if (IndexUpgradeAction.NAME.equals(group.getTaskInfo().getAction())) {
assertThat(upgradeGroup, nullValue());
upgradeGroup = group;
}
}
assertThat(upgradeGroup, notNullValue());
assertThat(upgradeGroup.getTaskInfo().isCancellable(), equalTo(true)); // The task should be cancellable
assertThat(upgradeGroup.getChildTasks(), hasSize(1)); // The reindex task should be a child
assertThat(upgradeGroup.getChildTasks().get(0).getTaskInfo().getAction(), equalTo(ReindexAction.NAME));
assertThat(upgradeResponse.get().getCreated(), equalTo(1L));
}
}

View File

@ -1,240 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ResourceAlreadyExistsException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.analysis.common.CommonAnalysisPlugin;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.ReindexPlugin;
import org.elasticsearch.indices.InvalidIndexNameException;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.protocol.xpack.migration.UpgradeActionRequired;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;
import org.elasticsearch.xpack.core.upgrade.IndexUpgradeCheckVersion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static org.elasticsearch.test.VersionUtils.randomVersionBetween;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.core.IsEqual.equalTo;
@ClusterScope(scope=Scope.TEST)
public class InternalIndexReindexerIT extends IndexUpgradeIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(LocalStateCompositeXPackPlugin.class,
ReindexPlugin.class, CustomScriptPlugin.class, CommonAnalysisPlugin.class);
}
public static class CustomScriptPlugin extends MockScriptPlugin {
@Override
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
scripts.put("add_bar", map -> {
@SuppressWarnings("unchecked") Map<String, Object> ctx = (Map<String, Object>) map.get("ctx");
ctx.put("_id", "bar" + "-" + ctx.get("_id"));
@SuppressWarnings("unchecked") Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
source.put("bar", true);
return null;
});
scripts.put("fail", map -> {
throw new RuntimeException("Stop reindexing");
});
return scripts;
}
}
public void testUpgradeIndex() throws Exception {
createTestIndex("test");
InternalIndexReindexer reindexer = createIndexReindexer(script("add_bar"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", clusterState(), future);
BulkByScrollResponse response = future.actionGet();
assertThat(response.getCreated(), equalTo(2L));
SearchResponse searchResponse = client().prepareSearch("test-" + IndexUpgradeCheckVersion.UPGRADE_VERSION).get();
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(2L));
assertThat(searchResponse.getHits().getHits().length, equalTo(2));
for (SearchHit hit : searchResponse.getHits().getHits()) {
assertThat(hit.getId(), startsWith("bar-"));
assertThat(hit.getSourceAsMap(), notNullValue());
assertThat(hit.getSourceAsMap().get("bar"), equalTo(true));
}
GetAliasesResponse aliasesResponse = client().admin().indices().prepareGetAliases("test").get();
assertThat(aliasesResponse.getAliases().size(), equalTo(1));
List<AliasMetaData> testAlias = aliasesResponse.getAliases().get("test-" + IndexUpgradeCheckVersion.UPGRADE_VERSION);
assertNotNull(testAlias);
assertThat(testAlias.size(), equalTo(1));
assertThat(testAlias.get(0).alias(), equalTo("test"));
}
public void testTargetIndexExists() throws Exception {
createTestIndex("test");
createTestIndex("test-" + IndexUpgradeCheckVersion.UPGRADE_VERSION);
InternalIndexReindexer reindexer = createIndexReindexer(script("add_bar"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", clusterState(), future);
assertThrows(future, ResourceAlreadyExistsException.class);
// Make sure that the index is not marked as read-only
client().prepareIndex("test", "doc").setSource("foo", "bar").get();
}
public void testTargetIndexExistsAsAlias() throws Exception {
createTestIndex("test");
createTestIndex("test-foo");
client().admin().indices().prepareAliases().addAlias("test-foo", "test-" + IndexUpgradeCheckVersion.UPGRADE_VERSION).get();
InternalIndexReindexer reindexer = createIndexReindexer(script("add_bar"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", clusterState(), future);
assertThrows(future, InvalidIndexNameException.class);
// Make sure that the index is not marked as read-only
client().prepareIndex("test-" + IndexUpgradeCheckVersion.UPGRADE_VERSION, "doc").setSource("foo", "bar").get();
}
public void testSourceIndexIsReadonly() throws Exception {
createTestIndex("test");
try {
Settings settings = Settings.builder().put(IndexMetaData.INDEX_READ_ONLY_SETTING.getKey(), true).build();
assertAcked(client().admin().indices().prepareUpdateSettings("test").setSettings(settings).get());
InternalIndexReindexer reindexer = createIndexReindexer(script("add_bar"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", clusterState(), future);
assertThrows(future, IllegalStateException.class);
// Make sure that the index is still marked as read-only
assertThrows(client().prepareIndex("test", "doc").setSource("foo", "bar"), ClusterBlockException.class);
} finally {
// Clean up the readonly index
Settings settings = Settings.builder().put(IndexMetaData.INDEX_READ_ONLY_SETTING.getKey(), false).build();
assertAcked(client().admin().indices().prepareUpdateSettings("test").setSettings(settings).get());
}
}
public void testReindexingFailureWithClusterRoutingAllocationDisabled() throws Exception {
createTestIndex("test");
Settings settings = Settings.builder().put(EnableAllocationDecider.CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "none")
.build();
ClusterUpdateSettingsResponse clusterUpdateResponse = client().admin().cluster().prepareUpdateSettings()
.setTransientSettings(settings).get();
assertThat(clusterUpdateResponse.isAcknowledged(), is(true));
assertThat(clusterUpdateResponse.getTransientSettings()
.get(EnableAllocationDecider.CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING.getKey()), is("none"));
InternalIndexReindexer reindexer = createIndexReindexer(script("add_bar"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", clusterState(), future);
ElasticsearchException e = expectThrows(ElasticsearchException.class, () -> future.actionGet());
assertThat(e.getMessage(), containsString(
"pre-upgrade check failed, please enable cluster routing allocation using setting [cluster.routing.allocation.enable]"));
}
public void testReindexingFailure() throws Exception {
createTestIndex("test");
// Make sure that the index is not marked as read-only
client().prepareIndex("test", "doc").setSource("foo", "bar").setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
InternalIndexReindexer reindexer = createIndexReindexer(script("fail"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", clusterState(), future);
assertThrows(future, RuntimeException.class);
// Make sure that the index is not marked as read-only
client().prepareIndex("test", "doc").setSource("foo", "bar").get();
}
public void testMixedNodeVersion() throws Exception {
createTestIndex("test");
InternalIndexReindexer reindexer = createIndexReindexer(script("add_bar"), Strings.EMPTY_ARRAY);
PlainActionFuture<BulkByScrollResponse> future = PlainActionFuture.newFuture();
reindexer.upgrade(new TaskId("abc", 123), "test", withRandomOldNode(), future);
assertThrows(future, IllegalStateException.class);
// Make sure that the index is not marked as read-only
client().prepareIndex("test_v123", "doc").setSource("foo", "bar").get();
}
private void createTestIndex(String indexName) throws Exception {
assertAcked(client().admin().indices().prepareCreate(indexName).get());
indexRandom(true,
client().prepareIndex(indexName, "doc", "1").setSource("{\"foo\":\"bar1-1\"}", XContentType.JSON),
client().prepareIndex(indexName, "doc", "2").setSource("{\"foo\":\"baz1-1\"}", XContentType.JSON)
);
ensureYellow(indexName);
}
private Script script(String name) {
return new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, name, new HashMap<>());
}
private InternalIndexReindexer createIndexReindexer(Script transformScript, String[] types) {
return new IndexUpgradeCheck("test", imd -> UpgradeActionRequired.UPGRADE, client(),
internalCluster().clusterService(internalCluster().getMasterName()), types, transformScript).getInternalIndexReindexer();
}
private ClusterState clusterState() {
return clusterService().state();
}
private ClusterState withRandomOldNode() {
ClusterState clusterState = clusterState();
DiscoveryNodes discoveryNodes = clusterState.nodes();
List<String> nodes = new ArrayList<>();
for (ObjectCursor<String> key : discoveryNodes.getMasterAndDataNodes().keys()) {
nodes.add(key.value);
}
// Fake one of the node versions
String nodeId = randomFrom(nodes);
DiscoveryNode node = discoveryNodes.get(nodeId);
DiscoveryNode newNode = new DiscoveryNode(node.getName(), node.getId(), node.getEphemeralId(), node.getHostName(),
node.getHostAddress(), node.getAddress(), node.getAttributes(), node.getRoles(),
randomVersionBetween(random(), Version.V_6_0_0, Version.V_6_4_0));
return ClusterState.builder(clusterState).nodes(DiscoveryNodes.builder(discoveryNodes).remove(node).add(newNode)).build();
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.upgrade.actions;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction.Request;
public class IndexUpgradeActionRequestTests extends AbstractWireSerializingTestCase<Request> {
@Override
protected Request createTestInstance() {
return new Request(randomAlphaOfLength(10));
}
@Override
protected Writeable.Reader<Request> instanceReader() {
return Request::new;
}
}

View File

@ -22,6 +22,7 @@ import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.test.StreamsUtils;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.upgrades.AbstractFullClusterRestartTestCase;
import org.elasticsearch.xpack.core.upgrade.UpgradeField;
import org.elasticsearch.xpack.core.watcher.client.WatchSourceBuilder;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.elasticsearch.xpack.watcher.actions.index.IndexAction;
@ -56,7 +57,6 @@ import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
public class FullClusterRestartIT extends AbstractFullClusterRestartTestCase {
@ -111,11 +111,9 @@ public class FullClusterRestartIT extends AbstractFullClusterRestartTestCase {
Response settingsResponse = client().performRequest(new Request("GET", "/.security/_settings/index.format"));
Map<String, Object> settingsResponseMap = entityAsMap(settingsResponse);
logger.info("settings response map {}", settingsResponseMap);
final boolean needsUpgrade;
final String concreteSecurityIndex;
if (settingsResponseMap.isEmpty()) {
needsUpgrade = true;
concreteSecurityIndex = ".security";
fail("The security index does not have the expected setting [index.format]");
} else {
concreteSecurityIndex = settingsResponseMap.keySet().iterator().next();
Map<String, Object> indexSettingsMap =
@ -123,29 +121,12 @@ public class FullClusterRestartIT extends AbstractFullClusterRestartTestCase {
Map<String, Object> settingsMap = (Map<String, Object>) indexSettingsMap.get("settings");
logger.info("settings map {}", settingsMap);
if (settingsMap.containsKey("index")) {
@SuppressWarnings("unchecked")
int format = Integer.parseInt(String.valueOf(((Map<String, Object>)settingsMap.get("index")).get("format")));
needsUpgrade = format == SecurityIndexManager.INTERNAL_INDEX_FORMAT ? false : true;
} else {
needsUpgrade = true;
assertEquals("The security index needs to be upgraded", SecurityIndexManager.INTERNAL_INDEX_FORMAT, format);
}
}
if (needsUpgrade) {
logger.info("upgrading security index {}", concreteSecurityIndex);
// without upgrade, an error should be thrown
try {
createUser(false);
fail("should not be able to add a user when upgrade hasn't taken place");
} catch (ResponseException e) {
assertThat(e.getMessage(), containsString("Security index is not on the current version - " +
"the native realm will not be operational until the upgrade API is run on the security index"));
}
// run upgrade API
Response upgradeResponse = client().performRequest(
new Request("POST", "_migration/upgrade/" + concreteSecurityIndex));
logger.info("upgrade response:\n{}", toStr(upgradeResponse));
}
// create additional user and role
createUser(false);
createRole(false);
@ -155,6 +136,7 @@ public class FullClusterRestartIT extends AbstractFullClusterRestartTestCase {
assertRoleInfo(isRunningAgainstOldCluster());
}
@SuppressWarnings("unchecked")
public void testWatcher() throws Exception {
if (isRunningAgainstOldCluster()) {
logger.info("Adding a watch on old cluster {}", getOldClusterVersion());
@ -185,34 +167,23 @@ public class FullClusterRestartIT extends AbstractFullClusterRestartTestCase {
logger.info("testing against {}", getOldClusterVersion());
waitForYellow(".watches,bwc_watch_index,.watcher-history*");
logger.info("checking if the upgrade procedure on the new cluster is required");
Map<String, Object> response = entityAsMap(client().performRequest(new Request("GET", "/_migration/assistance")));
logger.info(response);
logger.info("checking that the Watches index is the correct version");
@SuppressWarnings("unchecked") Map<String, Object> indices = (Map<String, Object>) response.get("indices");
if (indices.containsKey(".watches")) {
logger.info("upgrade procedure is required for watcher");
assertThat(indices.entrySet().size(), greaterThanOrEqualTo(1));
assertThat(indices.get(".watches"), notNullValue());
@SuppressWarnings("unchecked") Map<String, Object> index = (Map<String, Object>) indices.get(".watches");
assertThat(index.get("action_required"), equalTo("upgrade"));
logger.info("starting upgrade procedure on the new cluster");
Request migrationAssistantRequest = new Request("POST", "_migration/upgrade/.watches");
migrationAssistantRequest.addParameter("error_trace", "true");
Map<String, Object> upgradeResponse = entityAsMap(client().performRequest(migrationAssistantRequest));
assertThat(upgradeResponse.get("timed_out"), equalTo(Boolean.FALSE));
// we posted 3 watches, but monitoring can post a few more
assertThat((int) upgradeResponse.get("total"), greaterThanOrEqualTo(3));
logger.info("checking that upgrade procedure on the new cluster is no longer required");
Map<String, Object> responseAfter = entityAsMap(client().performRequest(
new Request("GET", "/_migration/assistance")));
@SuppressWarnings("unchecked") Map<String, Object> indicesAfter = (Map<String, Object>) responseAfter.get("indices");
assertNull(indicesAfter.get(".watches"));
Response settingsResponse = client().performRequest(new Request("GET", "/.watches/_settings/index.format"));
Map<String, Object> settingsResponseMap = entityAsMap(settingsResponse);
logger.info("settings response map {}", settingsResponseMap);
final String concreteWatchesIndex;
if (settingsResponseMap.isEmpty()) {
fail("The security index does not have the expected setting [index.format]");
} else {
logger.info("upgrade procedure is not required for watcher");
concreteWatchesIndex = settingsResponseMap.keySet().iterator().next();
Map<String, Object> indexSettingsMap = (Map<String, Object>) settingsResponseMap.get(concreteWatchesIndex);
Map<String, Object> settingsMap = (Map<String, Object>) indexSettingsMap.get("settings");
logger.info("settings map {}", settingsMap);
if (settingsMap.containsKey("index")) {
int format = Integer.parseInt(String.valueOf(((Map<String, Object>)settingsMap.get("index")).get("format")));
assertEquals("The watches index needs to be upgraded", UpgradeField.EXPECTED_INDEX_FORMAT_VERSION, format);
}
}
// Wait for watcher to actually start....