Skip to content

Commit 8878936

Browse files
Support the same format of reserved state metadata in GetClusterState API for single project MP clusters
1 parent 97bea1f commit 8878936

File tree

5 files changed

+80
-8
lines changed

5 files changed

+80
-8
lines changed

server/src/main/java/org/elasticsearch/action/admin/cluster/state/ClusterStateRequest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class ClusterStateRequest extends LocalClusterStateRequest implements Ind
3939
private TimeValue waitForTimeout = DEFAULT_WAIT_FOR_NODE_TIMEOUT;
4040
private String[] indices = Strings.EMPTY_ARRAY;
4141
private IndicesOptions indicesOptions = IndicesOptions.lenientExpandOpen();
42+
private boolean multiproject = false;
4243

4344
public ClusterStateRequest(TimeValue masterNodeTimeout) {
4445
super(masterNodeTimeout);
@@ -140,6 +141,14 @@ public boolean customs() {
140141
return customs;
141142
}
142143

144+
public void multiproject(boolean multiproject) {
145+
this.multiproject = multiproject;
146+
}
147+
148+
public boolean multiproject() {
149+
return multiproject;
150+
}
151+
143152
public TimeValue waitForTimeout() {
144153
return waitForTimeout;
145154
}
@@ -200,5 +209,4 @@ public String getDescription() {
200209
stringBuilder.append("master timeout [").append(masterTimeout()).append("]]");
201210
return stringBuilder.toString();
202211
}
203-
204212
}

server/src/main/java/org/elasticsearch/action/admin/cluster/state/TransportClusterStateAction.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.elasticsearch.cluster.metadata.Metadata;
2929
import org.elasticsearch.cluster.metadata.ProjectId;
3030
import org.elasticsearch.cluster.metadata.ProjectMetadata;
31+
import org.elasticsearch.cluster.metadata.ReservedStateHandlerMetadata;
32+
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
3133
import org.elasticsearch.cluster.project.ProjectResolver;
3234
import org.elasticsearch.cluster.project.ProjectStateRegistry;
3335
import org.elasticsearch.cluster.routing.GlobalRoutingTable;
@@ -47,6 +49,7 @@
4749

4850
import java.io.IOException;
4951
import java.util.Collection;
52+
import java.util.HashMap;
5053
import java.util.Map;
5154
import java.util.Set;
5255
import java.util.function.BiPredicate;
@@ -255,6 +258,19 @@ private ClusterStateResponse buildResponse(final ClusterStateRequest request, fi
255258
// If there are no requested indices, then we want all the metadata, except for customs that aren't exposed via the API
256259
mdBuilder = Metadata.builder(currentState.metadata());
257260
mdBuilder.removeCustomIf(notApi);
261+
262+
if (request.multiproject() == false) {
263+
ProjectStateRegistry projectStateRegistry = ProjectStateRegistry.get(currentState);
264+
if (projectStateRegistry.size() > 1) {
265+
throw new Metadata.MultiProjectPendingException("There are multiple projects " + projectStateRegistry.knownProjects());
266+
}
267+
var reservedStateMetadata = new HashMap<>(currentState.metadata().reservedStateMetadata());
268+
var singleProjectReservedStateMetadata = projectStateRegistry.reservedStateMetadata(projectResolver.getProjectId());
269+
singleProjectReservedStateMetadata.forEach((key, value) ->
270+
reservedStateMetadata.merge(key, value, this::mergeReservedStateMetadata));
271+
272+
mdBuilder.put(reservedStateMetadata);
273+
}
258274
}
259275

260276
for (ProjectMetadata project : currentState.metadata().projects().values()) {
@@ -308,4 +324,23 @@ private ClusterStateResponse buildResponse(final ClusterStateRequest request, fi
308324
return new ClusterStateResponse(currentState.getClusterName(), builder.build(), false);
309325
}
310326

327+
private ReservedStateMetadata mergeReservedStateMetadata(ReservedStateMetadata metadata1, ReservedStateMetadata metadata2) {
328+
ReservedStateMetadata.Builder builder = ReservedStateMetadata.builder(metadata1.namespace())
329+
.version(Math.max(metadata1.version(), metadata2.version()));
330+
331+
for (ReservedStateHandlerMetadata handler : metadata1.handlers().values()) {
332+
builder.putHandler(handler);
333+
}
334+
for (ReservedStateHandlerMetadata handler : metadata2.handlers().values()) {
335+
builder.putHandler(handler);
336+
}
337+
338+
if (metadata2.errorMetadata() != null) {
339+
builder.errorMetadata(metadata2.errorMetadata());
340+
} else if (metadata1.errorMetadata() != null) {
341+
builder.errorMetadata(metadata1.errorMetadata());
342+
}
343+
344+
return builder.build();
345+
}
311346
}

server/src/main/java/org/elasticsearch/cluster/project/ProjectStateRegistry.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,7 @@ public long getProjectsMarkedForDeletionGeneration() {
199199
return projectsMarkedForDeletionGeneration;
200200
}
201201

