Skip to content

Commit

Permalink
Add new parameters to snapshot restore to rename the restored aliases…
Browse files Browse the repository at this point in the history
… simlar to the existing parameters to rename indexes

Signed-off-by: Spencer G. Jones <spencer.jones2@tylertech.com>
  • Loading branch information
mispencer committed Oct 11, 2024
1 parent d6ea8eb commit 8e511d6
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- New `phone` & `phone-search` analyzer + tokenizer ([#15915](https://github.com/opensearch-project/OpenSearch/pull/15915))
- Add _list/shards API as paginated alternate to _cat/shards ([#14641](https://github.com/opensearch-project/OpenSearch/pull/14641))
- Latency and Memory allocation improvements to Multi Term Aggregation queries ([#14993](https://github.com/opensearch-project/OpenSearch/pull/14993))
- Add support for renaming aliases during snapshot restore ([XXXX](https://github.com/opensearch-project/OpenSearch/pull/XXXX))

### Dependencies
- Bump `com.azure:azure-identity` from 1.13.0 to 1.13.2 ([#15578](https://github.com/opensearch-project/OpenSearch/pull/15578))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ private static StorageType fromString(String string) {
private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen();
private String renamePattern;
private String renameReplacement;
private String renameAliasPattern;
private String renameAliasReplacement;
private boolean waitForCompletion;
private boolean includeGlobalState = false;
private boolean partial = false;
Expand Down Expand Up @@ -148,6 +150,8 @@ public RestoreSnapshotRequest(StreamInput in) throws IOException {
indicesOptions = IndicesOptions.readIndicesOptions(in);
renamePattern = in.readOptionalString();
renameReplacement = in.readOptionalString();
renameAliasPattern = in.readOptionalString();
renameAliasReplacement = in.readOptionalString();
waitForCompletion = in.readBoolean();
includeGlobalState = in.readBoolean();
partial = in.readBoolean();
Expand Down Expand Up @@ -175,6 +179,8 @@ public void writeTo(StreamOutput out) throws IOException {
indicesOptions.writeIndicesOptions(out);
out.writeOptionalString(renamePattern);
out.writeOptionalString(renameReplacement);
out.writeOptionalString(renameAliasPattern);
out.writeOptionalString(renameAliasReplacement);
out.writeBoolean(waitForCompletion);
out.writeBoolean(includeGlobalState);
out.writeBoolean(partial);
Expand Down Expand Up @@ -361,6 +367,51 @@ public String renameReplacement() {
return renameReplacement;
}

/**
* Sets rename pattern that should be applied to restored indices' alias.
* <p>
* Alias that match the rename pattern will be renamed according to {@link #renameAliasReplacement(String)}. The
* rename pattern is applied according to the {@link java.util.regex.Matcher#appendReplacement(StringBuffer, String)}
* The request will fail if two or more alias will be renamed into the same name.
*
* @param renameAliasPattern rename pattern
* @return this request
*/
public RestoreSnapshotRequest renameAliasPattern(String renameAliasPattern) {
this.renameAliasPattern = renameAliasPattern;
return this;
}

/**
* Returns rename alias pattern
*
* @return rename alias pattern
*/
public String renameAliasPattern() {
return renameAliasPattern;
}

/**
* Sets rename alias replacement
* <p>
* See {@link #renameAliasPattern(String)} for more information.
*
* @param renameAliasReplacement rename replacement
*/
public RestoreSnapshotRequest renameAliasReplacement(String renameAliasReplacement) {
this.renameAliasReplacement = renameAliasReplacement;
return this;
}

/**
* Returns rename alias replacement
*
* @return rename alias replacement
*/
public String renameAliasReplacement() {
return renameAliasReplacement;
}

/**
* If this parameter is set to true the operation will wait for completion of restore process before returning.
*
Expand Down Expand Up @@ -625,6 +676,18 @@ public RestoreSnapshotRequest source(Map<String, Object> source) {
} else {
throw new IllegalArgumentException("malformed rename_replacement");
}
} else if (name.equals("rename_alias_pattern")) {
if (entry.getValue() instanceof String) {
renameAliasPattern((String) entry.getValue());
} else {
throw new IllegalArgumentException("malformed rename_alias_pattern");
}
} else if (name.equals("rename_alias_replacement")) {
if (entry.getValue() instanceof String) {
renameAliasReplacement((String) entry.getValue());
} else {
throw new IllegalArgumentException("malformed rename_alias_replacement");
}
} else if (name.equals("index_settings")) {
if (!(entry.getValue() instanceof Map)) {
throw new IllegalArgumentException("malformed index_settings section");
Expand Down Expand Up @@ -685,6 +748,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
if (renameReplacement != null) {
builder.field("rename_replacement", renameReplacement);
}
if (renameAliasPattern != null) {
builder.field("rename_alias_pattern", renameAliasPattern);
}
if (renameAliasReplacement != null) {
builder.field("rename_alias_replacement", renameAliasReplacement);
}
builder.field("include_global_state", includeGlobalState);
builder.field("partial", partial);
builder.field("include_aliases", includeAliases);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,34 @@ public RestoreSnapshotRequestBuilder setRenameReplacement(String renameReplaceme
return this;
}

/**
* Sets rename pattern that should be applied to restored indices' aliases.
* <p>
* Aliases that match the rename pattern will be renamed according to {@link #setRenameAliasReplacement(String)}. The
* rename pattern is applied according to the {@link java.util.regex.Matcher#appendReplacement(StringBuffer, String)}
* The request will fail if two or more alias will be renamed into the same name.
*
* @param renameAliasPattern rename alias pattern
* @return this builder
*/
public RestoreSnapshotRequestBuilder setRenameAliasPattern(String renameAliasPattern) {
request.renameAliasPattern(renameAliasPattern);
return this;
}

/**
* Sets rename replacement
* <p>
* See {@link #setRenameAliasPattern(String)} for more information.
*
* @param renameAliasReplacement rename alias replacement
* @return this builder
*/
public RestoreSnapshotRequestBuilder setRenameAliasReplacement(String renameAliasReplacement) {
request.renameAliasReplacement(renameAliasReplacement);
return this;
}

/**
* If this parameter is set to true the operation will wait for completion of restore process before returning.
*
Expand Down
28 changes: 24 additions & 4 deletions server/src/main/java/org/opensearch/snapshots/RestoreService.java
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,18 @@ public ClusterState execute(ClusterState currentState) {
// Remove all aliases - they shouldn't be restored
indexMdBuilder.removeAllAliases();
} else {
for (final String alias : snapshotIndexMetadata.getAliases().keySet()) {
aliases.add(alias);
for (final Map.Entry<String, AliasMetadata> alias : snapshotIndexMetadata.getAliases().entrySet()) {
String aliasName = alias.getKey();
if (request.renameAliasPattern() != null && request.renameAliasReplacement() != null) {
indexMdBuilder.removeAlias(aliasName);
aliasName = aliasName.replaceAll(
request.renameAliasPattern(),
request.renameAliasReplacement()
);
AliasMetadata newAlias = AliasMetadata.newAliasMetadata(alias.getValue(), aliasName);
indexMdBuilder.putAlias(newAlias);
}
aliases.add(aliasName);
}
}
IndexMetadata updatedIndexMetadata = indexMdBuilder.build();
Expand Down Expand Up @@ -533,8 +543,18 @@ public ClusterState execute(ClusterState currentState) {
indexMdBuilder.putAlias(alias);
}
} else {
for (final String alias : snapshotIndexMetadata.getAliases().keySet()) {
aliases.add(alias);
for (final Map.Entry<String, AliasMetadata> alias : snapshotIndexMetadata.getAliases().entrySet()) {
String aliasName = alias.getKey();
if (request.renameAliasPattern() != null && request.renameAliasReplacement() != null) {
indexMdBuilder.removeAlias(aliasName);
aliasName = aliasName.replaceAll(
request.renameAliasPattern(),
request.renameAliasReplacement()
);
AliasMetadata newAlias = AliasMetadata.newAliasMetadata(alias.getValue(), aliasName);
indexMdBuilder.putAlias(newAlias);
}
aliases.add(aliasName);
}
}
final Settings.Builder indexSettingsBuilder = Settings.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ private RestoreSnapshotRequest randomState(RestoreSnapshotRequest instance) {
if (randomBoolean()) {
instance.renameReplacement(randomUnicodeOfLengthBetween(1, 100));
}
if (randomBoolean()) {
instance.renameAliasPattern(randomUnicodeOfLengthBetween(1, 100));
}
if (randomBoolean()) {
instance.renameAliasReplacement(randomUnicodeOfLengthBetween(1, 100));
}
instance.partial(randomBoolean());
instance.includeAliases(randomBoolean());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public void testRestoreSnapshotRequestParsing() throws IOException {
builder.field("allow_no_indices", indicesOptions.allowNoIndices());
builder.field("rename_pattern", "rename-from");
builder.field("rename_replacement", "rename-to");
builder.field("rename_alias_pattern", "alias-rename-from");
builder.field("rename_alias_replacement", "alias-rename-to");
boolean partial = randomBoolean();
builder.field("partial", partial);
builder.startObject("settings").field("set1", "val1").endObject();
Expand All @@ -103,6 +105,8 @@ public void testRestoreSnapshotRequestParsing() throws IOException {
assertArrayEquals(request.indices(), new String[] { "foo", "bar", "baz" });
assertEquals("rename-from", request.renamePattern());
assertEquals("rename-to", request.renameReplacement());
assertEquals("alias-rename-from", request.renameAliasPattern());
assertEquals("alias-rename-to", request.renameAliasReplacement());
assertEquals(partial, request.partial());
assertArrayEquals(request.ignoreIndexSettings(), new String[] { "set2", "set3" });
boolean expectedIgnoreAvailable = includeIgnoreUnavailable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
import org.opensearch.action.admin.cluster.state.ClusterStateRequest;
import org.opensearch.action.admin.cluster.state.ClusterStateResponse;
import org.opensearch.action.admin.cluster.state.TransportClusterStateAction;
import org.opensearch.action.admin.indices.alias.IndicesAliasesAction;
import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.opensearch.action.admin.indices.alias.TransportIndicesAliasesAction;
import org.opensearch.action.admin.indices.create.CreateIndexAction;
import org.opensearch.action.admin.indices.create.CreateIndexRequest;
import org.opensearch.action.admin.indices.create.CreateIndexResponse;
Expand Down Expand Up @@ -141,6 +144,7 @@
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
import org.opensearch.cluster.metadata.MetadataCreateIndexService;
import org.opensearch.cluster.metadata.MetadataDeleteIndexService;
import org.opensearch.cluster.metadata.MetadataIndexAliasesService;
import org.opensearch.cluster.metadata.MetadataIndexUpgradeService;
import org.opensearch.cluster.metadata.MetadataMappingService;
import org.opensearch.cluster.node.DiscoveryNode;
Expand Down Expand Up @@ -958,6 +962,7 @@ public void testConcurrentSnapshotRestoreAndDeleteOther() {
String repoName = "repo";
String snapshotName = "snapshot";
final String index = "test";
final String alias = "test_alias";
final int shards = randomIntBetween(1, 10);

TestClusterNodes.TestClusterNode clusterManagerNode = testClusterNodes.currentClusterManager(
Expand All @@ -967,9 +972,8 @@ public void testConcurrentSnapshotRestoreAndDeleteOther() {
final StepListener<CreateSnapshotResponse> createSnapshotResponseStepListener = new StepListener<>();

final int documentsFirstSnapshot = randomIntBetween(0, 100);

continueOrDie(
createRepoAndIndex(repoName, index, shards),
createRepoAndIndexAndAlias(repoName, index, shards, alias),
createIndexResponse -> indexNDocuments(
documentsFirstSnapshot,
index,
Expand Down Expand Up @@ -1009,27 +1013,39 @@ public void testConcurrentSnapshotRestoreAndDeleteOther() {
.cluster()
.restoreSnapshot(
new RestoreSnapshotRequest(repoName, secondSnapshotName).waitForCompletion(true)
.includeAliases(true)
.renamePattern("(.+)")
.renameReplacement("restored_$1"),
.renameReplacement("restored_$1")
.renameAliasPattern("(.+)")
.renameAliasReplacement("restored_alias_$1"),
restoreSnapshotResponseListener
)
);
});

final StepListener<SearchResponse> searchResponseListener = new StepListener<>();
final StepListener<SearchResponse> searchIndexResponseListener = new StepListener<>();
final StepListener<SearchResponse> searchAliasResponseListener = new StepListener<>();
continueOrDie(restoreSnapshotResponseListener, restoreSnapshotResponse -> {
assertEquals(shards, restoreSnapshotResponse.getRestoreInfo().totalShards());
client().search(
new SearchRequest("restored_" + index).source(new SearchSourceBuilder().size(0).trackTotalHits(true)),
searchResponseListener
searchIndexResponseListener
);
client().search(
new SearchRequest("restored_alias_" + alias).source(new SearchSourceBuilder().size(0).trackTotalHits(true)),
searchAliasResponseListener
);
});

deterministicTaskQueue.runAllRunnableTasks();

assertEquals(
documentsFirstSnapshot + documentsSecondSnapshot,
Objects.requireNonNull(searchResponseListener.result().getHits().getTotalHits()).value
Objects.requireNonNull(searchIndexResponseListener.result().getHits().getTotalHits()).value
);
assertEquals(
documentsFirstSnapshot + documentsSecondSnapshot,
Objects.requireNonNull(searchAliasResponseListener.result().getHits().getTotalHits()).value
);
assertThat(deleteSnapshotStepListener.result().isAcknowledged(), is(true));
assertThat(restoreSnapshotResponseListener.result().getRestoreInfo().failedShards(), is(0));
Expand Down Expand Up @@ -1520,6 +1536,22 @@ private StepListener<CreateIndexResponse> createRepoAndIndex(String repoName, St
return createIndexResponseStepListener;
}

private StepListener<AcknowledgedResponse> createRepoAndIndexAndAlias(String repoName, String index, int shards, String alias) {
final StepListener<AcknowledgedResponse> createAliasListener = new StepListener<>();

continueOrDie(
createRepoAndIndex(repoName, index, shards),
acknowledgedResponse -> client().admin()
.indices()
.aliases(
new IndicesAliasesRequest().addAliasAction(IndicesAliasesRequest.AliasActions.add().index(index).alias(alias)),
createAliasListener
)
);

return createAliasListener;
}

private void clearDisruptionsAndAwaitSync() {
testClusterNodes.clearNetworkDisruptions();
stabilize();
Expand Down Expand Up @@ -2171,6 +2203,30 @@ public void onFailure(final Exception e) {
indexNameExpressionResolver
)
);
final MetadataDeleteIndexService metadataDeleteIndexService = new MetadataDeleteIndexService(
settings,
clusterService,
allocationService
);
final MetadataIndexAliasesService metadataIndexAliasesService = new MetadataIndexAliasesService(
clusterService,
indicesService,
new AliasValidator(),
metadataDeleteIndexService,
namedXContentRegistry
);
actions.put(
IndicesAliasesAction.INSTANCE,
new TransportIndicesAliasesAction(
transportService,
clusterService,
threadPool,
metadataIndexAliasesService,
actionFilters,
indexNameExpressionResolver,
new RequestValidators<>(Collections.emptyList())
)
);
final MappingUpdatedAction mappingUpdatedAction = new MappingUpdatedAction(settings, clusterSettings, clusterService);
mappingUpdatedAction.setClient(client);
final TransportShardBulkAction transportShardBulkAction = new TransportShardBulkAction(
Expand Down Expand Up @@ -2337,7 +2393,7 @@ public void onFailure(final Exception e) {
transportService,
clusterService,
threadPool,
new MetadataDeleteIndexService(settings, clusterService, allocationService),
metadataDeleteIndexService,
actionFilters,
indexNameExpressionResolver,
new DestructiveOperations(settings, clusterSettings)
Expand Down

0 comments on commit 8e511d6

Please sign in to comment.