From 036381ffc5630120f1447fa5c6b011c8c84439f2 Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Tue, 14 Aug 2018 09:58:14 -0700 Subject: [PATCH 1/8] migrate allocate action pojo/xcontent to xpack.protocol This splits out the AllocateAction into some parts xpack-protocol so that it can be re-usable in the client. --- .../core/indexlifecycle/AllocateAction.java | 134 ++--------------- .../indexlifecycle/AllocateActionTests.java | 37 +---- .../xpack/indexlifecycle/AllocateAction.java | 142 ++++++++++++++++++ .../indexlifecycle/AllocateActionTests.java | 95 ++++++++++++ 4 files changed, 261 insertions(+), 147 deletions(-) create mode 100644 x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java create mode 100644 x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateActionTests.java diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java index 9cd74353237ac..8f61ef4e0119b 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java @@ -7,76 +7,21 @@ import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import java.io.IOException; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; -public class AllocateAction implements LifecycleAction { - - public static final String NAME = "allocate"; - public static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); - public static final ParseField INCLUDE_FIELD = new ParseField("include"); - public static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); - public static final ParseField REQUIRE_FIELD = new ParseField("require"); - - @SuppressWarnings("unchecked") - private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, - a -> new AllocateAction((Integer) a[0], (Map) a[1], (Map) a[2], (Map) a[3])); - - static { - PARSER.declareInt(ConstructingObjectParser.optionalConstructorArg(), NUMBER_OF_REPLICAS_FIELD); - PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), INCLUDE_FIELD); - PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), EXCLUDE_FIELD); - PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), REQUIRE_FIELD); - } - - private final Integer numberOfReplicas; - private final Map include; - private final Map exclude; - private final Map require; - - public static AllocateAction parse(XContentParser parser) { - return PARSER.apply(parser, null); - } +public class AllocateAction extends org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction implements LifecycleAction { public AllocateAction(Integer numberOfReplicas, Map include, Map exclude, Map require) { - if (include == null) { - this.include = Collections.emptyMap(); - } else { - this.include = include; - } - if (exclude == null) { - this.exclude = Collections.emptyMap(); - } else { - this.exclude = exclude; - } - if (require == null) { - this.require = Collections.emptyMap(); - } else { - this.require = require; - } - if (this.include.isEmpty() && this.exclude.isEmpty() && this.require.isEmpty() && numberOfReplicas == null) { - throw new IllegalArgumentException( - "At least one of " + INCLUDE_FIELD.getPreferredName() + ", " + EXCLUDE_FIELD.getPreferredName() + " or " - + REQUIRE_FIELD.getPreferredName() + "must contain attributes for action " + NAME); - } - if (numberOfReplicas != null && numberOfReplicas < 0) { - throw new IllegalArgumentException("[" + NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0"); - } - this.numberOfReplicas = numberOfReplicas; + super(numberOfReplicas, include, exclude, require); } @SuppressWarnings("unchecked") @@ -85,28 +30,19 @@ public AllocateAction(StreamInput in) throws IOException { (Map) in.readGenericValue()); } - public Integer getNumberOfReplicas() { - return numberOfReplicas; - } - - public Map getInclude() { - return include; - } - - public Map getExclude() { - return exclude; - } - - public Map getRequire() { - return require; + public static AllocateAction parse(XContentParser parser) { + org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction clientAction = + org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction.parse(parser); + return new AllocateAction(clientAction.getNumberOfReplicas(), clientAction.getInclude(), clientAction.getExclude(), + clientAction.getRequire()); } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeOptionalVInt(numberOfReplicas); - out.writeGenericValue(include); - out.writeGenericValue(exclude); - out.writeGenericValue(require); + out.writeOptionalVInt(getNumberOfReplicas()); + out.writeGenericValue(getInclude()); + out.writeGenericValue(getExclude()); + out.writeGenericValue(getRequire()); } @Override @@ -114,19 +50,6 @@ public String getWriteableName() { return NAME; } - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - if (numberOfReplicas != null) { - builder.field(NUMBER_OF_REPLICAS_FIELD.getPreferredName(), numberOfReplicas); - } - builder.field(INCLUDE_FIELD.getPreferredName(), include); - builder.field(EXCLUDE_FIELD.getPreferredName(), exclude); - builder.field(REQUIRE_FIELD.getPreferredName(), require); - builder.endObject(); - return builder; - } - @Override public boolean isSafeAction() { return true; @@ -138,12 +61,12 @@ public List toSteps(Client client, String phase, StepKey nextStepKey) { StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME); Settings.Builder newSettings = Settings.builder(); - if (numberOfReplicas != null) { - newSettings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numberOfReplicas); + if (getNumberOfReplicas() != null) { + newSettings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, getNumberOfReplicas()); } - include.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value)); - exclude.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + key, value)); - require.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + key, value)); + getInclude().forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value)); + getExclude().forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + key, value)); + getRequire().forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + key, value)); UpdateSettingsStep allocateStep = new UpdateSettingsStep(allocateKey, allocationRoutedKey, client, newSettings.build()); AllocationRoutedStep routedCheckStep = new AllocationRoutedStep(allocationRoutedKey, nextStepKey, true); return Arrays.asList(allocateStep, routedCheckStep); @@ -155,29 +78,4 @@ public List toStepKeys(String phase) { StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME); return Arrays.asList(allocateKey, allocationRoutedKey); } - - @Override - public int hashCode() { - return Objects.hash(numberOfReplicas, include, exclude, require); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj.getClass() != getClass()) { - return false; - } - AllocateAction other = (AllocateAction) obj; - return Objects.equals(numberOfReplicas, other.numberOfReplicas) && - Objects.equals(include, other.include) && - Objects.equals(exclude, other.exclude) && - Objects.equals(require, other.require); - } - - @Override - public String toString() { - return Strings.toString(this); - } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java index 147e1b7671c2c..33b2dcffd383d 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java @@ -85,35 +85,6 @@ protected AllocateAction mutateInstance(AllocateAction instance) { return new AllocateAction(numberOfReplicas, include, exclude, require); } - public void testAllMapsNullOrEmpty() { - Map include = randomBoolean() ? null : Collections.emptyMap(); - Map exclude = randomBoolean() ? null : Collections.emptyMap(); - Map require = randomBoolean() ? null : Collections.emptyMap(); - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, - () -> new AllocateAction(null, include, exclude, require)); - assertEquals("At least one of " + AllocateAction.INCLUDE_FIELD.getPreferredName() + ", " - + AllocateAction.EXCLUDE_FIELD.getPreferredName() + " or " + AllocateAction.REQUIRE_FIELD.getPreferredName() - + "must contain attributes for action " + AllocateAction.NAME, exception.getMessage()); - } - - public void testInvalidNumberOfReplicas() { - Map include = randomMap(1, 5); - Map exclude = randomBoolean() ? null : Collections.emptyMap(); - Map require = randomBoolean() ? null : Collections.emptyMap(); - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, - () -> new AllocateAction(randomIntBetween(-1000, -1), include, exclude, require)); - assertEquals("[" + AllocateAction.NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0", exception.getMessage()); - } - - public static Map randomMap(int minEntries, int maxEntries) { - Map map = new HashMap<>(); - int numIncludes = randomIntBetween(minEntries, maxEntries); - for (int i = 0; i < numIncludes; i++) { - map.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); - } - return map; - } - public void testToSteps() { AllocateAction action = createTestInstance(); String phase = randomAlphaOfLengthBetween(1, 10); @@ -143,4 +114,12 @@ public void testToSteps() { assertEquals(nextStepKey, secondStep.getNextStepKey()); } + public static Map randomMap(int minEntries, int maxEntries) { + Map map = new HashMap<>(); + int numIncludes = randomIntBetween(minEntries, maxEntries); + for (int i = 0; i < numIncludes; i++) { + map.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); + } + return map; + } } diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java new file mode 100644 index 0000000000000..cd8305b82cb58 --- /dev/null +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java @@ -0,0 +1,142 @@ +/* + * 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.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContent; +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.Collections; +import java.util.Map; +import java.util.Objects; + +public class AllocateAction implements ToXContentObject { + + public static final String NAME = "allocate"; + public static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); + public static final ParseField INCLUDE_FIELD = new ParseField("include"); + public static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); + public static final ParseField REQUIRE_FIELD = new ParseField("require"); + + @SuppressWarnings("unchecked") + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, + a -> new AllocateAction((Integer) a[0], (Map) a[1], (Map) a[2], (Map) a[3])); + + static { + PARSER.declareInt(ConstructingObjectParser.optionalConstructorArg(), NUMBER_OF_REPLICAS_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), INCLUDE_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), EXCLUDE_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), REQUIRE_FIELD); + } + + private final Integer numberOfReplicas; + private final Map include; + private final Map exclude; + private final Map require; + + public static AllocateAction parse(XContentParser parser) { + return PARSER.apply(parser, null); + } + + public AllocateAction(Integer numberOfReplicas, Map include, Map exclude, Map require) { + if (include == null) { + this.include = Collections.emptyMap(); + } else { + this.include = include; + } + if (exclude == null) { + this.exclude = Collections.emptyMap(); + } else { + this.exclude = exclude; + } + if (require == null) { + this.require = Collections.emptyMap(); + } else { + this.require = require; + } + if (this.include.isEmpty() && this.exclude.isEmpty() && this.require.isEmpty() && numberOfReplicas == null) { + throw new IllegalArgumentException( + "At least one of " + INCLUDE_FIELD.getPreferredName() + ", " + EXCLUDE_FIELD.getPreferredName() + " or " + + REQUIRE_FIELD.getPreferredName() + "must contain attributes for action " + NAME); + } + if (numberOfReplicas != null && numberOfReplicas < 0) { + throw new IllegalArgumentException("[" + NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0"); + } + this.numberOfReplicas = numberOfReplicas; + } + + public Integer getNumberOfReplicas() { + return numberOfReplicas; + } + + public Map getInclude() { + return include; + } + + public Map getExclude() { + return exclude; + } + + public Map getRequire() { + return require; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + builder.startObject(); + if (numberOfReplicas != null) { + builder.field(NUMBER_OF_REPLICAS_FIELD.getPreferredName(), numberOfReplicas); + } + builder.field(INCLUDE_FIELD.getPreferredName(), include); + builder.field(EXCLUDE_FIELD.getPreferredName(), exclude); + builder.field(REQUIRE_FIELD.getPreferredName(), require); + builder.endObject(); + return builder; + } + + @Override + public int hashCode() { + return Objects.hash(numberOfReplicas, include, exclude, require); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + AllocateAction other = (AllocateAction) obj; + return Objects.equals(numberOfReplicas, other.numberOfReplicas) && + Objects.equals(include, other.include) && + Objects.equals(exclude, other.exclude) && + Objects.equals(require, other.require); + } + + @Override + public String toString() { + return Strings.toString(this); + } +} diff --git a/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateActionTests.java b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateActionTests.java new file mode 100644 index 0000000000000..0edfc32710628 --- /dev/null +++ b/x-pack/protocol/src/test/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateActionTests.java @@ -0,0 +1,95 @@ +/* + * 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.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class AllocateActionTests extends AbstractXContentTestCase { + + @Override + protected AllocateAction createTestInstance() { + boolean hasAtLeastOneMap = false; + Map includes; + if (randomBoolean()) { + includes = randomMap(1, 100); + hasAtLeastOneMap = true; + } else { + includes = randomBoolean() ? null : Collections.emptyMap(); + } + Map excludes; + if (randomBoolean()) { + hasAtLeastOneMap = true; + excludes = randomMap(1, 100); + } else { + excludes = randomBoolean() ? null : Collections.emptyMap(); + } + Map requires; + if (hasAtLeastOneMap == false || randomBoolean()) { + requires = randomMap(1, 100); + } else { + requires = randomBoolean() ? null : Collections.emptyMap(); + } + Integer numberOfReplicas = randomBoolean() ? null : randomIntBetween(0, 10); + return new AllocateAction(numberOfReplicas, includes, excludes, requires); + } + + @Override + protected AllocateAction doParseInstance(XContentParser parser) { + return AllocateAction.parse(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } + + public void testAllMapsNullOrEmpty() { + Map include = randomBoolean() ? null : Collections.emptyMap(); + Map exclude = randomBoolean() ? null : Collections.emptyMap(); + Map require = randomBoolean() ? null : Collections.emptyMap(); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> new AllocateAction(null, include, exclude, require)); + assertEquals("At least one of " + AllocateAction.INCLUDE_FIELD.getPreferredName() + ", " + + AllocateAction.EXCLUDE_FIELD.getPreferredName() + " or " + AllocateAction.REQUIRE_FIELD.getPreferredName() + + "must contain attributes for action " + AllocateAction.NAME, exception.getMessage()); + } + + public void testInvalidNumberOfReplicas() { + Map include = randomMap(1, 5); + Map exclude = randomBoolean() ? null : Collections.emptyMap(); + Map require = randomBoolean() ? null : Collections.emptyMap(); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> new AllocateAction(randomIntBetween(-1000, -1), include, exclude, require)); + assertEquals("[" + AllocateAction.NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0", exception.getMessage()); + } + + public static Map randomMap(int minEntries, int maxEntries) { + Map map = new HashMap<>(); + int numIncludes = randomIntBetween(minEntries, maxEntries); + for (int i = 0; i < numIncludes; i++) { + map.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); + } + return map; + } +} From f122484d9bdfdf8c2bc5a5810a949f76d97e0cad Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Wed, 15 Aug 2018 06:19:11 -0700 Subject: [PATCH 2/8] add namedxcontent for client --- .../org/elasticsearch/xpack/core/XPackClientPlugin.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java index dc09766563306..4868ecad90e07 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java @@ -452,7 +452,11 @@ public List getNamedXContent() { 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) + new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse), + // ILM - Client - Lifecycle Actions + new NamedXContentRegistry.Entry(org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction.class, + new ParseField(org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction.NAME), + org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction::parse) ); } From f07ba1161bd3e29c78b4c39753bc871062de9d11 Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Wed, 15 Aug 2018 14:00:50 -0700 Subject: [PATCH 3/8] two AllocateActions to rule them all --- .../core/indexlifecycle/AllocateAction.java | 134 +++++++++++++++--- .../indexlifecycle/AllocateActionTests.java | 37 +++-- 2 files changed, 147 insertions(+), 24 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java index 8f61ef4e0119b..9cd74353237ac 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java @@ -7,21 +7,76 @@ import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; -public class AllocateAction extends org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction implements LifecycleAction { +public class AllocateAction implements LifecycleAction { + + public static final String NAME = "allocate"; + public static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); + public static final ParseField INCLUDE_FIELD = new ParseField("include"); + public static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); + public static final ParseField REQUIRE_FIELD = new ParseField("require"); + + @SuppressWarnings("unchecked") + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, + a -> new AllocateAction((Integer) a[0], (Map) a[1], (Map) a[2], (Map) a[3])); + + static { + PARSER.declareInt(ConstructingObjectParser.optionalConstructorArg(), NUMBER_OF_REPLICAS_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), INCLUDE_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), EXCLUDE_FIELD); + PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), REQUIRE_FIELD); + } + + private final Integer numberOfReplicas; + private final Map include; + private final Map exclude; + private final Map require; + + public static AllocateAction parse(XContentParser parser) { + return PARSER.apply(parser, null); + } public AllocateAction(Integer numberOfReplicas, Map include, Map exclude, Map require) { - super(numberOfReplicas, include, exclude, require); + if (include == null) { + this.include = Collections.emptyMap(); + } else { + this.include = include; + } + if (exclude == null) { + this.exclude = Collections.emptyMap(); + } else { + this.exclude = exclude; + } + if (require == null) { + this.require = Collections.emptyMap(); + } else { + this.require = require; + } + if (this.include.isEmpty() && this.exclude.isEmpty() && this.require.isEmpty() && numberOfReplicas == null) { + throw new IllegalArgumentException( + "At least one of " + INCLUDE_FIELD.getPreferredName() + ", " + EXCLUDE_FIELD.getPreferredName() + " or " + + REQUIRE_FIELD.getPreferredName() + "must contain attributes for action " + NAME); + } + if (numberOfReplicas != null && numberOfReplicas < 0) { + throw new IllegalArgumentException("[" + NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0"); + } + this.numberOfReplicas = numberOfReplicas; } @SuppressWarnings("unchecked") @@ -30,19 +85,28 @@ public AllocateAction(StreamInput in) throws IOException { (Map) in.readGenericValue()); } - public static AllocateAction parse(XContentParser parser) { - org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction clientAction = - org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction.parse(parser); - return new AllocateAction(clientAction.getNumberOfReplicas(), clientAction.getInclude(), clientAction.getExclude(), - clientAction.getRequire()); + public Integer getNumberOfReplicas() { + return numberOfReplicas; + } + + public Map getInclude() { + return include; + } + + public Map getExclude() { + return exclude; + } + + public Map getRequire() { + return require; } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeOptionalVInt(getNumberOfReplicas()); - out.writeGenericValue(getInclude()); - out.writeGenericValue(getExclude()); - out.writeGenericValue(getRequire()); + out.writeOptionalVInt(numberOfReplicas); + out.writeGenericValue(include); + out.writeGenericValue(exclude); + out.writeGenericValue(require); } @Override @@ -50,6 +114,19 @@ public String getWriteableName() { return NAME; } + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + if (numberOfReplicas != null) { + builder.field(NUMBER_OF_REPLICAS_FIELD.getPreferredName(), numberOfReplicas); + } + builder.field(INCLUDE_FIELD.getPreferredName(), include); + builder.field(EXCLUDE_FIELD.getPreferredName(), exclude); + builder.field(REQUIRE_FIELD.getPreferredName(), require); + builder.endObject(); + return builder; + } + @Override public boolean isSafeAction() { return true; @@ -61,12 +138,12 @@ public List toSteps(Client client, String phase, StepKey nextStepKey) { StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME); Settings.Builder newSettings = Settings.builder(); - if (getNumberOfReplicas() != null) { - newSettings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, getNumberOfReplicas()); + if (numberOfReplicas != null) { + newSettings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numberOfReplicas); } - getInclude().forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value)); - getExclude().forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + key, value)); - getRequire().forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + key, value)); + include.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value)); + exclude.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + key, value)); + require.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + key, value)); UpdateSettingsStep allocateStep = new UpdateSettingsStep(allocateKey, allocationRoutedKey, client, newSettings.build()); AllocationRoutedStep routedCheckStep = new AllocationRoutedStep(allocationRoutedKey, nextStepKey, true); return Arrays.asList(allocateStep, routedCheckStep); @@ -78,4 +155,29 @@ public List toStepKeys(String phase) { StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME); return Arrays.asList(allocateKey, allocationRoutedKey); } + + @Override + public int hashCode() { + return Objects.hash(numberOfReplicas, include, exclude, require); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj.getClass() != getClass()) { + return false; + } + AllocateAction other = (AllocateAction) obj; + return Objects.equals(numberOfReplicas, other.numberOfReplicas) && + Objects.equals(include, other.include) && + Objects.equals(exclude, other.exclude) && + Objects.equals(require, other.require); + } + + @Override + public String toString() { + return Strings.toString(this); + } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java index 6afaa9cb23dbd..dfe2afc5d19ef 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java @@ -90,6 +90,35 @@ protected AllocateAction mutateInstance(AllocateAction instance) { return new AllocateAction(numberOfReplicas, include, exclude, require); } + public void testAllMapsNullOrEmpty() { + Map include = randomBoolean() ? null : Collections.emptyMap(); + Map exclude = randomBoolean() ? null : Collections.emptyMap(); + Map require = randomBoolean() ? null : Collections.emptyMap(); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> new AllocateAction(null, include, exclude, require)); + assertEquals("At least one of " + AllocateAction.INCLUDE_FIELD.getPreferredName() + ", " + + AllocateAction.EXCLUDE_FIELD.getPreferredName() + " or " + AllocateAction.REQUIRE_FIELD.getPreferredName() + + "must contain attributes for action " + AllocateAction.NAME, exception.getMessage()); + } + + public void testInvalidNumberOfReplicas() { + Map include = randomMap(1, 5); + Map exclude = randomBoolean() ? null : Collections.emptyMap(); + Map require = randomBoolean() ? null : Collections.emptyMap(); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> new AllocateAction(randomIntBetween(-1000, -1), include, exclude, require)); + assertEquals("[" + AllocateAction.NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0", exception.getMessage()); + } + + public static Map randomMap(int minEntries, int maxEntries) { + Map map = new HashMap<>(); + int numIncludes = randomIntBetween(minEntries, maxEntries); + for (int i = 0; i < numIncludes; i++) { + map.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); + } + return map; + } + public void testToSteps() { AllocateAction action = createTestInstance(); String phase = randomAlphaOfLengthBetween(1, 10); @@ -119,12 +148,4 @@ public void testToSteps() { assertEquals(nextStepKey, secondStep.getNextStepKey()); } - public static Map randomMap(int minEntries, int maxEntries) { - Map map = new HashMap<>(); - int numIncludes = randomIntBetween(minEntries, maxEntries); - for (int i = 0; i < numIncludes; i++) { - map.put(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); - } - return map; - } } From 24d99c3900daa0d62a8b4022d5a7c67e803857b3 Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Wed, 15 Aug 2018 16:18:45 -0700 Subject: [PATCH 4/8] make parse fields private --- .../protocol/xpack/indexlifecycle/AllocateAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java index cd8305b82cb58..d7d22a58b3027 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java @@ -34,10 +34,10 @@ public class AllocateAction implements ToXContentObject { public static final String NAME = "allocate"; - public static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); - public static final ParseField INCLUDE_FIELD = new ParseField("include"); - public static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); - public static final ParseField REQUIRE_FIELD = new ParseField("require"); + private static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); + private static final ParseField INCLUDE_FIELD = new ParseField("include"); + private static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); + private static final ParseField REQUIRE_FIELD = new ParseField("require"); @SuppressWarnings("unchecked") private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, From 2ce7732c14895861155fe5617f167ba56499c1e5 Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Wed, 15 Aug 2018 19:32:16 -0700 Subject: [PATCH 5/8] make package-private fields --- .../protocol/xpack/indexlifecycle/AllocateAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java index d7d22a58b3027..60c5f7ebe67e5 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java @@ -34,10 +34,10 @@ public class AllocateAction implements ToXContentObject { public static final String NAME = "allocate"; - private static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); - private static final ParseField INCLUDE_FIELD = new ParseField("include"); - private static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); - private static final ParseField REQUIRE_FIELD = new ParseField("require"); + static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); + static final ParseField INCLUDE_FIELD = new ParseField("include"); + static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); + static final ParseField REQUIRE_FIELD = new ParseField("require"); @SuppressWarnings("unchecked") private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, From 40220a00577ed1bd7bea7006d24d54eedb8c466e Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Thu, 16 Aug 2018 06:27:15 -0700 Subject: [PATCH 6/8] add interface --- .../xpack/core/XPackClientPlugin.java | 2 +- .../xpack/indexlifecycle/AllocateAction.java | 2 +- .../xpack/indexlifecycle/LifecycleAction.java | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java index 4868ecad90e07..b5a7fbfcc12ef 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java @@ -454,7 +454,7 @@ public List getNamedXContent() { 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 - new NamedXContentRegistry.Entry(org.elasticsearch.protocol.xpack.indexlifecycle.AllocateAction.class, + 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) ); diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java index 60c5f7ebe67e5..8f1696d261cbd 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java @@ -31,7 +31,7 @@ import java.util.Map; import java.util.Objects; -public class AllocateAction 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"); diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java new file mode 100644 index 0000000000000..c99690a4a8733 --- /dev/null +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java @@ -0,0 +1,28 @@ +/* + * 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.xcontent.NamedXContentRegistry; + +/** + * empty interface to categorize client-side lifecycle actions + * for the {@link NamedXContentRegistry} + */ +public interface LifecycleAction { +} From 4c918d2a958e6c0e33e4496a99cd0edd9c9ee95d Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Thu, 16 Aug 2018 06:37:18 -0700 Subject: [PATCH 7/8] make into a class --- .../protocol/xpack/indexlifecycle/LifecycleAction.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java index c99690a4a8733..8a9761cf7e206 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java @@ -21,8 +21,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry; /** - * empty interface to categorize client-side lifecycle actions - * for the {@link NamedXContentRegistry} + * Parent class for the client-side ilm actions for the {@link NamedXContentRegistry} */ -public interface LifecycleAction { +public class LifecycleAction { } From 457eb9f72ba9c9c67f3790bc15932c955bafb82b Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Thu, 16 Aug 2018 08:40:22 -0700 Subject: [PATCH 8/8] fix --- .../protocol/xpack/indexlifecycle/AllocateAction.java | 2 +- .../protocol/xpack/indexlifecycle/LifecycleAction.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java index 8f1696d261cbd..7bbd67fa414cf 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/AllocateAction.java @@ -31,7 +31,7 @@ import java.util.Map; import java.util.Objects; -public class AllocateAction implements LifecycleAction, ToXContentObject { +public class AllocateAction extends LifecycleAction implements ToXContentObject { public static final String NAME = "allocate"; static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); diff --git a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java index 8a9761cf7e206..8765edabd228a 100644 --- a/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java +++ b/x-pack/protocol/src/main/java/org/elasticsearch/protocol/xpack/indexlifecycle/LifecycleAction.java @@ -18,10 +18,8 @@ */ package org.elasticsearch.protocol.xpack.indexlifecycle; -import org.elasticsearch.common.xcontent.NamedXContentRegistry; - /** - * Parent class for the client-side ilm actions for the {@link NamedXContentRegistry} + * Marker interface for index lifecycle management actions */ public class LifecycleAction { }