Skip to content

Allow static cluster.max_voting_config_exclusions #53717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
Expand All @@ -60,11 +62,21 @@ public class TransportAddVotingConfigExclusionsAction extends TransportMasterNod
public static final Setting<Integer> MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING
= Setting.intSetting("cluster.max_voting_config_exclusions", 10, 1, Property.Dynamic, Property.NodeScope);

private volatile int maxVotingConfigExclusions;

@Inject
public TransportAddVotingConfigExclusionsAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool,
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
public TransportAddVotingConfigExclusionsAction(Settings settings, ClusterSettings clusterSettings, TransportService transportService,
ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(AddVotingConfigExclusionsAction.NAME, transportService, clusterService, threadPool, actionFilters,
AddVotingConfigExclusionsRequest::new, indexNameExpressionResolver);

maxVotingConfigExclusions = MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.get(settings);
clusterSettings.addSettingsUpdateConsumer(MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING, this::setMaxVotingConfigExclusions);
}

private void setMaxVotingConfigExclusions(int maxVotingConfigExclusions) {
this.maxVotingConfigExclusions = maxVotingConfigExclusions;
}

@Override
Expand All @@ -81,7 +93,8 @@ protected AddVotingConfigExclusionsResponse read(StreamInput in) throws IOExcept
protected void masterOperation(Task task, AddVotingConfigExclusionsRequest request, ClusterState state,
ActionListener<AddVotingConfigExclusionsResponse> listener) throws Exception {

resolveVotingConfigExclusionsAndCheckMaximum(request, state); // throws IAE if no nodes matched or maximum exceeded
resolveVotingConfigExclusionsAndCheckMaximum(request, state, maxVotingConfigExclusions);
// throws IAE if no nodes matched or maximum exceeded

clusterService.submitStateUpdateTask("add-voting-config-exclusions", new ClusterStateUpdateTask(Priority.URGENT) {

Expand All @@ -90,14 +103,14 @@ protected void masterOperation(Task task, AddVotingConfigExclusionsRequest reque
@Override
public ClusterState execute(ClusterState currentState) {
assert resolvedExclusions == null : resolvedExclusions;
resolvedExclusions = resolveVotingConfigExclusionsAndCheckMaximum(request, currentState);
final int finalMaxVotingConfigExclusions = TransportAddVotingConfigExclusionsAction.this.maxVotingConfigExclusions;
resolvedExclusions = resolveVotingConfigExclusionsAndCheckMaximum(request, currentState, finalMaxVotingConfigExclusions);

final CoordinationMetaData.Builder builder = CoordinationMetaData.builder(currentState.coordinationMetaData());
resolvedExclusions.forEach(builder::addVotingConfigExclusion);
final MetaData newMetaData = MetaData.builder(currentState.metaData()).coordinationMetaData(builder.build()).build();
final ClusterState newState = ClusterState.builder(currentState).metaData(newMetaData).build();
assert newState.getVotingConfigExclusions().size() <= MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.get(
currentState.metaData().settings());
assert newState.getVotingConfigExclusions().size() <= finalMaxVotingConfigExclusions;
return newState;
}

Expand Down Expand Up @@ -149,9 +162,10 @@ public void onTimeout(TimeValue timeout) {
}

private static Set<VotingConfigExclusion> resolveVotingConfigExclusionsAndCheckMaximum(AddVotingConfigExclusionsRequest request,
ClusterState state) {
return request.resolveVotingConfigExclusionsAndCheckMaximum(state,
MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.get(state.metaData().settings()), MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey());
ClusterState state,
int maxVotingConfigExclusions) {
return request.resolveVotingConfigExclusionsAndCheckMaximum(state, maxVotingConfigExclusions,
MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.elasticsearch.cluster.node.DiscoveryNodes.Builder;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ESTestCase;
Expand Down Expand Up @@ -80,6 +81,8 @@ public class TransportAddVotingConfigExclusionsActionTests extends ESTestCase {

private TransportService transportService;
private ClusterStateObserver clusterStateObserver;
private ClusterSettings clusterSettings;
private int staticMaximum;

@BeforeClass
public static void createThreadPoolAndClusterService() {
Expand Down Expand Up @@ -116,8 +119,18 @@ public void setupForTest() {
transportService = transport.createTransportService(Settings.EMPTY, threadPool,
TransportService.NOOP_TRANSPORT_INTERCEPTOR, boundTransportAddress -> localNode, null, emptySet());

new TransportAddVotingConfigExclusionsAction(transportService, clusterService, threadPool, new ActionFilters(emptySet()),
new IndexNameExpressionResolver()); // registers action
final Settings.Builder nodeSettingsBuilder = Settings.builder();
if (randomBoolean()) {
staticMaximum = between(5, 15);
nodeSettingsBuilder.put(MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey(), staticMaximum);
} else {
staticMaximum = MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.get(Settings.EMPTY);
}
final Settings nodeSettings = nodeSettingsBuilder.build();
clusterSettings = new ClusterSettings(nodeSettings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);

new TransportAddVotingConfigExclusionsAction(nodeSettings, clusterSettings, transportService, clusterService, threadPool,
new ActionFilters(emptySet()), new IndexNameExpressionResolver()); // registers action

transportService.start();
transportService.acceptIncomingRequests();
Expand Down Expand Up @@ -307,20 +320,32 @@ public void testSucceedsEvenIfAllExclusionsAlreadyAdded() throws InterruptedExce
}

public void testReturnsErrorIfMaximumExclusionCountExceeded() throws InterruptedException {
final MetaData.Builder metaDataBuilder = MetaData.builder(clusterService.state().metaData()).persistentSettings(
Settings.builder().put(clusterService.state().metaData().persistentSettings())
.put(MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey(), 2).build());
final MetaData.Builder metaDataBuilder = MetaData.builder(clusterService.state().metaData());
CoordinationMetaData.Builder coordinationMetaDataBuilder =
CoordinationMetaData.builder(clusterService.state().coordinationMetaData())
.addVotingConfigExclusion(localNodeExclusion);
CoordinationMetaData.builder(clusterService.state().coordinationMetaData())
.addVotingConfigExclusion(localNodeExclusion);

final int actualMaximum;
if (randomBoolean()) {
actualMaximum = staticMaximum;
} else {
actualMaximum = between(2, 15);
clusterSettings.applySettings(Settings.builder().put(clusterService.state().metaData().persistentSettings())
.put(MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey(), actualMaximum).build());
}

for (int i = 2; i < actualMaximum; i++) {
coordinationMetaDataBuilder.addVotingConfigExclusion(
new VotingConfigExclusion(randomAlphaOfLength(10), randomAlphaOfLength(10)));
}

final int existingCount, newCount;
if (randomBoolean()) {
coordinationMetaDataBuilder.addVotingConfigExclusion(otherNode1Exclusion);
existingCount = 2;
existingCount = actualMaximum;
newCount = 1;
} else {
existingCount = 1;
existingCount = actualMaximum - 1;
newCount = 2;
}

Expand All @@ -345,7 +370,7 @@ public void testReturnsErrorIfMaximumExclusionCountExceeded() throws Interrupted
assertThat(rootCause, instanceOf(IllegalArgumentException.class));
assertThat(rootCause.getMessage(), equalTo("add voting config exclusions request for [other*] would add [" + newCount +
"] exclusions to the existing [" + existingCount +
"] which would exceed the maximum of [2] set by [cluster.max_voting_config_exclusions]"));
"] which would exceed the maximum of [" + actualMaximum + "] set by [cluster.max_voting_config_exclusions]"));
}

public void testTimesOut() throws InterruptedException {
Expand Down