Skip to content

Commit c168e1c

Browse files
authored
Update index settings during remote store migration (opensearch-project#12748)
Signed-off-by: Lakshya Taragi <lakshya.taragi@gmail.com>
1 parent 7345371 commit c168e1c

File tree

8 files changed

+569
-97
lines changed

8 files changed

+569
-97
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.remotemigration;
10+
11+
import org.opensearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
12+
import org.opensearch.client.Client;
13+
import org.opensearch.cluster.metadata.IndexMetadata;
14+
import org.opensearch.common.settings.Settings;
15+
import org.opensearch.core.rest.RestStatus;
16+
import org.opensearch.index.IndexSettings;
17+
import org.opensearch.indices.replication.common.ReplicationType;
18+
import org.opensearch.snapshots.SnapshotInfo;
19+
import org.opensearch.snapshots.SnapshotState;
20+
import org.opensearch.test.OpenSearchIntegTestCase;
21+
22+
import java.nio.file.Path;
23+
import java.util.Optional;
24+
25+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_REMOTE_SEGMENT_STORE_REPOSITORY;
26+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_REMOTE_STORE_ENABLED;
27+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_REMOTE_TRANSLOG_STORE_REPOSITORY;
28+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_REPLICATION_TYPE;
29+
import static org.opensearch.index.IndexSettings.INDEX_REMOTE_TRANSLOG_BUFFER_INTERVAL_SETTING;
30+
import static org.opensearch.node.remotestore.RemoteStoreNodeService.CompatibilityMode.MIXED;
31+
import static org.opensearch.node.remotestore.RemoteStoreNodeService.Direction.REMOTE_STORE;
32+
import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertAcked;
33+
34+
@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.TEST, numDataNodes = 0)
35+
public class RemoteStoreMigrationSettingsUpdateIT extends RemoteStoreMigrationShardAllocationBaseTestCase {
36+
37+
private Client client;
38+
39+
// remote store backed index setting tests
40+
41+
public void testNewIndexIsRemoteStoreBackedForRemoteStoreDirectionAndMixedMode() {
42+
logger.info("Initialize cluster: gives non remote cluster manager");
43+
initializeCluster(false);
44+
45+
String indexName1 = "test_index_1";
46+
String indexName2 = "test_index_2";
47+
48+
logger.info("Add non-remote node");
49+
addRemote = false;
50+
String nonRemoteNodeName = internalCluster().startNode();
51+
internalCluster().validateClusterFormed();
52+
assertNodeInCluster(nonRemoteNodeName);
53+
54+
logger.info("Create an index");
55+
prepareIndexWithoutReplica(Optional.of(indexName1));
56+
57+
logger.info("Verify that non remote-backed index is created");
58+
assertNonRemoteStoreBackedIndex(indexName1);
59+
60+
logger.info("Set mixed cluster compatibility mode and remote_store direction");
61+
setClusterMode(MIXED.mode);
62+
setDirection(REMOTE_STORE.direction);
63+
64+
logger.info("Add remote node");
65+
addRemote = true;
66+
String remoteNodeName = internalCluster().startNode();
67+
internalCluster().validateClusterFormed();
68+
assertNodeInCluster(remoteNodeName);
69+
70+
logger.info("Create another index");
71+
prepareIndexWithoutReplica(Optional.of(indexName2));
72+
73+
logger.info("Verify that remote backed index is created");
74+
assertRemoteStoreBackedIndex(indexName2);
75+
}
76+
77+
public void testNewRestoredIndexIsRemoteStoreBackedForRemoteStoreDirectionAndMixedMode() throws Exception {
78+
logger.info("Initialize cluster: gives non remote cluster manager");
79+
initializeCluster(false);
80+
81+
logger.info("Add remote and non-remote nodes");
82+
setClusterMode(MIXED.mode);
83+
addRemote = false;
84+
String nonRemoteNodeName = internalCluster().startNode();
85+
addRemote = true;
86+
String remoteNodeName = internalCluster().startNode();
87+
internalCluster().validateClusterFormed();
88+
assertNodeInCluster(nonRemoteNodeName);
89+
assertNodeInCluster(remoteNodeName);
90+
91+
logger.info("Create a non remote-backed index");
92+
client.admin()
93+
.indices()
94+
.prepareCreate(TEST_INDEX)
95+
.setSettings(
96+
Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).build()
97+
)
98+
.get();
99+
100+
logger.info("Verify that non remote stored backed index is created");
101+
assertNonRemoteStoreBackedIndex(TEST_INDEX);
102+
103+
logger.info("Create repository");
104+
String snapshotName = "test-snapshot";
105+
String snapshotRepoName = "test-restore-snapshot-repo";
106+
Path snapshotRepoNameAbsolutePath = randomRepoPath().toAbsolutePath();
107+
assertAcked(
108+
clusterAdmin().preparePutRepository(snapshotRepoName)
109+
.setType("fs")
110+
.setSettings(Settings.builder().put("location", snapshotRepoNameAbsolutePath))
111+
);
112+
113+
logger.info("Create snapshot of non remote stored backed index");
114+
115+
SnapshotInfo snapshotInfo = client().admin()
116+
.cluster()
117+
.prepareCreateSnapshot(snapshotRepoName, snapshotName)
118+
.setIndices(TEST_INDEX)
119+
.setWaitForCompletion(true)
120+
.get()
121+
.getSnapshotInfo();
122+
123+
assertEquals(SnapshotState.SUCCESS, snapshotInfo.state());
124+
assertTrue(snapshotInfo.successfulShards() > 0);
125+
assertEquals(0, snapshotInfo.failedShards());
126+
127+
logger.info("Restore index from snapshot under NONE direction");
128+
String restoredIndexName1 = TEST_INDEX + "-restored1";
129+
restoreSnapshot(snapshotRepoName, snapshotName, restoredIndexName1);
130+
131+
logger.info("Verify that restored index is non remote-backed");
132+
assertNonRemoteStoreBackedIndex(restoredIndexName1);
133+
134+
logger.info("Restore index from snapshot under REMOTE_STORE direction");
135+
setDirection(REMOTE_STORE.direction);
136+
String restoredIndexName2 = TEST_INDEX + "-restored2";
137+
restoreSnapshot(snapshotRepoName, snapshotName, restoredIndexName2);
138+
139+
logger.info("Verify that restored index is non remote-backed");
140+
assertRemoteStoreBackedIndex(restoredIndexName2);
141+
}
142+
143+
// restore indices from a snapshot
144+
private void restoreSnapshot(String snapshotRepoName, String snapshotName, String restoredIndexName) {
145+
RestoreSnapshotResponse restoreSnapshotResponse = client.admin()
146+
.cluster()
147+
.prepareRestoreSnapshot(snapshotRepoName, snapshotName)
148+
.setWaitForCompletion(false)
149+
.setIndices(TEST_INDEX)
150+
.setRenamePattern(TEST_INDEX)
151+
.setRenameReplacement(restoredIndexName)
152+
.get();
153+
154+
assertEquals(restoreSnapshotResponse.status(), RestStatus.ACCEPTED);
155+
ensureGreen(restoredIndexName);
156+
}
157+
158+
// verify that the created index is not remote store backed
159+
private void assertNonRemoteStoreBackedIndex(String indexName) {
160+
Settings indexSettings = client.admin().indices().prepareGetIndex().execute().actionGet().getSettings().get(indexName);
161+
assertEquals(ReplicationType.DOCUMENT.toString(), indexSettings.get(SETTING_REPLICATION_TYPE));
162+
assertNull(indexSettings.get(SETTING_REMOTE_STORE_ENABLED));
163+
assertNull(indexSettings.get(SETTING_REMOTE_SEGMENT_STORE_REPOSITORY));
164+
assertNull(indexSettings.get(SETTING_REMOTE_TRANSLOG_STORE_REPOSITORY));
165+
}
166+
167+
// verify that the created index is remote store backed
168+
private void assertRemoteStoreBackedIndex(String indexName) {
169+
Settings indexSettings = client.admin().indices().prepareGetIndex().execute().actionGet().getSettings().get(indexName);
170+
assertEquals(ReplicationType.SEGMENT.toString(), indexSettings.get(SETTING_REPLICATION_TYPE));
171+
assertEquals("true", indexSettings.get(SETTING_REMOTE_STORE_ENABLED));
172+
assertEquals(REPOSITORY_NAME, indexSettings.get(SETTING_REMOTE_SEGMENT_STORE_REPOSITORY));
173+
assertEquals(REPOSITORY_2_NAME, indexSettings.get(SETTING_REMOTE_TRANSLOG_STORE_REPOSITORY));
174+
assertEquals(
175+
IndexSettings.DEFAULT_REMOTE_TRANSLOG_BUFFER_INTERVAL,
176+
INDEX_REMOTE_TRANSLOG_BUFFER_INTERVAL_SETTING.get(indexSettings)
177+
);
178+
}
179+
180+
// bootstrap a cluster
181+
private void initializeCluster(boolean remoteClusterManager) {
182+
addRemote = remoteClusterManager;
183+
internalCluster().startClusterManagerOnlyNode();
184+
client = internalCluster().client();
185+
}
186+
187+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.remotemigration;
10+
11+
import org.opensearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
12+
import org.opensearch.cluster.node.DiscoveryNode;
13+
import org.opensearch.cluster.node.DiscoveryNodes;
14+
import org.opensearch.cluster.routing.IndexShardRoutingTable;
15+
import org.opensearch.cluster.routing.ShardRouting;
16+
import org.opensearch.common.settings.Settings;
17+
18+
import java.util.Map;
19+
import java.util.Optional;
20+
21+
import static org.opensearch.node.remotestore.RemoteStoreNodeService.MIGRATION_DIRECTION_SETTING;
22+
import static org.opensearch.node.remotestore.RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING;
23+
import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertAcked;
24+
25+
public class RemoteStoreMigrationShardAllocationBaseTestCase extends MigrationBaseTestCase {
26+
protected static final String TEST_INDEX = "test_index";
27+
protected static final String NAME = "remote_store_migration";
28+
29+
protected final ClusterUpdateSettingsRequest updateSettingsRequest = new ClusterUpdateSettingsRequest();
30+
31+
// set the compatibility mode of cluster [strict, mixed]
32+
protected void setClusterMode(String mode) {
33+
updateSettingsRequest.persistentSettings(Settings.builder().put(REMOTE_STORE_COMPATIBILITY_MODE_SETTING.getKey(), mode));
34+
assertAcked(internalCluster().client().admin().cluster().updateSettings(updateSettingsRequest).actionGet());
35+
}
36+
37+
// set the migration direction for cluster [remote_store, docrep, none]
38+
public void setDirection(String direction) {
39+
updateSettingsRequest.persistentSettings(Settings.builder().put(MIGRATION_DIRECTION_SETTING.getKey(), direction));
40+
assertAcked(internalCluster().client().admin().cluster().updateSettings(updateSettingsRequest).actionGet());
41+
}
42+
43+
// verify that the given nodeName exists in cluster
44+
protected DiscoveryNode assertNodeInCluster(String nodeName) {
45+
Map<String, DiscoveryNode> nodes = internalCluster().client().admin().cluster().prepareState().get().getState().nodes().getNodes();
46+
DiscoveryNode discoveryNode = null;
47+
for (Map.Entry<String, DiscoveryNode> entry : nodes.entrySet()) {
48+
DiscoveryNode node = entry.getValue();
49+
if (node.getName().equals(nodeName)) {
50+
discoveryNode = node;
51+
break;
52+
}
53+
}
54+
assertNotNull(discoveryNode);
55+
return discoveryNode;
56+
}
57+
58+
// returns a comma-separated list of node names excluding `except`
59+
protected String allNodesExcept(String except) {
60+
StringBuilder exclude = new StringBuilder();
61+
DiscoveryNodes allNodes = internalCluster().client().admin().cluster().prepareState().get().getState().nodes();
62+
for (DiscoveryNode node : allNodes) {
63+
if (node.getName().equals(except) == false) {
64+
exclude.append(node.getName()).append(",");
65+
}
66+
}
67+
return exclude.toString();
68+
}
69+
70+
// create a new test index
71+
protected void prepareIndexWithoutReplica(Optional<String> name) {
72+
String indexName = name.orElse(TEST_INDEX);
73+
internalCluster().client()
74+
.admin()
75+
.indices()
76+
.prepareCreate(indexName)
77+
.setSettings(
78+
Settings.builder()
79+
.put("index.number_of_shards", 1)
80+
.put("index.number_of_replicas", 0)
81+
.put("index.routing.allocation.exclude._name", allNodesExcept(null))
82+
)
83+
.execute()
84+
.actionGet();
85+
}
86+
87+
protected ShardRouting getShardRouting(boolean isPrimary) {
88+
IndexShardRoutingTable table = internalCluster().client()
89+
.admin()
90+
.cluster()
91+
.prepareState()
92+
.execute()
93+
.actionGet()
94+
.getState()
95+
.getRoutingTable()
96+
.index(TEST_INDEX)
97+
.shard(0);
98+
return (isPrimary ? table.primaryShard() : table.replicaShards().get(0));
99+
}
100+
101+
}

0 commit comments

Comments
 (0)