copy LifecyclePolicy to protocol.xpack (#32915)
This is the final PR for copying over the necessary components for clients to parse/render LifecyclePolicy. Changes include: - move of named-x-content server objects away from client - move validation into the client copy of LifecyclePolicy - move LifecycleAction into an interface with `getName`
This commit is contained in:
parent
3736097e19
commit
5ce082cd0a
|
@ -440,20 +440,7 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPl
|
|||
RollupJobStatus::fromXContent),
|
||||
new NamedXContentRegistry.Entry(PersistentTaskState.class, new ParseField(RollupJobStatus.NAME),
|
||||
RollupJobStatus::fromXContent),
|
||||
// ILM - Custom Metadata
|
||||
new NamedXContentRegistry.Entry(MetaData.Custom.class, new ParseField(IndexLifecycleMetadata.TYPE),
|
||||
parser -> IndexLifecycleMetadata.PARSER.parse(parser, null)),
|
||||
// ILM - Lifecycle Types
|
||||
new NamedXContentRegistry.Entry(LifecycleType.class, new ParseField(TimeseriesLifecycleType.TYPE),
|
||||
(p, c) -> TimeseriesLifecycleType.INSTANCE),
|
||||
// ILM - Lifecycle Actions
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(AllocateAction.NAME), AllocateAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ForceMergeAction.NAME), ForceMergeAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse),
|
||||
// ILM - Client - Lifecycle Actions
|
||||
// ILM
|
||||
new NamedXContentRegistry.Entry(org.elasticsearch.protocol.xpack.indexlifecycle.LifecycleAction.class,
|
||||
new ParseField(org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction.NAME),
|
||||
org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction::parse),
|
||||
|
|
|
@ -34,10 +34,9 @@ import java.util.stream.Collectors;
|
|||
/**
|
||||
* Represents the lifecycle of an index from creation to deletion. A
|
||||
* {@link LifecyclePolicy} is made up of a set of {@link Phase}s which it will
|
||||
* move through. Soon we will constrain the phases using some kinda of lifecycle
|
||||
* type which will allow only particular {@link Phase}s to be defined, will
|
||||
* dictate the order in which the {@link Phase}s are executed and will define
|
||||
* which {@link LifecycleAction}s are allowed in each phase.
|
||||
* move through. Policies are constrained by a {@link LifecycleType} which governs which
|
||||
* {@link Phase}s and {@link LifecycleAction}s are allowed to be defined and in which order
|
||||
* they are executed.
|
||||
*/
|
||||
public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
|
||||
implements ToXContentObject, Diffable<LifecyclePolicy> {
|
||||
|
@ -58,9 +57,9 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
|
|||
}, PHASES_FIELD);
|
||||
}
|
||||
|
||||
protected final String name;
|
||||
protected final LifecycleType type;
|
||||
protected final Map<String, Phase> phases;
|
||||
private final String name;
|
||||
private final LifecycleType type;
|
||||
private final Map<String, Phase> phases;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
|
@ -97,6 +96,7 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
|
|||
this.type = type;
|
||||
this.type.validate(phases.values());
|
||||
}
|
||||
|
||||
public static LifecyclePolicy parse(XContentParser parser, String name) {
|
||||
return PARSER.apply(parser, name);
|
||||
}
|
||||
|
|
|
@ -51,9 +51,9 @@ public class Phase implements ToXContentObject, Writeable {
|
|||
return PARSER.apply(parser, name);
|
||||
}
|
||||
|
||||
private String name;
|
||||
private Map<String, LifecycleAction> actions;
|
||||
private TimeValue after;
|
||||
private final String name;
|
||||
private final Map<String, LifecycleAction> actions;
|
||||
private final TimeValue after;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
|
@ -133,12 +133,12 @@ public class Phase implements ToXContentObject, Writeable {
|
|||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, after, actions);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
|
|
|
@ -15,7 +15,6 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -46,6 +45,14 @@ public class TimeseriesLifecycleType implements LifecycleType {
|
|||
static final Set<String> VALID_DELETE_ACTIONS = Sets.newHashSet(ORDERED_VALID_DELETE_ACTIONS);
|
||||
private static final Phase EMPTY_WARM_PHASE = new Phase("warm", TimeValue.ZERO,
|
||||
Collections.singletonMap("readonly", ReadOnlyAction.INSTANCE));
|
||||
private static Map<String, Set<String>> ALLOWED_ACTIONS = new HashMap<>();
|
||||
|
||||
static {
|
||||
ALLOWED_ACTIONS.put("hot", VALID_HOT_ACTIONS);
|
||||
ALLOWED_ACTIONS.put("warm", VALID_WARM_ACTIONS);
|
||||
ALLOWED_ACTIONS.put("cold", VALID_COLD_ACTIONS);
|
||||
ALLOWED_ACTIONS.put("delete", VALID_DELETE_ACTIONS);
|
||||
}
|
||||
|
||||
private TimeseriesLifecycleType() {
|
||||
}
|
||||
|
@ -182,18 +189,12 @@ public class TimeseriesLifecycleType implements LifecycleType {
|
|||
|
||||
@Override
|
||||
public void validate(Collection<Phase> phases) {
|
||||
Set<String> allowedPhases = new HashSet<>(VALID_PHASES);
|
||||
Map<String, Set<String>> allowedActions = new HashMap<>(allowedPhases.size());
|
||||
allowedActions.put("hot", VALID_HOT_ACTIONS);
|
||||
allowedActions.put("warm", VALID_WARM_ACTIONS);
|
||||
allowedActions.put("cold", VALID_COLD_ACTIONS);
|
||||
allowedActions.put("delete", VALID_DELETE_ACTIONS);
|
||||
phases.forEach(phase -> {
|
||||
if (allowedPhases.contains(phase.getName()) == false) {
|
||||
if (ALLOWED_ACTIONS.containsKey(phase.getName()) == false) {
|
||||
throw new IllegalArgumentException("Timeseries lifecycle does not support phase [" + phase.getName() + "]");
|
||||
}
|
||||
phase.getActions().forEach((actionName, action) -> {
|
||||
if (allowedActions.get(phase.getName()).contains(actionName) == false) {
|
||||
if (ALLOWED_ACTIONS.get(phase.getName()).contains(actionName) == false) {
|
||||
throw new IllegalArgumentException("invalid action [" + actionName + "] " +
|
||||
"defined in phase [" + phase.getName() +"]");
|
||||
}
|
||||
|
|
|
@ -10,8 +10,10 @@ import org.elasticsearch.action.ActionRequest;
|
|||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.metadata.MetaData;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.inject.Module;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
||||
|
@ -32,8 +34,17 @@ import org.elasticsearch.threadpool.ThreadPool;
|
|||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.core.XPackPlugin;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.AllocateAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.DeleteAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.ForceMergeAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleType;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.ReadOnlyAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.action.DeleteLifecycleAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
|
||||
|
@ -146,7 +157,21 @@ public class IndexLifecycle extends Plugin implements ActionPlugin {
|
|||
|
||||
@Override
|
||||
public List<org.elasticsearch.common.xcontent.NamedXContentRegistry.Entry> getNamedXContent() {
|
||||
return Arrays.asList();
|
||||
return Arrays.asList(
|
||||
// Custom Metadata
|
||||
new NamedXContentRegistry.Entry(MetaData.Custom.class, new ParseField(IndexLifecycleMetadata.TYPE),
|
||||
parser -> IndexLifecycleMetadata.PARSER.parse(parser, null)),
|
||||
// Lifecycle Types
|
||||
new NamedXContentRegistry.Entry(LifecycleType.class, new ParseField(TimeseriesLifecycleType.TYPE),
|
||||
(p, c) -> TimeseriesLifecycleType.INSTANCE),
|
||||
// Lifecycle Actions
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(AllocateAction.NAME), AllocateAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ForceMergeAction.NAME), ForceMergeAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class AllocateAction extends LifecycleAction implements ToXContentObject {
|
||||
public class AllocateAction implements LifecycleAction, ToXContentObject {
|
||||
|
||||
public static final String NAME = "allocate";
|
||||
static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas");
|
||||
|
@ -102,6 +102,11 @@ public class AllocateAction extends LifecycleAction implements ToXContentObject
|
|||
return require;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DeleteAction extends LifecycleAction implements ToXContentObject {
|
||||
public class DeleteAction implements LifecycleAction, ToXContentObject {
|
||||
public static final String NAME = "delete";
|
||||
|
||||
private static final ObjectParser<DeleteAction, Void> PARSER = new ObjectParser<>(NAME, DeleteAction::new);
|
||||
|
@ -46,6 +46,11 @@ public class DeleteAction extends LifecycleAction implements ToXContentObject {
|
|||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ForceMergeAction extends LifecycleAction implements ToXContentObject {
|
||||
public class ForceMergeAction implements LifecycleAction, ToXContentObject {
|
||||
public static final String NAME = "forcemerge";
|
||||
private static final ParseField MAX_NUM_SEGMENTS_FIELD = new ParseField("max_num_segments");
|
||||
|
||||
|
@ -60,6 +60,11 @@ public class ForceMergeAction extends LifecycleAction implements ToXContentObjec
|
|||
return maxNumSegments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
|
|
@ -19,7 +19,12 @@
|
|||
package org.elasticsearch.protocol.xpack.indexlifecycle;
|
||||
|
||||
/**
|
||||
* Marker interface for index lifecycle management actions
|
||||
* interface for index lifecycle management actions
|
||||
*/
|
||||
public class LifecycleAction {
|
||||
public interface LifecycleAction {
|
||||
|
||||
/**
|
||||
* @return the name of this action
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.xpack.indexlifecycle;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents the lifecycle of an index from creation to deletion. A
|
||||
* {@link LifecyclePolicy} is made up of a set of {@link Phase}s which it will
|
||||
* move through.
|
||||
*/
|
||||
public class LifecyclePolicy implements ToXContentObject {
|
||||
static final ParseField PHASES_FIELD = new ParseField("phases");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ConstructingObjectParser<LifecyclePolicy, String> PARSER = new ConstructingObjectParser<>("lifecycle_policy", false,
|
||||
(a, name) -> {
|
||||
List<Phase> phases = (List<Phase>) a[0];
|
||||
Map<String, Phase> phaseMap = phases.stream().collect(Collectors.toMap(Phase::getName, Function.identity()));
|
||||
return new LifecyclePolicy(name, phaseMap);
|
||||
});
|
||||
private static Map<String, Set<String>> ALLOWED_ACTIONS = new HashMap<>();
|
||||
|
||||
static {
|
||||
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> Phase.parse(p, n), v -> {
|
||||
throw new IllegalArgumentException("ordered " + PHASES_FIELD.getPreferredName() + " are not supported");
|
||||
}, PHASES_FIELD);
|
||||
|
||||
ALLOWED_ACTIONS.put("hot", Sets.newHashSet(RolloverAction.NAME));
|
||||
ALLOWED_ACTIONS.put("warm", Sets.newHashSet(AllocateAction.NAME, ForceMergeAction.NAME, ReadOnlyAction.NAME, ShrinkAction.NAME));
|
||||
ALLOWED_ACTIONS.put("cold", Sets.newHashSet(AllocateAction.NAME));
|
||||
ALLOWED_ACTIONS.put("delete", Sets.newHashSet(DeleteAction.NAME));
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final Map<String, Phase> phases;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name of this {@link LifecyclePolicy}
|
||||
* @param phases
|
||||
* a {@link Map} of {@link Phase}s which make up this
|
||||
* {@link LifecyclePolicy}.
|
||||
*/
|
||||
public LifecyclePolicy(String name, Map<String, Phase> phases) {
|
||||
phases.values().forEach(phase -> {
|
||||
if (ALLOWED_ACTIONS.containsKey(phase.getName()) == false) {
|
||||
throw new IllegalArgumentException("Lifecycle does not support phase [" + phase.getName() + "]");
|
||||
}
|
||||
phase.getActions().forEach((actionName, action) -> {
|
||||
if (ALLOWED_ACTIONS.get(phase.getName()).contains(actionName) == false) {
|
||||
throw new IllegalArgumentException("invalid action [" + actionName + "] " +
|
||||
"defined in phase [" + phase.getName() +"]");
|
||||
}
|
||||
});
|
||||
});
|
||||
this.name = name;
|
||||
this.phases = phases;
|
||||
}
|
||||
|
||||
public static LifecyclePolicy parse(XContentParser parser, String name) {
|
||||
return PARSER.apply(parser, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of this {@link LifecyclePolicy}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Phase}s for this {@link LifecyclePolicy} in the order
|
||||
* in which they will be executed.
|
||||
*/
|
||||
public Map<String, Phase> getPhases() {
|
||||
return phases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.startObject(PHASES_FIELD.getPreferredName());
|
||||
for (Phase phase : phases.values()) {
|
||||
builder.field(phase.getName(), phase);
|
||||
}
|
||||
builder.endObject();
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, phases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
LifecyclePolicy other = (LifecyclePolicy) obj;
|
||||
return Objects.equals(name, other.name) &&
|
||||
Objects.equals(phases, other.phases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Strings.toString(this, true, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.xpack.indexlifecycle;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents set of {@link LifecycleAction}s which should be executed at a
|
||||
* particular point in the lifecycle of an index.
|
||||
*/
|
||||
public class Phase implements ToXContentObject {
|
||||
|
||||
static final ParseField AFTER_FIELD = new ParseField("after");
|
||||
static final ParseField ACTIONS_FIELD = new ParseField("actions");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<Phase, String> PARSER = new ConstructingObjectParser<>("phase", false,
|
||||
(a, name) -> new Phase(name, (TimeValue) a[0], ((List<LifecycleAction>) a[1]).stream()
|
||||
.collect(Collectors.toMap(LifecycleAction::getName, Function.identity()))));
|
||||
static {
|
||||
PARSER.declareField(ConstructingObjectParser.optionalConstructorArg(),
|
||||
(p, c) -> TimeValue.parseTimeValue(p.text(), AFTER_FIELD.getPreferredName()), AFTER_FIELD, ValueType.VALUE);
|
||||
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(),
|
||||
(p, c, n) -> p.namedObject(LifecycleAction.class, n, null), v -> {
|
||||
throw new IllegalArgumentException("ordered " + ACTIONS_FIELD.getPreferredName() + " are not supported");
|
||||
}, ACTIONS_FIELD);
|
||||
}
|
||||
|
||||
public static Phase parse(XContentParser parser, String name) {
|
||||
return PARSER.apply(parser, name);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final Map<String, LifecycleAction> actions;
|
||||
private final TimeValue after;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name of this {@link Phase}.
|
||||
* @param after
|
||||
* the age of the index when the index should move to this
|
||||
* {@link Phase}.
|
||||
* @param actions
|
||||
* a {@link Map} of the {@link LifecycleAction}s to run when
|
||||
* during this {@link Phase}. The keys in this map are the associated
|
||||
* action names.
|
||||
*/
|
||||
public Phase(String name, TimeValue after, Map<String, LifecycleAction> actions) {
|
||||
this.name = name;
|
||||
if (after == null) {
|
||||
this.after = TimeValue.ZERO;
|
||||
} else {
|
||||
this.after = after;
|
||||
}
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the age of the index when the index should move to this
|
||||
* {@link Phase}.
|
||||
*/
|
||||
public TimeValue getAfter() {
|
||||
return after;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of this {@link Phase}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a {@link Map} of the {@link LifecycleAction}s to run when during
|
||||
* this {@link Phase}.
|
||||
*/
|
||||
public Map<String, LifecycleAction> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(AFTER_FIELD.getPreferredName(), after.seconds() + "s"); // Need a better way to get a parsable format out here
|
||||
builder.field(ACTIONS_FIELD.getPreferredName(), actions);
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, after, actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
Phase other = (Phase) obj;
|
||||
return Objects.equals(name, other.name) &&
|
||||
Objects.equals(after, other.after) &&
|
||||
Objects.equals(actions, other.actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Strings.toString(this, true, true);
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ReadOnlyAction extends LifecycleAction implements ToXContentObject {
|
||||
public class ReadOnlyAction implements LifecycleAction, ToXContentObject {
|
||||
public static final String NAME = "readonly";
|
||||
|
||||
private static final ObjectParser<ReadOnlyAction, Void> PARSER = new ObjectParser<>(NAME, false, ReadOnlyAction::new);
|
||||
|
@ -38,6 +38,11 @@ public class ReadOnlyAction extends LifecycleAction implements ToXContentObject
|
|||
public ReadOnlyAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.io.IOException;
|
|||
import java.util.Objects;
|
||||
|
||||
|
||||
public class RolloverAction extends LifecycleAction implements ToXContentObject {
|
||||
public class RolloverAction implements LifecycleAction, ToXContentObject {
|
||||
public static final String NAME = "rollover";
|
||||
private static final ParseField MAX_SIZE_FIELD = new ParseField("max_size");
|
||||
private static final ParseField MAX_DOCS_FIELD = new ParseField("max_docs");
|
||||
|
@ -76,6 +76,11 @@ public class RolloverAction extends LifecycleAction implements ToXContentObject
|
|||
return maxDocs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ShrinkAction extends LifecycleAction implements ToXContentObject {
|
||||
public class ShrinkAction implements LifecycleAction, ToXContentObject {
|
||||
public static final String NAME = "shrink";
|
||||
private static final ParseField NUMBER_OF_SHARDS_FIELD = new ParseField("number_of_shards");
|
||||
|
||||
|
@ -56,6 +56,11 @@ public class ShrinkAction extends LifecycleAction implements ToXContentObject {
|
|||
return numberOfShards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
|
|
@ -29,6 +29,10 @@ public class AllocateActionTests extends AbstractXContentTestCase<AllocateAction
|
|||
|
||||
@Override
|
||||
protected AllocateAction createTestInstance() {
|
||||
return randomInstance();
|
||||
}
|
||||
|
||||
static AllocateAction randomInstance() {
|
||||
boolean hasAtLeastOneMap = false;
|
||||
Map<String, String> includes;
|
||||
if (randomBoolean()) {
|
||||
|
|
|
@ -44,6 +44,10 @@ public class ForceMergeActionTests extends AbstractXContentTestCase<ForceMergeAc
|
|||
|
||||
@Override
|
||||
protected ForceMergeAction createTestInstance() {
|
||||
return randomInstance();
|
||||
}
|
||||
|
||||
static ForceMergeAction randomInstance() {
|
||||
return new ForceMergeAction(randomIntBetween(1, 100));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.xpack.indexlifecycle;
|
||||
|
||||
import org.elasticsearch.cluster.ClusterModule;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractXContentTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class LifecyclePolicyTests extends AbstractXContentTestCase<LifecyclePolicy> {
|
||||
private static final Set<String> VALID_HOT_ACTIONS = Sets.newHashSet(RolloverAction.NAME);
|
||||
private static final Set<String> VALID_WARM_ACTIONS = Sets.newHashSet(AllocateAction.NAME, ForceMergeAction.NAME,
|
||||
ReadOnlyAction.NAME, ShrinkAction.NAME);
|
||||
private static final Set<String> VALID_COLD_ACTIONS = Sets.newHashSet(AllocateAction.NAME);
|
||||
private static final Set<String> VALID_DELETE_ACTIONS = Sets.newHashSet(DeleteAction.NAME);
|
||||
|
||||
private String lifecycleName;
|
||||
|
||||
@Override
|
||||
protected LifecyclePolicy doParseInstance(XContentParser parser) {
|
||||
return LifecyclePolicy.parse(parser, lifecycleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsUnknownFields() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NamedXContentRegistry xContentRegistry() {
|
||||
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
|
||||
entries.addAll(Arrays.asList(
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(AllocateAction.NAME), AllocateAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ForceMergeAction.NAME), ForceMergeAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse),
|
||||
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse)
|
||||
));
|
||||
return new NamedXContentRegistry(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LifecyclePolicy createTestInstance() {
|
||||
lifecycleName = randomAlphaOfLength(5);
|
||||
List<String> phaseNames = randomSubsetOf(Arrays.asList("hot", "warm", "cold", "delete"));
|
||||
Map<String, Phase> phases = new HashMap<>(phaseNames.size());
|
||||
Function<String, Set<String>> validActions = (phase) -> {
|
||||
switch (phase) {
|
||||
case "hot":
|
||||
return VALID_HOT_ACTIONS;
|
||||
case "warm":
|
||||
return VALID_WARM_ACTIONS;
|
||||
case "cold":
|
||||
return VALID_COLD_ACTIONS;
|
||||
case "delete":
|
||||
return VALID_DELETE_ACTIONS;
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid phase [" + phase + "]");
|
||||
}};
|
||||
Function<String, LifecycleAction> randomAction = (action) -> {
|
||||
switch (action) {
|
||||
case AllocateAction.NAME:
|
||||
return AllocateActionTests.randomInstance();
|
||||
case DeleteAction.NAME:
|
||||
return new DeleteAction();
|
||||
case ForceMergeAction.NAME:
|
||||
return ForceMergeActionTests.randomInstance();
|
||||
case ReadOnlyAction.NAME:
|
||||
return new ReadOnlyAction();
|
||||
case RolloverAction.NAME:
|
||||
return RolloverActionTests.randomInstance();
|
||||
case ShrinkAction.NAME:
|
||||
return ShrinkActionTests.randomInstance();
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid action [" + action + "]");
|
||||
}};
|
||||
for (String phase : phaseNames) {
|
||||
TimeValue after = TimeValue.parseTimeValue(randomTimeValue(0, 1000000000, "s", "m", "h", "d"), "test_after");
|
||||
Map<String, LifecycleAction> actions = new HashMap<>();
|
||||
List<String> actionNames = randomSubsetOf(validActions.apply(phase));
|
||||
for (String action : actionNames) {
|
||||
actions.put(action, randomAction.apply(action));
|
||||
}
|
||||
phases.put(phase, new Phase(phase, after, actions));
|
||||
}
|
||||
return new LifecyclePolicy(lifecycleName, phases);
|
||||
}
|
||||
|
||||
public void testValidatePhases() {
|
||||
boolean invalid = randomBoolean();
|
||||
String phaseName = randomFrom("hot", "warm", "cold", "delete");
|
||||
if (invalid) {
|
||||
phaseName += randomAlphaOfLength(5);
|
||||
}
|
||||
Map<String, Phase> phases = Collections.singletonMap(phaseName,
|
||||
new Phase(phaseName, TimeValue.ZERO, Collections.emptyMap()));
|
||||
if (invalid) {
|
||||
Exception e = expectThrows(IllegalArgumentException.class, () -> new LifecyclePolicy(lifecycleName, phases));
|
||||
assertThat(e.getMessage(), equalTo("Lifecycle does not support phase [" + phaseName + "]"));
|
||||
} else {
|
||||
new LifecyclePolicy(lifecycleName, phases);
|
||||
}
|
||||
}
|
||||
|
||||
public void testValidateHotPhase() {
|
||||
LifecycleAction invalidAction = null;
|
||||
Map<String, LifecycleAction> actions = randomSubsetOf(VALID_HOT_ACTIONS)
|
||||
.stream().map(this::getTestAction).collect(Collectors.toMap(LifecycleAction::getName, Function.identity()));
|
||||
if (randomBoolean()) {
|
||||
invalidAction = getTestAction(randomFrom("allocate", "forcemerge", "delete", "shrink"));
|
||||
actions.put(invalidAction.getName(), invalidAction);
|
||||
}
|
||||
Map<String, Phase> hotPhase = Collections.singletonMap("hot",
|
||||
new Phase("hot", TimeValue.ZERO, actions));
|
||||
|
||||
if (invalidAction != null) {
|
||||
Exception e = expectThrows(IllegalArgumentException.class,
|
||||
() -> new LifecyclePolicy(lifecycleName, hotPhase));
|
||||
assertThat(e.getMessage(),
|
||||
equalTo("invalid action [" + invalidAction.getName() + "] defined in phase [hot]"));
|
||||
} else {
|
||||
new LifecyclePolicy(lifecycleName, hotPhase);
|
||||
}
|
||||
}
|
||||
|
||||
public void testValidateWarmPhase() {
|
||||
LifecycleAction invalidAction = null;
|
||||
Map<String, LifecycleAction> actions = randomSubsetOf(VALID_WARM_ACTIONS)
|
||||
.stream().map(this::getTestAction).collect(Collectors.toMap(LifecycleAction::getName, Function.identity()));
|
||||
if (randomBoolean()) {
|
||||
invalidAction = getTestAction(randomFrom("rollover", "delete"));
|
||||
actions.put(invalidAction.getName(), invalidAction);
|
||||
}
|
||||
Map<String, Phase> warmPhase = Collections.singletonMap("warm",
|
||||
new Phase("warm", TimeValue.ZERO, actions));
|
||||
|
||||
if (invalidAction != null) {
|
||||
Exception e = expectThrows(IllegalArgumentException.class,
|
||||
() -> new LifecyclePolicy(lifecycleName, warmPhase));
|
||||
assertThat(e.getMessage(),
|
||||
equalTo("invalid action [" + invalidAction.getName() + "] defined in phase [warm]"));
|
||||
} else {
|
||||
new LifecyclePolicy(lifecycleName, warmPhase);
|
||||
}
|
||||
}
|
||||
|
||||
public void testValidateColdPhase() {
|
||||
LifecycleAction invalidAction = null;
|
||||
Map<String, LifecycleAction> actions = randomSubsetOf(VALID_COLD_ACTIONS)
|
||||
.stream().map(this::getTestAction).collect(Collectors.toMap(LifecycleAction::getName, Function.identity()));
|
||||
if (randomBoolean()) {
|
||||
invalidAction = getTestAction(randomFrom("rollover", "delete", "forcemerge", "shrink"));
|
||||
actions.put(invalidAction.getName(), invalidAction);
|
||||
}
|
||||
Map<String, Phase> coldPhase = Collections.singletonMap("cold",
|
||||
new Phase("cold", TimeValue.ZERO, actions));
|
||||
|
||||
if (invalidAction != null) {
|
||||
Exception e = expectThrows(IllegalArgumentException.class,
|
||||
() -> new LifecyclePolicy(lifecycleName, coldPhase));
|
||||
assertThat(e.getMessage(),
|
||||
equalTo("invalid action [" + invalidAction.getName() + "] defined in phase [cold]"));
|
||||
} else {
|
||||
new LifecyclePolicy(lifecycleName, coldPhase);
|
||||
}
|
||||
}
|
||||
|
||||
public void testValidateDeletePhase() {
|
||||
LifecycleAction invalidAction = null;
|
||||
Map<String, LifecycleAction> actions = VALID_DELETE_ACTIONS
|
||||
.stream().map(this::getTestAction).collect(Collectors.toMap(LifecycleAction::getName, Function.identity()));
|
||||
if (randomBoolean()) {
|
||||
invalidAction = getTestAction(randomFrom("allocate", "rollover", "forcemerge", "shrink"));
|
||||
actions.put(invalidAction.getName(), invalidAction);
|
||||
}
|
||||
Map<String, Phase> deletePhase = Collections.singletonMap("delete",
|
||||
new Phase("delete", TimeValue.ZERO, actions));
|
||||
|
||||
if (invalidAction != null) {
|
||||
Exception e = expectThrows(IllegalArgumentException.class,
|
||||
() -> new LifecyclePolicy(lifecycleName, deletePhase));
|
||||
assertThat(e.getMessage(),
|
||||
equalTo("invalid action [" + invalidAction.getName() + "] defined in phase [delete]"));
|
||||
} else {
|
||||
new LifecyclePolicy(lifecycleName, deletePhase);
|
||||
}
|
||||
}
|
||||
|
||||
private LifecycleAction getTestAction(String actionName) {
|
||||
switch (actionName) {
|
||||
case AllocateAction.NAME:
|
||||
return AllocateActionTests.randomInstance();
|
||||
case DeleteAction.NAME:
|
||||
return new DeleteAction();
|
||||
case ForceMergeAction.NAME:
|
||||
return ForceMergeActionTests.randomInstance();
|
||||
case ReadOnlyAction.NAME:
|
||||
return new ReadOnlyAction();
|
||||
case RolloverAction.NAME:
|
||||
return RolloverActionTests.randomInstance();
|
||||
case ShrinkAction.NAME:
|
||||
return ShrinkActionTests.randomInstance();
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported phase action [" + actionName + "]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.xpack.indexlifecycle;
|
||||
|
||||
import org.elasticsearch.cluster.ClusterModule;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractXContentTestCase;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PhaseTests extends AbstractXContentTestCase<Phase> {
|
||||
private String phaseName;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
phaseName = randomAlphaOfLength(20);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Phase createTestInstance() {
|
||||
TimeValue after = null;
|
||||
if (randomBoolean()) {
|
||||
after = TimeValue.parseTimeValue(randomTimeValue(0, 1000000000, "s", "m", "h", "d"), "test_after");
|
||||
}
|
||||
Map<String, LifecycleAction> actions = Collections.emptyMap();
|
||||
if (randomBoolean()) {
|
||||
actions = Collections.singletonMap(DeleteAction.NAME, new DeleteAction());
|
||||
}
|
||||
return new Phase(phaseName, after, actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Phase doParseInstance(XContentParser parser) {
|
||||
return Phase.parse(parser, phaseName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NamedXContentRegistry xContentRegistry() {
|
||||
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
|
||||
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse));
|
||||
return new NamedXContentRegistry(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsUnknownFields() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testDefaultAfter() {
|
||||
Phase phase = new Phase(randomAlphaOfLength(20), null, Collections.emptyMap());
|
||||
assertEquals(TimeValue.ZERO, phase.getAfter());
|
||||
}
|
||||
}
|
|
@ -38,6 +38,10 @@ public class RolloverActionTests extends AbstractXContentTestCase<RolloverAction
|
|||
|
||||
@Override
|
||||
protected RolloverAction createTestInstance() {
|
||||
return randomInstance();
|
||||
}
|
||||
|
||||
static RolloverAction randomInstance() {
|
||||
ByteSizeUnit maxSizeUnit = randomFrom(ByteSizeUnit.values());
|
||||
ByteSizeValue maxSize = randomBoolean() ? null : new ByteSizeValue(randomNonNegativeLong() / maxSizeUnit.toBytes(1), maxSizeUnit);
|
||||
Long maxDocs = randomBoolean() ? null : randomNonNegativeLong();
|
||||
|
|
|
@ -34,6 +34,10 @@ public class ShrinkActionTests extends AbstractXContentTestCase<ShrinkAction> {
|
|||
|
||||
@Override
|
||||
protected ShrinkAction createTestInstance() {
|
||||
return randomInstance();
|
||||
}
|
||||
|
||||
static ShrinkAction randomInstance() {
|
||||
return new ShrinkAction(randomIntBetween(1, 100));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue