Skip to content

Commit fb21ab3

Browse files
committed
Use cluster default remote store path type during snapshot restore (opensearch-project#12753)
* Use cluster default remote store path type as fallback during snapshot restore --------- Signed-off-by: Ashish Singh <ssashish@amazon.com>
1 parent 7eec761 commit fb21ab3

File tree

4 files changed

+158
-7
lines changed

4 files changed

+158
-7
lines changed

server/src/internalClusterTest/java/org/opensearch/remotestore/RemoteRestoreSnapshotIT.java

+83-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.opensearch.action.support.PlainActionFuture;
1717
import org.opensearch.client.Client;
1818
import org.opensearch.client.Requests;
19+
import org.opensearch.cluster.ClusterState;
1920
import org.opensearch.cluster.metadata.IndexMetadata;
2021
import org.opensearch.common.io.PathUtils;
2122
import org.opensearch.common.settings.Settings;
@@ -24,6 +25,7 @@
2425
import org.opensearch.core.rest.RestStatus;
2526
import org.opensearch.index.IndexService;
2627
import org.opensearch.index.IndexSettings;
28+
import org.opensearch.index.remote.RemoteStorePathType;
2729
import org.opensearch.index.shard.IndexShard;
2830
import org.opensearch.indices.IndicesService;
2931
import org.opensearch.indices.replication.common.ReplicationType;
@@ -42,13 +44,14 @@
4244
import java.util.ArrayList;
4345
import java.util.Arrays;
4446
import java.util.List;
47+
import java.util.Map;
4548
import java.util.Optional;
4649
import java.util.concurrent.ExecutionException;
4750
import java.util.stream.Collectors;
4851
import java.util.stream.Stream;
4952

5053
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_REMOTE_STORE_ENABLED;
51-
import static org.opensearch.remotestore.RemoteStoreBaseIntegTestCase.remoteStoreClusterSettings;
54+
import static org.opensearch.indices.IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING;
5255
import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertAcked;
5356
import static org.hamcrest.Matchers.equalTo;
5457
import static org.hamcrest.Matchers.greaterThan;
@@ -199,6 +202,85 @@ public void testRestoreOperationsShallowCopyEnabled() throws Exception {
199202
assertDocsPresentInIndex(client, restoredIndexName1, numDocsInIndex1 + 2);
200203
}
201204

205+
/**
206+
* In this test, we validate presence of remote_store custom data in index metadata for standard index creation and
207+
* on snapshot restore.
208+
*/
209+
public void testRemoteStoreCustomDataOnIndexCreationAndRestore() {
210+
String clusterManagerNode = internalCluster().startClusterManagerOnlyNode();
211+
internalCluster().startDataOnlyNode();
212+
String indexName1 = "testindex1";
213+
String indexName2 = "testindex2";
214+
String snapshotRepoName = "test-restore-snapshot-repo";
215+
String snapshotName1 = "test-restore-snapshot1";
216+
Path absolutePath1 = randomRepoPath().toAbsolutePath();
217+
logger.info("Snapshot Path [{}]", absolutePath1);
218+
String restoredIndexName1version1 = indexName1 + "-restored-1";
219+
String restoredIndexName1version2 = indexName1 + "-restored-2";
220+
221+
createRepository(snapshotRepoName, "fs", getRepositorySettings(absolutePath1, true));
222+
Client client = client();
223+
Settings indexSettings = getIndexSettings(1, 0).build();
224+
createIndex(indexName1, indexSettings);
225+
226+
indexDocuments(client, indexName1, randomIntBetween(5, 10));
227+
ensureGreen(indexName1);
228+
validateRemoteStorePathType(indexName1, RemoteStorePathType.FIXED);
229+
230+
logger.info("--> snapshot");
231+
SnapshotInfo snapshotInfo = createSnapshot(snapshotRepoName, snapshotName1, new ArrayList<>(Arrays.asList(indexName1)));
232+
assertEquals(SnapshotState.SUCCESS, snapshotInfo.state());
233+
assertTrue(snapshotInfo.successfulShards() > 0);
234+
assertEquals(snapshotInfo.totalShards(), snapshotInfo.successfulShards());
235+
236+
RestoreSnapshotResponse restoreSnapshotResponse = client.admin()
237+
.cluster()
238+
.prepareRestoreSnapshot(snapshotRepoName, snapshotName1)
239+
.setWaitForCompletion(false)
240+
.setRenamePattern(indexName1)
241+
.setRenameReplacement(restoredIndexName1version1)
242+
.get();
243+
assertEquals(RestStatus.ACCEPTED, restoreSnapshotResponse.status());
244+
ensureGreen(restoredIndexName1version1);
245+
validateRemoteStorePathType(restoredIndexName1version1, RemoteStorePathType.FIXED);
246+
247+
client(clusterManagerNode).admin()
248+
.cluster()
249+
.prepareUpdateSettings()
250+
.setTransientSettings(
251+
Settings.builder().put(CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING.getKey(), RemoteStorePathType.HASHED_PREFIX)
252+
)
253+
.get();
254+
255+
restoreSnapshotResponse = client.admin()
256+
.cluster()
257+
.prepareRestoreSnapshot(snapshotRepoName, snapshotName1)
258+
.setWaitForCompletion(false)
259+
.setRenamePattern(indexName1)
260+
.setRenameReplacement(restoredIndexName1version2)
261+
.get();
262+
assertEquals(RestStatus.ACCEPTED, restoreSnapshotResponse.status());
263+
ensureGreen(restoredIndexName1version2);
264+
validateRemoteStorePathType(restoredIndexName1version2, RemoteStorePathType.HASHED_PREFIX);
265+
266+
// Create index with cluster setting cluster.remote_store.index.path.prefix.type as hashed_prefix.
267+
indexSettings = getIndexSettings(1, 0).build();
268+
createIndex(indexName2, indexSettings);
269+
ensureGreen(indexName2);
270+
validateRemoteStorePathType(indexName2, RemoteStorePathType.HASHED_PREFIX);
271+
272+
// Validating that custom data has not changed for indexes which were created before the cluster setting got updated
273+
validateRemoteStorePathType(indexName1, RemoteStorePathType.FIXED);
274+
}
275+
276+
private void validateRemoteStorePathType(String index, RemoteStorePathType pathType) {
277+
ClusterState state = client().admin().cluster().prepareState().execute().actionGet().getState();
278+
// Validate that the remote_store custom data is present in index metadata for the created index.
279+
Map<String, String> remoteCustomData = state.metadata().index(index).getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
280+
assertNotNull(remoteCustomData);
281+
assertEquals(pathType.toString(), remoteCustomData.get(RemoteStorePathType.NAME));
282+
}
283+
202284
public void testRestoreInSameRemoteStoreEnabledIndex() throws IOException {
203285
String clusterManagerNode = internalCluster().startClusterManagerOnlyNode();
204286
String primary = internalCluster().startDataOnlyNode();

server/src/internalClusterTest/java/org/opensearch/snapshots/RestoreSnapshotIT.java

+57
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.opensearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
4040
import org.opensearch.action.index.IndexRequestBuilder;
4141
import org.opensearch.client.Client;
42+
import org.opensearch.cluster.ClusterState;
4243
import org.opensearch.cluster.block.ClusterBlocks;
4344
import org.opensearch.cluster.metadata.IndexMetadata;
4445
import org.opensearch.cluster.metadata.MappingMetadata;
@@ -151,6 +152,62 @@ public void testParallelRestoreOperations() {
151152
assertThat(client.prepareGet(restoredIndexName2, docId2).get().isExists(), equalTo(true));
152153
}
153154

155+
/**
156+
* In this test, we test that an index created does not have any remote_store custom data in index metadata at the
157+
* time of index creation and after snapshot restore.
158+
*/
159+
public void testNoRemoteStoreCustomDataOnIndexCreationAndRestore() {
160+
String indexName1 = "testindex1";
161+
String repoName = "test-restore-snapshot-repo";
162+
String snapshotName1 = "test-restore-snapshot1";
163+
Path absolutePath = randomRepoPath().toAbsolutePath();
164+
logger.info("Path [{}]", absolutePath);
165+
String restoredIndexName1 = indexName1 + "-restored";
166+
String expectedValue = "expected";
167+
168+
Client client = client();
169+
// Write a document
170+
String docId = Integer.toString(randomInt());
171+
index(indexName1, "_doc", docId, "value", expectedValue);
172+
173+
createRepository(repoName, "fs", absolutePath);
174+
175+
logger.info("--> snapshot");
176+
CreateSnapshotResponse createSnapshotResponse = client.admin()
177+
.cluster()
178+
.prepareCreateSnapshot(repoName, snapshotName1)
179+
.setWaitForCompletion(true)
180+
.setIndices(indexName1)
181+
.get();
182+
assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
183+
assertThat(
184+
createSnapshotResponse.getSnapshotInfo().successfulShards(),
185+
equalTo(createSnapshotResponse.getSnapshotInfo().totalShards())
186+
);
187+
assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
188+
189+
ClusterState state = client().admin().cluster().prepareState().execute().actionGet().getState();
190+
191+
// Validate that the remote_store custom data is not present in index metadata for the created index.
192+
assertNull(state.metadata().index(indexName1).getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY));
193+
194+
RestoreSnapshotResponse restoreSnapshotResponse1 = client.admin()
195+
.cluster()
196+
.prepareRestoreSnapshot(repoName, snapshotName1)
197+
.setWaitForCompletion(false)
198+
.setRenamePattern(indexName1)
199+
.setRenameReplacement(restoredIndexName1)
200+
.get();
201+
assertThat(restoreSnapshotResponse1.status(), equalTo(RestStatus.ACCEPTED));
202+
ensureGreen(restoredIndexName1);
203+
assertThat(client.prepareGet(restoredIndexName1, docId).get().isExists(), equalTo(true));
204+
205+
state = client().admin().cluster().prepareState().execute().actionGet().getState();
206+
207+
// Validate that the remote_store custom data is not present in index metadata for the restored index.
208+
assertNull(state.metadata().index(restoredIndexName1).getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY));
209+
}
210+
154211
public void testParallelRestoreOperationsFromSingleSnapshot() throws Exception {
155212
String indexName1 = "testindex1";
156213
String indexName2 = "testindex2";

server/src/main/java/org/opensearch/cluster/metadata/MetadataCreateIndexService.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -557,11 +557,7 @@ IndexMetadata buildAndValidateTemporaryIndexMetadata(
557557
tmpImdBuilder.setRoutingNumShards(routingNumShards);
558558
tmpImdBuilder.settings(indexSettings);
559559
tmpImdBuilder.system(isSystem);
560-
561-
if (remoteStorePathResolver != null) {
562-
String pathType = remoteStorePathResolver.resolveType().toString();
563-
tmpImdBuilder.putCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY, Map.of(RemoteStorePathType.NAME, pathType));
564-
}
560+
addRemoteCustomData(tmpImdBuilder);
565561

566562
// Set up everything, now locally create the index to see that things are ok, and apply
567563
IndexMetadata tempMetadata = tmpImdBuilder.build();
@@ -570,6 +566,22 @@ IndexMetadata buildAndValidateTemporaryIndexMetadata(
570566
return tempMetadata;
571567
}
572568

569+
public void addRemoteCustomData(IndexMetadata.Builder tmpImdBuilder) {
570+
if (remoteStorePathResolver != null) {
571+
// It is possible that remote custom data exists already. In such cases, we need to only update the path type
572+
// in the remote store custom data map.
573+
Map<String, String> existingRemoteCustomData = tmpImdBuilder.removeCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
574+
Map<String, String> remoteCustomData = existingRemoteCustomData == null
575+
? new HashMap<>()
576+
: new HashMap<>(existingRemoteCustomData);
577+
// Determine the path type for use using the remoteStorePathResolver.
578+
String newPathType = remoteStorePathResolver.resolveType().toString();
579+
String oldPathType = remoteCustomData.put(RemoteStorePathType.NAME, newPathType);
580+
logger.trace(() -> new ParameterizedMessage("Added new path type {}, replaced old path type {}", newPathType, oldPathType));
581+
tmpImdBuilder.putCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY, remoteCustomData);
582+
}
583+
}
584+
573585
private ClusterState applyCreateIndexRequestWithV1Templates(
574586
final ClusterState currentState,
575587
final CreateIndexClusterStateUpdateRequest request,

server/src/main/java/org/opensearch/snapshots/RestoreService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,6 @@ public RestoreService(
232232

233233
// Task is onboarded for throttling, it will get retried from associated TransportClusterManagerNodeAction.
234234
restoreSnapshotTaskKey = clusterService.registerClusterManagerTask(ClusterManagerTaskKeys.RESTORE_SNAPSHOT_KEY, true);
235-
236235
}
237236

238237
/**
@@ -485,6 +484,7 @@ public ClusterState execute(ClusterState currentState) {
485484
.put(snapshotIndexMetadata.getSettings())
486485
.put(IndexMetadata.SETTING_INDEX_UUID, UUIDs.randomBase64UUID())
487486
);
487+
createIndexService.addRemoteCustomData(indexMdBuilder);
488488
shardLimitValidator.validateShardLimit(
489489
renamedIndexName,
490490
snapshotIndexMetadata.getSettings(),

0 commit comments

Comments
 (0)