Skip to content

Commit 87c6fa7

Browse files
authored
Introduce projectClient method on Client (elastic#129174)
We originally defined the `projectClient` method on `ProjectResolver` as a convenience method to execute API calls for specific projects. That method requires a reference to both a `ProjectResolver` and a `Client`. We now introduce the same method directly on the `Client` interface and inject a `ProjectResolver` there, removing the need for a `ProjectResolver` reference in places that just want to execute API requests on a specific project. To reduce the number of changes, this change solely focuses on introducing the new method. Future changes will migrate the uses of the original method to the new one and remove the original altogether.
1 parent 80aa17e commit 87c6fa7

File tree

44 files changed

+156
-60
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+156
-60
lines changed

modules/analysis-common/src/test/java/org/elasticsearch/analysis/common/PredicateTokenScriptFilterTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.client.internal.Client;
1717
import org.elasticsearch.client.internal.support.AbstractClient;
1818
import org.elasticsearch.cluster.metadata.IndexMetadata;
19+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1920
import org.elasticsearch.common.settings.Settings;
2021
import org.elasticsearch.env.Environment;
2122
import org.elasticsearch.env.TestEnvironment;
@@ -96,7 +97,7 @@ public <FactoryType> FactoryType compile(Script script, ScriptContext<FactoryTyp
9697

9798
private static class MockClient extends AbstractClient {
9899
MockClient(Settings settings, ThreadPool threadPool) {
99-
super(settings, threadPool);
100+
super(settings, threadPool, TestProjectResolvers.alwaysThrow());
100101
}
101102

102103
@Override

modules/analysis-common/src/test/java/org/elasticsearch/analysis/common/ScriptedConditionTokenFilterTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.client.internal.Client;
1717
import org.elasticsearch.client.internal.support.AbstractClient;
1818
import org.elasticsearch.cluster.metadata.IndexMetadata;
19+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1920
import org.elasticsearch.common.settings.Settings;
2021
import org.elasticsearch.env.Environment;
2122
import org.elasticsearch.env.TestEnvironment;
@@ -96,7 +97,7 @@ public <FactoryType> FactoryType compile(Script script, ScriptContext<FactoryTyp
9697

9798
private class MockClient extends AbstractClient {
9899
MockClient(Settings settings, ThreadPool threadPool) {
99-
super(settings, threadPool);
100+
super(settings, threadPool, TestProjectResolvers.alwaysThrow());
100101
}
101102

102103
@Override

modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/TransportRankEvalActionTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.action.support.ActionFilters;
1717
import org.elasticsearch.action.support.IndicesOptions;
1818
import org.elasticsearch.client.internal.node.NodeClient;
19+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1920
import org.elasticsearch.cluster.service.ClusterService;
2021
import org.elasticsearch.common.settings.Settings;
2122
import org.elasticsearch.env.Environment;
@@ -68,7 +69,7 @@ public void testTransferRequestParameters() throws Exception {
6869
);
6970
rankEvalRequest.indicesOptions(expectedIndicesOptions);
7071

71-
NodeClient client = new NodeClient(settings, null) {
72+
NodeClient client = new NodeClient(settings, null, TestProjectResolvers.alwaysThrow()) {
7273
@Override
7374
public void multiSearch(MultiSearchRequest request, ActionListener<MultiSearchResponse> listener) {
7475
assertEquals(1, request.requests().size());

modules/reindex/src/test/java/org/elasticsearch/reindex/ClientScrollableHitSourceTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.elasticsearch.action.search.TransportSearchScrollAction;
2222
import org.elasticsearch.client.internal.ParentTaskAssigningClient;
2323
import org.elasticsearch.client.internal.support.AbstractClient;
24+
import org.elasticsearch.cluster.project.TestProjectResolvers;
2425
import org.elasticsearch.common.BackoffPolicy;
2526
import org.elasticsearch.common.bytes.BytesArray;
2627
import org.elasticsearch.common.settings.Settings;
@@ -214,7 +215,7 @@ private static class MockClient extends AbstractClient {
214215
private ExecuteRequest<?, ?> executeRequest;
215216

216217
MockClient(ThreadPool threadPool) {
217-
super(Settings.EMPTY, threadPool);
218+
super(Settings.EMPTY, threadPool, TestProjectResolvers.alwaysThrow());
218219
}
219220

220221
@Override

server/src/main/java/org/elasticsearch/client/internal/Client.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
import org.elasticsearch.action.update.UpdateRequest;
5353
import org.elasticsearch.action.update.UpdateRequestBuilder;
5454
import org.elasticsearch.action.update.UpdateResponse;
55+
import org.elasticsearch.cluster.metadata.ProjectId;
56+
import org.elasticsearch.cluster.project.ProjectResolver;
5557
import org.elasticsearch.common.settings.Settings;
5658
import org.elasticsearch.core.Nullable;
5759
import org.elasticsearch.transport.RemoteClusterService;
@@ -399,6 +401,16 @@ public interface Client extends ElasticsearchClient {
399401
*/
400402
Client filterWithHeader(Map<String, String> headers);
401403

404+
/**
405+
* Returns a client that executes every request in the context of the given project.
406+
*/
407+
Client projectClient(ProjectId projectId);
408+
409+
/**
410+
* Returns this client's project resolver.
411+
*/
412+
ProjectResolver projectResolver();
413+
402414
/**
403415
* Returns a client to a remote cluster with the given cluster alias.
404416
*

server/src/main/java/org/elasticsearch/client/internal/FilterClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.elasticsearch.action.ActionResponse;
1414
import org.elasticsearch.action.ActionType;
1515
import org.elasticsearch.client.internal.support.AbstractClient;
16+
import org.elasticsearch.cluster.project.ProjectResolver;
1617
import org.elasticsearch.common.settings.Settings;
1718
import org.elasticsearch.threadpool.ThreadPool;
1819
import org.elasticsearch.transport.RemoteClusterService;
@@ -35,15 +36,15 @@ public abstract class FilterClient extends AbstractClient {
3536
* @see #in()
3637
*/
3738
public FilterClient(Client in) {
38-
this(in.settings(), in.threadPool(), in);
39+
this(in.settings(), in.threadPool(), in.projectResolver(), in);
3940
}
4041

4142
/**
4243
* A Constructor that allows to pass settings and threadpool separately. This is useful if the
4344
* client is a proxy and not yet fully constructed ie. both dependencies are not available yet.
4445
*/
45-
protected FilterClient(Settings settings, ThreadPool threadPool, Client in) {
46-
super(settings, threadPool);
46+
protected FilterClient(Settings settings, ThreadPool threadPool, ProjectResolver projectResolver, Client in) {
47+
super(settings, threadPool, projectResolver);
4748
this.in = in;
4849
}
4950

server/src/main/java/org/elasticsearch/client/internal/node/NodeClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.client.internal.RemoteClusterClient;
1919
import org.elasticsearch.client.internal.support.AbstractClient;
2020
import org.elasticsearch.cluster.node.DiscoveryNode;
21+
import org.elasticsearch.cluster.project.ProjectResolver;
2122
import org.elasticsearch.common.settings.Settings;
2223
import org.elasticsearch.tasks.Task;
2324
import org.elasticsearch.tasks.TaskCancelledException;
@@ -48,8 +49,8 @@ public class NodeClient extends AbstractClient {
4849
private Transport.Connection localConnection;
4950
private RemoteClusterService remoteClusterService;
5051

51-
public NodeClient(Settings settings, ThreadPool threadPool) {
52-
super(settings, threadPool);
52+
public NodeClient(Settings settings, ThreadPool threadPool, ProjectResolver projectResolver) {
53+
super(settings, threadPool, projectResolver);
5354
}
5455

5556
public void initialize(

server/src/main/java/org/elasticsearch/client/internal/support/AbstractClient.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
import org.elasticsearch.client.internal.AdminClient;
7777
import org.elasticsearch.client.internal.Client;
7878
import org.elasticsearch.client.internal.FilterClient;
79+
import org.elasticsearch.cluster.metadata.ProjectId;
80+
import org.elasticsearch.cluster.project.ProjectResolver;
7981
import org.elasticsearch.common.settings.Settings;
8082
import org.elasticsearch.common.util.concurrent.ThreadContext;
8183
import org.elasticsearch.core.Nullable;
@@ -92,12 +94,14 @@ public abstract class AbstractClient implements Client {
9294

9395
protected final Settings settings;
9496
private final ThreadPool threadPool;
97+
private final ProjectResolver projectResolver;
9598
private final AdminClient admin;
9699

97100
@SuppressWarnings("this-escape")
98-
public AbstractClient(Settings settings, ThreadPool threadPool) {
101+
public AbstractClient(Settings settings, ThreadPool threadPool, ProjectResolver projectResolver) {
99102
this.settings = settings;
100103
this.threadPool = threadPool;
104+
this.projectResolver = projectResolver;
101105
this.admin = new AdminClient(this);
102106
this.logger = LogManager.getLogger(this.getClass());
103107
}
@@ -112,6 +116,11 @@ public final ThreadPool threadPool() {
112116
return this.threadPool;
113117
}
114118

119+
@Override
120+
public ProjectResolver projectResolver() {
121+
return projectResolver;
122+
}
123+
115124
@Override
116125
public final AdminClient admin() {
117126
return admin;
@@ -407,6 +416,32 @@ protected <Request extends ActionRequest, Response extends ActionResponse> void
407416
};
408417
}
409418

419+
@Override
420+
public Client projectClient(ProjectId projectId) {
421+
// We only take the shortcut when the given project ID matches the "current" project ID. If it doesn't, we'll let #executeOnProject
422+
// take care of error handling.
423+
if (projectResolver.supportsMultipleProjects() == false && projectId.equals(projectResolver.getProjectId())) {
424+
return this;
425+
}
426+
return new FilterClient(this) {
427+
@Override
428+
protected <Request extends ActionRequest, Response extends ActionResponse> void doExecute(
429+
ActionType<Response> action,
430+
Request request,
431+
ActionListener<Response> listener
432+
) {
433+
projectResolver.executeOnProject(projectId, () -> super.doExecute(action, request, listener));
434+
}
435+
436+
@Override
437+
public Client projectClient(ProjectId projectId) {
438+
throw new IllegalStateException(
439+
"Unable to create a project client for project [" + projectId + "], nested project client creation is not supported"
440+
);
441+
}
442+
};
443+
}
444+
410445
/**
411446
* Same as {@link PlainActionFuture} but for use with {@link RefCounted} result types. Unlike {@code PlainActionFuture} this future
412447
* acquires a reference to its result. This means that the result reference must be released by a call to {@link RefCounted#decRef()}

server/src/main/java/org/elasticsearch/node/NodeConstruction.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,15 @@ static NodeConstruction prepareConstruction(
287287
// places they shouldn't. Best to explicitly drop them now to protect against such leakage.
288288
settingsModule = constructor.validateSettings(initialEnvironment.settings(), settings, threadPool);
289289
}
290+
// serverless deployments plug-in the multi-project resolver factory
291+
ProjectResolver projectResolver = constructor.pluginsService.loadSingletonServiceProvider(
292+
ProjectResolverFactory.class,
293+
() -> ProjectResolverFactory.DEFAULT
294+
).create();
295+
constructor.modules.bindToInstance(ProjectResolver.class, projectResolver);
290296

291297
SearchModule searchModule = constructor.createSearchModule(settingsModule.getSettings(), threadPool, telemetryProvider);
292-
constructor.createClientAndRegistries(settingsModule.getSettings(), threadPool, searchModule);
298+
constructor.createClientAndRegistries(settingsModule.getSettings(), threadPool, searchModule, projectResolver);
293299
DocumentParsingProvider documentParsingProvider = constructor.getDocumentParsingProvider();
294300

295301
ScriptService scriptService = constructor.createScriptService(settingsModule, threadPool, serviceProvider);
@@ -305,7 +311,8 @@ static NodeConstruction prepareConstruction(
305311
serviceProvider,
306312
forbidPrivateIndexSettings,
307313
telemetryProvider,
308-
documentParsingProvider
314+
documentParsingProvider,
315+
projectResolver
309316
);
310317

311318
return constructor;
@@ -562,8 +569,13 @@ private SearchModule createSearchModule(Settings settings, ThreadPool threadPool
562569
/**
563570
* Create various objects that are stored as member variables. This is so they are accessible as soon as possible.
564571
*/
565-
private void createClientAndRegistries(Settings settings, ThreadPool threadPool, SearchModule searchModule) {
566-
client = new NodeClient(settings, threadPool);
572+
private void createClientAndRegistries(
573+
Settings settings,
574+
ThreadPool threadPool,
575+
SearchModule searchModule,
576+
ProjectResolver projectResolver
577+
) {
578+
client = new NodeClient(settings, threadPool, projectResolver);
567579
modules.add(b -> {
568580
b.bind(Client.class).toInstance(client);
569581
b.bind(NodeClient.class).toInstance(client);
@@ -664,7 +676,8 @@ private void construct(
664676
NodeServiceProvider serviceProvider,
665677
boolean forbidPrivateIndexSettings,
666678
TelemetryProvider telemetryProvider,
667-
DocumentParsingProvider documentParsingProvider
679+
DocumentParsingProvider documentParsingProvider,
680+
ProjectResolver projectResolver
668681
) throws IOException {
669682

670683
Settings settings = settingsModule.getSettings();
@@ -681,12 +694,6 @@ private void construct(
681694
telemetryProvider.getTracer()
682695
);
683696

684-
// serverless deployments plug-in the multi-project resolver factory
685-
ProjectResolver projectResolver = pluginsService.loadSingletonServiceProvider(
686-
ProjectResolverFactory.class,
687-
() -> ProjectResolverFactory.DEFAULT
688-
).create();
689-
modules.bindToInstance(ProjectResolver.class, projectResolver);
690697
ClusterService clusterService = createClusterService(settingsModule, threadPool, taskManager);
691698
clusterService.addStateApplier(scriptService);
692699

server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TransportGetTaskActionTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public void testGetTaskActionWithMultiProjectEnabled() {
7373
var transportService = mock(TransportService.class);
7474
var clusterService = mock(ClusterService.class);
7575
var nodeId = "node1";
76-
NodeClient client = new NodeClient(Settings.EMPTY, threadPool) {
76+
NodeClient client = new NodeClient(Settings.EMPTY, threadPool, TestProjectResolvers.alwaysThrow()) {
7777
@Override
7878
@SuppressWarnings("unchecked")
7979
public <Request extends ActionRequest, Response extends ActionResponse> void doExecute(

0 commit comments

Comments
 (0)