mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-27 02:18:42 +00:00
Add index name to cluster block exception (#41489)
Updates the error message to reveal the index name that is causing it. Closes #40870
This commit is contained in:
parent
793f13c8b6
commit
4a88da70c5
@ -25,17 +25,26 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
public class ClusterBlockException extends ElasticsearchException {
|
||||
private final Set<ClusterBlock> blocks;
|
||||
|
||||
public ClusterBlockException(Set<ClusterBlock> blocks) {
|
||||
super(buildMessage(blocks));
|
||||
this.blocks = blocks;
|
||||
public ClusterBlockException(Set<ClusterBlock> globalLevelBlocks) {
|
||||
super(buildMessageForGlobalBlocks(globalLevelBlocks));
|
||||
this.blocks = globalLevelBlocks;
|
||||
}
|
||||
|
||||
public ClusterBlockException(Map<String, Set<ClusterBlock>> indexLevelBlocks) {
|
||||
super(buildMessageForIndexBlocks(indexLevelBlocks));
|
||||
this.blocks = indexLevelBlocks.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public ClusterBlockException(StreamInput in) throws IOException {
|
||||
@ -74,10 +83,26 @@ public class ClusterBlockException extends ElasticsearchException {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private static String buildMessage(Set<ClusterBlock> blocks) {
|
||||
StringBuilder sb = new StringBuilder("blocked by: ");
|
||||
for (ClusterBlock block : blocks) {
|
||||
sb.append("[").append(block.status()).append("/").append(block.id()).append("/").append(block.description()).append("];");
|
||||
private static String buildMessageForGlobalBlocks(Set<ClusterBlock> globalLevelBlocks) {
|
||||
assert globalLevelBlocks.isEmpty() == false;
|
||||
Function<ClusterBlock, String> blockDescription = block -> block.status() + "/" + block.id() + "/" + block.description();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (globalLevelBlocks.isEmpty() == false) {
|
||||
sb.append("blocked by: [");
|
||||
sb.append(globalLevelBlocks.stream().map(blockDescription).collect(Collectors.joining(", ")));
|
||||
sb.append("];");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String buildMessageForIndexBlocks(Map<String, Set<ClusterBlock>> indexLevelBlocks) {
|
||||
assert indexLevelBlocks.isEmpty() == false;
|
||||
Function<ClusterBlock, String> blockDescription = block -> block.status() + "/" + block.id() + "/" + block.description();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, Set<ClusterBlock>> entry : indexLevelBlocks.entrySet()) {
|
||||
sb.append("index [" + entry.getKey() + "] blocked by: [");
|
||||
sb.append(entry.getValue().stream().map(blockDescription).collect(Collectors.joining(", ")));
|
||||
sb.append("];");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
package org.elasticsearch.cluster.block;
|
||||
|
||||
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
|
||||
import org.elasticsearch.cluster.AbstractDiffable;
|
||||
import org.elasticsearch.cluster.Diff;
|
||||
@ -28,6 +27,7 @@ import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -36,14 +36,11 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static java.util.stream.Stream.concat;
|
||||
|
||||
/**
|
||||
* Represents current cluster level blocks to block dirty operations done against the cluster.
|
||||
@ -83,8 +80,9 @@ public class ClusterBlocks extends AbstractDiffable<ClusterBlocks> {
|
||||
return indices(level).getOrDefault(index, emptySet());
|
||||
}
|
||||
|
||||
private static EnumMap<ClusterBlockLevel, ImmutableLevelHolder> generateLevelHolders(Set<ClusterBlock> global,
|
||||
ImmutableOpenMap<String, Set<ClusterBlock>> indicesBlocks) {
|
||||
private static EnumMap<ClusterBlockLevel, ImmutableLevelHolder> generateLevelHolders(
|
||||
Set<ClusterBlock> global, ImmutableOpenMap<String, Set<ClusterBlock>> indicesBlocks) {
|
||||
|
||||
EnumMap<ClusterBlockLevel, ImmutableLevelHolder> levelHolders = new EnumMap<>(ClusterBlockLevel.class);
|
||||
for (final ClusterBlockLevel level : ClusterBlockLevel.values()) {
|
||||
Predicate<ClusterBlock> containsLevel = block -> block.contains(level);
|
||||
@ -199,13 +197,7 @@ public class ClusterBlocks extends AbstractDiffable<ClusterBlocks> {
|
||||
}
|
||||
|
||||
public ClusterBlockException indexBlockedException(ClusterBlockLevel level, String index) {
|
||||
if (!indexBlocked(level, index)) {
|
||||
return null;
|
||||
}
|
||||
Stream<ClusterBlock> blocks = concat(
|
||||
global(level).stream(),
|
||||
blocksForIndex(level, index).stream());
|
||||
return new ClusterBlockException(unmodifiableSet(blocks.collect(toSet())));
|
||||
return indicesBlockedException(level, new String[]{index});
|
||||
}
|
||||
|
||||
public boolean indexBlocked(ClusterBlockLevel level, String index) {
|
||||
@ -213,20 +205,21 @@ public class ClusterBlocks extends AbstractDiffable<ClusterBlocks> {
|
||||
}
|
||||
|
||||
public ClusterBlockException indicesBlockedException(ClusterBlockLevel level, String[] indices) {
|
||||
boolean indexIsBlocked = false;
|
||||
Set<ClusterBlock> globalLevelBlocks = global(level);
|
||||
Map<String, Set<ClusterBlock>> indexLevelBlocks = new HashMap<>();
|
||||
for (String index : indices) {
|
||||
if (indexBlocked(level, index)) {
|
||||
indexIsBlocked = true;
|
||||
Set<ClusterBlock> indexBlocks = blocksForIndex(level, index);
|
||||
if (indexBlocks.isEmpty() == false || globalLevelBlocks.isEmpty() == false) {
|
||||
indexLevelBlocks.put(index, Sets.union(indexBlocks, globalLevelBlocks));
|
||||
}
|
||||
}
|
||||
if (globalBlocked(level) == false && indexIsBlocked == false) {
|
||||
if (indexLevelBlocks.isEmpty()) {
|
||||
if(globalLevelBlocks.isEmpty() == false){
|
||||
return new ClusterBlockException(globalLevelBlocks);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Function<String, Stream<ClusterBlock>> blocksForIndexAtLevel = index -> blocksForIndex(level, index).stream();
|
||||
Stream<ClusterBlock> blocks = concat(
|
||||
global(level).stream(),
|
||||
Stream.of(indices).flatMap(blocksForIndexAtLevel));
|
||||
return new ClusterBlockException(unmodifiableSet(blocks.collect(toSet())));
|
||||
return new ClusterBlockException(indexLevelBlocks);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,20 +228,27 @@ public class ClusterBlocks extends AbstractDiffable<ClusterBlocks> {
|
||||
* like the deletion of an index to free up resources on nodes.
|
||||
* @param indices the indices to check
|
||||
*/
|
||||
|
||||
public ClusterBlockException indicesAllowReleaseResources(String[] indices) {
|
||||
final Function<String, Stream<ClusterBlock>> blocksForIndexAtLevel = index ->
|
||||
blocksForIndex(ClusterBlockLevel.METADATA_WRITE, index).stream();
|
||||
Stream<ClusterBlock> blocks = concat(
|
||||
global(ClusterBlockLevel.METADATA_WRITE).stream(),
|
||||
Stream.of(indices).flatMap(blocksForIndexAtLevel)).filter(clusterBlock -> clusterBlock.isAllowReleaseResources() == false);
|
||||
Set<ClusterBlock> clusterBlocks = unmodifiableSet(blocks.collect(toSet()));
|
||||
if (clusterBlocks.isEmpty()) {
|
||||
Set<ClusterBlock> globalBlocks = global(ClusterBlockLevel.METADATA_WRITE).stream()
|
||||
.filter(clusterBlock -> clusterBlock.isAllowReleaseResources() == false).collect(toSet());
|
||||
Map<String, Set<ClusterBlock>> indexLevelBlocks = new HashMap<>();
|
||||
for (String index : indices) {
|
||||
Set<ClusterBlock> blocks = Sets.union(globalBlocks, blocksForIndex(ClusterBlockLevel.METADATA_WRITE, index))
|
||||
.stream().filter(clusterBlock -> clusterBlock.isAllowReleaseResources() == false).collect(toSet());
|
||||
if (blocks.isEmpty() == false) {
|
||||
indexLevelBlocks.put(index, Sets.union(globalBlocks, blocks));
|
||||
}
|
||||
}
|
||||
if (indexLevelBlocks.isEmpty()) {
|
||||
if(globalBlocks.isEmpty() == false){
|
||||
return new ClusterBlockException(globalBlocks);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return new ClusterBlockException(clusterBlocks);
|
||||
return new ClusterBlockException(indexLevelBlocks);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (global.isEmpty() && indices().isEmpty()) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
package org.elasticsearch.action.admin.indices.delete;
|
||||
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.MetaData;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
@ -63,7 +64,22 @@ public class DeleteIndexBlocksIT extends ESIntegTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteIndexOnReadOnlyAllowDeleteSetting() {
|
||||
public void testClusterBlockMessageHasIndexName() {
|
||||
try {
|
||||
createIndex("test");
|
||||
ensureGreen("test");
|
||||
Settings settings = Settings.builder().put(IndexMetaData.SETTING_READ_ONLY_ALLOW_DELETE, true).build();
|
||||
client().admin().indices().prepareUpdateSettings("test").setSettings(settings).get();
|
||||
ClusterBlockException e = expectThrows(ClusterBlockException.class, () ->
|
||||
client().prepareIndex().setIndex("test").setType("doc").setId("1").setSource("foo", "bar").get());
|
||||
assertEquals("index [test] blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];", e.getMessage());
|
||||
} finally {
|
||||
assertAcked(client().admin().indices().prepareUpdateSettings("test")
|
||||
.setSettings(Settings.builder().putNull(IndexMetaData.SETTING_READ_ONLY_ALLOW_DELETE).build()).get());
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteIndexOnClusterReadOnlyAllowDeleteSetting() {
|
||||
createIndex("test");
|
||||
ensureGreen("test");
|
||||
client().prepareIndex().setIndex("test").setType("doc").setId("1").setSource("foo", "bar").get();
|
||||
|
@ -287,7 +287,7 @@ public class TransportBroadcastByNodeActionTests extends ESTestCase {
|
||||
action.new AsyncAction(null, request, listener).start();
|
||||
fail("expected ClusterBlockException");
|
||||
} catch (ClusterBlockException expected) {
|
||||
assertEquals("blocked by: [SERVICE_UNAVAILABLE/1/test-block];", expected.getMessage());
|
||||
assertEquals("index [" + TEST_INDEX + "] blocked by: [SERVICE_UNAVAILABLE/1/test-block];", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,7 +620,7 @@ public class IndexFollowingIT extends CcrIntegTestCase {
|
||||
assertThat(response.getStatsResponses().get(0).status().readExceptions().size(), equalTo(1));
|
||||
ElasticsearchException exception = response.getStatsResponses().get(0).status()
|
||||
.readExceptions().entrySet().iterator().next().getValue().v2();
|
||||
assertThat(exception.getRootCause().getMessage(), equalTo("blocked by: [FORBIDDEN/4/index closed];"));
|
||||
assertThat(exception.getRootCause().getMessage(), equalTo("index [index1] blocked by: [FORBIDDEN/4/index closed];"));
|
||||
});
|
||||
|
||||
leaderClient().admin().indices().open(new OpenIndexRequest("index1")).actionGet();
|
||||
|
Loading…
x
Reference in New Issue
Block a user