Skip to content

Commit ccfec46

Browse files
Implement GET API for System Feature Upgrades (elastic#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
1 parent 3e3d974 commit ccfec46

File tree

9 files changed

+485
-64
lines changed

9 files changed

+485
-64
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/MigrationIT.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.elasticsearch.client;
1010

1111
import org.elasticsearch.jdk.JavaVersion;
12+
import org.elasticsearch.Version;
1213
import org.elasticsearch.client.migration.DeprecationInfoRequest;
1314
import org.elasticsearch.client.migration.DeprecationInfoResponse;
1415
import org.elasticsearch.client.migration.GetFeatureUpgradeStatusRequest;
@@ -20,11 +21,14 @@
2021
import java.io.IOException;
2122
import java.util.Collections;
2223
import java.util.List;
24+
import java.util.Optional;
2325
import java.util.stream.Collectors;
2426

2527
import static org.hamcrest.Matchers.anEmptyMap;
2628
import static org.hamcrest.Matchers.empty;
2729
import static org.hamcrest.Matchers.equalTo;
30+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
31+
import static org.hamcrest.Matchers.is;
2832
import static org.hamcrest.Matchers.nullValue;
2933

3034
public class MigrationIT extends ESRestHighLevelClientTestCase {
@@ -51,19 +55,24 @@ public void testGetDeprecationInfo() throws IOException {
5155
public void testGetFeatureUpgradeStatus() throws IOException {
5256
GetFeatureUpgradeStatusRequest request = new GetFeatureUpgradeStatusRequest();
5357
GetFeatureUpgradeStatusResponse response = highLevelClient().migration().getFeatureUpgradeStatus(request, RequestOptions.DEFAULT);
54-
assertThat(response.getUpgradeStatus(), equalTo("UPGRADE_NEEDED"));
55-
assertThat(response.getFeatureUpgradeStatuses().size(), equalTo(1));
56-
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus status = response.getFeatureUpgradeStatuses().get(0);
57-
assertThat(status.getUpgradeStatus(), equalTo("UPGRADE_NEEDED"));
58-
assertThat(status.getMinimumIndexVersion(), equalTo("7.1.1"));
59-
assertThat(status.getFeatureName(), equalTo("security"));
60-
assertThat(status.getIndexVersions().size(), equalTo(1));
58+
assertThat(response.getUpgradeStatus(), equalTo("NO_UPGRADE_NEEDED"));
59+
assertThat(response.getFeatureUpgradeStatuses().size(), greaterThanOrEqualTo(1));
60+
Optional<GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus> optionalTasksStatus = response.getFeatureUpgradeStatuses().stream()
61+
.filter(status -> "tasks".equals(status.getFeatureName()))
62+
.findFirst();
63+
64+
assertThat(optionalTasksStatus.isPresent(), is(true));
65+
66+
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus tasksStatus = optionalTasksStatus.get();
67+
68+
assertThat(tasksStatus.getUpgradeStatus(), equalTo("NO_UPGRADE_NEEDED"));
69+
assertThat(tasksStatus.getMinimumIndexVersion(), equalTo(Version.CURRENT.toString()));
70+
assertThat(tasksStatus.getFeatureName(), equalTo("tasks"));
6171
}
6272

6373
public void testPostFeatureUpgradeStatus() throws IOException {
6474
PostFeatureUpgradeRequest request = new PostFeatureUpgradeRequest();
6575
PostFeatureUpgradeResponse response = highLevelClient().migration().postFeatureUpgrade(request, RequestOptions.DEFAULT);
66-
// a test like this cannot test actual deprecations
6776
assertThat(response.isAccepted(), equalTo(true));
6877
assertThat(response.getFeatures().size(), equalTo(1));
6978
PostFeatureUpgradeResponse.Feature feature = response.getFeatures().get(0);

client/rest-high-level/src/test/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponseTests.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.elasticsearch.client.migration;
1010

11+
import org.elasticsearch.Version;
1112
import org.elasticsearch.client.AbstractResponseTestCase;
1213
import org.elasticsearch.common.xcontent.XContentParser;
1314
import org.elasticsearch.common.xcontent.XContentType;
@@ -37,14 +38,14 @@ protected org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStat
3738
randomList(5,
3839
() -> new org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus(
3940
randomAlphaOfLengthBetween(3, 20),
40-
randomAlphaOfLengthBetween(5, 9),
41-
randomAlphaOfLengthBetween(4, 16),
41+
randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()),
42+
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values()),
4243
randomList(4,
4344
() -> new org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.IndexVersion(
4445
randomAlphaOfLengthBetween(3, 20),
45-
randomAlphaOfLengthBetween(5, 9)))
46+
randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion())))
4647
)),
47-
randomAlphaOfLength(5)
48+
randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values())
4849
);
4950
}
5051

