diff --git a/server/src/main/java/module-info.java b/server/src/main/java/module-info.java index 8da4f403c29bd..c793b4cfcfefd 100644 --- a/server/src/main/java/module-info.java +++ b/server/src/main/java/module-info.java @@ -8,6 +8,7 @@ */ import org.elasticsearch.plugins.internal.RestExtension; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; /** The Elasticsearch Server Module. */ module org.elasticsearch.server { @@ -411,7 +412,7 @@ org.elasticsearch.index.shard.ShardToolCliProvider; uses org.elasticsearch.reservedstate.service.FileSettingsServiceProvider; - uses org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; + uses ReservedStateHandlerProvider; uses org.elasticsearch.jdk.ModuleQualifiedExportsService; uses org.elasticsearch.node.internal.TerminationHandlerProvider; uses org.elasticsearch.internal.VersionExtension; diff --git a/server/src/main/java/org/elasticsearch/action/ActionModule.java b/server/src/main/java/org/elasticsearch/action/ActionModule.java index 2f9f4340bfa70..d7cb57bad4812 100644 --- a/server/src/main/java/org/elasticsearch/action/ActionModule.java +++ b/server/src/main/java/org/elasticsearch/action/ActionModule.java @@ -211,9 +211,7 @@ import org.elasticsearch.action.termvectors.TransportTermVectorsAction; import org.elasticsearch.action.update.TransportUpdateAction; import org.elasticsearch.client.internal.node.NodeClient; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.project.ProjectIdResolver; import org.elasticsearch.cluster.routing.RerouteService; @@ -254,6 +252,7 @@ import org.elasticsearch.repositories.VerifyNodeRepositoryAction; import org.elasticsearch.repositories.VerifyNodeRepositoryCoordinationAction; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.service.ReservedClusterStateService; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestHandler; @@ -474,8 +473,8 @@ public ActionModule( TelemetryProvider telemetryProvider, ClusterService clusterService, RerouteService rerouteService, - List> reservedClusterStateHandlers, - List> reservedProjectStateHandlers, + List> reservedClusterStateHandlers, + List> reservedProjectStateHandlers, RestExtension restExtension, IncrementalBulkService bulkService, ProjectIdResolver projectIdResolver diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryAction.java index 836edb26a90a0..ee6e7f320f513 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryAction.java @@ -34,7 +34,7 @@ * 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. */ -public class ReservedRepositoryAction implements ReservedClusterStateHandler> { +public class ReservedRepositoryAction implements ReservedClusterStateHandler> { public static final String NAME = "snapshot_repositories"; private final RepositoriesService repositoriesService; @@ -67,8 +67,7 @@ public Collection prepare(Object input) { } @Override - public TransformState transform(List source, TransformState prevState) - throws Exception { + public TransformState transform(List source, TransformState prevState) throws Exception { var requests = prepare(source); ClusterState state = prevState.state(); @@ -88,7 +87,7 @@ public TransformState transform(List source, state = task.execute(state); } - return new TransformState<>(state, entities); + return new TransformState(state, entities); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateAction.java b/server/src/main/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateAction.java index 90a6b24f40d7b..8f7f716a56b46 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateAction.java @@ -12,13 +12,16 @@ import org.elasticsearch.action.admin.indices.template.put.PutComponentTemplateAction; import org.elasticsearch.action.admin.indices.template.put.TransportPutComponentTemplateAction; import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction; +import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.ComponentTemplate; import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; import org.elasticsearch.cluster.metadata.MetadataIndexTemplateService; +import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; @@ -45,7 +48,7 @@ */ public class ReservedComposableIndexTemplateAction implements - ReservedClusterStateHandler { + ReservedProjectStateHandler { public static final String NAME = "index_templates"; public static final String COMPONENTS = "component_templates"; private static final String COMPONENT_PREFIX = "component_template:"; @@ -133,10 +136,10 @@ private ComponentsAndComposables prepare(ComponentsAndComposables componentsAndC } @Override - public TransformState transform(ComponentsAndComposables source, TransformState prevState) - throws Exception { + public TransformState transform(ProjectId projectId, ComponentsAndComposables source, TransformState prevState) throws Exception { var requests = prepare(source); - ProjectMetadata project = prevState.state(); + ClusterState clusterState = prevState.state(); + ProjectMetadata project = clusterState.getMetadata().getProject(projectId); // We transform in the following order: // 1. create or update component templates (composable templates depend on them) @@ -192,7 +195,10 @@ public TransformState transform(ComponentsAndComposables source project = MetadataIndexTemplateService.innerRemoveComponentTemplate(project, componentNames); } - return new TransformState<>(project, Sets.union(componentEntities, composableEntities)); + return new TransformState( + ClusterState.builder(clusterState).putProjectMetadata(project).build(), + Sets.union(componentEntities, composableEntities) + ); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/ingest/ReservedPipelineAction.java b/server/src/main/java/org/elasticsearch/action/ingest/ReservedPipelineAction.java index f21cc2d8b91c4..65d634aeb498b 100644 --- a/server/src/main/java/org/elasticsearch/action/ingest/ReservedPipelineAction.java +++ b/server/src/main/java/org/elasticsearch/action/ingest/ReservedPipelineAction.java @@ -10,11 +10,13 @@ package org.elasticsearch.action.ingest; import org.elasticsearch.ElasticsearchGenerationException; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.ingest.IngestMetadata; import org.elasticsearch.ingest.IngestService; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentFactory; @@ -36,7 +38,7 @@ * It is used by the ReservedClusterStateService to add/update or remove ingest pipelines. Typical usage * for this action is in the context of file based state. */ -public class ReservedPipelineAction implements ReservedClusterStateHandler> { +public class ReservedPipelineAction implements ReservedProjectStateHandler> { public static final String NAME = "ingest_pipelines"; /** @@ -78,21 +80,21 @@ private static ProjectMetadata wrapIngestTaskExecute(IngestService.PipelineClust } @Override - public TransformState transform(List source, TransformState prevState) - throws Exception { + public TransformState transform(ProjectId projectId, List source, TransformState prevState) throws Exception { var requests = prepare(source); - ProjectMetadata state = prevState.state(); + ClusterState clusterState = prevState.state(); + ProjectMetadata projectMetadata = clusterState.metadata().getProject(projectId); for (var request : requests) { - var nopUpdate = IngestService.isNoOpPipelineUpdate(state, request); + var nopUpdate = IngestService.isNoOpPipelineUpdate(projectMetadata, request); if (nopUpdate) { continue; } - var task = new IngestService.PutPipelineClusterStateUpdateTask(state.id(), request); - state = wrapIngestTaskExecute(task, state); + var task = new IngestService.PutPipelineClusterStateUpdateTask(projectMetadata.id(), request); + projectMetadata = wrapIngestTaskExecute(task, projectMetadata); } Set entities = requests.stream().map(PutPipelineRequest::getId).collect(Collectors.toSet()); @@ -102,7 +104,7 @@ public TransformState transform(List source for (var pipelineToDelete : toDelete) { var task = new IngestService.DeletePipelineClusterStateUpdateTask( - state.id(), + projectMetadata.id(), null, new DeletePipelineRequest( RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT, @@ -110,10 +112,10 @@ public TransformState transform(List source pipelineToDelete ) ); - state = wrapIngestTaskExecute(task, state); + projectMetadata = wrapIngestTaskExecute(task, projectMetadata); } - return new TransformState<>(state, entities); + return new TransformState(ClusterState.builder(clusterState).putProjectMetadata(projectMetadata).build(), entities); } @Override diff --git a/server/src/main/java/org/elasticsearch/node/NodeConstruction.java b/server/src/main/java/org/elasticsearch/node/NodeConstruction.java index eb4f2c2543475..65eb0251197f7 100644 --- a/server/src/main/java/org/elasticsearch/node/NodeConstruction.java +++ b/server/src/main/java/org/elasticsearch/node/NodeConstruction.java @@ -50,7 +50,6 @@ import org.elasticsearch.cluster.metadata.MetadataDataStreamsService; import org.elasticsearch.cluster.metadata.MetadataIndexTemplateService; import org.elasticsearch.cluster.metadata.MetadataUpdateSettingsService; -import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.metadata.SystemIndexMetadataUpgradeService; import org.elasticsearch.cluster.metadata.TemplateUpgradeService; import org.elasticsearch.cluster.node.DiscoveryNode; @@ -189,7 +188,8 @@ import org.elasticsearch.repositories.RepositoriesModule; import org.elasticsearch.repositories.RepositoriesService; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import org.elasticsearch.reservedstate.action.ReservedClusterSettingsAction; import org.elasticsearch.reservedstate.service.FileSettingsService; import org.elasticsearch.reservedstate.service.FileSettingsService.FileSettingsHealthIndicatorService; @@ -995,7 +995,7 @@ public Map queryFields() { final ResponseCollectorService responseCollectorService = new ResponseCollectorService(clusterService); modules.bindToInstance(ResponseCollectorService.class, responseCollectorService); - var reservedStateHandlerProviders = pluginsService.loadServiceProviders(ReservedClusterStateHandlerProvider.class); + var reservedStateHandlerProviders = pluginsService.loadServiceProviders(ReservedStateHandlerProvider.class); ActionModule actionModule = new ActionModule( settings, @@ -1599,11 +1599,11 @@ private Module loadPersistedClusterStateService( return b -> b.bind(PersistedClusterStateService.class).toInstance(service); } - private List> buildReservedClusterStateHandlers( - List handlers, + private List> buildReservedClusterStateHandlers( + List handlers, SettingsModule settingsModule ) { - List> reservedStateHandlers = new ArrayList<>(); + List> reservedStateHandlers = new ArrayList<>(); // add all reserved state handlers from server reservedStateHandlers.add(new ReservedClusterSettingsAction(settingsModule.getClusterSettings())); @@ -1614,8 +1614,8 @@ private Module loadPersistedClusterStateService( return reservedStateHandlers; } - private List> buildReservedProjectStateHandlers( - List handlers, + private List> buildReservedProjectStateHandlers( + List handlers, SettingsModule settingsModule, ClusterService clusterService, IndicesService indicesService, @@ -1624,7 +1624,7 @@ private Module loadPersistedClusterStateService( MetadataCreateIndexService metadataCreateIndexService, DataStreamGlobalRetentionSettings globalRetentionSettings ) { - List> reservedStateHandlers = new ArrayList<>(); + List> reservedStateHandlers = new ArrayList<>(); var templateService = new MetadataIndexTemplateService( clusterService, diff --git a/server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandler.java b/server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandler.java index c552020b241f9..e8d4972b2d7e9 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandler.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandler.java @@ -9,43 +9,12 @@ package org.elasticsearch.reservedstate; -import org.elasticsearch.action.ActionRequestValidationException; -import org.elasticsearch.action.support.master.MasterNodeRequest; -import org.elasticsearch.core.TimeValue; -import org.elasticsearch.xcontent.XContentParser; - -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; - /** - * Base interface used for implementing 'operator mode' cluster state updates. - * - *

- * Reserving cluster state, for file based settings and modules/plugins, requires - * that we have a separate update handler interface that is different than the REST handlers. This interface class declares - * the basic contract for implementing cluster state update handlers that result in a cluster state that is effectively immutable - * by the REST handlers. The only way the reserved cluster state can be updated is through the 'operator mode' actions, e.g. updating - * the file settings. - *

+ * {@link ReservedStateHandler} for updating cluster-wide cluster state. * - * @param The state type to be updated by this handler * @param The type used to represent the state update */ -public interface ReservedClusterStateHandler { - /** - * Unique identifier for the handler. - * - *

- * The handler name is a unique identifier that is matched to a section in a - * cluster state update content. The reserved cluster state updates are done as a single - * cluster state update and the cluster state is typically supplied as a combined content, - * unlike the REST handlers. This name must match a desired content key name in the combined - * cluster state update, e.g. "ilm" or "cluster_settings" (for persistent cluster settings update). - * - * @return a String with the handler name, e.g "ilm". - */ - String name(); +public interface ReservedClusterStateHandler extends ReservedStateHandler { /** * The transformation method implemented by the handler. @@ -58,77 +27,11 @@ public interface ReservedClusterStateHandler { * {@link TransformState}, which contains the current cluster state as well as any previous keys * set by this handler on prior invocation. * - * @param source The parsed information specific to this handler from the combined cluster state content + * @param source The parsed information specific to this handler from the combined cluster state content * @param prevState The previous cluster state and keys set by this handler (if any) * @return The modified state and the current keys set by this handler * @throws Exception */ - TransformState transform(T source, TransformState prevState) throws Exception; - - /** - * List of dependent handler names for this handler. - * - *

- * Sometimes certain parts of the cluster state cannot be created/updated without previously - * setting other cluster state components, e.g. composable templates. Since the reserved cluster state handlers - * are processed in random order by the ReservedClusterStateService, this method gives an opportunity - * to any reserved handler to declare other state handlers it depends on. Given dependencies exist, - * the ReservedClusterStateService will order those handlers such that the handlers that are dependent - * on are processed first. - * - * @return a collection of reserved state handler names - */ - default Collection dependencies() { - return Collections.emptyList(); - } - - /** - * List of optional dependent handler names for this handler. - * - *

- * These are dependent handlers which may or may not exist for this handler to be - * processed. If the optional dependency exists, then they are simply ordered to be - * merged into the cluster state before this handler. - * - * @return a collection of optional reserved state handler names - */ - default Collection optionalDependencies() { - return Collections.emptyList(); - } - - /** - * Generic validation helper method that throws consistent exception for all handlers. - * - *

- * All implementations of {@link ReservedClusterStateHandler} should call the request validate method, by calling this default - * implementation. To aid in any special validation logic that may need to be implemented by the reserved cluster state handler - * we provide this convenience method. - * - * @param request the master node request that we base this reserved state handler on - */ - default void validate(MasterNodeRequest request) { - ActionRequestValidationException exception = request.validate(); - if (exception != null) { - throw new IllegalStateException("Validation error", exception); - } - } + TransformState transform(T source, TransformState prevState) throws Exception; - /** - * The parse content method which is called during parsing of file based content. - * - *

- * The immutable state can be provided as XContent, which means that each handler needs - * to implement a method to convert an XContent to an object it can consume later in - * transform - * - * @param parser the XContent parser we are parsing from - * @return - * @throws IOException - */ - T fromXContent(XContentParser parser) throws IOException; - - /** - * Reserved-state handlers create master-node requests but never actually send them to the master node so the timeouts are not relevant. - */ - TimeValue RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT = TimeValue.THIRTY_SECONDS; } diff --git a/server/src/main/java/org/elasticsearch/reservedstate/ReservedProjectStateHandler.java b/server/src/main/java/org/elasticsearch/reservedstate/ReservedProjectStateHandler.java new file mode 100644 index 0000000000000..aa8eedec1a322 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/reservedstate/ReservedProjectStateHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.reservedstate; + +import org.elasticsearch.cluster.metadata.ProjectId; + +/** + * {@link ReservedStateHandler} for updating project-specific cluster state. + * + * @param The type used to represent the state update + */ +public interface ReservedProjectStateHandler extends ReservedStateHandler { + + /** + * The transformation method implemented by the handler. + * + *

+ * The transform method of the handler should apply the necessary changes to + * the cluster state as it normally would in a REST handler. One difference is that the + * transform method in an reserved state handler must perform all CRUD operations of the cluster + * state in one go. For that reason, we supply a wrapper class to the cluster state called + * {@link TransformState}, which contains the current cluster state as well as any previous keys + * set by this handler on prior invocation. + * + * @param projectId The project id for the update state content + * @param source The parsed information specific to this handler from the combined cluster state content + * @param prevState The previous cluster state and keys set by this handler (if any) + * @return The modified state and the current keys set by this handler + * @throws Exception + */ + TransformState transform(ProjectId projectId, T source, TransformState prevState) throws Exception; + +} diff --git a/server/src/main/java/org/elasticsearch/reservedstate/ReservedStateHandler.java b/server/src/main/java/org/elasticsearch/reservedstate/ReservedStateHandler.java new file mode 100644 index 0000000000000..f906bf274a6ae --- /dev/null +++ b/server/src/main/java/org/elasticsearch/reservedstate/ReservedStateHandler.java @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.reservedstate; + +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.support.master.MasterNodeRequest; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.xcontent.XContentParser; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; + +/** + * Base interface used for implementing 'operator mode' cluster state updates. + * + *

+ * Reserving cluster state, for file based settings and modules/plugins, requires + * that we have a separate update handler interface that is different than the REST handlers. This interface class declares + * the basic contract for implementing cluster state update handlers that result in a cluster state that is effectively immutable + * by the REST handlers. The only way the reserved cluster state can be updated is through the 'operator mode' actions, e.g. updating + * the file settings. + *

+ * + * @param The type used to represent the state update + */ +public interface ReservedStateHandler { + + /** + * Reserved-state handlers create master-node requests but never actually send them to the master node so the timeouts are not relevant. + */ + TimeValue RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT = TimeValue.THIRTY_SECONDS; + + /** + * Unique identifier for the handler. + * + *

+ * The handler name is a unique identifier that is matched to a section in a + * cluster state update content. The reserved cluster state updates are done as a single + * cluster state update and the cluster state is typically supplied as a combined content, + * unlike the REST handlers. This name must match a desired content key name in the combined + * cluster state update, e.g. "ilm" or "cluster_settings" (for persistent cluster settings update). + * + * @return a String with the handler name, e.g "ilm". + */ + String name(); + + /** + * List of dependent handler names for this handler. + * + *

+ * Sometimes certain parts of the cluster state cannot be created/updated without previously + * setting other cluster state components, e.g. composable templates. Since the reserved cluster state handlers + * are processed in random order by the ReservedClusterStateService, this method gives an opportunity + * to any reserved handler to declare other state handlers it depends on. Given dependencies exist, + * the ReservedClusterStateService will order those handlers such that the handlers that are dependent + * on are processed first. + * + * @return a collection of reserved state handler names + */ + default Collection dependencies() { + return Collections.emptyList(); + } + + /** + * List of optional dependent handler names for this handler. + * + *

+ * These are dependent handlers which may or may not exist for this handler to be + * processed. If the optional dependency exists, then they are simply ordered to be + * merged into the cluster state before this handler. + * + * @return a collection of optional reserved state handler names + */ + default Collection optionalDependencies() { + return Collections.emptyList(); + } + + /** + * Generic validation helper method that throws consistent exception for all handlers. + * + *

+ * All implementations of {@link ReservedProjectStateHandler} should call the request validate method, by calling this default + * implementation. To aid in any special validation logic that may need to be implemented by the reserved cluster state handler + * we provide this convenience method. + * + * @param request the master node request that we base this reserved state handler on + */ + default void validate(MasterNodeRequest request) { + ActionRequestValidationException exception = request.validate(); + if (exception != null) { + throw new IllegalStateException("Validation error", exception); + } + } + + /** + * The parse content method which is called during parsing of file based content. + * + *

+ * The immutable state can be provided as XContent, which means that each handler needs + * to implement a method to convert an XContent to an object it can consume later in + * transform + * + * @param parser the XContent parser we are parsing from + * @return + * @throws IOException + */ + T fromXContent(XContentParser parser) throws IOException; +} diff --git a/server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerProvider.java b/server/src/main/java/org/elasticsearch/reservedstate/ReservedStateHandlerProvider.java similarity index 74% rename from server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerProvider.java rename to server/src/main/java/org/elasticsearch/reservedstate/ReservedStateHandlerProvider.java index 8c063b321e938..6ff80390aedd7 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerProvider.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/ReservedStateHandlerProvider.java @@ -9,9 +9,6 @@ package org.elasticsearch.reservedstate; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.ProjectMetadata; - import java.util.Collection; import java.util.Set; @@ -19,18 +16,18 @@ * SPI service interface for supplying {@link ReservedClusterStateHandler} implementations to Elasticsearch * from plugins/modules. */ -public interface ReservedClusterStateHandlerProvider { +public interface ReservedStateHandlerProvider { /** * Returns a list of {@link ReservedClusterStateHandler} implementations for updating cluster state. */ - default Collection> clusterHandlers() { + default Collection> clusterHandlers() { return Set.of(); } /** * Returns a list of {@link ReservedClusterStateHandler} implementations for updating project state. */ - default Collection> projectHandlers() { + default Collection> projectHandlers() { return Set.of(); } } diff --git a/server/src/main/java/org/elasticsearch/reservedstate/TransformState.java b/server/src/main/java/org/elasticsearch/reservedstate/TransformState.java index d151375e3612d..d5b5af0894bbc 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/TransformState.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/TransformState.java @@ -9,13 +9,13 @@ package org.elasticsearch.reservedstate; +import org.elasticsearch.cluster.ClusterState; + import java.util.Set; /** - * A state wrapper used by the ReservedClusterStateService to pass the + * A {@link org.elasticsearch.cluster.ClusterState} wrapper used by the ReservedClusterStateService to pass the * current state as well as previous keys set by an {@link ReservedClusterStateHandler} to each transform - * step of the state update. - * - * @param The type of state to update + * step of the cluster state update. */ -public record TransformState(S state, Set keys) {} +public record TransformState(ClusterState state, Set keys) {} diff --git a/server/src/main/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsAction.java b/server/src/main/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsAction.java index cc3dea9fec309..cb6b54605f60d 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsAction.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsAction.java @@ -12,7 +12,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsUpdater; @@ -32,7 +31,7 @@ * It is used by the ReservedClusterStateService to update the persistent cluster settings. * Since transient cluster settings are deprecated, this action doesn't support updating transient cluster settings. */ -public class ReservedClusterSettingsAction implements ReservedClusterStateHandler> { +public class ReservedClusterSettingsAction implements ReservedClusterStateHandler> { private static final Logger logger = LogManager.getLogger(ReservedClusterSettingsAction.class); @@ -69,7 +68,7 @@ private static ClusterUpdateSettingsRequest prepare(Object input, Set pr } @Override - public TransformState transform(Map input, TransformState prevState) { + public TransformState transform(Map input, TransformState prevState) { ClusterUpdateSettingsRequest request = prepare(input, prevState.keys()); // allow empty requests, this is how we clean up settings @@ -90,7 +89,7 @@ public TransformState transform(Map input, Transfo .filter(k -> request.persistentSettings().hasValue(k)) .collect(Collectors.toSet()); - return new TransformState<>(state, currentKeys); + return new TransformState(state, currentKeys); } @Override diff --git a/server/src/main/java/org/elasticsearch/reservedstate/service/ProjectClusterStateHandlerAdapter.java b/server/src/main/java/org/elasticsearch/reservedstate/service/ProjectClusterStateHandlerAdapter.java index 3fcb330689b7d..b0f7c06a53032 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/service/ProjectClusterStateHandlerAdapter.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/service/ProjectClusterStateHandlerAdapter.java @@ -10,22 +10,21 @@ package org.elasticsearch.reservedstate.service; import org.elasticsearch.action.support.master.MasterNodeRequest; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.ProjectId; -import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.XContentParser; import java.io.IOException; import java.util.Collection; -class ProjectClusterStateHandlerAdapter implements ReservedClusterStateHandler { +class ProjectClusterStateHandlerAdapter implements ReservedClusterStateHandler { private final ProjectId projectId; - private final ReservedClusterStateHandler handler; + private final ReservedProjectStateHandler handler; - ProjectClusterStateHandlerAdapter(ProjectId projectId, ReservedClusterStateHandler handler) { + ProjectClusterStateHandlerAdapter(ProjectId projectId, ReservedProjectStateHandler handler) { this.projectId = projectId; this.handler = handler; } @@ -56,18 +55,8 @@ public T fromXContent(XContentParser parser) throws IOException { } @Override - public TransformState transform(T source, TransformState prevState) throws Exception { - ProjectMetadata project = prevState.state().metadata().getProject(projectId); - - TransformState oldProjectState = new TransformState<>(project, prevState.keys()); - TransformState newProjectState = handler.transform(source, oldProjectState); - - return newProjectState == oldProjectState - ? prevState - : new TransformState<>( - ClusterState.builder(prevState.state()).putProjectMetadata(newProjectState.state()).build(), - newProjectState.keys() - ); + public TransformState transform(T source, TransformState prevState) throws Exception { + return handler.transform(projectId, source, prevState); } @Override diff --git a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateService.java b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateService.java index d455a978dcf70..0e0320e258b6c 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateService.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateService.java @@ -27,6 +27,8 @@ import org.elasticsearch.core.Tuple; import org.elasticsearch.env.BuildVersion; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; @@ -66,9 +68,9 @@ public class ReservedClusterStateService { public static final ParseField STATE_FIELD = new ParseField("state"); public static final ParseField METADATA_FIELD = new ParseField("metadata"); - private final Map> allHandlers; - private final Map> clusterHandlers; - private final Map> projectHandlers; + private final Map> allHandlers; + private final Map> clusterHandlers; + private final Map> projectHandlers; private final ClusterService clusterService; private final ReservedStateUpdateTaskExecutor updateTaskExecutor; private final ReservedStateErrorTaskExecutor errorTaskExecutor; @@ -87,9 +89,7 @@ public class ReservedClusterStateService { } ); - private static ReservedClusterStateHandler adaptForDefaultProject( - ReservedClusterStateHandler handler - ) { + private static ReservedClusterStateHandler adaptForDefaultProject(ReservedProjectStateHandler handler) { return new ProjectClusterStateHandlerAdapter<>(Metadata.DEFAULT_PROJECT_ID, handler); } @@ -107,15 +107,15 @@ static ProjectMetadata getPotentiallyNewProject(ClusterState state, ProjectId pr public ReservedClusterStateService( ClusterService clusterService, RerouteService rerouteService, - List> clusterHandlerList, - List> projectHandlerList + List> clusterHandlerList, + List> projectHandlerList ) { this.clusterService = clusterService; this.updateTaskExecutor = new ReservedStateUpdateTaskExecutor(rerouteService); this.errorTaskExecutor = new ReservedStateErrorTaskExecutor(); allHandlers = Stream.concat(clusterHandlerList.stream(), projectHandlerList.stream()) - .collect(Collectors.toMap(ReservedClusterStateHandler::name, Function.identity(), (v1, v2) -> { + .collect(Collectors.toMap(ReservedStateHandler::name, Function.identity(), (v1, v2) -> { throw new IllegalArgumentException("Duplicate handler name: [" + v1.name() + "]"); })); // project handlers also need to be cluster state handlers for the default project, @@ -124,10 +124,10 @@ public ReservedClusterStateService( clusterHandlerList.stream(), projectHandlerList.stream().map(ReservedClusterStateService::adaptForDefaultProject) ).collect(Collectors.toMap(ReservedClusterStateHandler::name, Function.identity())); - projectHandlers = projectHandlerList.stream().collect(Collectors.toMap(ReservedClusterStateHandler::name, Function.identity())); + projectHandlers = projectHandlerList.stream().collect(Collectors.toMap(ReservedStateHandler::name, Function.identity())); stateChunkParser.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, name) -> { - ReservedClusterStateHandler handler = allHandlers.get(name); + ReservedStateHandler handler = allHandlers.get(name); if (handler == null) { throw new IllegalStateException("Missing handler definition for content key [" + name + "]"); } @@ -447,7 +447,10 @@ public void process( } ClusterState state = clusterService.state(); + // use an empty project if it doesn't exist, this is then added to ClusterState below. ProjectMetadata projectMetadata = getPotentiallyNewProject(state, projectId); + state = ClusterState.builder(state).putProjectMetadata(projectMetadata).build(); + ReservedStateMetadata existingMetadata = projectMetadata.reservedStateMetadata().get(namespace); // We check if we should exit early on the state version from clusterService. The ReservedStateUpdateTask @@ -458,7 +461,7 @@ public void process( } // We trial run all handler validations to ensure that we can process all of the cluster state error free. - var trialRunErrors = trialRun(namespace, projectMetadata, reservedStateChunk, orderedHandlers); + var trialRunErrors = trialRun(namespace, state, reservedStateChunk, orderedHandlers); // this is not using the modified trial state above, but that doesn't matter, we're just setting errors here var error = checkAndReportError(Optional.of(projectId), namespace, trialRunErrors, reservedStateVersion, versionCheck); @@ -635,37 +638,74 @@ List trialRun( * @return Any errors that occurred */ List trialRun( + ProjectId projectId, String namespace, - ProjectMetadata currentState, + ClusterState currentState, ReservedStateChunk stateChunk, SequencedSet orderedHandlers ) { - return trialRun(currentState.reservedStateMetadata().get(namespace), currentState, stateChunk, projectHandlers, orderedHandlers); + return trialRun( + projectId, + currentState.metadata().reservedStateMetadata().get(namespace), + currentState, + stateChunk, + projectHandlers, + orderedHandlers + ); } - private static List trialRun( + private static List trialRun( + ProjectId projectId, ReservedStateMetadata existingMetadata, - S currentMetadata, + ClusterState currentState, ReservedStateChunk stateChunk, - Map> handlers, + Map> handlers, SequencedSet orderedHandlers ) { Map reservedState = stateChunk.state(); List errors = new ArrayList<>(); - S metadata = currentMetadata; + for (var handlerName : orderedHandlers) { + ReservedProjectStateHandler handler = handlers.get(handlerName); + try { + Set existingKeys = keysForHandler(existingMetadata, handlerName); + TransformState transformState = transform( + handler, + projectId, + reservedState.get(handlerName), + new TransformState(currentState, existingKeys) + ); + currentState = transformState.state(); + } catch (Exception e) { + errors.add(format("Error processing %s state change: %s", handler.name(), stackTrace(e))); + } + } + + return errors; + } + + private static List trialRun( + ReservedStateMetadata existingMetadata, + ClusterState currentState, + ReservedStateChunk stateChunk, + Map> handlers, + SequencedSet orderedHandlers + ) { + Map reservedState = stateChunk.state(); + + List errors = new ArrayList<>(); for (var handlerName : orderedHandlers) { - ReservedClusterStateHandler handler = handlers.get(handlerName); + ReservedClusterStateHandler handler = handlers.get(handlerName); try { Set existingKeys = keysForHandler(existingMetadata, handlerName); - TransformState transformState = transform( + TransformState transformState = transform( handler, reservedState.get(handlerName), - new TransformState<>(metadata, existingKeys) + new TransformState(currentState, existingKeys) ); - metadata = transformState.state(); + currentState = transformState.state(); } catch (Exception e) { errors.add(format("Error processing %s state change: %s", handler.name(), stackTrace(e))); } @@ -675,11 +715,21 @@ private static List trialRun( } @SuppressWarnings("unchecked") - static TransformState transform(ReservedClusterStateHandler handler, Object state, TransformState transform) + static TransformState transform(ReservedClusterStateHandler handler, Object state, TransformState transform) throws Exception { return handler.transform((T) state, transform); } + @SuppressWarnings("unchecked") + static TransformState transform( + ReservedProjectStateHandler handler, + ProjectId projectId, + Object state, + TransformState transformState + ) throws Exception { + return handler.transform(projectId, (T) state, transformState); + } + /** * Returns an ordered set ({@link LinkedHashSet}) of the cluster state handlers that need to * execute for a given list of handler names supplied through the {@link ReservedStateChunk}. @@ -713,7 +763,7 @@ LinkedHashSet orderedProjectStateHandlers(Set handlerNames) { } private void addStateHandler( - Map> handlers, + Map> handlers, String key, Set keys, SequencedSet ordered, @@ -735,7 +785,7 @@ private void addStateHandler( } visited.add(key); - ReservedClusterStateHandler handler = handlers.get(key); + ReservedStateHandler handler = handlers.get(key); if (handler == null) { throw new IllegalStateException("Unknown handler type: " + key); @@ -762,7 +812,7 @@ private void addStateHandler( * Adds additional {@link ReservedClusterStateHandler} to the handler registry * @param handler an additional reserved state handler to be added */ - public void installClusterStateHandler(ReservedClusterStateHandler handler) { + public void installClusterStateHandler(ReservedClusterStateHandler handler) { allHandlers.put(handler.name(), handler); clusterHandlers.put(handler.name(), handler); } @@ -771,7 +821,7 @@ public void installClusterStateHandler(ReservedClusterStateHandler handler) { + public void installProjectStateHandler(ReservedProjectStateHandler handler) { allHandlers.put(handler.name(), handler); projectHandlers.put(handler.name(), handler); clusterHandlers.put(handler.name(), adaptForDefaultProject(handler)); diff --git a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateUpdateTask.java b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateUpdateTask.java index 9cdc5844d12b3..3da882caab2e0 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateUpdateTask.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateUpdateTask.java @@ -16,18 +16,19 @@ import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.TransformState; import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; -public class ReservedClusterStateUpdateTask extends ReservedStateUpdateTask { +public class ReservedClusterStateUpdateTask extends ReservedStateUpdateTask> { public ReservedClusterStateUpdateTask( String namespace, ReservedStateChunk stateChunk, ReservedStateVersionCheck versionCheck, - Map> handlers, + Map> handlers, Collection orderedHandlers, Consumer errorReporter, ActionListener listener @@ -41,7 +42,13 @@ protected Optional projectId() { } @Override - protected ClusterState execute(ClusterState currentState) { + protected TransformState transform(ReservedClusterStateHandler handler, Object state, TransformState transformState) + throws Exception { + return ReservedClusterStateService.transform(handler, state, transformState); + } + + @Override + ClusterState execute(ClusterState currentState) { if (currentState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) { // If cluster state has become blocked, this task was submitted while the node was master but is now not master. // The new master will re-read file settings, so whatever update was to be written here will be handled @@ -49,7 +56,7 @@ protected ClusterState execute(ClusterState currentState) { return currentState; } - var result = execute(currentState, currentState.metadata().reservedStateMetadata()); + var result = execute(currentState, currentState.getMetadata().reservedStateMetadata()); if (result == null) { return currentState; } diff --git a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedProjectStateUpdateTask.java b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedProjectStateUpdateTask.java index a43f30591b565..8dfe160a2aebc 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedProjectStateUpdateTask.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedProjectStateUpdateTask.java @@ -15,14 +15,15 @@ import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.gateway.GatewayService; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.TransformState; import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; -public class ReservedProjectStateUpdateTask extends ReservedStateUpdateTask { +public class ReservedProjectStateUpdateTask extends ReservedStateUpdateTask> { private final ProjectId projectId; public ReservedProjectStateUpdateTask( @@ -30,7 +31,7 @@ public ReservedProjectStateUpdateTask( String namespace, ReservedStateChunk stateChunk, ReservedStateVersionCheck versionCheck, - Map> handlers, + Map> handlers, Collection orderedHandlers, Consumer errorReporter, ActionListener listener @@ -44,6 +45,12 @@ protected Optional projectId() { return Optional.of(projectId); } + @Override + protected TransformState transform(ReservedProjectStateHandler handler, Object state, TransformState transformState) + throws Exception { + return ReservedClusterStateService.transform(handler, projectId, state, transformState); + } + @Override protected ClusterState execute(ClusterState currentState) { if (currentState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) { @@ -54,13 +61,16 @@ protected ClusterState execute(ClusterState currentState) { } // use an empty project if it doesnt exist, this is then added to ClusterState below. - ProjectMetadata project = ReservedClusterStateService.getPotentiallyNewProject(currentState, projectId); - - var result = execute(project, project.reservedStateMetadata()); + ProjectMetadata currentProject = ReservedClusterStateService.getPotentiallyNewProject(currentState, projectId); + var result = execute( + ClusterState.builder(currentState).putProjectMetadata(currentProject).build(), + currentProject.reservedStateMetadata() + ); if (result == null) { return currentState; } - return ClusterState.builder(currentState).putProjectMetadata(ProjectMetadata.builder(result.v1()).put(result.v2())).build(); + ProjectMetadata updatedProject = result.v1().getMetadata().getProject(projectId); + return ClusterState.builder(currentState).putProjectMetadata(ProjectMetadata.builder(updatedProject).put(result.v2())).build(); } } diff --git a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedStateUpdateTask.java b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedStateUpdateTask.java index cb09d16741713..9de0e7c8c5ecb 100644 --- a/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedStateUpdateTask.java +++ b/server/src/main/java/org/elasticsearch/reservedstate/service/ReservedStateUpdateTask.java @@ -20,7 +20,7 @@ import org.elasticsearch.cluster.metadata.ReservedStateHandlerMetadata; import org.elasticsearch.cluster.metadata.ReservedStateMetadata; import org.elasticsearch.core.Tuple; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandler; import org.elasticsearch.reservedstate.TransformState; import java.util.ArrayList; @@ -42,13 +42,13 @@ * Reserved cluster state can only be modified by using the {@link ReservedClusterStateService}. Updating * the reserved cluster state through REST APIs is not permitted. */ -public abstract class ReservedStateUpdateTask implements ClusterStateTaskListener { +public abstract class ReservedStateUpdateTask> implements ClusterStateTaskListener { private static final Logger logger = LogManager.getLogger(ReservedStateUpdateTask.class); private final String namespace; private final ReservedStateChunk stateChunk; private final ReservedStateVersionCheck versionCheck; - private final Map> handlers; + private final Map handlers; private final Collection orderedHandlers; private final Consumer errorReporter; private final ActionListener listener; @@ -57,7 +57,7 @@ public ReservedStateUpdateTask( String namespace, ReservedStateChunk stateChunk, ReservedStateVersionCheck versionCheck, - Map> handlers, + Map handlers, Collection orderedHandlers, Consumer errorReporter, ActionListener listener @@ -82,13 +82,15 @@ ActionListener listener() { protected abstract Optional projectId(); - protected abstract ClusterState execute(ClusterState state); + protected abstract TransformState transform(T handler, Object state, TransformState transformState) throws Exception; + + abstract ClusterState execute(ClusterState currentState); /** * Produces a new state {@code S} with the reserved state info in {@code reservedStateMap} * @return A tuple of the new state and new reserved state metadata, or {@code null} if no changes are required. */ - final Tuple execute(S state, Map reservedStateMap) { + final Tuple execute(ClusterState state, Map reservedStateMap) { Map reservedState = stateChunk.state(); ReservedStateVersion reservedStateVersion = stateChunk.metadata(); ReservedStateMetadata reservedStateMetadata = reservedStateMap.get(namespace); @@ -102,14 +104,10 @@ final Tuple execute(S state, Map handler = handlers.get(handlerName); + T handler = handlers.get(handlerName); try { Set existingKeys = keysForHandler(reservedStateMetadata, handlerName); - TransformState transformState = ReservedClusterStateService.transform( - handler, - reservedState.get(handlerName), - new TransformState<>(state, existingKeys) - ); + TransformState transformState = transform(handler, reservedState.get(handlerName), new TransformState(state, existingKeys)); state = transformState.state(); reservedMetadataBuilder.putHandler(new ReservedStateHandlerMetadata(handlerName, transformState.keys())); } catch (Exception e) { diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryActionTests.java index 4d07c9fe897e2..d62d99aa1c434 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/repositories/reservedstate/ReservedRepositoryActionTests.java @@ -43,8 +43,7 @@ */ public class ReservedRepositoryActionTests extends ESTestCase { - private TransformState processJSON(ReservedRepositoryAction action, TransformState prevState, String json) - throws Exception { + private TransformState processJSON(ReservedRepositoryAction action, TransformState prevState, String json) throws Exception { try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { return action.transform(action.fromXContent(parser), prevState); } @@ -54,7 +53,7 @@ public void testValidation() throws Exception { var repositoriesService = mockRepositoriesService(); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + TransformState prevState = new TransformState(state, Collections.emptySet()); ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService); String badPolicyJSON = """ @@ -77,12 +76,12 @@ public void testAddRepo() throws Exception { var repositoriesService = mockRepositoriesService(); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + TransformState prevState = new TransformState(state, Collections.emptySet()); ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertEquals(0, updatedState.keys().size()); assertEquals(prevState.state(), updatedState.state()); @@ -111,7 +110,7 @@ public void testRemoveRepo() { var repositoriesService = mockRepositoriesService(); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Set.of("repo1")); + TransformState prevState = new TransformState(state, Set.of("repo1")); ReservedRepositoryAction action = new ReservedRepositoryAction(repositoriesService); String emptyJSON = ""; diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateActionTests.java index eacd2d4edc276..cb9fa23aaefbc 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/template/reservedstate/ReservedComposableIndexTemplateActionTests.java @@ -40,7 +40,7 @@ import org.elasticsearch.indices.InvalidIndexTemplateException; import org.elasticsearch.indices.SystemIndices; import org.elasticsearch.reservedstate.ActionWithReservedState; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.MockUtils; @@ -109,19 +109,18 @@ public void setup() throws IOException { ); } - private TransformState processJSON( - ReservedClusterStateHandler action, - TransformState prevState, + private TransformState processJSON( + ReservedProjectStateHandler action, + TransformState prevState, String json ) throws Exception { 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); } } public void testComponentValidation() { - ProjectMetadata project = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); - TransformState prevState = new TransformState<>(project, Collections.emptySet()); + TransformState prevState = transformState(); var action = new ReservedComposableIndexTemplateAction(templateService, indexScopedSettings); String badComponentJSON = """ @@ -148,8 +147,7 @@ public void testComponentValidation() { } public void testComposableIndexValidation() { - ProjectMetadata project = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); - TransformState prevState = new TransformState<>(project, Collections.emptySet()); + TransformState prevState = transformState(); var action = new ReservedComposableIndexTemplateAction(templateService, indexScopedSettings); String badComponentJSON = """ @@ -239,17 +237,13 @@ public void testComposableIndexValidation() { } public void testAddRemoveComponentTemplates() throws Exception { - TransformState prevState = new TransformState<>( - ProjectMetadata.builder(projectId).build(), - Collections.emptySet() - ); + TransformState prevState = transformState(); var action = new ReservedComposableIndexTemplateAction(templateService, indexScopedSettings); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); - assertEquals(prevState.state(), updatedState.state()); String settingsJSON = """ { @@ -316,17 +310,13 @@ public void testAddRemoveComponentTemplates() throws Exception { } public void testAddRemoveIndexTemplates() throws Exception { - TransformState prevState = new TransformState<>( - ProjectMetadata.builder(projectId).build(), - Collections.emptySet() - ); + TransformState prevState = transformState(); var action = new ReservedComposableIndexTemplateAction(templateService, indexScopedSettings); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); - assertEquals(prevState.state(), updatedState.state()); String settingsJSON = """ { @@ -510,17 +500,13 @@ public void testAddRemoveIndexTemplates() throws Exception { } public void testAddRemoveIndexTemplatesWithOverlap() throws Exception { - TransformState prevState = new TransformState<>( - ProjectMetadata.builder(projectId).build(), - Collections.emptySet() - ); + TransformState prevState = transformState(); var action = new ReservedComposableIndexTemplateAction(templateService, indexScopedSettings); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); - assertEquals(prevState.state(), updatedState.state()); // Adding two composable index templates with same index patterns will fail String settingsJSON = """ @@ -746,10 +732,7 @@ public void testHandlerCorrectness() { } public void testBlockUsingReservedComponentTemplates() throws Exception { - TransformState prevState = new TransformState<>( - ProjectMetadata.builder(projectId).build(), - Collections.emptySet() - ); + TransformState prevState = transformState(); var action = new ReservedComposableIndexTemplateAction(templateService, indexScopedSettings); String settingsJSON = """ @@ -771,7 +754,7 @@ public void testBlockUsingReservedComponentTemplates() throws Exception { var updatedState = processJSON(action, prevState, settingsJSON); - ProjectMetadata withReservedState = ProjectMetadata.builder(updatedState.state()) + ProjectMetadata withReservedState = ProjectMetadata.builder(updatedState.state().getMetadata().getProject(projectId)) .put( ReservedStateMetadata.builder("test") .putHandler(new ReservedStateHandlerMetadata(ReservedComposableIndexTemplateAction.NAME, updatedState.keys())) @@ -924,10 +907,10 @@ public void testTemplatesWithReservedPrefix() throws Exception { // we should see the weird composable name prefixed 'validate_template' assertThat(project.templatesV2(), allOf(aMapWithSize(1), hasKey(reservedComposableIndexName(conflictingTemplateName)))); - TransformState prevState = new TransformState<>(project, Collections.emptySet()); + TransformState prevState = transformState(project); var action = new ReservedComposableIndexTemplateAction(mockedTemplateService, indexScopedSettings); - TransformState updatedState = processJSON(action, prevState, composableTemplate); + TransformState updatedState = processJSON(action, prevState, composableTemplate); // only one reserved key for 'validate_template' assertThat(updatedState.keys(), containsInAnyOrder(reservedComposableIndexName(conflictingTemplateName))); @@ -935,11 +918,11 @@ public void testTemplatesWithReservedPrefix() throws Exception { // added that weird name 'composable_index_template:validate_template', using this prefix in the name shouldn't make us fail // any reservation validation assertThat( - updatedState.state().templatesV2(), + updatedState.state().getMetadata().getProject(projectId).templatesV2(), allOf(aMapWithSize(2), hasKey(reservedComposableIndexName(conflictingTemplateName)), hasKey(conflictingTemplateName)) ); - ProjectMetadata withReservedMetadata = ProjectMetadata.builder(updatedState.state()) + ProjectMetadata withReservedMetadata = ProjectMetadata.builder(updatedState.state().getMetadata().getProject(projectId)) .put( new ReservedStateMetadata.Builder("file_settings").putHandler( new ReservedStateHandlerMetadata(ReservedComposableIndexTemplateAction.NAME, updatedState.keys()) @@ -996,4 +979,15 @@ public void testTemplatesWithReservedPrefix() throws Exception { prOK.name() ); } + + private TransformState transformState() { + return transformState(ProjectMetadata.builder(projectId).build()); + } + + private TransformState transformState(ProjectMetadata projectMetadata) { + return new TransformState( + ClusterState.builder(ClusterName.DEFAULT).putProjectMetadata(projectMetadata).build(), + Collections.emptySet() + ); + } } diff --git a/server/src/test/java/org/elasticsearch/action/ingest/ReservedPipelineActionTests.java b/server/src/test/java/org/elasticsearch/action/ingest/ReservedPipelineActionTests.java index 2d3de94d05ccb..9ac7b07f74eaf 100644 --- a/server/src/test/java/org/elasticsearch/action/ingest/ReservedPipelineActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/ingest/ReservedPipelineActionTests.java @@ -9,6 +9,9 @@ package org.elasticsearch.action.ingest; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.test.ESTestCase; @@ -23,26 +26,26 @@ public class ReservedPipelineActionTests extends ESTestCase { - private TransformState processJSON( - ReservedPipelineAction action, - TransformState prevState, - String json - ) throws Exception { + private TransformState processJSON(ProjectId projectId, ReservedPipelineAction action, TransformState prevState, String json) + throws Exception { 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); } } public void testAddRemoveIngestPipeline() throws Exception { - ProjectMetadata state = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + ProjectId projectId = randomProjectIdOrDefault(); + ProjectMetadata projectMetadata = ProjectMetadata.builder(projectId).build(); + TransformState prevState = new TransformState( + ClusterState.builder(ClusterName.DEFAULT).putProjectMetadata(projectMetadata).build(), + Collections.emptySet() + ); ReservedPipelineAction action = new ReservedPipelineAction(); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(projectId, action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); - assertEquals(prevState.state(), updatedState.state()); String json = """ { @@ -71,7 +74,7 @@ public void testAddRemoveIngestPipeline() throws Exception { }"""; prevState = updatedState; - updatedState = processJSON(action, prevState, json); + updatedState = processJSON(projectId, action, prevState, json); assertThat(updatedState.keys(), containsInAnyOrder("my_ingest_pipeline", "my_ingest_pipeline_1")); String halfJSON = """ @@ -89,10 +92,10 @@ public void testAddRemoveIngestPipeline() throws Exception { } }"""; - updatedState = processJSON(action, prevState, halfJSON); + updatedState = processJSON(projectId, action, prevState, halfJSON); assertThat(updatedState.keys(), containsInAnyOrder("my_ingest_pipeline_1")); - updatedState = processJSON(action, prevState, emptyJSON); + updatedState = processJSON(projectId, action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); } } diff --git a/server/src/test/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerTests.java b/server/src/test/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerTests.java index 885769a82f3bf..4b578a16b21a1 100644 --- a/server/src/test/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerTests.java +++ b/server/src/test/java/org/elasticsearch/reservedstate/ReservedClusterStateHandlerTests.java @@ -21,14 +21,14 @@ public class ReservedClusterStateHandlerTests extends ESTestCase { public void testValidation() { - ReservedClusterStateHandler handler = new ReservedClusterStateHandler<>() { + ReservedClusterStateHandler handler = new ReservedClusterStateHandler<>() { @Override public String name() { return "handler"; } @Override - public TransformState transform(ValidRequest source, TransformState prevState) throws Exception { + public TransformState transform(ValidRequest source, TransformState prevState) throws Exception { return prevState; } diff --git a/server/src/test/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsActionTests.java b/server/src/test/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsActionTests.java index d2c3980685520..974f5e3c53bfa 100644 --- a/server/src/test/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsActionTests.java +++ b/server/src/test/java/org/elasticsearch/reservedstate/action/ReservedClusterSettingsActionTests.java @@ -37,11 +37,7 @@ public class ReservedClusterSettingsActionTests extends ESTestCase { static final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, Set.of(dummySetting1, dummySetting2)); static final ReservedClusterSettingsAction testAction = new ReservedClusterSettingsAction(clusterSettings); - private TransformState processJSON( - ReservedClusterSettingsAction action, - TransformState prevState, - String json - ) throws Exception { + private TransformState processJSON(ReservedClusterSettingsAction action, TransformState prevState, String json) throws Exception { try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { return action.transform(parser.map(), prevState); } @@ -51,7 +47,7 @@ public void testValidation() throws Exception { ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + TransformState prevState = new TransformState(state, Collections.emptySet()); ReservedClusterSettingsAction action = new ReservedClusterSettingsAction(clusterSettings); String badPolicyJSON = """ @@ -69,12 +65,12 @@ public void testSetUnsetSettings() throws Exception { ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + TransformState prevState = new TransformState(state, Collections.emptySet()); ReservedClusterSettingsAction action = new ReservedClusterSettingsAction(clusterSettings); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); assertEquals(prevState.state(), updatedState.state()); @@ -123,7 +119,7 @@ public void testSettingNameNormalization() throws Exception { prevSettings, logger ); - TransformState prevState = new TransformState<>(clusterState, Set.of("dummy.setting1")); + TransformState prevState = new TransformState(clusterState, Set.of("dummy.setting1")); String json = """ { @@ -134,7 +130,7 @@ public void testSettingNameNormalization() throws Exception { } """; - TransformState newState = processJSON(testAction, prevState, json); + TransformState newState = processJSON(testAction, prevState, json); assertThat(newState.keys(), containsInAnyOrder("dummy.setting1", "dummy.setting2")); assertThat(newState.state().metadata().persistentSettings().get("dummy.setting1"), is("value1")); assertThat(newState.state().metadata().persistentSettings().get("dummy.setting2"), is("value2")); @@ -146,7 +142,7 @@ public void testSettingNameNormalization() throws Exception { } } """; - TransformState newState2 = processJSON(testAction, prevState, jsonRemoval); + TransformState newState2 = processJSON(testAction, prevState, jsonRemoval); assertThat(newState2.keys(), containsInAnyOrder("dummy.setting2")); assertThat(newState2.state().metadata().persistentSettings().get("dummy.setting2"), is("value2")); } diff --git a/server/src/test/java/org/elasticsearch/reservedstate/service/ReservedClusterStateServiceTests.java b/server/src/test/java/org/elasticsearch/reservedstate/service/ReservedClusterStateServiceTests.java index ac860d1b21508..981dd5e9475a2 100644 --- a/server/src/test/java/org/elasticsearch/reservedstate/service/ReservedClusterStateServiceTests.java +++ b/server/src/test/java/org/elasticsearch/reservedstate/service/ReservedClusterStateServiceTests.java @@ -31,6 +31,8 @@ import org.elasticsearch.env.BuildVersion; import org.elasticsearch.env.BuildVersionTests; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.reservedstate.action.ReservedClusterSettingsAction; import org.elasticsearch.test.ESTestCase; @@ -134,7 +136,7 @@ public Releasable captureResponseHeaders() { } } - private static class TestStateHandler implements ReservedClusterStateHandler> { + private static class TestStateHandler implements ReservedStateHandler> { private final String name; private TestStateHandler(String name) { @@ -146,38 +148,33 @@ public String name() { return name; } - @Override - public TransformState transform(Map source, TransformState prevState) throws Exception { - return new TransformState<>(prevState.state(), prevState.keys()); - } - @Override public Map fromXContent(XContentParser parser) throws IOException { return parser.map(); } } - private static class TestClusterStateHandler extends TestStateHandler { + private static class TestClusterStateHandler extends TestStateHandler implements ReservedClusterStateHandler> { private TestClusterStateHandler(String name) { super(name); } @Override - public TransformState transform(Map source, TransformState prevState) { + public TransformState transform(Map source, TransformState prevState) throws Exception { ClusterState newState = new ClusterState.Builder(prevState.state()).build(); - return new TransformState<>(newState, prevState.keys()); + return new TransformState(newState, prevState.keys()); } } - private static class TestProjectStateHandler extends TestStateHandler { + private static class TestProjectStateHandler extends TestStateHandler implements ReservedProjectStateHandler> { private TestProjectStateHandler(String name) { super(name); } @Override - public TransformState transform(Map source, TransformState prevState) { - ProjectMetadata newState = ProjectMetadata.builder(prevState.state()).build(); - return new TransformState<>(newState, prevState.keys()); + public TransformState transform(ProjectId projectId, Map source, TransformState prevState) throws Exception { + ClusterState newState = new ClusterState.Builder(prevState.state()).build(); + return new TransformState(newState, prevState.keys()); } } @@ -406,7 +403,7 @@ public void testProcessMultipleChunks() throws Exception { String[] randomStateKeys = generateRandomStringArray(randomIntBetween(5, 10), randomIntBetween(10, 15), false, false); - List> projectHandlers = new ArrayList<>(); + List> projectHandlers = new ArrayList<>(); for (var key : randomStateKeys) { projectHandlers.add(spy(new TestProjectStateHandler(key))); } @@ -438,7 +435,7 @@ public void testProcessMultipleChunks() throws Exception { assertThat(exceptionRef.get(), nullValue()); for (var projectHandler : projectHandlers) { - verify(projectHandler, times(1)).transform(any(), any()); + verify(projectHandler, times(1)).transform(any(), any(), any()); } } @@ -486,8 +483,8 @@ public void testProcessMultipleChunksVersionMismatch() throws Exception { assertThat(exceptionRef.get(), notNullValue()); assertThat(exceptionRef.get().getMessage(), containsString("Failed to merge reserved state chunks because of version mismatch: [")); - verify(projectStateHandler1, times(0)).transform(any(), any()); - verify(projectStateHandler2, times(0)).transform(any(), any()); + verify(projectStateHandler1, times(0)).transform(any(), any(), any()); + verify(projectStateHandler2, times(0)).transform(any(), any(), any()); } public void testProcessMultipleChunksDuplicateKeys() throws Exception { @@ -536,7 +533,7 @@ public void testProcessMultipleChunksDuplicateKeys() throws Exception { exceptionRef.get().getMessage(), containsString("Failed to merge reserved state chunks because of duplicate keys: [test]") ); - verify(projectStateHandler1, times(0)).transform(any(), any()); + verify(projectStateHandler1, times(0)).transform(any(), any(), any()); } public void testUpdateErrorState() { @@ -764,10 +761,10 @@ public void testUpdateTaskDuplicateError() { // original state by pointer reference to avoid cluster state update task to run. ReservedStateUpdateTask task; if (projectId.isPresent()) { - ReservedClusterStateHandler> newStateMaker = new TestProjectStateHandler("maker"); - ReservedClusterStateHandler> exceptionThrower = new TestStateHandler<>("one") { + ReservedProjectStateHandler> newStateMaker = new TestProjectStateHandler("maker"); + ReservedProjectStateHandler> exceptionThrower = new TestProjectStateHandler("one") { @Override - public TransformState transform(Map source, TransformState prevState) + public TransformState transform(ProjectId projectId1, Map source, TransformState prevState) throws Exception { throw new Exception("anything"); } @@ -796,19 +793,13 @@ public TransformState transform(Map source, Tra ) ); - var trialRunErrors = controller.trialRun( - "namespace_one", - state.metadata().getProject(projectId.get()), - chunk, - new LinkedHashSet<>(orderedHandlers) - ); + var trialRunErrors = controller.trialRun(projectId.get(), "namespace_one", state, chunk, new LinkedHashSet<>(orderedHandlers)); assertThat(trialRunErrors, contains(containsString("Error processing one state change:"))); } else { - ReservedClusterStateHandler> newStateMaker = new TestClusterStateHandler("maker"); - ReservedClusterStateHandler> exceptionThrower = new TestStateHandler<>("one") { + ReservedClusterStateHandler> newStateMaker = new TestClusterStateHandler("maker"); + ReservedClusterStateHandler> exceptionThrower = new TestClusterStateHandler("one") { @Override - public TransformState transform(Map source, TransformState prevState) - throws Exception { + public TransformState transform(Map source, TransformState prevState) throws Exception { throw new Exception("anything"); } }; @@ -940,10 +931,24 @@ public void testCheckMetadataVersion() { assertThat("Cluster state should not be modified", task.execute(state), sameInstance(state)); } - private ReservedClusterStateHandler> makeHandlerHelper(String name, List deps) { - return new TestStateHandler<>(name) { + private ReservedClusterStateHandler> makeClusterHandlerHelper(String name, List deps) { + return new TestClusterStateHandler(name) { + @Override + public TransformState transform(Map source, TransformState prevState) throws Exception { + return null; + } + + @Override + public Collection dependencies() { + return deps; + } + }; + } + + private ReservedProjectStateHandler> makeProjectHandlerHelper(String name, List deps) { + return new TestProjectStateHandler(name) { @Override - public TransformState transform(Map source, TransformState prevState) throws Exception { + public TransformState transform(ProjectId projectId, Map source, TransformState prevState) throws Exception { return null; } @@ -955,9 +960,9 @@ public Collection dependencies() { } public void testClusterHandlerOrdering() { - ReservedClusterStateHandler> oh1 = makeHandlerHelper("one", List.of("two", "three")); - ReservedClusterStateHandler> oh2 = makeHandlerHelper("two", List.of()); - ReservedClusterStateHandler> oh3 = makeHandlerHelper("three", List.of("two")); + ReservedClusterStateHandler> oh1 = makeClusterHandlerHelper("one", List.of("two", "three")); + ReservedClusterStateHandler> oh2 = makeClusterHandlerHelper("two", List.of()); + ReservedClusterStateHandler> oh3 = makeClusterHandlerHelper("three", List.of("two")); ClusterService clusterService = mock(ClusterService.class); final var controller = new ReservedClusterStateService( @@ -983,7 +988,7 @@ public void testClusterHandlerOrdering() { ); // Change the second handler so that we create cycle - oh2 = makeHandlerHelper("two", List.of("one")); + oh2 = makeClusterHandlerHelper("two", List.of("one")); final var controller1 = new ReservedClusterStateService(clusterService, mock(RerouteService.class), List.of(oh1, oh2), List.of()); @@ -997,9 +1002,9 @@ public void testClusterHandlerOrdering() { } public void testProjectHandlerOrdering() { - ReservedClusterStateHandler> oh1 = makeHandlerHelper("one", List.of("two", "three")); - ReservedClusterStateHandler> oh2 = makeHandlerHelper("two", List.of()); - ReservedClusterStateHandler> oh3 = makeHandlerHelper("three", List.of("two")); + ReservedProjectStateHandler> oh1 = makeProjectHandlerHelper("one", List.of("two", "three")); + ReservedProjectStateHandler> oh2 = makeProjectHandlerHelper("two", List.of()); + ReservedProjectStateHandler> oh3 = makeProjectHandlerHelper("three", List.of("two")); ClusterService clusterService = mock(ClusterService.class); final var controller = new ReservedClusterStateService( @@ -1025,7 +1030,7 @@ public void testProjectHandlerOrdering() { ); // Change the second handler so that we create cycle - oh2 = makeHandlerHelper("two", List.of("one")); + oh2 = makeProjectHandlerHelper("two", List.of("one")); final var controller1 = new ReservedClusterStateService(clusterService, mock(RerouteService.class), List.of(), List.of(oh1, oh2)); @@ -1052,7 +1057,10 @@ public void testDuplicateHandlerNames() { () -> new ReservedClusterStateService( clusterService, mock(RerouteService.class), - List.of(new ReservedClusterSettingsAction(clusterSettings), new TestStateHandler<>(ReservedClusterSettingsAction.NAME)), + List.of( + new ReservedClusterSettingsAction(clusterSettings), + new TestClusterStateHandler(ReservedClusterSettingsAction.NAME) + ), List.of() ) ).getMessage(), @@ -1066,7 +1074,7 @@ public void testDuplicateHandlerNames() { clusterService, mock(RerouteService.class), List.of(new ReservedClusterSettingsAction(clusterSettings)), - List.of(new TestStateHandler<>(ReservedClusterSettingsAction.NAME)) + List.of(new TestProjectStateHandler(ReservedClusterSettingsAction.NAME)) ) ).getMessage(), startsWith("Duplicate handler name: [cluster_settings]") diff --git a/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/LocalStateReservedAutoscalingStateHandlerProvider.java b/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/LocalStateReservedAutoscalingStateHandlerProvider.java index 7fb9de4109a27..f375b90c34ebf 100644 --- a/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/LocalStateReservedAutoscalingStateHandlerProvider.java +++ b/x-pack/plugin/autoscaling/src/internalClusterTest/java/org/elasticsearch/xpack/autoscaling/LocalStateReservedAutoscalingStateHandlerProvider.java @@ -7,21 +7,20 @@ package org.elasticsearch.xpack.autoscaling; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import java.util.Collection; /** - * Mock autoscaling provider implementation for the {@link ReservedClusterStateHandlerProvider} service interface + * Mock autoscaling provider implementation for the {@link ReservedStateHandlerProvider} service interface *

* This class is a test version of the {@link ReservedAutoscalingStateHandlerProvider}. When we load handler providers through * our custom SPI interface, we must match the plugin type exactly. With MockNode, when we run * {@link org.elasticsearch.test.ESIntegTestCase} test cases, the version of the {@link Autoscaling} plugin * is {@link LocalStateAutoscaling}, therefore we need to provide a test version of this class. */ -public class LocalStateReservedAutoscalingStateHandlerProvider implements ReservedClusterStateHandlerProvider { +public class LocalStateReservedAutoscalingStateHandlerProvider implements ReservedStateHandlerProvider { private final LocalStateAutoscaling plugin; public LocalStateReservedAutoscalingStateHandlerProvider() { @@ -33,7 +32,7 @@ public LocalStateReservedAutoscalingStateHandlerProvider(LocalStateAutoscaling p } @Override - public Collection> clusterHandlers() { + public Collection> clusterHandlers() { return plugin.testPlugin().reservedClusterStateHandlers(); } } diff --git a/x-pack/plugin/autoscaling/src/internalClusterTest/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider b/x-pack/plugin/autoscaling/src/internalClusterTest/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider similarity index 100% rename from x-pack/plugin/autoscaling/src/internalClusterTest/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider rename to x-pack/plugin/autoscaling/src/internalClusterTest/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider diff --git a/x-pack/plugin/autoscaling/src/main/java/module-info.java b/x-pack/plugin/autoscaling/src/main/java/module-info.java index 9f800611c9ccb..f1eb4dcd92b0d 100644 --- a/x-pack/plugin/autoscaling/src/main/java/module-info.java +++ b/x-pack/plugin/autoscaling/src/main/java/module-info.java @@ -5,6 +5,8 @@ * 2.0. */ +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; + module org.elasticsearch.autoscaling { requires org.apache.logging.log4j; requires org.apache.lucene.core; @@ -18,7 +20,5 @@ exports org.elasticsearch.xpack.autoscaling.capacity; exports org.elasticsearch.xpack.autoscaling; - provides org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider - with - org.elasticsearch.xpack.autoscaling.ReservedAutoscalingStateHandlerProvider; + provides ReservedStateHandlerProvider with org.elasticsearch.xpack.autoscaling.ReservedAutoscalingStateHandlerProvider; } diff --git a/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/Autoscaling.java b/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/Autoscaling.java index ac5fe2f1eabce..0da86b1a2bfaa 100644 --- a/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/Autoscaling.java +++ b/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/Autoscaling.java @@ -8,7 +8,6 @@ package org.elasticsearch.xpack.autoscaling; import org.apache.lucene.util.SetOnce; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.Metadata; @@ -231,7 +230,7 @@ public Set createDeciderServices() { return autoscalingExtensions.stream().flatMap(p -> p.deciders().stream()).collect(Collectors.toSet()); } - public Collection> reservedClusterStateHandlers() { + public Collection> reservedClusterStateHandlers() { return Set.of(reservedAutoscalingPolicyAction.get()); } } diff --git a/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/ReservedAutoscalingStateHandlerProvider.java b/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/ReservedAutoscalingStateHandlerProvider.java index 6339c3f936739..b995ae8ce4d94 100644 --- a/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/ReservedAutoscalingStateHandlerProvider.java +++ b/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/ReservedAutoscalingStateHandlerProvider.java @@ -7,16 +7,15 @@ package org.elasticsearch.xpack.autoscaling; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import java.util.Collection; /** - * Autoscaling provider implementation for the {@link ReservedClusterStateHandlerProvider} service interface + * Autoscaling provider implementation for the {@link ReservedStateHandlerProvider} service interface */ -public class ReservedAutoscalingStateHandlerProvider implements ReservedClusterStateHandlerProvider { +public class ReservedAutoscalingStateHandlerProvider implements ReservedStateHandlerProvider { private final Autoscaling plugin; public ReservedAutoscalingStateHandlerProvider() { @@ -28,7 +27,7 @@ public ReservedAutoscalingStateHandlerProvider(Autoscaling plugin) { } @Override - public Collection> clusterHandlers() { + public Collection> clusterHandlers() { return plugin.reservedClusterStateHandlers(); } } diff --git a/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyAction.java b/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyAction.java index 2b8c1afb1b82e..0dc4adc108624 100644 --- a/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyAction.java +++ b/x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyAction.java @@ -31,9 +31,7 @@ * It is used by the ReservedClusterStateService to add/update or remove autoscaling policies. Typical usage * for this action is in the context of file based settings. */ -public class ReservedAutoscalingPolicyAction - implements - ReservedClusterStateHandler> { +public class ReservedAutoscalingPolicyAction implements ReservedClusterStateHandler> { public static final String NAME = "autoscaling"; private final AutoscalingCalculateCapacityService.Holder policyValidatorHolder; @@ -61,8 +59,7 @@ private Collection prepare(List transform(List source, TransformState prevState) - throws Exception { + public TransformState transform(List source, TransformState prevState) throws Exception { var requests = prepare(source); ClusterState state = prevState.state(); @@ -79,7 +76,7 @@ public TransformState transform(List(state, entities); + return new TransformState(state, entities); } diff --git a/x-pack/plugin/autoscaling/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider b/x-pack/plugin/autoscaling/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider similarity index 100% rename from x-pack/plugin/autoscaling/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider rename to x-pack/plugin/autoscaling/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider diff --git a/x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyTests.java b/x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyTests.java index 464e9ffb3f674..4f8cec0ee845d 100644 --- a/x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyTests.java +++ b/x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/ReservedAutoscalingPolicyTests.java @@ -31,11 +31,7 @@ * Tests that the ReservedAutoscalingPolicyAction does validation, can add and remove autoscaling policies */ public class ReservedAutoscalingPolicyTests extends ESTestCase { - private TransformState processJSON( - ReservedAutoscalingPolicyAction action, - TransformState prevState, - String json - ) throws Exception { + private TransformState processJSON(ReservedAutoscalingPolicyAction action, TransformState prevState, String json) throws Exception { try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { return action.transform(action.fromXContent(parser), prevState); } @@ -45,7 +41,7 @@ public void testValidation() { var mocks = createMockServices(); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + TransformState prevState = new TransformState(state, Collections.emptySet()); ReservedAutoscalingPolicyAction action = new ReservedAutoscalingPolicyAction(mocks); String badPolicyJSON = """ @@ -76,12 +72,12 @@ public void testAddRemoveRoleMapping() throws Exception { var mocks = createMockServices(); ClusterState state = ClusterState.builder(new ClusterName("elasticsearch")).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + TransformState prevState = new TransformState(state, Collections.emptySet()); ReservedAutoscalingPolicyAction action = new ReservedAutoscalingPolicyAction(mocks); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertEquals(0, updatedState.keys().size()); assertEquals(prevState.state(), updatedState.state()); diff --git a/x-pack/plugin/ilm/src/main/java/module-info.java b/x-pack/plugin/ilm/src/main/java/module-info.java index aa24c2d6f333c..f24d3b2d1e313 100644 --- a/x-pack/plugin/ilm/src/main/java/module-info.java +++ b/x-pack/plugin/ilm/src/main/java/module-info.java @@ -1,3 +1,5 @@ +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; + /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -15,7 +17,5 @@ exports org.elasticsearch.xpack.ilm.action to org.elasticsearch.server; exports org.elasticsearch.xpack.ilm; - provides org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider - with - org.elasticsearch.xpack.ilm.ReservedLifecycleStateHandlerProvider; + provides ReservedStateHandlerProvider with org.elasticsearch.xpack.ilm.ReservedLifecycleStateHandlerProvider; } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java index 4561bf6fe6a7a..b030f70b0e680 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java @@ -9,7 +9,6 @@ import org.apache.lucene.util.SetOnce; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.client.internal.OriginSettingClient; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.node.DiscoveryNodes; @@ -27,7 +26,7 @@ import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.HealthPlugin; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestHandler; import org.elasticsearch.xcontent.NamedXContentRegistry; @@ -292,7 +291,7 @@ public List getActions() { ); } - List> reservedClusterStateHandlers() { + List> reservedProjectStateHandlers() { return List.of(reservedLifecycleAction.get()); } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/ReservedLifecycleStateHandlerProvider.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/ReservedLifecycleStateHandlerProvider.java index e4fc79344a5c3..5f16b9cc74254 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/ReservedLifecycleStateHandlerProvider.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/ReservedLifecycleStateHandlerProvider.java @@ -7,16 +7,15 @@ package org.elasticsearch.xpack.ilm; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import java.util.Collection; /** - * ILM Provider implementation for the {@link ReservedClusterStateHandlerProvider} service interface + * ILM Provider implementation for the {@link ReservedStateHandlerProvider} service interface */ -public class ReservedLifecycleStateHandlerProvider implements ReservedClusterStateHandlerProvider { +public class ReservedLifecycleStateHandlerProvider implements ReservedStateHandlerProvider { private final IndexLifecycle plugin; public ReservedLifecycleStateHandlerProvider() { @@ -28,7 +27,7 @@ public ReservedLifecycleStateHandlerProvider(IndexLifecycle plugin) { } @Override - public Collection> clusterHandlers() { - return plugin.reservedClusterStateHandlers(); + public Collection> projectHandlers() { + return plugin.reservedProjectStateHandlers(); } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java index 48a6dcc2d5a52..180e0b2a9758b 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleAction.java @@ -10,9 +10,11 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.NamedXContentRegistry; import org.elasticsearch.xcontent.XContentParser; @@ -40,7 +42,7 @@ * {@link TransportDeleteLifecycleAction} to add, update and delete ILM policies. */ @FixForMultiProject // ILM is not a thing on serverless, so this will only ever operate on default project. How do we handle this long-term? -public class ReservedLifecycleAction implements ReservedClusterStateHandler> { +public class ReservedLifecycleAction implements ReservedProjectStateHandler> { private final NamedXContentRegistry xContentRegistry; private final Client client; @@ -78,14 +80,14 @@ public Collection prepare(Object input) throws IOException } @Override - public TransformState transform(List source, TransformState prevState) throws Exception { + public TransformState transform(ProjectId projectId, List source, TransformState prevState) throws Exception { var requests = prepare(source); ClusterState state = prevState.state(); for (var request : requests) { TransportPutLifecycleAction.UpdateLifecyclePolicyTask task = new TransportPutLifecycleAction.UpdateLifecyclePolicyTask( - state.metadata().getProject().id(), + state.metadata().getProject(projectId).id(), request, licenseState, xContentRegistry, @@ -102,7 +104,7 @@ public TransformState transform(List source, Tran for (var policyToDelete : toDelete) { TransportDeleteLifecycleAction.DeleteLifecyclePolicyTask task = new TransportDeleteLifecycleAction.DeleteLifecyclePolicyTask( - state.metadata().getProject().id(), + state.metadata().getProject(projectId).id(), new DeleteLifecycleAction.Request( RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT, RESERVED_CLUSTER_STATE_HANDLER_IGNORED_TIMEOUT, @@ -113,7 +115,7 @@ public TransformState transform(List source, Tran state = task.execute(state); } - return new TransformState<>(state, entities); + return new TransformState(state, entities); } @Override diff --git a/x-pack/plugin/ilm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider b/x-pack/plugin/ilm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider similarity index 100% rename from x-pack/plugin/ilm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider rename to x-pack/plugin/ilm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleStateServiceTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleStateServiceTests.java index 27ccb60e45ec1..6d7de77ef1453 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleStateServiceTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/action/ReservedLifecycleStateServiceTests.java @@ -15,6 +15,8 @@ import org.elasticsearch.cluster.ClusterStateAckListener; import org.elasticsearch.cluster.ClusterStateTaskExecutor; import org.elasticsearch.cluster.ClusterStateTaskListener; +import org.elasticsearch.cluster.metadata.ProjectId; +import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.MasterServiceTaskQueue; import org.elasticsearch.common.settings.ClusterSettings; @@ -121,10 +123,10 @@ protected NamedXContentRegistry xContentRegistry() { return new NamedXContentRegistry(entries); } - private TransformState processJSON(ReservedLifecycleAction action, TransformState prevState, String json) + private TransformState processJSON(ProjectId projectId, ReservedLifecycleAction action, TransformState prevState, String json) throws Exception { 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); } } @@ -133,9 +135,11 @@ public void testValidationFails() { when(client.settings()).thenReturn(Settings.EMPTY); final ClusterName clusterName = new ClusterName("elasticsearch"); - ClusterState state = ClusterState.builder(clusterName).build(); + ProjectId projectId = randomProjectIdOrDefault(); + ProjectMetadata projectMetadata = ProjectMetadata.builder(projectId).build(); + ClusterState state = ClusterState.builder(clusterName).putProjectMetadata(projectMetadata).build(); ReservedLifecycleAction action = new ReservedLifecycleAction(xContentRegistry(), client, mock(XPackLicenseState.class)); - TransformState prevState = new TransformState<>(state, Set.of()); + TransformState prevState = new TransformState(state, Set.of()); String badPolicyJSON = """ { @@ -151,7 +155,7 @@ public void testValidationFails() { }"""; assertThat( - expectThrows(XContentParseException.class, () -> processJSON(action, prevState, badPolicyJSON)).getMessage(), + expectThrows(XContentParseException.class, () -> processJSON(projectId, action, prevState, badPolicyJSON)).getMessage(), is("[1:2] [lifecycle_policy] unknown field [phase] did you mean [phases]?") ); } @@ -161,15 +165,17 @@ public void testActionAddRemove() throws Exception { when(client.settings()).thenReturn(Settings.EMPTY); final ClusterName clusterName = new ClusterName("elasticsearch"); - ClusterState state = ClusterState.builder(clusterName).build(); + ProjectId projectId = randomProjectIdOrDefault(); + ProjectMetadata projectMetadata = ProjectMetadata.builder(projectId).build(); + ClusterState state = ClusterState.builder(clusterName).putProjectMetadata(projectMetadata).build(); ReservedLifecycleAction action = new ReservedLifecycleAction(xContentRegistry(), client, mock(XPackLicenseState.class)); String emptyJSON = ""; - TransformState prevState = new TransformState<>(state, Set.of()); + TransformState prevState = new TransformState(state, Set.of()); - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(projectId, action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); assertEquals(prevState.state(), updatedState.state()); @@ -201,11 +207,11 @@ public void testActionAddRemove() throws Exception { }"""; prevState = updatedState; - updatedState = processJSON(action, prevState, twoPoliciesJSON); + updatedState = processJSON(projectId, action, prevState, twoPoliciesJSON); assertThat(updatedState.keys(), containsInAnyOrder("my_timeseries_lifecycle", "my_timeseries_lifecycle1")); IndexLifecycleMetadata ilmMetadata = updatedState.state() .metadata() - .getProject() + .getProject(projectId) .custom(IndexLifecycleMetadata.TYPE, IndexLifecycleMetadata.EMPTY); assertThat(ilmMetadata.getPolicyMetadatas().keySet(), containsInAnyOrder("my_timeseries_lifecycle", "my_timeseries_lifecycle1")); @@ -223,9 +229,12 @@ public void testActionAddRemove() throws Exception { }"""; prevState = updatedState; - updatedState = processJSON(action, prevState, onePolicyRemovedJSON); + updatedState = processJSON(projectId, action, prevState, onePolicyRemovedJSON); assertThat(updatedState.keys(), containsInAnyOrder("my_timeseries_lifecycle")); - ilmMetadata = updatedState.state().metadata().getProject().custom(IndexLifecycleMetadata.TYPE, IndexLifecycleMetadata.EMPTY); + ilmMetadata = updatedState.state() + .metadata() + .getProject(projectId) + .custom(IndexLifecycleMetadata.TYPE, IndexLifecycleMetadata.EMPTY); assertThat(ilmMetadata.getPolicyMetadatas().keySet(), containsInAnyOrder("my_timeseries_lifecycle")); String onePolicyRenamedJSON = """ @@ -242,9 +251,12 @@ public void testActionAddRemove() throws Exception { }"""; prevState = updatedState; - updatedState = processJSON(action, prevState, onePolicyRenamedJSON); + updatedState = processJSON(projectId, action, prevState, onePolicyRenamedJSON); assertThat(updatedState.keys(), containsInAnyOrder("my_timeseries_lifecycle2")); - ilmMetadata = updatedState.state().metadata().getProject().custom(IndexLifecycleMetadata.TYPE, IndexLifecycleMetadata.EMPTY); + ilmMetadata = updatedState.state() + .metadata() + .getProject(projectId) + .custom(IndexLifecycleMetadata.TYPE, IndexLifecycleMetadata.EMPTY); assertThat(ilmMetadata.getPolicyMetadatas().keySet(), containsInAnyOrder("my_timeseries_lifecycle2")); } @@ -381,11 +393,8 @@ public void testOperatorControllerFromJSONContent() throws IOException { controller = new ReservedClusterStateService( clusterService, null, - List.of( - new ReservedClusterSettingsAction(clusterSettings), - new ReservedLifecycleAction(xContentRegistry(), client, licenseState) - ), - List.of() + List.of(new ReservedClusterSettingsAction(clusterSettings)), + List.of(new ReservedLifecycleAction(xContentRegistry(), client, licenseState)) ); try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, testJSON)) { @@ -440,11 +449,8 @@ public void testOperatorControllerWithPluginPackage() { controller = new ReservedClusterStateService( clusterService, null, - List.of( - new ReservedClusterSettingsAction(clusterSettings), - new ReservedLifecycleAction(xContentRegistry(), client, licenseState) - ), - List.of() + List.of(new ReservedClusterSettingsAction(clusterSettings)), + List.of(new ReservedLifecycleAction(xContentRegistry(), client, licenseState)) ); controller.process("operator", pack, randomFrom(ReservedStateVersionCheck.values()), Assert::assertNull); diff --git a/x-pack/plugin/security/src/main/java/module-info.java b/x-pack/plugin/security/src/main/java/module-info.java index 7af53479b0844..3186a59fe4c0a 100644 --- a/x-pack/plugin/security/src/main/java/module-info.java +++ b/x-pack/plugin/security/src/main/java/module-info.java @@ -5,6 +5,8 @@ * 2.0. */ +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; + module org.elasticsearch.security { requires java.naming; requires java.security.jgss; @@ -89,9 +91,7 @@ org.elasticsearch.xpack.security.authc.file.tool.UsersToolProvider, org.elasticsearch.xpack.security.enrollment.tool.AutoConfigGenerateElasticPasswordHashToolProvider; - provides org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider - with - org.elasticsearch.xpack.security.ReservedSecurityStateHandlerProvider; + provides ReservedStateHandlerProvider with org.elasticsearch.xpack.security.ReservedSecurityStateHandlerProvider; provides org.elasticsearch.features.FeatureSpecification with org.elasticsearch.xpack.security.SecurityFeatures; } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/ReservedSecurityStateHandlerProvider.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/ReservedSecurityStateHandlerProvider.java index 64c14c0d32427..3e26b8542e91f 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/ReservedSecurityStateHandlerProvider.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/ReservedSecurityStateHandlerProvider.java @@ -7,16 +7,15 @@ package org.elasticsearch.xpack.security; -import org.elasticsearch.cluster.metadata.ProjectMetadata; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import java.util.Collection; /** - * Security Provider implementation for the {@link ReservedClusterStateHandlerProvider} service interface + * Security Provider implementation for the {@link ReservedStateHandlerProvider} service interface */ -public class ReservedSecurityStateHandlerProvider implements ReservedClusterStateHandlerProvider { +public class ReservedSecurityStateHandlerProvider implements ReservedStateHandlerProvider { private final Security plugin; public ReservedSecurityStateHandlerProvider() { @@ -28,7 +27,7 @@ public ReservedSecurityStateHandlerProvider(Security plugin) { } @Override - public Collection> projectHandlers() { + public Collection> projectHandlers() { return plugin.reservedProjectStateHandlers(); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index 60b034294bcfc..c3161fc1b40cf 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -31,7 +31,6 @@ import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexTemplateMetadata; import org.elasticsearch.cluster.metadata.ProjectId; -import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.project.ProjectResolver; @@ -100,7 +99,7 @@ import org.elasticsearch.plugins.SearchPlugin; import org.elasticsearch.plugins.SystemIndexPlugin; import org.elasticsearch.plugins.interceptor.RestServerActionPlugin; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestHandler; import org.elasticsearch.rest.RestHeaderDefinition; @@ -2490,7 +2489,7 @@ public List> getPersistentTasksExecutor( return this.securityMigrationExecutor.get() != null ? List.of(this.securityMigrationExecutor.get()) : List.of(); } - List> reservedProjectStateHandlers() { + List> reservedProjectStateHandlers() { // If security is disabled we never call the plugin createComponents if (enabled == false) { return Collections.emptyList(); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/rolemapping/ReservedRoleMappingAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/rolemapping/ReservedRoleMappingAction.java index ab02fe800c12c..d09a08c363a8d 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/rolemapping/ReservedRoleMappingAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/rolemapping/ReservedRoleMappingAction.java @@ -7,8 +7,10 @@ package org.elasticsearch.xpack.security.action.rolemapping; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.metadata.ProjectMetadata; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; import org.elasticsearch.reservedstate.TransformState; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; @@ -32,7 +34,7 @@ * It is used by the ReservedClusterStateService to add/update or remove role mappings. Typical usage * for this action is in the context of file based settings. */ -public class ReservedRoleMappingAction implements ReservedClusterStateHandler> { +public class ReservedRoleMappingAction implements ReservedProjectStateHandler> { public static final String NAME = "role_mappings"; @Override @@ -41,19 +43,19 @@ public String name() { } @Override - public TransformState transform(List source, TransformState prevState) - throws Exception { + public TransformState transform(ProjectId projectId, List source, TransformState prevState) throws Exception { Set roleMappings = validateAndTranslate(source); + ProjectMetadata projectMetadata = prevState.state().getMetadata().getProject(projectId); RoleMappingMetadata newRoleMappingMetadata = new RoleMappingMetadata(roleMappings); - if (newRoleMappingMetadata.equals(RoleMappingMetadata.getFromProject(prevState.state()))) { + if (newRoleMappingMetadata.equals(RoleMappingMetadata.getFromProject(projectMetadata))) { return prevState; } else { - ProjectMetadata newState = newRoleMappingMetadata.updateProject(prevState.state()); + ProjectMetadata newProjectMetadata = newRoleMappingMetadata.updateProject(projectMetadata); Set entities = newRoleMappingMetadata.getRoleMappings() .stream() .map(ExpressionRoleMapping::getName) .collect(Collectors.toSet()); - return new TransformState<>(newState, entities); + return new TransformState(ClusterState.builder(prevState.state()).putProjectMetadata(newProjectMetadata).build(), entities); } } diff --git a/x-pack/plugin/security/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider b/x-pack/plugin/security/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider similarity index 100% rename from x-pack/plugin/security/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider rename to x-pack/plugin/security/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalReservedSecurityStateHandlerProvider.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalReservedSecurityStateHandlerProvider.java index c9a8078b64735..f45f9877e87dd 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalReservedSecurityStateHandlerProvider.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalReservedSecurityStateHandlerProvider.java @@ -7,20 +7,19 @@ package org.elasticsearch.xpack.security; -import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedProjectStateHandler; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import java.util.Collection; import java.util.Collections; import java.util.Objects; /** - * Mock Security Provider implementation for the {@link ReservedClusterStateHandlerProvider} service interface. This is used + * Mock Security Provider implementation for the {@link ReservedStateHandlerProvider} service interface. This is used * for {@link org.elasticsearch.test.ESIntegTestCase} because the Security Plugin is really LocalStateSecurity in those tests. */ -public class LocalReservedSecurityStateHandlerProvider implements ReservedClusterStateHandlerProvider { +public class LocalReservedSecurityStateHandlerProvider implements ReservedStateHandlerProvider { protected final LocalStateSecurity plugin; public LocalReservedSecurityStateHandlerProvider() { @@ -45,7 +44,7 @@ public int hashCode() { } @Override - public Collection> projectHandlers() { + public Collection> projectHandlers() { for (Plugin subPlugin : plugin.plugins()) { if (subPlugin instanceof Security security) { return security.reservedProjectStateHandlers(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/reservedstate/ReservedRoleMappingActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/reservedstate/ReservedRoleMappingActionTests.java index 1decb6e59fffa..1f865eb8594a8 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/reservedstate/ReservedRoleMappingActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/reservedstate/ReservedRoleMappingActionTests.java @@ -7,6 +7,9 @@ package org.elasticsearch.xpack.security.action.reservedstate; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.ProjectId; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.common.ParsingException; import org.elasticsearch.reservedstate.TransformState; @@ -26,20 +29,21 @@ */ public class ReservedRoleMappingActionTests extends ESTestCase { - private TransformState processJSON( - ReservedRoleMappingAction action, - TransformState prevState, - String json - ) throws Exception { + private TransformState processJSON(ProjectId projectId, ReservedRoleMappingAction action, TransformState prevState, String json) + throws Exception { try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { var content = action.fromXContent(parser); - return action.transform(content, prevState); + return action.transform(projectId, content, prevState); } } public void testValidation() { - ProjectMetadata state = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + ProjectId projectId = randomProjectIdOrDefault(); + ProjectMetadata project = ProjectMetadata.builder(projectId).build(); + TransformState prevState = new TransformState( + ClusterState.builder(ClusterName.DEFAULT).putProjectMetadata(project).build(), + Collections.emptySet() + ); ReservedRoleMappingAction action = new ReservedRoleMappingAction(); String badPolicyJSON = """ { @@ -62,17 +66,21 @@ public void testValidation() { }"""; assertEquals( "failed to parse role-mapping [everyone_fleet]. missing field [rules]", - expectThrows(ParsingException.class, () -> processJSON(action, prevState, badPolicyJSON)).getMessage() + expectThrows(ParsingException.class, () -> processJSON(projectId, action, prevState, badPolicyJSON)).getMessage() ); } public void testAddRemoveRoleMapping() throws Exception { - ProjectMetadata state = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); - TransformState prevState = new TransformState<>(state, Collections.emptySet()); + ProjectId projectId = randomProjectIdOrDefault(); + ProjectMetadata project = ProjectMetadata.builder(projectId).build(); + TransformState prevState = new TransformState( + ClusterState.builder(ClusterName.DEFAULT).putProjectMetadata(project).build(), + Collections.emptySet() + ); ReservedRoleMappingAction action = new ReservedRoleMappingAction(); String emptyJSON = ""; - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(projectId, action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); assertEquals(prevState.state(), updatedState.state()); @@ -99,10 +107,10 @@ public void testAddRemoveRoleMapping() throws Exception { }"""; prevState = updatedState; - updatedState = processJSON(action, prevState, json); + updatedState = processJSON(projectId, action, prevState, json); assertThat(updatedState.keys(), containsInAnyOrder("everyone_kibana", "everyone_fleet")); - updatedState = processJSON(action, prevState, emptyJSON); + updatedState = processJSON(projectId, action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); } } diff --git a/x-pack/plugin/security/src/test/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider b/x-pack/plugin/security/src/test/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider similarity index 100% rename from x-pack/plugin/security/src/test/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider rename to x-pack/plugin/security/src/test/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider diff --git a/x-pack/plugin/slm/src/main/java/module-info.java b/x-pack/plugin/slm/src/main/java/module-info.java index bdfdbd85a434e..5199c1cf3d900 100644 --- a/x-pack/plugin/slm/src/main/java/module-info.java +++ b/x-pack/plugin/slm/src/main/java/module-info.java @@ -1,3 +1,5 @@ +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; + /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -15,9 +17,7 @@ exports org.elasticsearch.xpack.slm.action to org.elasticsearch.server; exports org.elasticsearch.xpack.slm to org.elasticsearch.server; - provides org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider - with - org.elasticsearch.xpack.slm.ReservedLifecycleStateHandlerProvider; + provides ReservedStateHandlerProvider with org.elasticsearch.xpack.slm.ReservedLifecycleStateHandlerProvider; provides org.elasticsearch.features.FeatureSpecification with org.elasticsearch.xpack.slm.SnapshotLifecycleFeatures; } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/ReservedLifecycleStateHandlerProvider.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/ReservedLifecycleStateHandlerProvider.java index c2576675886d5..15e8359248058 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/ReservedLifecycleStateHandlerProvider.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/ReservedLifecycleStateHandlerProvider.java @@ -7,16 +7,15 @@ package org.elasticsearch.xpack.slm; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.reservedstate.ReservedClusterStateHandler; -import org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider; +import org.elasticsearch.reservedstate.ReservedStateHandlerProvider; import java.util.Collection; /** - * SLM Provider implementation for the {@link ReservedClusterStateHandlerProvider} service interface + * SLM Provider implementation for the {@link ReservedStateHandlerProvider} service interface */ -public class ReservedLifecycleStateHandlerProvider implements ReservedClusterStateHandlerProvider { +public class ReservedLifecycleStateHandlerProvider implements ReservedStateHandlerProvider { private final SnapshotLifecycle plugin; public ReservedLifecycleStateHandlerProvider() { @@ -28,7 +27,7 @@ public ReservedLifecycleStateHandlerProvider(SnapshotLifecycle plugin) { } @Override - public Collection> clusterHandlers() { + public Collection> clusterHandlers() { return plugin.reservedClusterStateHandlers(); } } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java index cf7bf2c85cfd1..e65a3d6b41910 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/SnapshotLifecycle.java @@ -10,7 +10,6 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.OriginSettingClient; -import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.node.DiscoveryNodes; @@ -233,7 +232,7 @@ public List getActions() { return actions; } - List> reservedClusterStateHandlers() { + List> reservedClusterStateHandlers() { return List.of(new ReservedSnapshotAction()); } diff --git a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java index f2f657d8b490e..1076f1f19397c 100644 --- a/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java +++ b/x-pack/plugin/slm/src/main/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotAction.java @@ -36,7 +36,7 @@ * Internally it uses {@link TransportPutSnapshotLifecycleAction} and * {@link TransportDeleteSnapshotLifecycleAction} to add, update and delete ILM policies. */ -public class ReservedSnapshotAction implements ReservedClusterStateHandler> { +public class ReservedSnapshotAction implements ReservedClusterStateHandler> { public static final String NAME = "slm"; @@ -77,8 +77,7 @@ private Collection prepare(List transform(List source, TransformState prevState) - throws Exception { + public TransformState transform(List source, TransformState prevState) throws Exception { var requests = prepare(source, prevState.state()); ClusterState state = prevState.state(); @@ -107,7 +106,7 @@ public TransformState transform(List sour state = task.execute(state); } - return new TransformState<>(state, entities); + return new TransformState(state, entities); } @Override diff --git a/x-pack/plugin/slm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider b/x-pack/plugin/slm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider similarity index 100% rename from x-pack/plugin/slm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedClusterStateHandlerProvider rename to x-pack/plugin/slm/src/main/resources/META-INF/services/org.elasticsearch.reservedstate.ReservedStateHandlerProvider diff --git a/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java b/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java index a0f52a23fd95e..044cc8d1d1594 100644 --- a/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java +++ b/x-pack/plugin/slm/src/test/java/org/elasticsearch/xpack/slm/action/ReservedSnapshotLifecycleStateServiceTests.java @@ -72,8 +72,7 @@ */ public class ReservedSnapshotLifecycleStateServiceTests extends ESTestCase { - private TransformState processJSON(ReservedSnapshotAction action, TransformState prevState, String json) - throws Exception { + private TransformState processJSON(ReservedSnapshotAction action, TransformState prevState, String json) throws Exception { try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, json)) { return action.transform(action.fromXContent(parser), prevState); } @@ -91,7 +90,7 @@ public void testValidationFailsNeitherScheduleOrInterval() { ClusterState state = ClusterState.builder(clusterName).build(); ReservedSnapshotAction action = new ReservedSnapshotAction(); - TransformState prevState = new TransformState<>(state, Set.of()); + TransformState prevState = new TransformState(state, Set.of()); String badPolicyJSON = """ { @@ -133,9 +132,9 @@ public void testActionAddRemove() throws Exception { String emptyJSON = ""; - TransformState prevState = new TransformState<>(state, Set.of()); + TransformState prevState = new TransformState(state, Set.of()); - TransformState updatedState = processJSON(action, prevState, emptyJSON); + TransformState updatedState = processJSON(action, prevState, emptyJSON); assertThat(updatedState.keys(), empty()); assertEquals(prevState.state(), updatedState.state());