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:
parent
38e9522218
commit
c8a4a7fc9d
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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"));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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]
|
||||
--------------------------------------------------
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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.
|
|
@ -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[]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')]
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
}
|
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"}
|
|
@ -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 } }
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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";
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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....
|
||||
|
|
Loading…
Reference in New Issue