mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-25 07:37:19 -04:00
* Implement GET API for System Feature Upgrades (#78642) * Implement and test get feature upgrade status API * Add integration test for feature upgrade endpoint * Use constant enum for statuses * Add unit tests for transport class methods * Fix bwc tests for 7.x
This commit is contained in:
parent
3b45d0ab53
commit
1b5827da3e
9 changed files with 500 additions and 64 deletions
|
@ -9,6 +9,7 @@
|
|||
package org.elasticsearch.client;
|
||||
|
||||
import org.elasticsearch.jdk.JavaVersion;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.client.migration.DeprecationInfoRequest;
|
||||
import org.elasticsearch.client.migration.DeprecationInfoResponse;
|
||||
import org.elasticsearch.client.migration.GetFeatureUpgradeStatusRequest;
|
||||
|
@ -20,11 +21,14 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.anEmptyMap;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class MigrationIT extends ESRestHighLevelClientTestCase {
|
||||
|
@ -51,19 +55,24 @@ public class MigrationIT extends ESRestHighLevelClientTestCase {
|
|||
public void testGetFeatureUpgradeStatus() throws IOException {
|
||||
GetFeatureUpgradeStatusRequest request = new GetFeatureUpgradeStatusRequest();
|
||||
GetFeatureUpgradeStatusResponse response = highLevelClient().migration().getFeatureUpgradeStatus(request, RequestOptions.DEFAULT);
|
||||
assertThat(response.getUpgradeStatus(), equalTo("UPGRADE_NEEDED"));
|
||||
assertThat(response.getFeatureUpgradeStatuses().size(), equalTo(1));
|
||||
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus status = response.getFeatureUpgradeStatuses().get(0);
|
||||
assertThat(status.getUpgradeStatus(), equalTo("UPGRADE_NEEDED"));
|
||||
assertThat(status.getMinimumIndexVersion(), equalTo("7.1.1"));
|
||||
assertThat(status.getFeatureName(), equalTo("security"));
|
||||
assertThat(status.getIndexVersions().size(), equalTo(1));
|
||||
assertThat(response.getUpgradeStatus(), equalTo("NO_UPGRADE_NEEDED"));
|
||||
assertThat(response.getFeatureUpgradeStatuses().size(), greaterThanOrEqualTo(1));
|
||||
Optional<GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus> optionalTasksStatus = response.getFeatureUpgradeStatuses().stream()
|
||||
.filter(status -> "tasks".equals(status.getFeatureName()))
|
||||
.findFirst();
|
||||
|
||||
assertThat(optionalTasksStatus.isPresent(), is(true));
|
||||
|
||||
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus tasksStatus = optionalTasksStatus.get();
|
||||
|
||||
assertThat(tasksStatus.getUpgradeStatus(), equalTo("NO_UPGRADE_NEEDED"));
|
||||
assertThat(tasksStatus.getMinimumIndexVersion(), equalTo(Version.CURRENT.toString()));
|
||||
assertThat(tasksStatus.getFeatureName(), equalTo("tasks"));
|
||||
}
|
||||
|
||||
public void testPostFeatureUpgradeStatus() throws IOException {
|
||||
PostFeatureUpgradeRequest request = new PostFeatureUpgradeRequest();
|
||||
PostFeatureUpgradeResponse response = highLevelClient().migration().postFeatureUpgrade(request, RequestOptions.DEFAULT);
|
||||
// a test like this cannot test actual deprecations
|
||||
assertThat(response.isAccepted(), equalTo(true));
|
||||
assertThat(response.getFeatures().size(), equalTo(1));
|
||||
PostFeatureUpgradeResponse.Feature feature = response.getFeatures().get(0);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package org.elasticsearch.client.migration;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.client.AbstractResponseTestCase;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
|
@ -37,14 +38,14 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractResponseTestCa
|
|||
randomList(5,
|
||||
() -> new org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus(
|
||||
randomAlphaOfLengthBetween(3, 20),
|
||||
randomAlphaOfLengthBetween(5, 9),
|
||||
randomAlphaOfLengthBetween(4, 16),
|
||||
randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()),
|
||||
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values()),
|
||||
randomList(4,
|
||||
() -> new org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.IndexVersion(
|
||||
randomAlphaOfLengthBetween(3, 20),
|
||||
randomAlphaOfLengthBetween(5, 9)))
|
||||
randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())))
|
||||
)),
|
||||
randomAlphaOfLength(5)
|
||||
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -58,7 +59,7 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractResponseTestCa
|
|||
org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse serverTestInstance,
|
||||
GetFeatureUpgradeStatusResponse clientInstance) {
|
||||
|
||||
assertThat(clientInstance.getUpgradeStatus(), equalTo(serverTestInstance.getUpgradeStatus()));
|
||||
assertThat(clientInstance.getUpgradeStatus(), equalTo(serverTestInstance.getUpgradeStatus().toString()));
|
||||
|
||||
assertNotNull(serverTestInstance.getFeatureUpgradeStatuses());
|
||||
assertNotNull(clientInstance.getFeatureUpgradeStatuses());
|
||||
|
@ -71,8 +72,8 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractResponseTestCa
|
|||
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus clientStatus = clientInstance.getFeatureUpgradeStatuses().get(i);
|
||||
|
||||
assertThat(clientStatus.getFeatureName(), equalTo(serverTestStatus.getFeatureName()));
|
||||
assertThat(clientStatus.getMinimumIndexVersion(), equalTo(serverTestStatus.getMinimumIndexVersion()));
|
||||
assertThat(clientStatus.getUpgradeStatus(), equalTo(serverTestStatus.getUpgradeStatus()));
|
||||
assertThat(clientStatus.getMinimumIndexVersion(), equalTo(serverTestStatus.getMinimumIndexVersion().toString()));
|
||||
assertThat(clientStatus.getUpgradeStatus(), equalTo(serverTestStatus.getUpgradeStatus().toString()));
|
||||
|
||||
assertThat(clientStatus.getIndexVersions(), hasSize(serverTestStatus.getIndexVersions().size()));
|
||||
|
||||
|
@ -82,7 +83,7 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractResponseTestCa
|
|||
GetFeatureUpgradeStatusResponse.IndexVersion clientIndexVersion = clientStatus.getIndexVersions().get(j);
|
||||
|
||||
assertThat(clientIndexVersion.getIndexName(), equalTo(serverIndexVersion.getIndexName()));
|
||||
assertThat(clientIndexVersion.getVersion(), equalTo(serverIndexVersion.getVersion()));
|
||||
assertThat(clientIndexVersion.getVersion(), equalTo(serverIndexVersion.getVersion().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,21 +43,83 @@ Example response:
|
|||
--------------------------------------------------
|
||||
{
|
||||
"features" : [
|
||||
{
|
||||
"feature_name" : "async_search",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "enrich",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "fleet",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "geoip",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "kibana",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "logstash_management",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "machine_learning",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "searchable_snapshots",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "security",
|
||||
"minimum_index_version" : "7.1.1",
|
||||
"upgrade_status" : "UPGRADE_NEEDED",
|
||||
"indices" : [
|
||||
{
|
||||
"index" : ".security-7",
|
||||
"version" : "7.1.1"
|
||||
}
|
||||
]
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "tasks",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "transform",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
},
|
||||
{
|
||||
"feature_name" : "watcher",
|
||||
"minimum_index_version" : "7.0.0",
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED",
|
||||
"indices" : [ ]
|
||||
}
|
||||
],
|
||||
"upgrade_status" : "UPGRADE_NEEDED"
|
||||
"upgrade_status" : "NO_UPGRADE_NEEDED"
|
||||
}
|
||||
--------------------------------------------------
|
||||
// TESTRESPONSE[s/"minimum_index_version" : "7.0.0"/"minimum_index_version" : $body.$_path/]
|
||||
|
||||
This response tells us that Elasticsearch security needs its internal
|
||||
indices upgraded before we can upgrade the cluster to 8.0.
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.upgrades;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.admin.cluster.migration.TransportGetFeatureUpgradeStatusAction;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.test.XContentTestUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class FeatureUpgradeIT extends AbstractRollingTestCase {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testGetFeatureUpgradeStatus() throws Exception {
|
||||
|
||||
final String systemIndexWarning = "this request accesses system indices: [.tasks], but in a future major version, direct " +
|
||||
"access to system indices will be prevented by default";
|
||||
if (CLUSTER_TYPE == ClusterType.OLD) {
|
||||
// setup - put something in the tasks index
|
||||
// create index
|
||||
Request createTestIndex = new Request("PUT", "/feature_test_index_old");
|
||||
createTestIndex.setJsonEntity("{\"settings\": {" +
|
||||
"\"index.number_of_replicas\": 0," +
|
||||
"\"index.number_of_shards\": 1" +
|
||||
"}}");
|
||||
client().performRequest(createTestIndex);
|
||||
|
||||
Request bulk = new Request("POST", "/_bulk");
|
||||
bulk.addParameter("refresh", "true");
|
||||
if (UPGRADE_FROM_VERSION.before(Version.V_7_0_0)) {
|
||||
bulk.setJsonEntity("{\"index\": {\"_index\": \"feature_test_index_old\", \"_type\" : \"_doc\"}}\n" +
|
||||
"{\"f1\": \"v1\", \"f2\": \"v2\"}\n");
|
||||
} else {
|
||||
bulk.setJsonEntity("{\"index\": {\"_index\": \"feature_test_index_old\"}\n" +
|
||||
"{\"f1\": \"v1\", \"f2\": \"v2\"}\n");
|
||||
}
|
||||
client().performRequest(bulk);
|
||||
|
||||
// start a async reindex job
|
||||
Request reindex = new Request("POST", "/_reindex");
|
||||
reindex.setJsonEntity(
|
||||
"{\n" +
|
||||
" \"source\":{\n" +
|
||||
" \"index\":\"feature_test_index_old\"\n" +
|
||||
" },\n" +
|
||||
" \"dest\":{\n" +
|
||||
" \"index\":\"feature_test_index_reindex\"\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
reindex.addParameter("wait_for_completion", "false");
|
||||
Map<String, Object> response = entityAsMap(client().performRequest(reindex));
|
||||
String taskId = (String) response.get("task");
|
||||
|
||||
// wait for task
|
||||
Request getTask = new Request("GET", "/_tasks/" + taskId);
|
||||
getTask.addParameter("wait_for_completion", "true");
|
||||
client().performRequest(getTask);
|
||||
|
||||
// make sure .tasks index exists
|
||||
Request getTasksIndex = new Request("GET", "/.tasks");
|
||||
getTasksIndex.addParameter("allow_no_indices", "false");
|
||||
if (UPGRADE_FROM_VERSION.before(Version.V_7_0_0)) {
|
||||
getTasksIndex.addParameter("include_type_name", "false");
|
||||
}
|
||||
|
||||
getTasksIndex.setOptions(expectVersionSpecificWarnings(v -> {
|
||||
v.current(systemIndexWarning);
|
||||
v.compatible(systemIndexWarning);
|
||||
}));
|
||||
assertBusy(() -> {
|
||||
try {
|
||||
assertThat(client().performRequest(getTasksIndex).getStatusLine().getStatusCode(), is(200));
|
||||
} catch (ResponseException e) {
|
||||
throw new AssertionError(".tasks index does not exist yet");
|
||||
}
|
||||
});
|
||||
|
||||
} else if (CLUSTER_TYPE == ClusterType.UPGRADED) {
|
||||
// check results
|
||||
assertBusy(() -> {
|
||||
Request clusterStateRequest = new Request("GET", "/_migration/system_features");
|
||||
XContentTestUtils.JsonMapView view = new XContentTestUtils.JsonMapView(
|
||||
entityAsMap(client().performRequest(clusterStateRequest)));
|
||||
|
||||
List<Map<String, Object>> features = view.get("features");
|
||||
Map<String, Object> feature = features.stream()
|
||||
.filter(e -> "tasks".equals(e.get("feature_name")))
|
||||
.findFirst()
|
||||
.orElse(Collections.emptyMap());
|
||||
|
||||
assertThat(feature.size(), equalTo(4));
|
||||
assertThat(feature.get("minimum_index_version"), equalTo(UPGRADE_FROM_VERSION.toString()));
|
||||
if (UPGRADE_FROM_VERSION.before(TransportGetFeatureUpgradeStatusAction.NO_UPGRADE_REQUIRED_VERSION)) {
|
||||
assertThat(feature.get("upgrade_status"), equalTo("UPGRADE_NEEDED"));
|
||||
} else {
|
||||
assertThat(feature.get("upgrade_status"), equalTo("NO_UPGRADE_NEEDED"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.system.indices;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.test.XContentTestUtils;
|
||||
import org.elasticsearch.test.rest.ESRestTestCase;
|
||||
import org.junit.After;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class FeatureUpgradeApiIT extends ESRestTestCase {
|
||||
|
||||
static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("rest_user", new SecureString("rest-user-password".toCharArray()));
|
||||
|
||||
@After
|
||||
public void resetFeatures() throws Exception {
|
||||
client().performRequest(new Request("POST", "/_features/_reset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings restClientSettings() {
|
||||
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE).build();
|
||||
}
|
||||
|
||||
public void testCreatingSystemIndex() throws Exception {
|
||||
Response response = client().performRequest(new Request("PUT", "/_net_new_sys_index/_create"));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testGetFeatureUpgradedStatuses() throws Exception {
|
||||
client().performRequest(new Request("PUT", "/_net_new_sys_index/_create"));
|
||||
Response response = client().performRequest(new Request("GET", "/_migration/system_features"));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
XContentTestUtils.JsonMapView view = XContentTestUtils.createJsonMapView(response.getEntity().getContent());
|
||||
String upgradeStatus = view.get("upgrade_status");
|
||||
assertThat(upgradeStatus, equalTo("NO_UPGRADE_NEEDED"));
|
||||
List<Map<String, Object>> features = view.get("features");
|
||||
Map<String, Object> testFeature = features.stream()
|
||||
.filter(feature -> "system indices qa".equals(feature.get("feature_name")))
|
||||
.findFirst()
|
||||
.orElse(Collections.emptyMap());
|
||||
|
||||
assertThat(testFeature.size(), equalTo(4));
|
||||
assertThat(testFeature.get("minimum_index_version"), equalTo(Version.CURRENT.toString()));
|
||||
assertThat(testFeature.get("upgrade_status"), equalTo("NO_UPGRADE_NEEDED"));
|
||||
assertThat(testFeature.get("indices"), instanceOf(List.class));
|
||||
|
||||
assertThat((List<Object>) testFeature.get("indices"), hasSize(1));
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package org.elasticsearch.action.admin.cluster.migration;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
@ -27,13 +28,13 @@ import java.util.Objects;
|
|||
public class GetFeatureUpgradeStatusResponse extends ActionResponse implements ToXContentObject {
|
||||
|
||||
private final List<FeatureUpgradeStatus> featureUpgradeStatuses;
|
||||
private final String upgradeStatus;
|
||||
private final UpgradeStatus upgradeStatus;
|
||||
|
||||
/**
|
||||
* @param statuses A list of feature statuses
|
||||
* @param upgradeStatus Whether system features need to be upgraded
|
||||
*/
|
||||
public GetFeatureUpgradeStatusResponse(List<FeatureUpgradeStatus> statuses, String upgradeStatus) {
|
||||
public GetFeatureUpgradeStatusResponse(List<FeatureUpgradeStatus> statuses, UpgradeStatus upgradeStatus) {
|
||||
this.featureUpgradeStatuses = Objects.nonNull(statuses) ? statuses : Collections.emptyList();
|
||||
this.upgradeStatus = upgradeStatus;
|
||||
}
|
||||
|
@ -45,7 +46,7 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
public GetFeatureUpgradeStatusResponse(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
this.featureUpgradeStatuses = in.readList(FeatureUpgradeStatus::new);
|
||||
this.upgradeStatus = in.readString();
|
||||
this.upgradeStatus = in.readEnum(UpgradeStatus.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,14 +65,14 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeList(this.featureUpgradeStatuses);
|
||||
out.writeString(upgradeStatus);
|
||||
out.writeEnum(upgradeStatus);
|
||||
}
|
||||
|
||||
public List<FeatureUpgradeStatus> getFeatureUpgradeStatuses() {
|
||||
return featureUpgradeStatuses;
|
||||
}
|
||||
|
||||
public String getUpgradeStatus() {
|
||||
public UpgradeStatus getUpgradeStatus() {
|
||||
return upgradeStatus;
|
||||
}
|
||||
|
||||
|
@ -88,14 +89,28 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
return Objects.hash(featureUpgradeStatuses, upgradeStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GetFeatureUpgradeStatusResponse{" +
|
||||
"featureUpgradeStatuses=" + featureUpgradeStatuses +
|
||||
", upgradeStatus='" + upgradeStatus + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public enum UpgradeStatus {
|
||||
UPGRADE_NEEDED,
|
||||
NO_UPGRADE_NEEDED,
|
||||
IN_PROGRESS
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for a particular feature, showing whether it needs to be upgraded and the earliest
|
||||
* Elasticsearch version used to create one of this feature's system indices.
|
||||
*/
|
||||
public static class FeatureUpgradeStatus implements Writeable, ToXContentObject {
|
||||
private final String featureName;
|
||||
private final String minimumIndexVersion;
|
||||
private final String upgradeStatus;
|
||||
private final Version minimumIndexVersion;
|
||||
private final UpgradeStatus upgradeStatus;
|
||||
private final List<IndexVersion> indexVersions;
|
||||
|
||||
/**
|
||||
|
@ -104,8 +119,8 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
* @param upgradeStatus Whether the feature needs to be upgraded
|
||||
* @param indexVersions A list of this feature's concrete indices and the Elasticsearch version that created them
|
||||
*/
|
||||
public FeatureUpgradeStatus(String featureName, String minimumIndexVersion,
|
||||
String upgradeStatus, List<IndexVersion> indexVersions) {
|
||||
public FeatureUpgradeStatus(String featureName, Version minimumIndexVersion,
|
||||
UpgradeStatus upgradeStatus, List<IndexVersion> indexVersions) {
|
||||
this.featureName = featureName;
|
||||
this.minimumIndexVersion = minimumIndexVersion;
|
||||
this.upgradeStatus = upgradeStatus;
|
||||
|
@ -118,8 +133,8 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
*/
|
||||
public FeatureUpgradeStatus(StreamInput in) throws IOException {
|
||||
this.featureName = in.readString();
|
||||
this.minimumIndexVersion = in.readString();
|
||||
this.upgradeStatus = in.readString();
|
||||
this.minimumIndexVersion = Version.readVersion(in);
|
||||
this.upgradeStatus = in.readEnum(UpgradeStatus.class);
|
||||
this.indexVersions = in.readList(IndexVersion::new);
|
||||
}
|
||||
|
||||
|
@ -127,11 +142,11 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
return this.featureName;
|
||||
}
|
||||
|
||||
public String getMinimumIndexVersion() {
|
||||
public Version getMinimumIndexVersion() {
|
||||
return this.minimumIndexVersion;
|
||||
}
|
||||
|
||||
public String getUpgradeStatus() {
|
||||
public UpgradeStatus getUpgradeStatus() {
|
||||
return this.upgradeStatus;
|
||||
}
|
||||
|
||||
|
@ -142,8 +157,8 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(this.featureName);
|
||||
out.writeString(this.minimumIndexVersion);
|
||||
out.writeString(this.upgradeStatus);
|
||||
Version.writeVersion(this.minimumIndexVersion, out);
|
||||
out.writeEnum(this.upgradeStatus);
|
||||
out.writeList(this.indexVersions);
|
||||
}
|
||||
|
||||
|
@ -151,7 +166,7 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field("feature_name", this.featureName);
|
||||
builder.field("minimum_index_version", this.minimumIndexVersion);
|
||||
builder.field("minimum_index_version", this.minimumIndexVersion.toString());
|
||||
builder.field("upgrade_status", this.upgradeStatus);
|
||||
builder.startArray("indices");
|
||||
for (IndexVersion version : this.indexVersions) {
|
||||
|
@ -177,6 +192,16 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
public int hashCode() {
|
||||
return Objects.hash(featureName, minimumIndexVersion, upgradeStatus, indexVersions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FeatureUpgradeStatus{" +
|
||||
"featureName='" + featureName + '\'' +
|
||||
", minimumIndexVersion='" + minimumIndexVersion + '\'' +
|
||||
", upgradeStatus='" + upgradeStatus + '\'' +
|
||||
", indexVersions=" + indexVersions +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,13 +209,13 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
*/
|
||||
public static class IndexVersion implements Writeable, ToXContentObject {
|
||||
private final String indexName;
|
||||
private final String version;
|
||||
private final Version version;
|
||||
|
||||
/**
|
||||
* @param indexName Name of the index
|
||||
* @param version Version of Elasticsearch that created the index
|
||||
*/
|
||||
public IndexVersion(String indexName, String version) {
|
||||
public IndexVersion(String indexName, Version version) {
|
||||
this.indexName = indexName;
|
||||
this.version = version;
|
||||
}
|
||||
|
@ -201,28 +226,28 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
*/
|
||||
public IndexVersion(StreamInput in) throws IOException {
|
||||
this.indexName = in.readString();
|
||||
this.version = in.readString();
|
||||
this.version = Version.readVersion(in);
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return this.indexName;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
public Version getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(this.indexName);
|
||||
out.writeString(this.version);
|
||||
Version.writeVersion(this.version, out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field("index", this.indexName);
|
||||
builder.field("version", this.version);
|
||||
builder.field("version", this.version.toString());
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
@ -239,5 +264,13 @@ public class GetFeatureUpgradeStatusResponse extends ActionResponse implements T
|
|||
public int hashCode() {
|
||||
return Objects.hash(indexName, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IndexVersion{" +
|
||||
"indexName='" + indexName + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package org.elasticsearch.action.admin.cluster.migration;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
|
||||
|
@ -21,8 +22,14 @@ import org.elasticsearch.indices.SystemIndices;
|
|||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_UPGRADE_NEEDED;
|
||||
import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.UPGRADE_NEEDED;
|
||||
|
||||
/**
|
||||
* Transport class for the get feature upgrade status action
|
||||
|
@ -31,6 +38,8 @@ public class TransportGetFeatureUpgradeStatusAction extends TransportMasterNodeA
|
|||
GetFeatureUpgradeStatusRequest,
|
||||
GetFeatureUpgradeStatusResponse> {
|
||||
|
||||
public static final Version NO_UPGRADE_REQUIRED_VERSION = Version.V_7_0_0;
|
||||
|
||||
private final SystemIndices systemIndices;
|
||||
|
||||
@Inject
|
||||
|
@ -59,16 +68,51 @@ public class TransportGetFeatureUpgradeStatusAction extends TransportMasterNodeA
|
|||
@Override
|
||||
protected void masterOperation(GetFeatureUpgradeStatusRequest request, ClusterState state,
|
||||
ActionListener<GetFeatureUpgradeStatusResponse> listener) throws Exception {
|
||||
List<GetFeatureUpgradeStatusResponse.IndexVersion> indexVersions = new ArrayList<>();
|
||||
indexVersions.add(new GetFeatureUpgradeStatusResponse.IndexVersion(".security-7", "7.1.1"));
|
||||
List<GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus> features = new ArrayList<>();
|
||||
features.add(new GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus(
|
||||
"security",
|
||||
"7.1.1",
|
||||
"UPGRADE_NEEDED",
|
||||
|
||||
List<GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus> features = systemIndices.getFeatures().entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.map(entry -> getFeatureUpgradeStatus(state, entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
boolean isUpgradeNeeded = features.stream()
|
||||
.map(GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus::getMinimumIndexVersion)
|
||||
.min(Version::compareTo)
|
||||
.orElse(Version.CURRENT)
|
||||
.before(Version.V_7_0_0);
|
||||
|
||||
listener.onResponse(new GetFeatureUpgradeStatusResponse(features, isUpgradeNeeded ? UPGRADE_NEEDED : NO_UPGRADE_NEEDED));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
static GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus getFeatureUpgradeStatus(
|
||||
ClusterState state, String featureName, SystemIndices.Feature feature) {
|
||||
|
||||
List<GetFeatureUpgradeStatusResponse.IndexVersion> indexVersions = getIndexVersions(state, feature);
|
||||
|
||||
Version minimumVersion = indexVersions.stream()
|
||||
.map(GetFeatureUpgradeStatusResponse.IndexVersion::getVersion)
|
||||
.min(Version::compareTo)
|
||||
.orElse(Version.CURRENT);
|
||||
|
||||
return new GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus(
|
||||
featureName,
|
||||
minimumVersion,
|
||||
minimumVersion.before(Version.V_7_0_0) ? UPGRADE_NEEDED : NO_UPGRADE_NEEDED,
|
||||
indexVersions
|
||||
));
|
||||
listener.onResponse(new GetFeatureUpgradeStatusResponse(features, "UPGRADE_NEEDED"));
|
||||
);
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
static List<GetFeatureUpgradeStatusResponse.IndexVersion> getIndexVersions(ClusterState state, SystemIndices.Feature feature) {
|
||||
return Stream.of(feature.getIndexDescriptors(), feature.getAssociatedIndexDescriptors())
|
||||
.flatMap(Collection::stream)
|
||||
.flatMap(descriptor -> descriptor.getMatchingIndices(state.metadata()).stream())
|
||||
.sorted(String::compareTo)
|
||||
.map(index -> state.metadata().index(index))
|
||||
.map(indexMetadata -> new GetFeatureUpgradeStatusResponse.IndexVersion(
|
||||
indexMetadata.getIndex().getName(),
|
||||
indexMetadata.getCreationVersion()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
|
||||
package org.elasticsearch.action.admin.cluster.migration;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.UPGRADE_NEEDED;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
|
@ -31,7 +33,7 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractWireSerializin
|
|||
protected GetFeatureUpgradeStatusResponse createTestInstance() {
|
||||
return new GetFeatureUpgradeStatusResponse(
|
||||
randomList(8, GetFeatureUpgradeStatusResponseTests::createFeatureStatus),
|
||||
randomAlphaOfLengthBetween(4, 16)
|
||||
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -41,13 +43,14 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractWireSerializin
|
|||
randomList(8,
|
||||
() -> randomValueOtherThanMany(instance.getFeatureUpgradeStatuses()::contains,
|
||||
GetFeatureUpgradeStatusResponseTests::createFeatureStatus)),
|
||||
randomValueOtherThan(instance.getUpgradeStatus(), () -> randomAlphaOfLengthBetween(4, 16))
|
||||
);
|
||||
randomValueOtherThan(instance.getUpgradeStatus(), () ->
|
||||
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values())));
|
||||
|
||||
}
|
||||
|
||||
/** If constructor is called with null for a list, we just use an empty list */
|
||||
public void testConstructorHandlesNullLists() {
|
||||
GetFeatureUpgradeStatusResponse response = new GetFeatureUpgradeStatusResponse(null, "status");
|
||||
GetFeatureUpgradeStatusResponse response = new GetFeatureUpgradeStatusResponse(null, UPGRADE_NEEDED);
|
||||
assertThat(response.getFeatureUpgradeStatuses(), notNullValue());
|
||||
assertThat(response.getFeatureUpgradeStatuses(), equalTo(Collections.emptyList()));
|
||||
}
|
||||
|
@ -55,8 +58,8 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractWireSerializin
|
|||
private static GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus createFeatureStatus() {
|
||||
return new GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus(
|
||||
randomAlphaOfLengthBetween(3, 20),
|
||||
randomAlphaOfLengthBetween(5, 9),
|
||||
randomAlphaOfLengthBetween(4, 16),
|
||||
randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()),
|
||||
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values()),
|
||||
randomList(4, GetFeatureUpgradeStatusResponseTests::getIndexVersion)
|
||||
);
|
||||
}
|
||||
|
@ -64,7 +67,7 @@ public class GetFeatureUpgradeStatusResponseTests extends AbstractWireSerializin
|
|||
private static GetFeatureUpgradeStatusResponse.IndexVersion getIndexVersion() {
|
||||
return new GetFeatureUpgradeStatusResponse.IndexVersion(
|
||||
randomAlphaOfLengthBetween(3, 20),
|
||||
randomAlphaOfLengthBetween(5, 9)
|
||||
randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.cluster.migration;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||
import org.elasticsearch.cluster.metadata.Metadata;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.indices.SystemIndexDescriptor;
|
||||
import org.elasticsearch.indices.SystemIndices;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_UPGRADE_NEEDED;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class TransportGetFeatureUpgradeStatusActionTests extends ESTestCase {
|
||||
|
||||
public static String TEST_SYSTEM_INDEX_PATTERN = ".test*";
|
||||
private static final ClusterState CLUSTER_STATE = getClusterState();
|
||||
private static final SystemIndices.Feature FEATURE = getFeature();
|
||||
|
||||
public void testGetFeatureStatus() {
|
||||
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus status =
|
||||
TransportGetFeatureUpgradeStatusAction.getFeatureUpgradeStatus(
|
||||
CLUSTER_STATE, "test-feature", FEATURE);
|
||||
|
||||
assertThat(status.getUpgradeStatus(), equalTo(NO_UPGRADE_NEEDED));
|
||||
assertThat(status.getFeatureName(), equalTo("test-feature"));
|
||||
assertThat(status.getMinimumIndexVersion(), equalTo(Version.V_7_0_0));
|
||||
assertThat(status.getIndexVersions().size(), equalTo(2)); // additional testing below
|
||||
}
|
||||
|
||||
public void testGetIndexVersion() {
|
||||
List<GetFeatureUpgradeStatusResponse.IndexVersion> versions =
|
||||
TransportGetFeatureUpgradeStatusAction.getIndexVersions(CLUSTER_STATE, FEATURE);
|
||||
|
||||
assertThat(versions.size(), equalTo(2));
|
||||
|
||||
{
|
||||
GetFeatureUpgradeStatusResponse.IndexVersion version = versions.get(0);
|
||||
assertThat(version.getVersion(), equalTo(Version.CURRENT));
|
||||
assertThat(version.getIndexName(), equalTo(".test-index-1"));
|
||||
}
|
||||
{
|
||||
GetFeatureUpgradeStatusResponse.IndexVersion version = versions.get(1);
|
||||
assertThat(version.getVersion(), equalTo(Version.V_7_0_0));
|
||||
assertThat(version.getIndexName(), equalTo(".test-index-2"));
|
||||
}
|
||||
}
|
||||
|
||||
private static SystemIndices.Feature getFeature() {
|
||||
SystemIndexDescriptor descriptor = new SystemIndexDescriptor(TEST_SYSTEM_INDEX_PATTERN, "descriptor for tests");
|
||||
|
||||
List<SystemIndexDescriptor> descriptors = new ArrayList<>();
|
||||
descriptors.add(descriptor);
|
||||
|
||||
// system indices feature object
|
||||
SystemIndices.Feature feature = new SystemIndices.Feature(
|
||||
"test-feature",
|
||||
"feature for tests",
|
||||
descriptors);
|
||||
return feature;
|
||||
}
|
||||
|
||||
private static ClusterState getClusterState() {
|
||||
IndexMetadata indexMetadata1 = IndexMetadata.builder(".test-index-1")
|
||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build();
|
||||
|
||||
IndexMetadata indexMetadata2 = IndexMetadata.builder(".test-index-2")
|
||||
.settings(Settings.builder().put("index.version.created", Version.V_7_0_0).build())
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build();
|
||||
|
||||
ClusterState clusterState = new ClusterState.Builder(ClusterState.EMPTY_STATE)
|
||||
.metadata(new Metadata.Builder()
|
||||
.indices(ImmutableOpenMap.<String, IndexMetadata>builder()
|
||||
.fPut(".test-index-1", indexMetadata1)
|
||||
.fPut(".test-index-2", indexMetadata2)
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
return clusterState;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue