From 901aafb946d3b4dd22fff1194543ead43b48587e Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Thu, 21 Jun 2018 09:56:02 -0700 Subject: [PATCH] add APIs to Maintenance Mode in ILM (#31410) - POST _xpack/index_lifecycle/_stop - issues a request to be placed into STOPPED mode (maintenance mode). This is not immediate, since we must first verify that it is safe to go from STOPPING -> STOPPED. - POST _xpack/index_lifecycle/_start - issues a request to be placed back into RUNNING mode (immediately) - GET _xpack/index_lifecycle/_status - get back the current mode our lifecycle management is in - update task was hardened to support uninstalled metadata - if no metadata is installed, the start/stop actions will install metadata and proceed to try and change it (default start mode is RUNNING) - rename MAINTENANCE -> STOPPED, MAINTENANCE_REQUESTED -> STOPPING, NORMAL -> RUNNING follow-up to #31164. --- .../IndexLifecycleMetadata.java | 36 +++--- .../core/indexlifecycle/OperationMode.java | 16 +-- .../action/GetStatusAction.java | 112 ++++++++++++++++++ .../action/PutOperationModeAction.java | 98 +++++++++++++++ .../xpack/indexlifecycle/IndexLifecycle.java | 16 ++- .../indexlifecycle/IndexLifecycleService.java | 24 ++-- ...Task.java => OperationModeUpdateTask.java} | 21 ++-- .../action/RestGetStatusAction.java | 37 ++++++ .../action/RestStartAction.java | 38 ++++++ .../indexlifecycle/action/RestStopAction.java | 38 ++++++ .../TransportDeleteLifecycleAction.java | 2 +- .../action/TransportGetStatusAction.java | 64 ++++++++++ .../action/TransportPutLifecycleAction.java | 2 +- .../TransportPutOperationModeAction.java | 67 +++++++++++ .../ExecuteStepsUpdateTaskTests.java | 2 +- .../IndexLifecycleMetadataTests.java | 4 +- .../IndexLifecycleServiceTests.java | 18 +-- ...java => OperationModeUpdateTaskTests.java} | 47 +++++--- .../PolicyStepsRegistryTests.java | 8 +- .../api/xpack.index_lifecycle.get_status.json | 13 ++ .../api/xpack.index_lifecycle.start.json | 13 ++ .../api/xpack.index_lifecycle.stop.json | 13 ++ .../index_lifecycle/60_operation_mode.yml | 68 +++++++++++ 23 files changed, 677 insertions(+), 80 deletions(-) create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetStatusAction.java create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/PutOperationModeAction.java rename x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/{MaintenanceModeUpdateTask.java => OperationModeUpdateTask.java} (73%) create mode 100644 x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestGetStatusAction.java create mode 100644 x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStartAction.java create mode 100644 x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStopAction.java create mode 100644 x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetStatusAction.java create mode 100644 x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutOperationModeAction.java rename x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/{MaintenanceModeUpdateTaskTests.java => OperationModeUpdateTaskTests.java} (51%) create mode 100644 x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.get_status.json create mode 100644 x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.start.json create mode 100644 x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.stop.json create mode 100644 x-pack/plugin/src/test/resources/rest-api-spec/test/index_lifecycle/60_operation_mode.yml diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleMetadata.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleMetadata.java index 106f29d6e8d99..670473b8c6706 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleMetadata.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleMetadata.java @@ -33,9 +33,9 @@ public class IndexLifecycleMetadata implements XPackMetaDataCustom { public static final String TYPE = "index_lifecycle"; - public static final ParseField MAINTENANCE_MODE_FIELD = new ParseField("maintenance_mode"); + public static final ParseField OPERATION_MODE_FIELD = new ParseField("operation_mode"); public static final ParseField POLICIES_FIELD = new ParseField("policies"); - public static final IndexLifecycleMetadata EMPTY = new IndexLifecycleMetadata(Collections.emptySortedMap(), OperationMode.NORMAL); + public static final IndexLifecycleMetadata EMPTY = new IndexLifecycleMetadata(Collections.emptySortedMap(), OperationMode.RUNNING); @SuppressWarnings("unchecked") public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( @@ -47,15 +47,15 @@ public class IndexLifecycleMetadata implements XPackMetaDataCustom { v -> { throw new IllegalArgumentException("ordered " + POLICIES_FIELD.getPreferredName() + " are not supported"); }, POLICIES_FIELD); - PARSER.declareString(ConstructingObjectParser.constructorArg(), MAINTENANCE_MODE_FIELD); + PARSER.declareString(ConstructingObjectParser.constructorArg(), OPERATION_MODE_FIELD); } private final Map policyMetadatas; - private final OperationMode maintenanceMode; + private final OperationMode operationMode; - public IndexLifecycleMetadata(Map policies, OperationMode maintenanceMode) { + public IndexLifecycleMetadata(Map policies, OperationMode operationMode) { this.policyMetadatas = Collections.unmodifiableMap(policies); - this.maintenanceMode = maintenanceMode; + this.operationMode = operationMode; } public IndexLifecycleMetadata(StreamInput in) throws IOException { @@ -65,7 +65,7 @@ public IndexLifecycleMetadata(StreamInput in) throws IOException { policies.put(in.readString(), new LifecyclePolicyMetadata(in)); } this.policyMetadatas = policies; - this.maintenanceMode = in.readEnum(OperationMode.class); + this.operationMode = in.readEnum(OperationMode.class); } @Override @@ -75,15 +75,15 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(entry.getKey()); entry.getValue().writeTo(out); } - out.writeEnum(maintenanceMode); + out.writeEnum(operationMode); } public Map getPolicyMetadatas() { return policyMetadatas; } - public OperationMode getMaintenanceMode() { - return maintenanceMode; + public OperationMode getOperationMode() { + return operationMode; } public Map getPolicies() { @@ -99,7 +99,7 @@ public Diff diff(Custom previousState) { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.field(POLICIES_FIELD.getPreferredName(), policyMetadatas); - builder.field(MAINTENANCE_MODE_FIELD.getPreferredName(), maintenanceMode); + builder.field(OPERATION_MODE_FIELD.getPreferredName(), operationMode); return builder; } @@ -120,7 +120,7 @@ public EnumSet context() { @Override public int hashCode() { - return Objects.hash(policyMetadatas, maintenanceMode); + return Objects.hash(policyMetadatas, operationMode); } @Override @@ -133,7 +133,7 @@ public boolean equals(Object obj) { } IndexLifecycleMetadata other = (IndexLifecycleMetadata) obj; return Objects.equals(policyMetadatas, other.policyMetadatas) - && Objects.equals(maintenanceMode, other.maintenanceMode); + && Objects.equals(operationMode, other.operationMode); } @Override @@ -144,30 +144,30 @@ public String toString() { public static class IndexLifecycleMetadataDiff implements NamedDiff { final Diff> policies; - final OperationMode maintenanceMode; + final OperationMode operationMode; IndexLifecycleMetadataDiff(IndexLifecycleMetadata before, IndexLifecycleMetadata after) { this.policies = DiffableUtils.diff(before.policyMetadatas, after.policyMetadatas, DiffableUtils.getStringKeySerializer()); - this.maintenanceMode = after.maintenanceMode; + this.operationMode = after.operationMode; } public IndexLifecycleMetadataDiff(StreamInput in) throws IOException { this.policies = DiffableUtils.readJdkMapDiff(in, DiffableUtils.getStringKeySerializer(), LifecyclePolicyMetadata::new, IndexLifecycleMetadataDiff::readLifecyclePolicyDiffFrom); - this.maintenanceMode = in.readEnum(OperationMode.class); + this.operationMode = in.readEnum(OperationMode.class); } @Override public MetaData.Custom apply(MetaData.Custom part) { TreeMap newPolicies = new TreeMap<>( policies.apply(((IndexLifecycleMetadata) part).policyMetadatas)); - return new IndexLifecycleMetadata(newPolicies, this.maintenanceMode); + return new IndexLifecycleMetadata(newPolicies, this.operationMode); } @Override public void writeTo(StreamOutput out) throws IOException { policies.writeTo(out); - out.writeEnum(maintenanceMode); + out.writeEnum(operationMode); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/OperationMode.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/OperationMode.java index 1ba5dbcce7d0f..51f50c44a7e72 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/OperationMode.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/OperationMode.java @@ -12,31 +12,31 @@ public enum OperationMode { /** * This represents a state where no policies are executed */ - MAINTENANCE { + STOPPED { @Override public boolean isValidChange(OperationMode nextMode) { - return nextMode == NORMAL; + return nextMode == RUNNING; } }, /** - * this representes a state where only sensitive actions (like {@link ShrinkAction}) will be executed - * until they finish, at which point the operation mode will move to maintenance mode. + * this represents a state where only sensitive actions (like {@link ShrinkAction}) will be executed + * until they finish, at which point the operation mode will move to STOPPED. */ - MAINTENANCE_REQUESTED { + STOPPING { @Override public boolean isValidChange(OperationMode nextMode) { - return nextMode == NORMAL || nextMode == MAINTENANCE; + return nextMode == RUNNING || nextMode == STOPPED; } }, /** * Normal operation where all policies are executed as normal. */ - NORMAL { + RUNNING { @Override public boolean isValidChange(OperationMode nextMode) { - return nextMode == MAINTENANCE_REQUESTED; + return nextMode == STOPPING; } }; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetStatusAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetStatusAction.java new file mode 100644 index 0000000000000..30213604f37a2 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/GetStatusAction.java @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.core.indexlifecycle.action; + +import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.support.master.AcknowledgedRequest; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; + +import java.io.IOException; +import java.util.Objects; + +public class GetStatusAction extends Action { + public static final GetStatusAction INSTANCE = new GetStatusAction(); + public static final String NAME = "cluster:admin/xpack/index_lifecycle/operation_mode/get"; + + protected GetStatusAction() { + super(NAME); + } + + @Override + public Response newResponse() { + return new Response(); + } + + public static class Response extends ActionResponse implements ToXContentObject { + + private OperationMode mode; + + public Response() { + } + + public Response(OperationMode mode) { + this.mode = mode; + } + + public OperationMode getMode() { + return mode; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field("operation_mode", mode); + builder.endObject(); + return builder; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + mode = in.readEnum(OperationMode.class); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeEnum(mode); + } + + @Override + public int hashCode() { + return Objects.hash(mode); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + Response other = (Response) obj; + return Objects.equals(mode, other.mode); + } + + @Override + public String toString() { + return Strings.toString(this, true, true); + } + + } + + public static class Request extends AcknowledgedRequest { + + public Request() { + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + } + } +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/PutOperationModeAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/PutOperationModeAction.java new file mode 100644 index 0000000000000..0a684dc607f33 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/action/PutOperationModeAction.java @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.core.indexlifecycle.action; + +import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.support.master.AcknowledgedRequest; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; + +import java.io.IOException; +import java.util.Objects; + +public class PutOperationModeAction extends Action { + public static final PutOperationModeAction INSTANCE = new PutOperationModeAction(); + public static final String NAME = "cluster:admin/xpack/index_lifecycle/operation_mode/set"; + + protected PutOperationModeAction() { + super(NAME); + } + + @Override + public Response newResponse() { + return new Response(); + } + + public static class Response extends AcknowledgedResponse implements ToXContentObject { + + public Response() { + } + + public Response(boolean acknowledged) { + super(acknowledged); + } + } + + public static class Request extends AcknowledgedRequest { + + private OperationMode mode; + + public Request(OperationMode mode) { + this.mode = mode; + } + + public Request() { + } + + public OperationMode getMode() { + return mode; + } + + @Override + public ActionRequestValidationException validate() { + if (mode == OperationMode.STOPPED) { + ActionRequestValidationException exception = new ActionRequestValidationException(); + exception.addValidationError("cannot directly stop index-lifecycle"); + return exception; + } + return null; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + mode = in.readEnum(OperationMode.class); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeEnum(mode); + } + + @Override + public int hashCode() { + return Objects.hash(mode); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + Request other = (Request) obj; + return Objects.equals(mode, other.mode); + } + } + +} diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java index c7dc7512e5a26..ffb1d837fe749 100644 --- a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java @@ -37,24 +37,31 @@ import org.elasticsearch.xpack.core.indexlifecycle.action.DeleteLifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction; import org.elasticsearch.xpack.core.indexlifecycle.action.MoveToStepAction; import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction; +import org.elasticsearch.xpack.core.indexlifecycle.action.PutOperationModeAction; import org.elasticsearch.xpack.core.indexlifecycle.action.RemovePolicyForIndexAction; import org.elasticsearch.xpack.core.indexlifecycle.action.RetryAction; import org.elasticsearch.xpack.core.indexlifecycle.action.SetPolicyForIndexAction; import org.elasticsearch.xpack.indexlifecycle.action.RestDeleteLifecycleAction; import org.elasticsearch.xpack.indexlifecycle.action.RestExplainLifecycleAction; import org.elasticsearch.xpack.indexlifecycle.action.RestGetLifecycleAction; +import org.elasticsearch.xpack.indexlifecycle.action.RestGetStatusAction; import org.elasticsearch.xpack.indexlifecycle.action.RestMoveToStepAction; import org.elasticsearch.xpack.indexlifecycle.action.RestPutLifecycleAction; import org.elasticsearch.xpack.indexlifecycle.action.RestRemovePolicyForIndexAction; import org.elasticsearch.xpack.indexlifecycle.action.RestRetryAction; import org.elasticsearch.xpack.indexlifecycle.action.RestSetPolicyForIndexAction; +import org.elasticsearch.xpack.indexlifecycle.action.RestStartAction; +import org.elasticsearch.xpack.indexlifecycle.action.RestStopAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportDeleteLifecycleAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportExplainLifecycleAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportGetLifecycleAction; +import org.elasticsearch.xpack.indexlifecycle.action.TransportGetStatusAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportMoveToStepAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportPutLifecycleAction; +import org.elasticsearch.xpack.indexlifecycle.action.TransportPutOperationModeAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportRemovePolicyForIndexAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportRetryAction; import org.elasticsearch.xpack.indexlifecycle.action.TransportSetPolicyForIndexAction; @@ -156,7 +163,10 @@ public List getRestHandlers(Settings settings, RestController restC new RestSetPolicyForIndexAction(settings, restController), new RestRemovePolicyForIndexAction(settings, restController), new RestMoveToStepAction(settings, restController), - new RestRetryAction(settings, restController) + new RestRetryAction(settings, restController), + new RestStopAction(settings, restController), + new RestStartAction(settings, restController), + new RestGetStatusAction(settings, restController) ); } @@ -173,7 +183,9 @@ public List getRestHandlers(Settings settings, RestController restC new ActionHandler<>(SetPolicyForIndexAction.INSTANCE, TransportSetPolicyForIndexAction.class), new ActionHandler<>(RemovePolicyForIndexAction.INSTANCE, TransportRemovePolicyForIndexAction.class), new ActionHandler<>(MoveToStepAction.INSTANCE, TransportMoveToStepAction.class), - new ActionHandler<>(RetryAction.INSTANCE, TransportRetryAction.class)); + new ActionHandler<>(RetryAction.INSTANCE, TransportRetryAction.class), + new ActionHandler<>(PutOperationModeAction.INSTANCE, TransportPutOperationModeAction.class), + new ActionHandler<>(GetStatusAction.INSTANCE, TransportGetStatusAction.class)); } @Override diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleService.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleService.java index cb10a2ff728dd..55c730799c0db 100644 --- a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleService.java +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleService.java @@ -151,7 +151,7 @@ public void triggered(SchedulerEngine.Event event) { /** * executes the policy execution on the appropriate indices by running cluster-state tasks per index. * - * If maintenance-mode was requested, and it is safe to move into maintenance-mode, this will also be done here + * If stopping ILM was requested, and it is safe to stop, this will also be done here * when possible after no policies are executed. * * @param clusterState the current cluster state @@ -164,13 +164,13 @@ void triggerPolicies(ClusterState clusterState, boolean fromClusterStateChange) return; } - OperationMode currentMode = currentMetadata.getMaintenanceMode(); + OperationMode currentMode = currentMetadata.getOperationMode(); - if (OperationMode.MAINTENANCE.equals(currentMode)) { + if (OperationMode.STOPPED.equals(currentMode)) { return; } - boolean safeToEnterMaintenanceMode = true; // true until proven false by a run policy + boolean safeToStop = true; // true until proven false by a run policy // loop through all indices in cluster state and filter for ones that are // managed by the Index Lifecycle Service they have a index.lifecycle.name setting @@ -180,18 +180,18 @@ void triggerPolicies(ClusterState clusterState, boolean fromClusterStateChange) String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()); if (Strings.isNullOrEmpty(policyName) == false) { StepKey stepKey = IndexLifecycleRunner.getCurrentStepKey(idxMeta.getSettings()); - if (OperationMode.MAINTENANCE_REQUESTED == currentMode && stepKey != null + if (OperationMode.STOPPING == currentMode && stepKey != null && IGNORE_ACTIONS_MAINTENANCE_REQUESTED.contains(stepKey.getAction()) == false) { logger.info("skipping policy [" + policyName + "] for index [" + idxMeta.getIndex().getName() - + "]. maintenance mode requested"); + + "]. stopping Index Lifecycle execution"); continue; } lifecycleRunner.runPolicy(policyName, idxMeta, clusterState, fromClusterStateChange); - safeToEnterMaintenanceMode = false; // proven false! + safeToStop = false; // proven false! } } - if (safeToEnterMaintenanceMode && OperationMode.MAINTENANCE_REQUESTED == currentMode) { - submitMaintenanceModeUpdate(OperationMode.MAINTENANCE); + if (safeToStop && OperationMode.STOPPING == currentMode) { + submitOperationModeUpdate(OperationMode.STOPPED); } } @@ -203,8 +203,8 @@ public void close() { } } - public void submitMaintenanceModeUpdate(OperationMode mode) { - clusterService.submitStateUpdateTask("ilm_maintenance_update", - new MaintenanceModeUpdateTask(mode)); + public void submitOperationModeUpdate(OperationMode mode) { + clusterService.submitStateUpdateTask("ilm_operation_mode_update", + new OperationModeUpdateTask(mode)); } } diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/MaintenanceModeUpdateTask.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/OperationModeUpdateTask.java similarity index 73% rename from x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/MaintenanceModeUpdateTask.java rename to x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/OperationModeUpdateTask.java index d224a84564b29..1956e5bb0e192 100644 --- a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/MaintenanceModeUpdateTask.java +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/OperationModeUpdateTask.java @@ -13,11 +13,11 @@ import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; -public class MaintenanceModeUpdateTask extends ClusterStateUpdateTask { - private static final Logger logger = ESLoggerFactory.getLogger(MaintenanceModeUpdateTask.class); +public class OperationModeUpdateTask extends ClusterStateUpdateTask { + private static final Logger logger = ESLoggerFactory.getLogger(OperationModeUpdateTask.class); private final OperationMode mode; - public MaintenanceModeUpdateTask(OperationMode mode) { + public OperationModeUpdateTask(OperationMode mode) { this.mode = mode; } @@ -28,16 +28,23 @@ OperationMode getOperationMode() { @Override public ClusterState execute(ClusterState currentState) { IndexLifecycleMetadata currentMetadata = currentState.metaData().custom(IndexLifecycleMetadata.TYPE); - - - if (currentMetadata.getMaintenanceMode().isValidChange(mode) == false) { + if (currentMetadata != null && currentMetadata.getOperationMode().isValidChange(mode) == false) { return currentState; + } else if (currentMetadata == null) { + currentMetadata = IndexLifecycleMetadata.EMPTY; + } + + final OperationMode newMode; + if (currentMetadata.getOperationMode().isValidChange(mode)) { + newMode = mode; + } else { + newMode = currentMetadata.getOperationMode(); } ClusterState.Builder builder = new ClusterState.Builder(currentState); MetaData.Builder metadataBuilder = MetaData.builder(currentState.metaData()); metadataBuilder.putCustom(IndexLifecycleMetadata.TYPE, - new IndexLifecycleMetadata(currentMetadata.getPolicyMetadatas(), mode)); + new IndexLifecycleMetadata(currentMetadata.getPolicyMetadatas(), newMode)); builder.metaData(metadataBuilder.build()); return builder.build(); } diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestGetStatusAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestGetStatusAction.java new file mode 100644 index 0000000000000..d80ac0e64d7e4 --- /dev/null +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestGetStatusAction.java @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.indexlifecycle.action; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction; +import org.elasticsearch.xpack.indexlifecycle.IndexLifecycle; + +public class RestGetStatusAction extends BaseRestHandler { + + public RestGetStatusAction(Settings settings, RestController controller) { + super(settings); + controller.registerHandler(RestRequest.Method.GET, + IndexLifecycle.BASE_PATH + "_status", this); + } + + @Override + public String getName() { + return "xpack_lifecycle_get_operation_mode_action"; + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + GetStatusAction.Request request = new GetStatusAction.Request(); + request.timeout(restRequest.paramAsTime("timeout", request.timeout())); + request.masterNodeTimeout(restRequest.paramAsTime("master_timeout", request.masterNodeTimeout())); + return channel -> client.execute(GetStatusAction.INSTANCE, request, new RestToXContentListener<>(channel)); + } +} diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStartAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStartAction.java new file mode 100644 index 0000000000000..dc271a2747c05 --- /dev/null +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStartAction.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.indexlifecycle.action; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; +import org.elasticsearch.xpack.core.indexlifecycle.action.PutOperationModeAction; +import org.elasticsearch.xpack.indexlifecycle.IndexLifecycle; + +public class RestStartAction extends BaseRestHandler { + + public RestStartAction(Settings settings, RestController controller) { + super(settings); + controller.registerHandler(RestRequest.Method.POST, + IndexLifecycle.BASE_PATH + "_start", this); + } + + @Override + public String getName() { + return "xpack_lifecycle_start_action"; + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + PutOperationModeAction.Request request = new PutOperationModeAction.Request(OperationMode.RUNNING); + request.timeout(restRequest.paramAsTime("timeout", request.timeout())); + request.masterNodeTimeout(restRequest.paramAsTime("master_timeout", request.masterNodeTimeout())); + return channel -> client.execute(PutOperationModeAction.INSTANCE, request, new RestToXContentListener<>(channel)); + } +} diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStopAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStopAction.java new file mode 100644 index 0000000000000..a19b8d98faccd --- /dev/null +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/RestStopAction.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.indexlifecycle.action; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; +import org.elasticsearch.xpack.core.indexlifecycle.action.PutOperationModeAction; +import org.elasticsearch.xpack.indexlifecycle.IndexLifecycle; + +public class RestStopAction extends BaseRestHandler { + + public RestStopAction(Settings settings, RestController controller) { + super(settings); + controller.registerHandler(RestRequest.Method.POST, + IndexLifecycle.BASE_PATH + "_stop", this); + } + + @Override + public String getName() { + return "xpack_lifecycle_stop_action"; + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + PutOperationModeAction.Request request = new PutOperationModeAction.Request(OperationMode.STOPPING); + request.timeout(restRequest.paramAsTime("timeout", request.timeout())); + request.masterNodeTimeout(restRequest.paramAsTime("master_timeout", request.masterNodeTimeout())); + return channel -> client.execute(PutOperationModeAction.INSTANCE, request, new RestToXContentListener<>(channel)); + } +} diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportDeleteLifecycleAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportDeleteLifecycleAction.java index 6b38ea77e9707..7b3b5a89aa3bc 100644 --- a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportDeleteLifecycleAction.java +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportDeleteLifecycleAction.java @@ -81,7 +81,7 @@ public ClusterState execute(ClusterState currentState) { } SortedMap newPolicies = new TreeMap<>(currentMetadata.getPolicyMetadatas()); newPolicies.remove(request.getPolicyName()); - IndexLifecycleMetadata newMetadata = new IndexLifecycleMetadata(newPolicies, currentMetadata.getMaintenanceMode()); + IndexLifecycleMetadata newMetadata = new IndexLifecycleMetadata(newPolicies, currentMetadata.getOperationMode()); newState.metaData(MetaData.builder(currentState.getMetaData()) .putCustom(IndexLifecycleMetadata.TYPE, newMetadata).build()); return newState.build(); diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetStatusAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetStatusAction.java new file mode 100644 index 0000000000000..db8171ccbba01 --- /dev/null +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportGetStatusAction.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + * + */ +package org.elasticsearch.xpack.indexlifecycle.action; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.master.TransportMasterNodeAction; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; +import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction.Request; +import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction.Response; + +public class TransportGetStatusAction extends TransportMasterNodeAction { + + @Inject + public TransportGetStatusAction(Settings settings, TransportService transportService, ClusterService clusterService, + ThreadPool threadPool, ActionFilters actionFilters, + IndexNameExpressionResolver indexNameExpressionResolver) { + super(settings, GetStatusAction.NAME, transportService, clusterService, threadPool, actionFilters, + indexNameExpressionResolver, Request::new); + } + + @Override + protected String executor() { + return ThreadPool.Names.SAME; + } + + @Override + protected Response newResponse() { + return new Response(); + } + + @Override + protected void masterOperation(Request request, ClusterState state, ActionListener listener) { + IndexLifecycleMetadata metadata = state.metaData().custom(IndexLifecycleMetadata.TYPE); + final Response response; + if (metadata == null) { + // no need to actually install metadata just yet, but safe to say it is not stopped + response = new Response(OperationMode.RUNNING); + } else { + response = new Response(metadata.getOperationMode()); + } + listener.onResponse(response); + } + + @Override + protected ClusterBlockException checkBlock(Request request, ClusterState state) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); + } +} diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java index 0d1096c6e23b5..b8bce5aa29b75 100644 --- a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java @@ -85,7 +85,7 @@ public ClusterState execute(ClusterState currentState) throws Exception { .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); LifecyclePolicyMetadata lifecyclePolicyMetadata = new LifecyclePolicyMetadata(request.getPolicy(), filteredHeaders); newPolicies.put(lifecyclePolicyMetadata.getName(), lifecyclePolicyMetadata); - IndexLifecycleMetadata newMetadata = new IndexLifecycleMetadata(newPolicies, OperationMode.NORMAL); + IndexLifecycleMetadata newMetadata = new IndexLifecycleMetadata(newPolicies, OperationMode.RUNNING); newState.metaData(MetaData.builder(currentState.getMetaData()) .putCustom(IndexLifecycleMetadata.TYPE, newMetadata).build()); return newState.build(); diff --git a/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutOperationModeAction.java b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutOperationModeAction.java new file mode 100644 index 0000000000000..1a1d3977303a3 --- /dev/null +++ b/x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutOperationModeAction.java @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + * + */ +package org.elasticsearch.xpack.indexlifecycle.action; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.master.TransportMasterNodeAction; +import org.elasticsearch.cluster.AckedClusterStateUpdateTask; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.indexlifecycle.action.PutOperationModeAction; +import org.elasticsearch.xpack.core.indexlifecycle.action.PutOperationModeAction.Request; +import org.elasticsearch.xpack.core.indexlifecycle.action.PutOperationModeAction.Response; +import org.elasticsearch.xpack.indexlifecycle.OperationModeUpdateTask; + +public class TransportPutOperationModeAction extends TransportMasterNodeAction { + + @Inject + public TransportPutOperationModeAction(Settings settings, TransportService transportService, ClusterService clusterService, + ThreadPool threadPool, ActionFilters actionFilters, + IndexNameExpressionResolver indexNameExpressionResolver) { + super(settings, PutOperationModeAction.NAME, transportService, clusterService, threadPool, actionFilters, + indexNameExpressionResolver, Request::new); + } + + @Override + protected String executor() { + return ThreadPool.Names.SAME; + } + + @Override + protected Response newResponse() { + return new Response(); + } + + @Override + protected void masterOperation(Request request, ClusterState state, ActionListener listener) { + clusterService.submitStateUpdateTask("ilm_operation_mode_update", + new AckedClusterStateUpdateTask(request, listener) { + @Override + public ClusterState execute(ClusterState currentState) { + return (new OperationModeUpdateTask(request.getMode())).execute(currentState); + } + + @Override + protected Response newResponse(boolean acknowledged) { + return new Response(acknowledged); + } + }); + } + + @Override + protected ClusterBlockException checkBlock(Request request, ClusterState state) { + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); + } +} diff --git a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java index 21c2989beac7f..8102d99250d87 100644 --- a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java +++ b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java @@ -99,7 +99,7 @@ public void prepareState() { MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.NORMAL)) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING)) .put(IndexMetaData.builder(indexMetadata)) .build(); String nodeId = randomAlphaOfLength(10); diff --git a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java index 1b3bb632b7652..b577aa6714254 100644 --- a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java +++ b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleMetadataTests.java @@ -94,13 +94,13 @@ protected MetaData.Custom mutateInstance(MetaData.Custom instance) { IndexLifecycleMetadata metadata = (IndexLifecycleMetadata) instance; Map policies = metadata.getPolicyMetadatas(); policies = new TreeMap<>(policies); - OperationMode mode = metadata.getMaintenanceMode(); + OperationMode mode = metadata.getOperationMode(); if (randomBoolean()) { String policyName = randomAlphaOfLength(10); policies.put(policyName, new LifecyclePolicyMetadata( new LifecyclePolicy(TestLifecycleType.INSTANCE, policyName, Collections.emptyMap()), Collections.emptyMap())); } else { - mode = randomValueOtherThan(metadata.getMaintenanceMode(), () -> randomFrom(OperationMode.values())); + mode = randomValueOtherThan(metadata.getOperationMode(), () -> randomFrom(OperationMode.values())); } return new IndexLifecycleMetadata(policies, mode); } diff --git a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java index a549677e1fcdd..73228fbec76bc 100644 --- a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java +++ b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleServiceTests.java @@ -237,7 +237,7 @@ public void testSchedulerInitializationAndUpdate() { Mockito.verifyNoMoreInteractions(clusterService); } - public void testMaintenanceModeSkip() { + public void testStoppedModeSkip() { String policyName = randomAlphaOfLengthBetween(1, 20); IndexLifecycleRunnerTests.MockClusterStateActionStep mockStep = new IndexLifecycleRunnerTests.MockClusterStateActionStep(randomStepKey(), randomStepKey()); @@ -254,7 +254,7 @@ public void testMaintenanceModeSkip() { ImmutableOpenMap.Builder indices = ImmutableOpenMap. builder() .fPut(index.getName(), indexMetadata); MetaData metaData = MetaData.builder() - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.MAINTENANCE)) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPED)) .indices(indices.build()) .persistentSettings(settings(Version.CURRENT).build()) .build(); @@ -266,7 +266,7 @@ public void testMaintenanceModeSkip() { assertThat(mockStep.getExecuteCount(), equalTo(0L)); } - public void testRequestedMaintenanceOnShrink() { + public void testRequestedStopOnShrink() { Step.StepKey mockShrinkStep = new Step.StepKey(randomAlphaOfLength(4), ShrinkAction.NAME, randomAlphaOfLength(5)); String policyName = randomAlphaOfLengthBetween(1, 20); IndexLifecycleRunnerTests.MockClusterStateActionStep mockStep = @@ -287,7 +287,7 @@ public void testRequestedMaintenanceOnShrink() { ImmutableOpenMap.Builder indices = ImmutableOpenMap. builder() .fPut(index.getName(), indexMetadata); MetaData metaData = MetaData.builder() - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.MAINTENANCE_REQUESTED)) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPING)) .indices(indices.build()) .persistentSettings(settings(Version.CURRENT).build()) .build(); @@ -307,7 +307,7 @@ public void testRequestedMaintenanceOnShrink() { assertTrue(executedShrink.get()); } - public void testRequestedMaintenanceOnSafeAction() { + public void testRequestedStopOnSafeAction() { String policyName = randomAlphaOfLengthBetween(1, 20); Step.StepKey currentStepKey = randomStepKey(); IndexLifecycleRunnerTests.MockClusterStateActionStep mockStep = @@ -328,7 +328,7 @@ public void testRequestedMaintenanceOnSafeAction() { ImmutableOpenMap.Builder indices = ImmutableOpenMap. builder() .fPut(index.getName(), indexMetadata); MetaData metaData = MetaData.builder() - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.MAINTENANCE_REQUESTED)) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPING)) .indices(indices.build()) .persistentSettings(settings(Version.CURRENT).build()) .build(); @@ -347,11 +347,11 @@ public void testRequestedMaintenanceOnSafeAction() { }).when(clusterService).submitStateUpdateTask(anyString(), any(ExecuteStepsUpdateTask.class)); doAnswer(invocationOnMock -> { - MaintenanceModeUpdateTask task = (MaintenanceModeUpdateTask) invocationOnMock.getArguments()[1]; - assertThat(task.getOperationMode(), equalTo(OperationMode.MAINTENANCE)); + OperationModeUpdateTask task = (OperationModeUpdateTask) invocationOnMock.getArguments()[1]; + assertThat(task.getOperationMode(), equalTo(OperationMode.STOPPED)); moveToMaintenance.set(true); return null; - }).when(clusterService).submitStateUpdateTask(anyString(), any(MaintenanceModeUpdateTask.class)); + }).when(clusterService).submitStateUpdateTask(anyString(), any(OperationModeUpdateTask.class)); indexLifecycleService.clusterChanged(event); assertNull(ranPolicy.get()); diff --git a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/MaintenanceModeUpdateTaskTests.java b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/OperationModeUpdateTaskTests.java similarity index 51% rename from x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/MaintenanceModeUpdateTaskTests.java rename to x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/OperationModeUpdateTaskTests.java index 8534799ea4801..1b934c1d928b3 100644 --- a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/MaintenanceModeUpdateTaskTests.java +++ b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/OperationModeUpdateTaskTests.java @@ -17,45 +17,62 @@ import java.util.Collections; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; -public class MaintenanceModeUpdateTaskTests extends ESTestCase { +public class OperationModeUpdateTaskTests extends ESTestCase { public void testExecute() { - assertMove(OperationMode.NORMAL, randomFrom(OperationMode.MAINTENANCE_REQUESTED)); - assertMove(OperationMode.MAINTENANCE_REQUESTED, randomFrom(OperationMode.NORMAL, OperationMode.MAINTENANCE)); - assertMove(OperationMode.MAINTENANCE, randomFrom(OperationMode.NORMAL)); + assertMove(OperationMode.RUNNING, OperationMode.STOPPING); + assertMove(OperationMode.STOPPING, randomFrom(OperationMode.RUNNING, OperationMode.STOPPED)); + assertMove(OperationMode.STOPPED, OperationMode.RUNNING); OperationMode mode = randomFrom(OperationMode.values()); assertNoMove(mode, mode); - assertNoMove(OperationMode.MAINTENANCE, randomFrom(OperationMode.MAINTENANCE_REQUESTED)); - assertNoMove(OperationMode.NORMAL, randomFrom(OperationMode.MAINTENANCE)); + assertNoMove(OperationMode.STOPPED, OperationMode.STOPPING); + assertNoMove(OperationMode.RUNNING, OperationMode.STOPPED); + } + + public void testExecuteWithEmptyMetadata() { + OperationMode requestedMode = OperationMode.STOPPING; + OperationMode newMode = executeUpdate(false, IndexLifecycleMetadata.EMPTY.getOperationMode(), + requestedMode, false); + assertThat(newMode, equalTo(requestedMode)); + + requestedMode = randomFrom(OperationMode.RUNNING, OperationMode.STOPPED); + newMode = executeUpdate(false, IndexLifecycleMetadata.EMPTY.getOperationMode(), + requestedMode, false); + assertThat(newMode, equalTo(OperationMode.RUNNING)); } private void assertMove(OperationMode currentMode, OperationMode requestedMode) { - OperationMode newMode = executeUpdate(currentMode, requestedMode, false); + OperationMode newMode = executeUpdate(true, currentMode, requestedMode, false); assertThat(newMode, equalTo(requestedMode)); } private void assertNoMove(OperationMode currentMode, OperationMode requestedMode) { - OperationMode newMode = executeUpdate(currentMode, requestedMode, true); + OperationMode newMode = executeUpdate(true, currentMode, requestedMode, true); assertThat(newMode, equalTo(currentMode)); } - private OperationMode executeUpdate(OperationMode currentMode, OperationMode requestMode, boolean assertSameClusterState) { + private OperationMode executeUpdate(boolean metadataInstalled, OperationMode currentMode, OperationMode requestMode, + boolean assertSameClusterState) { IndexLifecycleMetadata indexLifecycleMetadata = new IndexLifecycleMetadata(Collections.emptyMap(), currentMode); ImmutableOpenMap.Builder customsMapBuilder = ImmutableOpenMap.builder(); - MetaData metaData = MetaData.builder() - .customs(customsMapBuilder.fPut(IndexLifecycleMetadata.TYPE, indexLifecycleMetadata).build()) - .persistentSettings(settings(Version.CURRENT).build()) - .build(); + MetaData.Builder metaData = MetaData.builder() + .persistentSettings(settings(Version.CURRENT).build()); + if (metadataInstalled) { + metaData.customs(customsMapBuilder.fPut(IndexLifecycleMetadata.TYPE, indexLifecycleMetadata).build()); + } ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build(); - MaintenanceModeUpdateTask task = new MaintenanceModeUpdateTask(requestMode); + OperationModeUpdateTask task = new OperationModeUpdateTask(requestMode); ClusterState newState = task.execute(state); if (assertSameClusterState) { assertSame(state, newState); + } else { + assertThat(state, not(equalTo(newState))); } IndexLifecycleMetadata newMetaData = newState.metaData().custom(IndexLifecycleMetadata.TYPE); assertThat(newMetaData.getPolicyMetadatas(), equalTo(indexLifecycleMetadata.getPolicyMetadatas())); - return newMetaData.getMaintenanceMode(); + return newMetaData.getOperationMode(); } } diff --git a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java index bd9f28c5f0b78..22a38702fb173 100644 --- a/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java +++ b/x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java @@ -109,7 +109,7 @@ public void testUpdateFromNothingToSomethingToNothing() { new LifecyclePolicyMetadata(newPolicy, headers)); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.NORMAL)) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING)) .build(); String nodeId = randomAlphaOfLength(10); DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT) @@ -152,7 +152,7 @@ public void testUpdateFromNothingToSomethingToNothing() { .metaData( MetaData.builder(metaData) .putCustom(IndexLifecycleMetadata.TYPE, - new IndexLifecycleMetadata(Collections.emptyMap(), OperationMode.NORMAL))).build(); + new IndexLifecycleMetadata(Collections.emptyMap(), OperationMode.RUNNING))).build(); registry.update(currentState, client, () -> 0L); assertTrue(registry.getLifecyclePolicyMap().isEmpty()); assertTrue(registry.getFirstStepMap().isEmpty()); @@ -173,7 +173,7 @@ public void testUpdateChangedPolicy() { new LifecyclePolicyMetadata(newPolicy, headers)); MetaData metaData = MetaData.builder() .persistentSettings(settings(Version.CURRENT).build()) - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.NORMAL)) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING)) .build(); String nodeId = randomAlphaOfLength(10); DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT) @@ -194,7 +194,7 @@ public void testUpdateChangedPolicy() { MetaData.builder(metaData) .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(Collections.singletonMap(policyName, - new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap())), OperationMode.NORMAL))) + new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap())), OperationMode.RUNNING))) .build(); registry.update(currentState, client, () -> 0L); // TODO(talevy): assert changes... right now we do not support updates to policies. will require internal cleanup diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.get_status.json b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.get_status.json new file mode 100644 index 0000000000000..46a0cc5eac221 --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.get_status.json @@ -0,0 +1,13 @@ +{ + "xpack.index_lifecycle.get_status": { + "documentation": "http://www.elastic.co/guide/en/index_lifecycle/current/index_lifecycle.html", + "methods": [ "GET" ], + "url": { + "path": "/_xpack/index_lifecycle/_status", + "paths": ["/_xpack/index_lifecycle/_status"], + "parts": {}, + "params": {} + }, + "body": null + } +} diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.start.json b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.start.json new file mode 100644 index 0000000000000..631a1a7e3ec1a --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.start.json @@ -0,0 +1,13 @@ +{ + "xpack.index_lifecycle.start": { + "documentation": "http://www.elastic.co/guide/en/index_lifecycle/current/index_lifecycle.html", + "methods": [ "POST" ], + "url": { + "path": "/_xpack/index_lifecycle/_start", + "paths": ["/_xpack/index_lifecycle/_start"], + "parts": {}, + "params": {} + }, + "body": null + } +} diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.stop.json b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.stop.json new file mode 100644 index 0000000000000..125d2b954d27e --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.index_lifecycle.stop.json @@ -0,0 +1,13 @@ +{ + "xpack.index_lifecycle.stop": { + "documentation": "http://www.elastic.co/guide/en/index_lifecycle/current/index_lifecycle.html", + "methods": [ "POST" ], + "url": { + "path": "/_xpack/index_lifecycle/_stop", + "paths": ["/_xpack/index_lifecycle/_stop"], + "parts": {}, + "params": {} + }, + "body": null + } +} diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/index_lifecycle/60_operation_mode.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/index_lifecycle/60_operation_mode.yml new file mode 100644 index 0000000000000..ba963e17d2b89 --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/index_lifecycle/60_operation_mode.yml @@ -0,0 +1,68 @@ +--- +setup: + - do: + cluster.health: + wait_for_status: yellow + +--- +"Test Changing Operation Modes": + - do: + xpack.index_lifecycle.get_status: {} + - match: { operation_mode: "RUNNING" } + + - do: + acknowlege: true + xpack.index_lifecycle.put_lifecycle: + lifecycle: "my_timeseries_lifecycle" + body: | + { + "policy": { + "type": "timeseries", + "phases": { + "warm": { + "after": "10s", + "actions": { + "forcemerge": { + "max_num_segments": 10000 + } + } + }, + "delete": { + "after": "30s", + "actions": { + "delete": {} + } + } + } + } + } + + - do: + xpack.index_lifecycle.get_status: {} + - match: { operation_mode: "RUNNING" } + + - do: + acknowledge: true + xpack.index_lifecycle.stop: {} + + - do: + xpack.index_lifecycle.get_status: {} + - match: { operation_mode: "STOPPING" } + + - do: + acknowledge: true + xpack.index_lifecycle.start: {} + + - do: + xpack.index_lifecycle.get_status: {} + - match: { operation_mode: "RUNNING" } + + - do: + acknowledge: true + xpack.index_lifecycle.delete_lifecycle: + lifecycle: "my_timeseries_lifecycle" + + - do: + catch: missing + xpack.index_lifecycle.get_lifecycle: + lifecycle: "my_timeseries_lifecycle"