202-
// visible for testing
203-
Set<ProjectId> knownProjects() {
202+
public Set<ProjectId> knownProjects() {
204203
return projectsEntries.keySet();
205204
}
206205

server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterStateAction.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
112112
final Map<String, String> params;
113113
if (request.paramAsBoolean("multi_project", false)) {
114114
params = Map.of(Metadata.CONTEXT_MODE_PARAM, Metadata.CONTEXT_MODE_API, "multi-project", "true");
115+
clusterStateRequest.multiproject(true);
115116
} else {
116117
params = Map.of(Metadata.CONTEXT_MODE_PARAM, Metadata.CONTEXT_MODE_API);
117118
}

server/src/test/java/org/elasticsearch/action/admin/cluster/state/TransportClusterStateActionTests.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.elasticsearch.cluster.metadata.Metadata;
2020
import org.elasticsearch.cluster.metadata.ProjectId;
2121
import org.elasticsearch.cluster.metadata.ProjectMetadata;
22+
import org.elasticsearch.cluster.metadata.ReservedStateHandlerMetadata;
23+
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
2224
import org.elasticsearch.cluster.node.VersionInformation;
2325
import org.elasticsearch.cluster.project.DefaultProjectResolver;
2426
import org.elasticsearch.cluster.project.ProjectResolver;
@@ -94,7 +96,7 @@ public void testGetClusterStateWithDefaultProjectOnly() throws Exception {
9496
final ProjectResolver projectResolver = DefaultProjectResolver.INSTANCE;
9597

9698
final Set<String> indexNames = randomSet(1, 8, () -> randomAlphaOfLengthBetween(4, 12));
97-
final ClusterStateRequest request = buildRandomRequest(indexNames);
99+
final ClusterStateRequest request = buildRandomRequest(indexNames, false);
98100
final String[] expectedIndices = getExpectedIndices(request, indexNames);
99101

100102
final ProjectId projectId = Metadata.DEFAULT_PROJECT_ID;
@@ -112,7 +114,7 @@ public void testGetClusterStateForOneProjectOfMany() throws Exception {
112114
final ProjectId projectId = randomUniqueProjectId();
113115

114116
final ProjectResolver projectResolver = TestProjectResolvers.singleProject(projectId);
115-
final ClusterStateRequest request = buildRandomRequest(indexNames);
117+
final ClusterStateRequest request = buildRandomRequest(indexNames, false);
116118
final String[] expectedIndices = getExpectedIndices(request, indexNames);
117119

118120
final int numberOfProjects = randomIntBetween(2, 5);
@@ -141,7 +143,7 @@ public void testGetClusterStateForManyProjects() throws Exception {
141143
final ClusterState state = buildClusterState(projects);
142144

143145
final ProjectResolver projectResolver = TestProjectResolvers.allProjects();
144-
final ClusterStateRequest request = buildRandomRequest(indexNames);
146+
final ClusterStateRequest request = buildRandomRequest(indexNames, true);
145147
final Set<String> requestedIndices = Set.of(getExpectedIndices(request, indexNames));
146148

147149
final ClusterStateResponse response = executeAction(projectResolver, request, state);
@@ -190,6 +192,22 @@ private static void assertSingleProjectResponse(
190192
assertThat(metadata.projects().keySet(), contains(projectId));
191193
if (request.metadata()) {
192194
assertThat(metadata.getProject(projectId).indices().keySet(), containsInAnyOrder(expectedIndices));
195+
196+
if (expectedIndices.length == 0) {
197+
Map<String, ReservedStateMetadata> reservedStateMetadataMap = metadata.reservedStateMetadata();
198+
assertThat(reservedStateMetadataMap, aMapWithSize(1));
199+
ReservedStateMetadata fileSettings = reservedStateMetadataMap.get("file_settings");
200+
assertNotNull(fileSettings);
201+
assertThat(fileSettings.version(), equalTo(43L));
202+
Map<String, ReservedStateHandlerMetadata> handlers = fileSettings.handlers();
203+
assertThat(handlers, aMapWithSize(2));
204+
ReservedStateHandlerMetadata clusterSettingsHandler = handlers.get("cluster_settings");
205+
assertNotNull(clusterSettingsHandler);
206+
assertThat(clusterSettingsHandler.keys(), containsInAnyOrder("setting_1", "setting_2"));
207+
ReservedStateHandlerMetadata projectSettingsHandler = handlers.get("project_settings");
208+
assertNotNull(projectSettingsHandler);
209+
assertThat(projectSettingsHandler.keys(), containsInAnyOrder("setting_1", "setting_2"));
210+
}
193211
} else {
194212
assertThat(metadata.getProject(projectId).indices(), anEmptyMap());
195213
}
@@ -235,7 +253,7 @@ private static String[] getExpectedIndices(ClusterStateRequest request, Set<Stri
235253
}
236254
}
237255

238-
private static ClusterStateRequest buildRandomRequest(Set<String> indexNames) {
256+
private static ClusterStateRequest buildRandomRequest(Set<String> indexNames, boolean multipleProjects) {
239257
final ClusterStateRequest request = new ClusterStateRequest(TEST_REQUEST_TIMEOUT);
240258
if (randomBoolean()) {
241259
final int numberSelectedIndices = randomIntBetween(1, indexNames.size());
@@ -248,18 +266,29 @@ private static ClusterStateRequest buildRandomRequest(Set<String> indexNames) {
248266
request.routingTable(randomBoolean());
249267
request.blocks(randomBoolean());
250268
request.customs(true);
269+
request.multiproject(multipleProjects);
251270
return request;
252271
}
253272

254273
private static ClusterState buildClusterState(ProjectMetadata.Builder... projects) {
255274
final Metadata.Builder metadataBuilder = Metadata.builder();
275+
metadataBuilder.put(ReservedStateMetadata.builder("file_settings")
276+
.version(43L)
277+
.putHandler(new ReservedStateHandlerMetadata("cluster_settings", Set.of("setting_1", "setting_2")))
278+
.build()
279+
);
256280
Arrays.stream(projects).forEach(metadataBuilder::put);
257281
final var metadata = metadataBuilder.build();
258282

259283
ClusterState.Builder csBuilder = ClusterState.builder(new ClusterName(randomAlphaOfLengthBetween(4, 12)));
260284
ProjectStateRegistry.Builder psBuilder = ProjectStateRegistry.builder();
261285
for (ProjectMetadata.Builder project : projects) {
262-
psBuilder.putProjectSettings(project.getId(), Settings.builder().put("setting_1", randomIdentifier()).build());
286+
psBuilder
287+
.putReservedStateMetadata(project.getId(), ReservedStateMetadata.builder("file_settings")
288+
.version(43L)
289+
.putHandler(new ReservedStateHandlerMetadata("project_settings", Set.of("setting_1")))
290+
.build())
291+
.putProjectSettings(project.getId(), Settings.builder().put("setting_1", randomIdentifier()).build());
263292
}
264293
return csBuilder.metadata(metadata)
265294
.routingTable(GlobalRoutingTableTestHelper.buildRoutingTable(metadata, RoutingTable.Builder::addAsNew))

0 commit comments

Comments
 (0)