Migrate the reserved repository action to be per-project (#130155)
Resolves: ES-10479
This commit is contained in:
parent
f3c5eb7815
commit
c17bfcbfc2
|
@ -85,4 +85,16 @@ public class TransportDeleteRepositoryAction extends AcknowledgedTransportMaster
|
||||||
public Set<String> modifiedKeys(DeleteRepositoryRequest request) {
|
public Set<String> modifiedKeys(DeleteRepositoryRequest request) {
|
||||||
return Set.of(request.name());
|
return Set.of(request.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void validateForReservedState(DeleteRepositoryRequest request, ClusterState state) {
|
||||||
|
super.validateForReservedState(request, state);
|
||||||
|
|
||||||
|
validateForReservedState(
|
||||||
|
projectResolver.getProjectMetadata(state).reservedStateMetadata().values(),
|
||||||
|
reservedStateHandlerName().get(),
|
||||||
|
modifiedKeys(request),
|
||||||
|
request.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,8 @@ package org.elasticsearch.action.admin.cluster.repositories.reservedstate;
|
||||||
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
|
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.metadata.ProjectId;
|
import org.elasticsearch.cluster.metadata.ProjectId;
|
||||||
import org.elasticsearch.core.FixForMultiProject;
|
|
||||||
import org.elasticsearch.repositories.RepositoriesService;
|
import org.elasticsearch.repositories.RepositoriesService;
|
||||||
import org.elasticsearch.reservedstate.ReservedClusterStateHandler;
|
import org.elasticsearch.reservedstate.ReservedProjectStateHandler;
|
||||||
import org.elasticsearch.reservedstate.TransformState;
|
import org.elasticsearch.reservedstate.TransformState;
|
||||||
import org.elasticsearch.xcontent.XContentParser;
|
import org.elasticsearch.xcontent.XContentParser;
|
||||||
import org.elasticsearch.xcontent.XContentParserConfiguration;
|
import org.elasticsearch.xcontent.XContentParserConfiguration;
|
||||||
|
@ -36,7 +35,7 @@ import static org.elasticsearch.common.xcontent.XContentHelper.mapToXContentPars
|
||||||
* It is used by the ReservedClusterStateService to add/update or remove snapshot repositories. Typical usage
|
* It is used by the ReservedClusterStateService to add/update or remove snapshot repositories. Typical usage
|
||||||
* for this action is in the context of file based settings.
|
* for this action is in the context of file based settings.
|
||||||
*/
|
*/
|
||||||
public class ReservedRepositoryAction implements ReservedClusterStateHandler<List<PutRepositoryRequest>> {
|
public class ReservedRepositoryAction implements ReservedProjectStateHandler<List<PutRepositoryRequest>> {
|
||||||
public static final String NAME = "snapshot_repositories";
|
public static final String NAME = "snapshot_repositories";
|
||||||
|
|
||||||
private final RepositoriesService repositoriesService;
|
private final RepositoriesService repositoriesService;
|
||||||
|
@ -56,14 +55,12 @@ public class ReservedRepositoryAction implements ReservedClusterStateHandler<Lis
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Collection<PutRepositoryRequest> prepare(Object input) {
|
public Collection<PutRepositoryRequest> prepare(ProjectId projectId, Object input) {
|
||||||
List<PutRepositoryRequest> repositories = (List<PutRepositoryRequest>) input;
|
List<PutRepositoryRequest> repositories = (List<PutRepositoryRequest>) input;
|
||||||
|
|
||||||
for (var repositoryRequest : repositories) {
|
for (var repositoryRequest : repositories) {
|
||||||
validate(repositoryRequest);
|
validate(repositoryRequest);
|
||||||
RepositoriesService.validateRepositoryName(repositoryRequest.name());
|
RepositoriesService.validateRepositoryName(repositoryRequest.name());
|
||||||
@FixForMultiProject(description = "resolve the actual projectId, ES-10479")
|
|
||||||
final var projectId = ProjectId.DEFAULT;
|
|
||||||
repositoriesService.validateRepositoryCanBeCreated(projectId, repositoryRequest);
|
repositoriesService.validateRepositoryCanBeCreated(projectId, repositoryRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,13 +68,11 @@ public class ReservedRepositoryAction implements ReservedClusterStateHandler<Lis
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransformState transform(List<PutRepositoryRequest> source, TransformState prevState) throws Exception {
|
public TransformState transform(ProjectId projectId, List<PutRepositoryRequest> source, TransformState prevState) throws Exception {
|
||||||
var requests = prepare(source);
|
var requests = prepare(projectId, source);
|
||||||
|
|
||||||
ClusterState state = prevState.state();
|
ClusterState state = prevState.state();
|
||||||
|
|
||||||
@FixForMultiProject(description = "resolve the actual projectId, ES-10479")
|
|
||||||
final var projectId = ProjectId.DEFAULT;
|
|
||||||
for (var request : requests) {
|
for (var request : requests) {
|
||||||
RepositoriesService.RegisterRepositoryTask task = new RepositoriesService.RegisterRepositoryTask(
|
RepositoriesService.RegisterRepositoryTask task = new RepositoriesService.RegisterRepositoryTask(
|
||||||
repositoriesService,
|
repositoriesService,
|
||||||
|
|
|
@ -1125,7 +1125,7 @@ class NodeConstruction {
|
||||||
indicesService
|
indicesService
|
||||||
);
|
);
|
||||||
|
|
||||||
actionModule.getReservedClusterStateService().installClusterStateHandler(new ReservedRepositoryAction(repositoriesService));
|
actionModule.getReservedClusterStateService().installProjectStateHandler(new ReservedRepositoryAction(repositoriesService));
|
||||||
actionModule.getReservedClusterStateService().installProjectStateHandler(new ReservedPipelineAction());
|
actionModule.getReservedClusterStateService().installProjectStateHandler(new ReservedPipelineAction());
|
||||||
|
|
||||||
var fileSettingsHealthIndicatorPublisher = new FileSettingsService.FileSettingsHealthIndicatorPublisherImpl(clusterService, client);
|
var fileSettingsHealthIndicatorPublisher = new FileSettingsService.FileSettingsHealthIndicatorPublisherImpl(clusterService, client);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.client.internal.node.NodeClient;
|
||||||
import org.elasticsearch.cluster.ClusterName;
|
import org.elasticsearch.cluster.ClusterName;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.metadata.ProjectId;
|
import org.elasticsearch.cluster.metadata.ProjectId;
|
||||||
|
import org.elasticsearch.cluster.metadata.ProjectMetadata;
|
||||||
import org.elasticsearch.cluster.metadata.RepositoryMetadata;
|
import org.elasticsearch.cluster.metadata.RepositoryMetadata;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
@ -34,7 +35,6 @@ import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
@ -44,9 +44,10 @@ import static org.mockito.Mockito.spy;
|
||||||
*/
|
*/
|
||||||
public class ReservedRepositoryActionTests extends ESTestCase {
|
public class ReservedRepositoryActionTests extends ESTestCase {
|
||||||
|
|
||||||
private TransformState processJSON(ReservedRepositoryAction action, TransformState prevState, String json) throws Exception {
|
private TransformState processJSON(ProjectId projectId, ReservedRepositoryAction action, TransformState prevState, String json)
|
||||||
|
throws Exception {
|
||||||
try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) {
|
try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) {
|
||||||
return action.transform(action.fromXContent(parser), prevState);
|
return action.transform(projectId, action.fromXContent(parser), prevState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,20 +70,24 @@ public class ReservedRepositoryActionTests extends ESTestCase {
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"[repo] repository type [inter_planetary] does not exist",
|
"[repo] repository type [inter_planetary] does not exist",
|
||||||
expectThrows(RepositoryException.class, () -> processJSON(action, prevState, badPolicyJSON)).getMessage()
|
expectThrows(RepositoryException.class, () -> processJSON(randomProjectIdOrDefault(), action, prevState, badPolicyJSON))
|
||||||
|
.getMessage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAddRepo() throws Exception {
|
public void testAddRepo() throws Exception {
|
||||||
var repositoriesService = mockRepositoriesService();
|
var repositoriesService = mockRepositoriesService();
|
||||||
|
final var projectId = randomProjectIdOrDefault();
|
||||||
|
|
||||||
ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build();
|
ClusterState state = ClusterState.builder(new ClusterName("elasticsearch"))
|
||||||
|
.putProjectMetadata(ProjectMetadata.builder(projectId))
|
||||||
|
.build();
|
||||||
TransformState prevState = new TransformState(state, Collections.emptySet());
|
TransformState prevState = new TransformState(state, Collections.emptySet());
|
||||||
ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService);
|
ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService);
|
||||||
|
|
||||||
String emptyJSON = "";
|
String emptyJSON = "";
|
||||||
|
|
||||||
TransformState updatedState = processJSON(action, prevState, emptyJSON);
|
TransformState updatedState = processJSON(projectId, action, prevState, emptyJSON);
|
||||||
assertEquals(0, updatedState.keys().size());
|
assertEquals(0, updatedState.keys().size());
|
||||||
assertEquals(prevState.state(), updatedState.state());
|
assertEquals(prevState.state(), updatedState.state());
|
||||||
|
|
||||||
|
@ -103,14 +108,17 @@ public class ReservedRepositoryActionTests extends ESTestCase {
|
||||||
}""";
|
}""";
|
||||||
|
|
||||||
prevState = updatedState;
|
prevState = updatedState;
|
||||||
updatedState = processJSON(action, prevState, settingsJSON);
|
updatedState = processJSON(projectId, action, prevState, settingsJSON);
|
||||||
assertThat(updatedState.keys(), containsInAnyOrder("repo", "repo1"));
|
assertThat(updatedState.keys(), containsInAnyOrder("repo", "repo1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRemoveRepo() {
|
public void testRemoveRepo() {
|
||||||
var repositoriesService = mockRepositoriesService();
|
var repositoriesService = mockRepositoriesService();
|
||||||
|
final var projectId = randomProjectIdOrDefault();
|
||||||
|
|
||||||
ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build();
|
ClusterState state = ClusterState.builder(new ClusterName("elasticsearch"))
|
||||||
|
.putProjectMetadata(ProjectMetadata.builder(projectId))
|
||||||
|
.build();
|
||||||
TransformState prevState = new TransformState(state, Set.of("repo1"));
|
TransformState prevState = new TransformState(state, Set.of("repo1"));
|
||||||
ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService);
|
ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService);
|
||||||
|
|
||||||
|
@ -120,7 +128,7 @@ public class ReservedRepositoryActionTests extends ESTestCase {
|
||||||
// missing is sufficient to tell that we attempted to delete that repo
|
// missing is sufficient to tell that we attempted to delete that repo
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"[repo1] missing",
|
"[repo1] missing",
|
||||||
expectThrows(RepositoryMissingException.class, () -> processJSON(action, prevState, emptyJSON)).getMessage()
|
expectThrows(RepositoryMissingException.class, () -> processJSON(projectId, action, prevState, emptyJSON)).getMessage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +161,7 @@ public class ReservedRepositoryActionTests extends ESTestCase {
|
||||||
throw new RepositoryException(request.name(), "repository type [" + request.type() + "] does not exist");
|
throw new RepositoryException(request.name(), "repository type [" + request.type() + "] does not exist");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}).when(repositoriesService).validateRepositoryCanBeCreated(eq(ProjectId.DEFAULT), any());
|
}).when(repositoriesService).validateRepositoryCanBeCreated(any(ProjectId.class), any());
|
||||||
|
|
||||||
return repositoriesService;
|
return repositoriesService;
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,8 +290,8 @@ public class ReservedSnapshotLifecycleStateServiceTests extends ESTestCase {
|
||||||
ReservedClusterStateService controller = new ReservedClusterStateService(
|
ReservedClusterStateService controller = new ReservedClusterStateService(
|
||||||
clusterService,
|
clusterService,
|
||||||
null,
|
null,
|
||||||
List.of(new ReservedClusterSettingsAction(clusterSettings), new ReservedRepositoryAction(repositoriesService)),
|
List.of(new ReservedClusterSettingsAction(clusterSettings)),
|
||||||
List.of()
|
List.of(new ReservedRepositoryAction(repositoriesService))
|
||||||
);
|
);
|
||||||
|
|
||||||
String testJSON = """
|
String testJSON = """
|
||||||
|
@ -362,12 +362,8 @@ public class ReservedSnapshotLifecycleStateServiceTests extends ESTestCase {
|
||||||
controller = new ReservedClusterStateService(
|
controller = new ReservedClusterStateService(
|
||||||
clusterService,
|
clusterService,
|
||||||
null,
|
null,
|
||||||
List.of(
|
List.of(new ReservedClusterSettingsAction(clusterSettings), new ReservedSnapshotAction()),
|
||||||
new ReservedClusterSettingsAction(clusterSettings),
|
List.of(new ReservedRepositoryAction(repositoriesService))
|
||||||
new ReservedSnapshotAction(),
|
|
||||||
new ReservedRepositoryAction(repositoriesService)
|
|
||||||
),
|
|
||||||
List.of()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, testJSON)) {
|
try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, testJSON)) {
|
||||||
|
|
Loading…
Reference in New Issue