@@ -58,7 +59,7 @@ protected void assertInstances(
5859
org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse serverTestInstance,
5960
GetFeatureUpgradeStatusResponse clientInstance) {
6061

61-
assertThat(clientInstance.getUpgradeStatus(), equalTo(serverTestInstance.getUpgradeStatus()));
62+
assertThat(clientInstance.getUpgradeStatus(), equalTo(serverTestInstance.getUpgradeStatus().toString()));
6263

6364
assertNotNull(serverTestInstance.getFeatureUpgradeStatuses());
6465
assertNotNull(clientInstance.getFeatureUpgradeStatuses());
@@ -71,8 +72,8 @@ protected void assertInstances(
7172
GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus clientStatus = clientInstance.getFeatureUpgradeStatuses().get(i);
7273

7374
assertThat(clientStatus.getFeatureName(), equalTo(serverTestStatus.getFeatureName()));
74-
assertThat(clientStatus.getMinimumIndexVersion(), equalTo(serverTestStatus.getMinimumIndexVersion()));
75-
assertThat(clientStatus.getUpgradeStatus(), equalTo(serverTestStatus.getUpgradeStatus()));
75+
assertThat(clientStatus.getMinimumIndexVersion(), equalTo(serverTestStatus.getMinimumIndexVersion().toString()));
76+
assertThat(clientStatus.getUpgradeStatus(), equalTo(serverTestStatus.getUpgradeStatus().toString()));
7677

7778
assertThat(clientStatus.getIndexVersions(), hasSize(serverTestStatus.getIndexVersions().size()));
7879

@@ -82,7 +83,7 @@ protected void assertInstances(
8283
GetFeatureUpgradeStatusResponse.IndexVersion clientIndexVersion = clientStatus.getIndexVersions().get(j);
8384

8485
assertThat(clientIndexVersion.getIndexName(), equalTo(serverIndexVersion.getIndexName()));
85-
assertThat(clientIndexVersion.getVersion(), equalTo(serverIndexVersion.getVersion()));
86+
assertThat(clientIndexVersion.getVersion(), equalTo(serverIndexVersion.getVersion().toString()));
8687
}
8788
}
8889
}

