Skip to content

Commit e1c930f

Browse files
authored
Make RepositoriesService project-aware (#129821)
This PR makes RepositoriesService project aware so that the basic Put, Get, Delete and Verify repository actions are now project scoped. It intentionally leaves the following aspects out of scope for the current changes: * Repository stats reporting * Repository clean-up, analysis and integrity verification * Repository usages for searchable snapshots and CCR They will be worked on separately. One main reason for leaving them out is that they are not needed by OBS which is currently blocked by repository/snapshot changes. They may also have their own complexities, e.g. stats reporting. Resolves: ES-10478
1 parent 4fe787a commit e1c930f

File tree

34 files changed

+720
-322
lines changed

34 files changed

+720
-322
lines changed

server/src/internalClusterTest/java/org/elasticsearch/repositories/RepositoriesServiceIT.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
1313
import org.elasticsearch.client.internal.Client;
14+
import org.elasticsearch.cluster.metadata.ProjectId;
1415
import org.elasticsearch.cluster.metadata.RepositoryMetadata;
1516
import org.elasticsearch.common.settings.Settings;
1617
import org.elasticsearch.env.Environment;
@@ -65,7 +66,7 @@ public void testUpdateRepository() {
6566

6667
assertThat(originalRepositoryMetadata.type(), equalTo(FsRepository.TYPE));
6768

68-
final Repository originalRepository = repositoriesService.repository(repositoryName);
69+
final Repository originalRepository = repositoriesService.repository(ProjectId.DEFAULT, repositoryName);
6970
assertThat(originalRepository, instanceOf(FsRepository.class));
7071

7172
final boolean updated = randomBoolean();
@@ -89,7 +90,7 @@ public void testUpdateRepository() {
8990

9091
assertThat(updatedRepositoryMetadata.type(), equalTo(updatedRepositoryType));
9192

92-
final Repository updatedRepository = repositoriesService.repository(repositoryName);
93+
final Repository updatedRepository = repositoriesService.repository(ProjectId.DEFAULT, repositoryName);
9394
assertThat(updatedRepository, updated ? not(sameInstance(originalRepository)) : sameInstance(originalRepository));
9495

9596
// check that a noop update does not verify. Since the new data node does not share the same `path.repo`, verification will fail if

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/delete/TransportDeleteRepositoryAction.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.cluster.ClusterState;
1919
import org.elasticsearch.cluster.block.ClusterBlockException;
2020
import org.elasticsearch.cluster.block.ClusterBlockLevel;
21+
import org.elasticsearch.cluster.project.ProjectResolver;
2122
import org.elasticsearch.cluster.service.ClusterService;
2223
import org.elasticsearch.common.util.concurrent.EsExecutors;
2324
import org.elasticsearch.injection.guice.Inject;
@@ -36,14 +37,16 @@ public class TransportDeleteRepositoryAction extends AcknowledgedTransportMaster
3637

3738
public static final ActionType<AcknowledgedResponse> TYPE = new ActionType<>("cluster:admin/repository/delete");
3839
private final RepositoriesService repositoriesService;
40+
private final ProjectResolver projectResolver;
3941

4042
@Inject
4143
public TransportDeleteRepositoryAction(
4244
TransportService transportService,
4345
ClusterService clusterService,
4446
RepositoriesService repositoriesService,
4547
ThreadPool threadPool,
46-
ActionFilters actionFilters
48+
ActionFilters actionFilters,
49+
ProjectResolver projectResolver
4750
) {
4851
super(
4952
TYPE.name(),
@@ -55,11 +58,12 @@ public TransportDeleteRepositoryAction(
5558
EsExecutors.DIRECT_EXECUTOR_SERVICE
5659
);
5760
this.repositoriesService = repositoriesService;
61+
this.projectResolver = projectResolver;
5862
}
5963

6064
@Override
6165
protected ClusterBlockException checkBlock(DeleteRepositoryRequest request, ClusterState state) {
62-
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
66+
return state.blocks().globalBlockedException(projectResolver.getProjectId(), ClusterBlockLevel.METADATA_WRITE);
6367
}
6468

6569
@Override
@@ -69,7 +73,7 @@ protected void masterOperation(
6973
ClusterState state,
7074
final ActionListener<AcknowledgedResponse> listener
7175
) {
72-
repositoriesService.unregisterRepository(request, listener);
76+
repositoriesService.unregisterRepository(projectResolver.getProjectId(), request, listener);
7377
}
7478

7579
@Override

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/get/TransportGetRepositoriesAction.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111

1212
import org.elasticsearch.action.ActionListener;
1313
import org.elasticsearch.action.support.ActionFilters;
14-
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
15-
import org.elasticsearch.cluster.ClusterState;
14+
import org.elasticsearch.action.support.master.TransportMasterNodeReadProjectAction;
15+
import org.elasticsearch.cluster.ProjectState;
1616
import org.elasticsearch.cluster.block.ClusterBlockException;
1717
import org.elasticsearch.cluster.block.ClusterBlockLevel;
1818
import org.elasticsearch.cluster.metadata.RepositoriesMetadata;
19+
import org.elasticsearch.cluster.project.ProjectResolver;
1920
import org.elasticsearch.cluster.service.ClusterService;
2021
import org.elasticsearch.common.util.concurrent.EsExecutors;
2122
import org.elasticsearch.injection.guice.Inject;
@@ -28,14 +29,15 @@
2829
/**
2930
* Transport action for get repositories operation
3031
*/
31-
public class TransportGetRepositoriesAction extends TransportMasterNodeReadAction<GetRepositoriesRequest, GetRepositoriesResponse> {
32+
public class TransportGetRepositoriesAction extends TransportMasterNodeReadProjectAction<GetRepositoriesRequest, GetRepositoriesResponse> {
3233

3334
@Inject
3435
public TransportGetRepositoriesAction(
3536
TransportService transportService,
3637
ClusterService clusterService,
3738
ThreadPool threadPool,
38-
ActionFilters actionFilters
39+
ActionFilters actionFilters,
40+
ProjectResolver projectResolver
3941
) {
4042
super(
4143
GetRepositoriesAction.NAME,
@@ -44,24 +46,25 @@ public TransportGetRepositoriesAction(
4446
threadPool,
4547
actionFilters,
4648
GetRepositoriesRequest::new,
49+
projectResolver,
4750
GetRepositoriesResponse::new,
4851
EsExecutors.DIRECT_EXECUTOR_SERVICE
4952
);
5053
}
5154

5255
@Override
53-
protected ClusterBlockException checkBlock(GetRepositoriesRequest request, ClusterState state) {
54-
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
56+
protected ClusterBlockException checkBlock(GetRepositoriesRequest request, ProjectState state) {
57+
return state.blocks().globalBlockedException(state.projectId(), ClusterBlockLevel.METADATA_READ);
5558
}
5659

5760
@Override
5861
protected void masterOperation(
5962
Task task,
6063
final GetRepositoriesRequest request,
61-
ClusterState state,
64+
ProjectState state,
6265
final ActionListener<GetRepositoriesResponse> listener
6366
) {
64-
final var result = ResolvedRepositories.resolve(state, request.repositories());
67+
final var result = ResolvedRepositories.resolve(state.metadata(), request.repositories());
6568
if (result.hasMissingRepositories()) {
6669
listener.onFailure(new RepositoryMissingException(String.join(", ", result.missing())));
6770
} else {

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/TransportPutRepositoryAction.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.cluster.ClusterState;
1919
import org.elasticsearch.cluster.block.ClusterBlockException;
2020
import org.elasticsearch.cluster.block.ClusterBlockLevel;
21+
import org.elasticsearch.cluster.project.ProjectResolver;
2122
import org.elasticsearch.cluster.service.ClusterService;
2223
import org.elasticsearch.common.util.concurrent.EsExecutors;
2324
import org.elasticsearch.injection.guice.Inject;
@@ -36,14 +37,16 @@ public class TransportPutRepositoryAction extends AcknowledgedTransportMasterNod
3637

3738
public static final ActionType<AcknowledgedResponse> TYPE = new ActionType<>("cluster:admin/repository/put");
3839
private final RepositoriesService repositoriesService;
40+
private final ProjectResolver projectResolver;
3941

4042
@Inject
4143
public TransportPutRepositoryAction(
4244
TransportService transportService,
4345
ClusterService clusterService,
4446
RepositoriesService repositoriesService,
4547
ThreadPool threadPool,
46-
ActionFilters actionFilters
48+
ActionFilters actionFilters,
49+
ProjectResolver projectResolver
4750
) {
4851
super(
4952
TYPE.name(),
@@ -55,11 +58,12 @@ public TransportPutRepositoryAction(
5558
EsExecutors.DIRECT_EXECUTOR_SERVICE
5659
);
5760
this.repositoriesService = repositoriesService;
61+
this.projectResolver = projectResolver;
5862
}
5963

6064
@Override
6165
protected ClusterBlockException checkBlock(PutRepositoryRequest request, ClusterState state) {
62-
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
66+
return state.blocks().globalBlockedException(projectResolver.getProjectId(), ClusterBlockLevel.METADATA_WRITE);
6367
}
6468

6569
@Override
@@ -69,7 +73,7 @@ protected void masterOperation(
6973
ClusterState state,
7074
final ActionListener<AcknowledgedResponse> listener
7175
) {
72-
repositoriesService.registerRepository(request, listener);
76+
repositoriesService.registerRepository(projectResolver.getProjectId(), request, listener);
7377
}
7478

7579
@Override

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryAction.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
1313
import org.elasticsearch.cluster.ClusterState;
14+
import org.elasticsearch.cluster.metadata.ProjectId;
15+
import org.elasticsearch.core.FixForMultiProject;
1416
import org.elasticsearch.repositories.RepositoriesService;
1517
import org.elasticsearch.reservedstate.ReservedClusterStateHandler;
1618
import org.elasticsearch.reservedstate.TransformState;
@@ -60,7 +62,9 @@ public Collection<PutRepositoryRequest> prepare(Object input) {
6062
for (var repositoryRequest : repositories) {
6163
validate(repositoryRequest);
6264
RepositoriesService.validateRepositoryName(repositoryRequest.name());
63-
repositoriesService.validateRepositoryCanBeCreated(repositoryRequest);
65+
@FixForMultiProject(description = "resolve the actual projectId, ES-10479")
66+
final var projectId = ProjectId.DEFAULT;
67+
repositoriesService.validateRepositoryCanBeCreated(projectId, repositoryRequest);
6468
}
6569

6670
return repositories;
@@ -72,8 +76,14 @@ public TransformState transform(List<PutRepositoryRequest> source, TransformStat
7276

7377
ClusterState state = prevState.state();
7478

79+
@FixForMultiProject(description = "resolve the actual projectId, ES-10479")
80+
final var projectId = ProjectId.DEFAULT;
7581
for (var request : requests) {
76-
RepositoriesService.RegisterRepositoryTask task = new RepositoriesService.RegisterRepositoryTask(repositoriesService, request);
82+
RepositoriesService.RegisterRepositoryTask task = new RepositoriesService.RegisterRepositoryTask(
83+
repositoriesService,
84+
projectId,
85+
request
86+
);
7787
state = task.execute(state);
7888
}
7989

@@ -83,7 +93,11 @@ public TransformState transform(List<PutRepositoryRequest> source, TransformStat
8393
toDelete.removeAll(entities);
8494

8595
for (var repositoryToDelete : toDelete) {
86-
var task = new RepositoriesService.UnregisterRepositoryTask(RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT, repositoryToDelete);
96+
var task = new RepositoriesService.UnregisterRepositoryTask(
97+
RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT,
98+
projectId,
99+
repositoryToDelete
100+
);
87101
state = task.execute(state);
88102
}
89103

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/verify/TransportVerifyRepositoryAction.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.cluster.block.ClusterBlockException;
1717
import org.elasticsearch.cluster.block.ClusterBlockLevel;
1818
import org.elasticsearch.cluster.node.DiscoveryNode;
19+
import org.elasticsearch.cluster.project.ProjectResolver;
1920
import org.elasticsearch.cluster.service.ClusterService;
2021
import org.elasticsearch.common.util.concurrent.EsExecutors;
2122
import org.elasticsearch.injection.guice.Inject;
@@ -30,14 +31,16 @@
3031
public class TransportVerifyRepositoryAction extends TransportMasterNodeAction<VerifyRepositoryRequest, VerifyRepositoryResponse> {
3132

3233
private final RepositoriesService repositoriesService;
34+
private final ProjectResolver projectResolver;
3335

3436
@Inject
3537
public TransportVerifyRepositoryAction(
3638
TransportService transportService,
3739
ClusterService clusterService,
3840
RepositoriesService repositoriesService,
3941
ThreadPool threadPool,
40-
ActionFilters actionFilters
42+
ActionFilters actionFilters,
43+
ProjectResolver projectResolver
4144
) {
4245
super(
4346
VerifyRepositoryAction.NAME,
@@ -50,11 +53,12 @@ public TransportVerifyRepositoryAction(
5053
EsExecutors.DIRECT_EXECUTOR_SERVICE
5154
);
5255
this.repositoriesService = repositoriesService;
56+
this.projectResolver = projectResolver;
5357
}
5458

5559
@Override
5660
protected ClusterBlockException checkBlock(VerifyRepositoryRequest request, ClusterState state) {
57-
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
61+
return state.blocks().globalBlockedException(projectResolver.getProjectId(), ClusterBlockLevel.METADATA_READ);
5862
}
5963

6064
@Override
@@ -65,6 +69,7 @@ protected void masterOperation(
6569
final ActionListener<VerifyRepositoryResponse> listener
6670
) {
6771
repositoriesService.verifyRepository(
72+
projectResolver.getProjectId(),
6873
request.name(),
6974
listener.map(verifyResponse -> new VerifyRepositoryResponse(verifyResponse.toArray(new DiscoveryNode[0])))
7075
);

server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/TransportGetSnapshotsAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ protected void masterOperation(
144144
) {
145145
assert task instanceof CancellableTask : task + " not cancellable";
146146

147-
final var resolvedRepositories = ResolvedRepositories.resolve(state, request.repositories());
147+
final var resolvedRepositories = ResolvedRepositories.resolve(state.metadata().getProject(), request.repositories());
148148
if (resolvedRepositories.hasMissingRepositories()) {
149149
throw new RepositoryMissingException(String.join(", ", resolvedRepositories.missing()));
150150
}

server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/TransportSnapshotsStatusAction.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
import org.elasticsearch.cluster.block.ClusterBlockException;
2525
import org.elasticsearch.cluster.block.ClusterBlockLevel;
2626
import org.elasticsearch.cluster.metadata.IndexMetadata;
27+
import org.elasticsearch.cluster.metadata.ProjectId;
2728
import org.elasticsearch.cluster.service.ClusterService;
2829
import org.elasticsearch.common.Strings;
2930
import org.elasticsearch.common.util.CollectionUtils;
3031
import org.elasticsearch.common.util.concurrent.ListenableFuture;
3132
import org.elasticsearch.common.util.set.Sets;
33+
import org.elasticsearch.core.FixForMultiProject;
3234
import org.elasticsearch.index.shard.ShardId;
3335
import org.elasticsearch.index.snapshots.IndexShardSnapshotStatus;
3436
import org.elasticsearch.injection.guice.Inject;
@@ -252,7 +254,7 @@ void buildResponse(
252254
// BWC behavior, load the stats directly from the repository.
253255
shardStatus = new SnapshotIndexShardStatus(
254256
shardId,
255-
repositoriesService.repository(entry.repository())
257+
repositoriesService.repository(entry.projectId(), entry.repository())
256258
.getShardSnapshotStatus(
257259
entry.snapshot().getSnapshotId(),
258260
entry.indices().get(shardId.getIndexName()),
@@ -297,7 +299,9 @@ private void loadRepositoryData(
297299
) {
298300
final Set<String> requestedSnapshotNames = Sets.newHashSet(request.snapshots());
299301
final ListenableFuture<RepositoryData> repositoryDataListener = new ListenableFuture<>();
300-
repositoriesService.getRepositoryData(repositoryName, repositoryDataListener);
302+
@FixForMultiProject(description = "resolve the actual projectId, ES-10166")
303+
final var projectId = ProjectId.DEFAULT;
304+
repositoriesService.getRepositoryData(projectId, repositoryName, repositoryDataListener);
301305
final Collection<SnapshotId> snapshotIdsToLoad = new ArrayList<>();
302306
repositoryDataListener.addListener(listener.delegateFailureAndWrap((delegate, repositoryData) -> {
303307
task.ensureNotCancelled();

server/src/main/java/org/elasticsearch/health/node/tracker/RepositoriesHealthTracker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected RepositoriesHealthInfo determineCurrentHealth() {
4242

4343
var unknown = new ArrayList<String>();
4444
var invalid = new ArrayList<String>();
45-
repositories.values().forEach(repository -> {
45+
repositories.forEach(repository -> {
4646
if (repository instanceof UnknownTypeRepository) {
4747
unknown.add(repository.getMetadata().name());
4848
} else if (repository instanceof InvalidRepository) {

server/src/main/java/org/elasticsearch/index/shard/IndexShard.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.elasticsearch.cluster.metadata.DataStream;
4040
import org.elasticsearch.cluster.metadata.IndexMetadata;
4141
import org.elasticsearch.cluster.metadata.MappingMetadata;
42+
import org.elasticsearch.cluster.metadata.ProjectId;
4243
import org.elasticsearch.cluster.routing.IndexShardRoutingTable;
4344
import org.elasticsearch.cluster.routing.RecoverySource;
4445
import org.elasticsearch.cluster.routing.RecoverySource.SnapshotRecoverySource;
@@ -154,6 +155,7 @@
154155
import org.elasticsearch.rest.RestStatus;
155156
import org.elasticsearch.search.internal.FieldUsageTrackingDirectoryReader;
156157
import org.elasticsearch.search.suggest.completion.CompletionStats;
158+
import org.elasticsearch.snapshots.Snapshot;
157159
import org.elasticsearch.threadpool.ThreadPool;
158160
import org.elasticsearch.transport.Transports;
159161

@@ -3527,12 +3529,14 @@ public void startRecovery(
35273529
}
35283530
}
35293531
case SNAPSHOT -> {
3530-
final String repo = ((SnapshotRecoverySource) recoveryState.getRecoverySource()).snapshot().getRepository();
3532+
final Snapshot snapshot = ((SnapshotRecoverySource) recoveryState.getRecoverySource()).snapshot();
3533+
final ProjectId projectId = snapshot.getProjectId();
3534+
final String repo = snapshot.getRepository();
35313535
executeRecovery(
35323536
"from snapshot",
35333537
recoveryState,
35343538
recoveryListener,
3535-
l -> restoreFromRepository(repositoriesService.repository(repo), l)
3539+
l -> restoreFromRepository(repositoriesService.repository(projectId, repo), l)
35363540
);
35373541
}
35383542
case LOCAL_SHARDS -> {

0 commit comments

Comments
 (0)