Skip to content

Commit

Permalink
add APIs to Maintenance Mode in ILM (#31410)
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
talevy authored Jun 21, 2018
1 parent fc2f982 commit 901aafb
Show file tree
Hide file tree
Showing 23 changed files with 677 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<IndexLifecycleMetadata, Void> PARSER = new ConstructingObjectParser<>(
Expand All @@ -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<String, LifecyclePolicyMetadata> policyMetadatas;
private final OperationMode maintenanceMode;
private final OperationMode operationMode;

public IndexLifecycleMetadata(Map<String, LifecyclePolicyMetadata> policies, OperationMode maintenanceMode) {
public IndexLifecycleMetadata(Map<String, LifecyclePolicyMetadata> policies, OperationMode operationMode) {
this.policyMetadatas = Collections.unmodifiableMap(policies);
this.maintenanceMode = maintenanceMode;
this.operationMode = operationMode;
}

public IndexLifecycleMetadata(StreamInput in) throws IOException {
Expand All @@ -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
Expand All @@ -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<String, LifecyclePolicyMetadata> getPolicyMetadatas() {
return policyMetadatas;
}

public OperationMode getMaintenanceMode() {
return maintenanceMode;
public OperationMode getOperationMode() {
return operationMode;
}

public Map<String, LifecyclePolicy> getPolicies() {
Expand All @@ -99,7 +99,7 @@ public Diff<Custom> 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;
}

Expand All @@ -120,7 +120,7 @@ public EnumSet<MetaData.XContentContext> context() {

@Override
public int hashCode() {
return Objects.hash(policyMetadatas, maintenanceMode);
return Objects.hash(policyMetadatas, operationMode);
}

@Override
Expand All @@ -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
Expand All @@ -144,30 +144,30 @@ public String toString() {
public static class IndexLifecycleMetadataDiff implements NamedDiff<MetaData.Custom> {

final Diff<Map<String, LifecyclePolicyMetadata>> 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<String, LifecyclePolicyMetadata> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>STOPPED</code>.
*/
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;
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -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<GetStatusAction.Response> {
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<Request> {

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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<PutOperationModeAction.Response> {
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<Request> {

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);
}
}

}
Loading

0 comments on commit 901aafb

Please sign in to comment.