Skip to content

Commit 4c35a2b

Browse files
authored
fix rollover alias supports restored searchable snapshot index (opensearch-project#16483)
Signed-off-by: kkewwei <kkewwei@163.com> Signed-off-by: kkewwei <kewei.11@bytedance.com>
1 parent f32f5c6 commit 4c35a2b

File tree

6 files changed

+215
-13
lines changed

6 files changed

+215
-13
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3030
- Ensure index templates are not applied to system indices ([#16418](https://github.com/opensearch-project/OpenSearch/pull/16418))
3131
- Remove resource usages object from search response headers ([#16532](https://github.com/opensearch-project/OpenSearch/pull/16532))
3232
- Support retrieving doc values of unsigned long field ([#16543](https://github.com/opensearch-project/OpenSearch/pull/16543))
33+
- Fix rollover alias supports restored searchable snapshot index([#16483](https://github.com/opensearch-project/OpenSearch/pull/16483))
3334

3435
### Security
3536

server/src/main/java/org/opensearch/action/admin/indices/alias/TransportIndicesAliasesAction.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import org.opensearch.cluster.ClusterState;
4242
import org.opensearch.cluster.ack.ClusterStateUpdateResponse;
4343
import org.opensearch.cluster.block.ClusterBlockException;
44-
import org.opensearch.cluster.block.ClusterBlockLevel;
44+
import org.opensearch.cluster.block.ClusterBlocks;
4545
import org.opensearch.cluster.metadata.AliasAction;
4646
import org.opensearch.cluster.metadata.AliasMetadata;
4747
import org.opensearch.cluster.metadata.IndexAbstraction;
@@ -123,7 +123,7 @@ protected ClusterBlockException checkBlock(IndicesAliasesRequest request, Cluste
123123
for (IndicesAliasesRequest.AliasActions aliasAction : request.aliasActions()) {
124124
Collections.addAll(indices, aliasAction.indices());
125125
}
126-
return state.blocks().indicesBlockedException(ClusterBlockLevel.METADATA_WRITE, indices.toArray(new String[0]));
126+
return ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, state);
127127
}
128128

129129
@Override

server/src/main/java/org/opensearch/action/admin/indices/rollover/TransportRolloverAction.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
import org.opensearch.cluster.ClusterState;
4545
import org.opensearch.cluster.ClusterStateUpdateTask;
4646
import org.opensearch.cluster.block.ClusterBlockException;
47-
import org.opensearch.cluster.block.ClusterBlockLevel;
47+
import org.opensearch.cluster.block.ClusterBlocks;
4848
import org.opensearch.cluster.metadata.IndexMetadata;
4949
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
5050
import org.opensearch.cluster.metadata.Metadata;
@@ -62,8 +62,10 @@
6262
import org.opensearch.transport.TransportService;
6363

6464
import java.io.IOException;
65+
import java.util.Arrays;
6566
import java.util.Collection;
6667
import java.util.Collections;
68+
import java.util.HashSet;
6769
import java.util.List;
6870
import java.util.Map;
6971
import java.util.Optional;
@@ -127,11 +129,10 @@ protected ClusterBlockException checkBlock(RolloverRequest request, ClusterState
127129
request.indicesOptions().expandWildcardsClosed()
128130
);
129131

130-
return state.blocks()
131-
.indicesBlockedException(
132-
ClusterBlockLevel.METADATA_WRITE,
133-
indexNameExpressionResolver.concreteIndexNames(state, indicesOptions, request)
134-
);
132+
return ClusterBlocks.indicesWithRemoteSnapshotBlockedException(
133+
new HashSet<>(Arrays.asList(indexNameExpressionResolver.concreteIndexNames(state, indicesOptions, request))),
134+
state
135+
);
135136
}
136137

137138
@Override

server/src/main/java/org/opensearch/action/admin/indices/settings/put/TransportUpdateSettingsAction.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import org.opensearch.cluster.ack.ClusterStateUpdateResponse;
4343
import org.opensearch.cluster.block.ClusterBlockException;
4444
import org.opensearch.cluster.block.ClusterBlockLevel;
45-
import org.opensearch.cluster.metadata.IndexMetadata;
45+
import org.opensearch.cluster.block.ClusterBlocks;
4646
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
4747
import org.opensearch.cluster.metadata.MetadataUpdateSettingsService;
4848
import org.opensearch.cluster.service.ClusterService;
@@ -118,9 +118,8 @@ protected ClusterBlockException checkBlock(UpdateSettingsRequest request, Cluste
118118
return globalBlock;
119119
}
120120
if (request.settings().size() == 1 && // we have to allow resetting these settings otherwise users can't unblock an index
121-
IndexMetadata.INDEX_BLOCKS_METADATA_SETTING.exists(request.settings())
122-
|| IndexMetadata.INDEX_READ_ONLY_SETTING.exists(request.settings())
123-
|| IndexMetadata.INDEX_BLOCKS_READ_ONLY_ALLOW_DELETE_SETTING.exists(request.settings())) {
121+
ClusterBlocks.INDEX_DATA_READ_ONLY_BLOCK_SETTINGS.stream()
122+
.anyMatch(booleanSetting -> booleanSetting.exists(request.settings()))) {
124123
return null;
125124
}
126125

server/src/main/java/org/opensearch/cluster/block/ClusterBlocks.java

+25-1
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,23 @@
3333
package org.opensearch.cluster.block;
3434

3535
import org.opensearch.cluster.AbstractDiffable;
36+
import org.opensearch.cluster.ClusterState;
3637
import org.opensearch.cluster.Diff;
3738
import org.opensearch.cluster.metadata.IndexMetadata;
3839
import org.opensearch.cluster.metadata.MetadataIndexStateService;
3940
import org.opensearch.common.Nullable;
4041
import org.opensearch.common.annotation.PublicApi;
42+
import org.opensearch.common.settings.Setting;
4143
import org.opensearch.common.util.set.Sets;
4244
import org.opensearch.core.common.io.stream.BufferedChecksumStreamOutput;
4345
import org.opensearch.core.common.io.stream.StreamInput;
4446
import org.opensearch.core.common.io.stream.StreamOutput;
4547
import org.opensearch.core.common.io.stream.VerifiableWriteable;
4648
import org.opensearch.core.rest.RestStatus;
49+
import org.opensearch.index.IndexModule;
4750

4851
import java.io.IOException;
52+
import java.util.Collection;
4953
import java.util.Collections;
5054
import java.util.EnumMap;
5155
import java.util.HashMap;
@@ -57,6 +61,7 @@
5761
import static java.util.Collections.emptySet;
5862
import static java.util.Collections.unmodifiableSet;
5963
import static java.util.stream.Collectors.toSet;
64+
import static org.opensearch.index.IndexModule.INDEX_STORE_TYPE_SETTING;
6065

6166
/**
6267
* Represents current cluster level blocks to block dirty operations done against the cluster.
@@ -66,7 +71,11 @@
6671
@PublicApi(since = "1.0.0")
6772
public class ClusterBlocks extends AbstractDiffable<ClusterBlocks> implements VerifiableWriteable {
6873
public static final ClusterBlocks EMPTY_CLUSTER_BLOCK = new ClusterBlocks(emptySet(), Map.of());
69-
74+
public static final Set<Setting<Boolean>> INDEX_DATA_READ_ONLY_BLOCK_SETTINGS = Set.of(
75+
IndexMetadata.INDEX_READ_ONLY_SETTING,
76+
IndexMetadata.INDEX_BLOCKS_METADATA_SETTING,
77+
IndexMetadata.INDEX_BLOCKS_READ_ONLY_ALLOW_DELETE_SETTING
78+
);
7079
private final Set<ClusterBlock> global;
7180

7281
private final Map<String, Set<ClusterBlock>> indicesBlocks;
@@ -276,6 +285,21 @@ public ClusterBlockException indicesAllowReleaseResources(String[] indices) {
276285
return new ClusterBlockException(indexLevelBlocks);
277286
}
278287

288+
public static ClusterBlockException indicesWithRemoteSnapshotBlockedException(Collection<String> concreteIndices, ClusterState state) {
289+
for (String index : concreteIndices) {
290+
if (state.blocks().indexBlocked(ClusterBlockLevel.METADATA_WRITE, index)) {
291+
IndexMetadata indexMeta = state.metadata().index(index);
292+
if (indexMeta != null
293+
&& (IndexModule.Type.REMOTE_SNAPSHOT.match(indexMeta.getSettings().get(INDEX_STORE_TYPE_SETTING.getKey())) == false
294+
|| ClusterBlocks.INDEX_DATA_READ_ONLY_BLOCK_SETTINGS.stream()
295+
.anyMatch(booleanSetting -> booleanSetting.exists(indexMeta.getSettings())))) {
296+
return state.blocks().indicesBlockedException(ClusterBlockLevel.METADATA_WRITE, concreteIndices.toArray(new String[0]));
297+
}
298+
}
299+
}
300+
return null;
301+
}
302+
279303
@Override
280304
public String toString() {
281305
if (global.isEmpty() && indices().isEmpty()) {

server/src/test/java/org/opensearch/cluster/block/ClusterBlocksTests.java

+177
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,40 @@
88

99
package org.opensearch.cluster.block;
1010

11+
import com.carrotsearch.randomizedtesting.RandomizedTest;
12+
13+
import org.opensearch.Version;
14+
import org.opensearch.cluster.ClusterName;
15+
import org.opensearch.cluster.ClusterState;
16+
import org.opensearch.cluster.metadata.AliasMetadata;
17+
import org.opensearch.cluster.metadata.IndexMetadata;
18+
import org.opensearch.cluster.metadata.Metadata;
1119
import org.opensearch.common.io.stream.BytesStreamOutput;
20+
import org.opensearch.common.settings.Setting;
21+
import org.opensearch.common.settings.Settings;
1222
import org.opensearch.core.common.io.stream.BufferedChecksumStreamOutput;
1323
import org.opensearch.core.common.io.stream.StreamInput;
24+
import org.opensearch.index.IndexModule;
25+
import org.opensearch.index.IndexSettings;
1426
import org.opensearch.test.OpenSearchTestCase;
1527

28+
import java.util.ArrayList;
29+
import java.util.Arrays;
30+
import java.util.Collections;
31+
import java.util.HashSet;
32+
import java.util.Set;
33+
1634
import static org.opensearch.cluster.block.ClusterBlockTests.randomClusterBlock;
35+
import static org.opensearch.cluster.metadata.IndexMetadata.INDEX_METADATA_BLOCK;
36+
import static org.opensearch.cluster.metadata.IndexMetadata.INDEX_READ_BLOCK;
37+
import static org.opensearch.cluster.metadata.IndexMetadata.INDEX_READ_ONLY_ALLOW_DELETE_BLOCK;
38+
import static org.opensearch.cluster.metadata.IndexMetadata.INDEX_READ_ONLY_BLOCK;
39+
import static org.opensearch.cluster.metadata.IndexMetadata.INDEX_WRITE_BLOCK;
40+
import static org.opensearch.cluster.metadata.IndexMetadata.REMOTE_READ_ONLY_ALLOW_DELETE;
41+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_CREATION_DATE;
42+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_REPLICAS;
43+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SHARDS;
44+
import static org.opensearch.cluster.metadata.IndexMetadata.SETTING_VERSION_CREATED;
1745

1846
public class ClusterBlocksTests extends OpenSearchTestCase {
1947

@@ -52,4 +80,153 @@ public void testWriteVerifiableTo() throws Exception {
5280
clusterBlocks2.writeVerifiableTo(checksumOut2);
5381
assertEquals(checksumOut.getChecksum(), checksumOut2.getChecksum());
5482
}
83+
84+
public void testGlobalBlock() {
85+
String index = "test-000001";
86+
ClusterState.Builder stateBuilder = ClusterState.builder(new ClusterName("cluster"));
87+
Set<String> indices = new HashSet<>();
88+
indices.add(index);
89+
90+
// no global blocks
91+
{
92+
stateBuilder.blocks(ClusterBlocks.EMPTY_CLUSTER_BLOCK);
93+
ClusterState clusterState = stateBuilder.build();
94+
clusterState.blocks();
95+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, clusterState));
96+
}
97+
98+
// has global block
99+
{
100+
for (ClusterBlock block : Arrays.asList(
101+
INDEX_READ_ONLY_BLOCK,
102+
INDEX_READ_BLOCK,
103+
INDEX_WRITE_BLOCK,
104+
INDEX_METADATA_BLOCK,
105+
INDEX_READ_ONLY_ALLOW_DELETE_BLOCK,
106+
REMOTE_READ_ONLY_ALLOW_DELETE
107+
)) {
108+
stateBuilder.blocks(ClusterBlocks.builder().addGlobalBlock(block).build());
109+
ClusterState clusterState = stateBuilder.build();
110+
clusterState.blocks();
111+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, clusterState));
112+
}
113+
}
114+
}
115+
116+
public void testIndexWithBlock() {
117+
String index = "test-000001";
118+
Set<String> indices = new HashSet<>();
119+
indices.add(index);
120+
ClusterState.Builder stateBuilder = ClusterState.builder(new ClusterName("cluster"));
121+
stateBuilder.blocks(ClusterBlocks.builder().addIndexBlock(index, IndexMetadata.INDEX_METADATA_BLOCK));
122+
stateBuilder.metadata(Metadata.builder().put(createIndexMetadata(index, false, null, null), false));
123+
ClusterState clusterState = stateBuilder.build();
124+
clusterState.blocks();
125+
assertNotNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, stateBuilder.build()));
126+
}
127+
128+
public void testRemoteIndexBlock() {
129+
String remoteIndex = "remote_index";
130+
Set<String> indices = new HashSet<>();
131+
indices.add(remoteIndex);
132+
ClusterState.Builder stateBuilder = ClusterState.builder(new ClusterName("cluster"));
133+
134+
{
135+
IndexMetadata remoteSnapshotIndexMetadata = createIndexMetadata(remoteIndex, true, null, null);
136+
stateBuilder.metadata(Metadata.builder().put(remoteSnapshotIndexMetadata, false));
137+
stateBuilder.blocks(ClusterBlocks.builder().addBlocks(remoteSnapshotIndexMetadata));
138+
139+
ClusterState clusterState = stateBuilder.build();
140+
assertTrue(clusterState.blocks().hasIndexBlock(remoteIndex, IndexMetadata.REMOTE_READ_ONLY_ALLOW_DELETE));
141+
clusterState.blocks();
142+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, clusterState));
143+
}
144+
145+
// searchable snapshot index with block
146+
{
147+
Setting<Boolean> setting = RandomizedTest.randomFrom(new ArrayList<>(ClusterBlocks.INDEX_DATA_READ_ONLY_BLOCK_SETTINGS));
148+
IndexMetadata remoteSnapshotIndexMetadata = createIndexMetadata(remoteIndex, true, null, setting);
149+
stateBuilder.metadata(Metadata.builder().put(remoteSnapshotIndexMetadata, false));
150+
stateBuilder.blocks(ClusterBlocks.builder().addBlocks(remoteSnapshotIndexMetadata));
151+
ClusterState clusterState = stateBuilder.build();
152+
clusterState.blocks();
153+
assertNotNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, clusterState));
154+
}
155+
}
156+
157+
public void testRemoteIndexWithoutBlock() {
158+
String remoteIndex = "remote_index";
159+
ClusterState.Builder stateBuilder = ClusterState.builder(new ClusterName("cluster"));
160+
161+
String alias = "alias1";
162+
IndexMetadata remoteSnapshotIndexMetadata = createIndexMetadata(remoteIndex, true, alias, null);
163+
String index = "test-000001";
164+
IndexMetadata indexMetadata = createIndexMetadata(index, false, alias, null);
165+
stateBuilder.metadata(Metadata.builder().put(remoteSnapshotIndexMetadata, false).put(indexMetadata, false));
166+
167+
Set<String> indices = new HashSet<>();
168+
indices.add(remoteIndex);
169+
ClusterState clusterState = stateBuilder.build();
170+
clusterState.blocks();
171+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(indices, clusterState));
172+
}
173+
174+
public void testRemoteIndexWithIndexBlock() {
175+
String index = "test-000001";
176+
String remoteIndex = "remote_index";
177+
String alias = "alias1";
178+
{
179+
ClusterState.Builder stateBuilder = ClusterState.builder(new ClusterName("cluster"));
180+
IndexMetadata remoteSnapshotIndexMetadata = createIndexMetadata(remoteIndex, true, alias, null);
181+
IndexMetadata indexMetadata = createIndexMetadata(index, false, alias, null);
182+
stateBuilder.metadata(Metadata.builder().put(remoteSnapshotIndexMetadata, false).put(indexMetadata, false))
183+
.blocks(ClusterBlocks.builder().addBlocks(remoteSnapshotIndexMetadata));
184+
ClusterState clusterState = stateBuilder.build();
185+
clusterState.blocks();
186+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(Collections.singleton(index), clusterState));
187+
clusterState.blocks();
188+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(Collections.singleton(remoteIndex), clusterState));
189+
}
190+
191+
{
192+
ClusterState.Builder stateBuilder = ClusterState.builder(new ClusterName("cluster"));
193+
Setting<Boolean> setting = RandomizedTest.randomFrom(new ArrayList<>(ClusterBlocks.INDEX_DATA_READ_ONLY_BLOCK_SETTINGS));
194+
IndexMetadata remoteSnapshotIndexMetadata = createIndexMetadata(remoteIndex, true, alias, setting);
195+
IndexMetadata indexMetadata = createIndexMetadata(index, false, alias, null);
196+
stateBuilder.metadata(Metadata.builder().put(remoteSnapshotIndexMetadata, false).put(indexMetadata, false))
197+
.blocks(ClusterBlocks.builder().addBlocks(remoteSnapshotIndexMetadata));
198+
ClusterState clusterState = stateBuilder.build();
199+
assertNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(Collections.singleton(index), clusterState));
200+
assertNotNull(ClusterBlocks.indicesWithRemoteSnapshotBlockedException(Collections.singleton(remoteIndex), clusterState));
201+
}
202+
}
203+
204+
private IndexMetadata createIndexMetadata(String index, boolean isRemoteIndex, String alias, Setting<Boolean> blockSetting) {
205+
IndexMetadata.Builder builder = IndexMetadata.builder(index).settings(createIndexSettingBuilder(isRemoteIndex, blockSetting));
206+
if (alias != null) {
207+
AliasMetadata.Builder aliasBuilder = AliasMetadata.builder(alias);
208+
return builder.putAlias(aliasBuilder.build()).build();
209+
}
210+
return builder.build();
211+
}
212+
213+
private Settings.Builder createIndexSettingBuilder(boolean isRemoteIndex, Setting<Boolean> blockSetting) {
214+
Settings.Builder builder = Settings.builder()
215+
.put(IndexMetadata.SETTING_INDEX_UUID, "abc")
216+
.put(SETTING_VERSION_CREATED, Version.CURRENT)
217+
.put(SETTING_CREATION_DATE, System.currentTimeMillis())
218+
.put(SETTING_NUMBER_OF_SHARDS, 1)
219+
.put(SETTING_NUMBER_OF_REPLICAS, 1);
220+
221+
if (isRemoteIndex) {
222+
builder.put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), IndexModule.Type.REMOTE_SNAPSHOT.getSettingsKey())
223+
.put(IndexSettings.SEARCHABLE_SNAPSHOT_REPOSITORY.getKey(), "repo")
224+
.put(IndexSettings.SEARCHABLE_SNAPSHOT_ID_NAME.getKey(), "snapshot");
225+
}
226+
if (blockSetting != null) {
227+
builder.put(blockSetting.getKey(), true);
228+
}
229+
230+
return builder;
231+
}
55232
}

0 commit comments

Comments
 (0)