docs/reference/migration/apis/feature_upgrade.asciidoc

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,80 @@ Example response:
4343
--------------------------------------------------
4444
{
4545
"features" : [
46+
{
47+
"feature_name" : "async_search",
48+
"minimum_index_version" : "8.0.0",
49+
"upgrade_status" : "NO_UPGRADE_NEEDED",
50+
"indices" : [ ]
51+
},
52+
{
53+
"feature_name" : "enrich",
54+
"minimum_index_version" : "8.0.0",
55+
"upgrade_status" : "NO_UPGRADE_NEEDED",
56+
"indices" : [ ]
57+
},
58+
{
59+
"feature_name" : "fleet",
60+
"minimum_index_version" : "8.0.0",
61+
"upgrade_status" : "NO_UPGRADE_NEEDED",
62+
"indices" : [ ]
63+
},
64+
{
65+
"feature_name" : "geoip",
66+
"minimum_index_version" : "8.0.0",
67+
"upgrade_status" : "NO_UPGRADE_NEEDED",
68+
"indices" : [ ]
69+
},
70+
{
71+
"feature_name" : "kibana",
72+
"minimum_index_version" : "8.0.0",
73+
"upgrade_status" : "NO_UPGRADE_NEEDED",
74+
"indices" : [ ]
75+
},
76+
{
77+
"feature_name" : "logstash_management",
78+
"minimum_index_version" : "8.0.0",
79+
"upgrade_status" : "NO_UPGRADE_NEEDED",
80+
"indices" : [ ]
81+
},
82+
{
83+
"feature_name" : "machine_learning",
84+
"minimum_index_version" : "8.0.0",
85+
"upgrade_status" : "NO_UPGRADE_NEEDED",
86+
"indices" : [ ]
87+
},
88+
{
89+
"feature_name" : "searchable_snapshots",
90+
"minimum_index_version" : "8.0.0",
91+
"upgrade_status" : "NO_UPGRADE_NEEDED",
92+
"indices" : [ ]
93+
},
4694
{
4795
"feature_name" : "security",
48-
"minimum_index_version" : "7.1.1",
49-
"upgrade_status" : "UPGRADE_NEEDED",
50-
"indices" : [
51-
{
52-
"index" : ".security-7",
53-
"version" : "7.1.1"
54-
}
55-
]
96+
"minimum_index_version" : "8.0.0",
97+
"upgrade_status" : "NO_UPGRADE_NEEDED",
98+
"indices" : [ ]
99+
},
100+
{
101+
"feature_name" : "tasks",
102+
"minimum_index_version" : "8.0.0",
103+
"upgrade_status" : "NO_UPGRADE_NEEDED",
104+
"indices" : [ ]
105+
},
106+
{
107+
"feature_name" : "transform",
108+
"minimum_index_version" : "8.0.0",
109+
"upgrade_status" : "NO_UPGRADE_NEEDED",
110+
"indices" : [ ]
111+
},
112+
{
113+
"feature_name" : "watcher",
114+
"minimum_index_version" : "8.0.0",
115+
"upgrade_status" : "NO_UPGRADE_NEEDED",
116+
"indices" : [ ]
56117
}
57118
],
58-
"upgrade_status" : "UPGRADE_NEEDED"
119+
"upgrade_status" : "NO_UPGRADE_NEEDED"
59120
}
60121
--------------------------------------------------
61122

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.upgrades;
10+
11+
import org.elasticsearch.Version;
12+
import org.elasticsearch.client.Request;
13+
import org.elasticsearch.client.ResponseException;
14+
import org.elasticsearch.test.XContentTestUtils;
15+
16+
import java.util.Collections;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
import static org.hamcrest.Matchers.equalTo;
21+
import static org.hamcrest.Matchers.is;
22+
23+
public class FeatureUpgradeIT extends AbstractRollingTestCase {
24+
25+
@SuppressWarnings("unchecked")
26+
public void testGetFeatureUpgradeStatus() throws Exception {
27+
28+
final String systemIndexWarning = "this request accesses system indices: [.tasks], but in a future major version, direct " +
29+
"access to system indices will be prevented by default";
30+
if (CLUSTER_TYPE == ClusterType.OLD) {
31+
// setup - put something in the tasks index
32+
// create index
33+
Request createTestIndex = new Request("PUT", "/feature_test_index_old");
34+
createTestIndex.setJsonEntity("{\"settings\": {\"index.number_of_replicas\": 0}}");
35+
client().performRequest(createTestIndex);
36+
37+
Request bulk = new Request("POST", "/_bulk");
38+
bulk.addParameter("refresh", "true");
39+
bulk.setJsonEntity("{\"index\": {\"_index\": \"feature_test_index_old\"}}\n" +
40+
"{\"f1\": \"v1\", \"f2\": \"v2\"}\n");
41+
client().performRequest(bulk);
42+
43+
// start a async reindex job
44+
Request reindex = new Request("POST", "/_reindex");
45+
reindex.setJsonEntity(
46+
"{\n" +
47+
" \"source\":{\n" +
48+
" \"index\":\"feature_test_index_old\"\n" +
49+
" },\n" +
50+
" \"dest\":{\n" +
51+
" \"index\":\"feature_test_index_reindex\"\n" +
52+
" }\n" +
53+
"}");
54+
reindex.addParameter("wait_for_completion", "false");
55+
Map<String, Object> response = entityAsMap(client().performRequest(reindex));
56+
String taskId = (String) response.get("task");
57+
58+
// wait for task
59+
Request getTask = new Request("GET", "/_tasks/" + taskId);
60+
getTask.addParameter("wait_for_completion", "true");
61+
client().performRequest(getTask);
62+
63+
// make sure .tasks index exists
64+
Request getTasksIndex = new Request("GET", "/.tasks");
65+
getTasksIndex.setOptions(expectVersionSpecificWarnings(v -> {
66+
v.current(systemIndexWarning);
67+
v.compatible(systemIndexWarning);
68+
}));
69+
getTasksIndex.addParameter("allow_no_indices", "false");
70+
71+
assertBusy(() -> {
72+
try {
73+
assertThat(client().performRequest(getTasksIndex).getStatusLine().getStatusCode(), is(200));
74+
} catch (ResponseException e) {
75+
throw new AssertionError(".tasks index does not exist yet");
76+
}
77+
});
78+
79+
} else if (CLUSTER_TYPE == ClusterType.UPGRADED) {
80+
// check results
81+
assertBusy(() -> {
82+
Request clusterStateRequest = new Request("GET", "/_migration/system_features");
83+
XContentTestUtils.JsonMapView view = new XContentTestUtils.JsonMapView(
84+
entityAsMap(client().performRequest(clusterStateRequest)));
85+
86+
List<Map<String, Object>> features = view.get("features");
87+
Map<String, Object> feature = features.stream()
88+
.filter(e -> "tasks".equals(e.get("feature_name")))
89+
.findFirst()
90+
.orElse(Collections.emptyMap());
91+
92+
assertThat(feature.size(), equalTo(4));
93+
assertThat(feature.get("minimum_index_version"), equalTo(UPGRADE_FROM_VERSION.toString()));
94+
if (UPGRADE_FROM_VERSION.before(Version.CURRENT.minimumIndexCompatibilityVersion())) {
95+
assertThat(feature.get("upgrade_status"), equalTo("UPGRADE_NEEDED"));
96+
} else {
97+
assertThat(feature.get("upgrade_status"), equalTo("NO_UPGRADE_NEEDED"));
98+
}
99+
});
100+
}
101+
}
102+
103+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.system.indices;
10+
11+
import org.elasticsearch.Version;
12+
import org.elasticsearch.client.Request;
13+
import org.elasticsearch.client.Response;
14+
import org.elasticsearch.common.settings.SecureString;
15+
import org.elasticsearch.common.settings.Settings;
16+
import org.elasticsearch.common.util.concurrent.ThreadContext;
17+
import org.elasticsearch.test.XContentTestUtils;
18+
import org.elasticsearch.test.rest.ESRestTestCase;
19+
import org.junit.After;
20+
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
import static org.hamcrest.Matchers.equalTo;
26+
import static org.hamcrest.Matchers.hasSize;
27+
import static org.hamcrest.Matchers.instanceOf;
28+
import static org.hamcrest.Matchers.is;
29+
30+
public class FeatureUpgradeApiIT extends ESRestTestCase {
31+
32+
static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("rest_user", new SecureString("rest-user-password".toCharArray()));
33+
34+
@After
35+
public void resetFeatures() throws Exception {
36+
client().performRequest(new Request("POST", "/_features/_reset"));
37+
}
38+
39+
@Override
40+
protected Settings restClientSettings() {
41+
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE).build();
42+
}
43+
44+
public void testCreatingSystemIndex() throws Exception {
45+
Response response = client().performRequest(new Request("PUT", "/_net_new_sys_index/_create"));
46+
assertThat(response.getStatusLine().getStatusCode(), is(200));
47+
}
48+
49+
@SuppressWarnings("unchecked")
50+
public void testGetFeatureUpgradedStatuses() throws Exception {
51+
client().performRequest(new Request("PUT", "/_net_new_sys_index/_create"));
52+
Response response = client().performRequest(new Request("GET", "/_migration/system_features"));
53+
assertThat(response.getStatusLine().getStatusCode(), is(200));
54+
XContentTestUtils.JsonMapView view = XContentTestUtils.createJsonMapView(response.getEntity().getContent());
55+
String upgradeStatus = view.get("upgrade_status");
56+
assertThat(upgradeStatus, equalTo("NO_UPGRADE_NEEDED"));
57+
List<Map<String, Object>> features = view.get("features");
58+
Map<String, Object> testFeature = features.stream()
59+
.filter(feature -> "system indices qa".equals(feature.get("feature_name")))
60+
.findFirst()
61+
.orElse(Collections.emptyMap());
62+
63+
assertThat(testFeature.size(), equalTo(4));
64+
assertThat(testFeature.get("minimum_index_version"), equalTo(Version.CURRENT.toString()));
65+
assertThat(testFeature.get("upgrade_status"), equalTo("NO_UPGRADE_NEEDED"));
66+
assertThat(testFeature.get("indices"), instanceOf(List.class));
67+
68+
assertThat((List<Object>) testFeature.get("indices"), hasSize(1));
69+
}
70+
}

0 commit comments

Comments
 (0)