diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 90b8aa8423f..63133dd851b 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -37,8 +37,6 @@ - - diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequest.java index dcc45ab21b9..4ec729bbc53 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequest.java @@ -19,20 +19,15 @@ package org.elasticsearch.action.admin.cluster.reroute; -import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.cluster.routing.allocation.command.AllocationCommand; -import org.elasticsearch.cluster.routing.allocation.command.AllocationCommandRegistry; import org.elasticsearch.cluster.routing.allocation.command.AllocationCommands; -import org.elasticsearch.common.ParseFieldMatcher; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.XContentHelper; -import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Objects; /** * Request to submit cluster reroute allocation commands @@ -109,8 +104,8 @@ public class ClusterRerouteRequest extends AcknowledgedRequest { - +public class ClusterRerouteRequestBuilder + extends AcknowledgedRequestBuilder { public ClusterRerouteRequestBuilder(ElasticsearchClient client, ClusterRerouteAction action) { super(client, action, new ClusterRerouteRequest()); } @@ -68,12 +67,4 @@ public class ClusterRerouteRequestBuilder extends AcknowledgedRequestBuilder { diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/AllocationCommands.java b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/AllocationCommands.java index ca0eab6e33b..10ba3f55944 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/AllocationCommands.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/AllocationCommands.java @@ -20,12 +20,12 @@ package org.elasticsearch.cluster.routing.allocation.command; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.action.support.ToXContentToBytes; import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; import org.elasticsearch.cluster.routing.allocation.RoutingExplanations; import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -33,12 +33,13 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * A simple {@link AllocationCommand} composite managing several * {@link AllocationCommand} implementations */ -public class AllocationCommands { +public class AllocationCommands extends ToXContentToBytes { private final List commands = new ArrayList<>(); /** @@ -171,21 +172,31 @@ public class AllocationCommands { return commands; } - /** - * Writes {@link AllocationCommands} to a {@link XContentBuilder} - * - * @param commands {@link AllocationCommands} to write - * @param builder {@link XContentBuilder} to use - * @param params Parameters to use for building - * @throws IOException if something bad happens while building the content - */ - public static void toXContent(AllocationCommands commands, XContentBuilder builder, ToXContent.Params params) throws IOException { + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startArray("commands"); - for (AllocationCommand command : commands.commands) { + for (AllocationCommand command : commands) { builder.startObject(); builder.field(command.name(), command); builder.endObject(); } builder.endArray(); + return builder; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + AllocationCommands other = (AllocationCommands) obj; + // Override equals and hashCode for testing + return Objects.equals(commands, other.commands); + } + + @Override + public int hashCode() { + // Override equals and hashCode for testing + return Objects.hashCode(commands); } } diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/BasePrimaryAllocationCommand.java b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/BasePrimaryAllocationCommand.java index 0013061e8ea..2eb3af9d4f9 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/BasePrimaryAllocationCommand.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/BasePrimaryAllocationCommand.java @@ -83,4 +83,18 @@ public abstract class BasePrimaryAllocationCommand extends AbstractAllocateAlloc protected void extraXContent(XContentBuilder builder) throws IOException { builder.field(ACCEPT_DATA_LOSS_FIELD, acceptDataLoss); } + + @Override + public boolean equals(Object obj) { + if (false == super.equals(obj)) { + return false; + } + BasePrimaryAllocationCommand other = (BasePrimaryAllocationCommand) obj; + return acceptDataLoss == other.acceptDataLoss; + } + + @Override + public int hashCode() { + return 31 * super.hashCode() + Boolean.hashCode(acceptDataLoss); + } } diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/CancelAllocationCommand.java b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/CancelAllocationCommand.java index 60b0842b273..9adb3e30708 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/CancelAllocationCommand.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/CancelAllocationCommand.java @@ -35,6 +35,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Objects; import static org.elasticsearch.cluster.routing.ShardRoutingState.RELOCATING; @@ -240,4 +241,23 @@ public class CancelAllocationCommand implements AllocationCommand { } return new CancelAllocationCommand(index, shardId, nodeId, allowPrimary); } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + CancelAllocationCommand other = (CancelAllocationCommand) obj; + // Override equals and hashCode for testing + return Objects.equals(index, other.index) && + Objects.equals(shardId, other.shardId) && + Objects.equals(node, other.node) && + Objects.equals(allowPrimary, other.allowPrimary); + } + + @Override + public int hashCode() { + // Override equals and hashCode for testing + return Objects.hash(index, shardId, node, allowPrimary); + } } diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/MoveAllocationCommand.java b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/MoveAllocationCommand.java index a2e1a54e515..69bd8f0eeca 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/MoveAllocationCommand.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/allocation/command/MoveAllocationCommand.java @@ -34,6 +34,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Objects; /** * A command that moves a shard from a specific node to another node.
@@ -195,4 +196,23 @@ public class MoveAllocationCommand implements AllocationCommand { } return new MoveAllocationCommand(index, shardId, fromNode, toNode); } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + MoveAllocationCommand other = (MoveAllocationCommand) obj; + // Override equals and hashCode for testing + return Objects.equals(index, other.index) && + Objects.equals(shardId, other.shardId) && + Objects.equals(fromNode, other.fromNode) && + Objects.equals(toNode, other.toNode); + } + + @Override + public int hashCode() { + // Override equals and hashCode for testing + return Objects.hash(index, shardId, fromNode, toNode); + } } diff --git a/core/src/main/java/org/elasticsearch/common/network/NetworkModule.java b/core/src/main/java/org/elasticsearch/common/network/NetworkModule.java index eebd8544bf8..201e5297511 100644 --- a/core/src/main/java/org/elasticsearch/common/network/NetworkModule.java +++ b/core/src/main/java/org/elasticsearch/common/network/NetworkModule.java @@ -19,9 +19,6 @@ package org.elasticsearch.common.network; -import java.util.Arrays; -import java.util.List; - import org.elasticsearch.action.support.replication.ReplicationTask; import org.elasticsearch.client.transport.TransportClientNodesService; import org.elasticsearch.client.transport.support.TransportProxyClient; @@ -68,6 +65,12 @@ import org.elasticsearch.rest.action.admin.cluster.snapshots.restore.RestRestore import org.elasticsearch.rest.action.admin.cluster.snapshots.status.RestSnapshotsStatusAction; import org.elasticsearch.rest.action.admin.cluster.state.RestClusterStateAction; import org.elasticsearch.rest.action.admin.cluster.stats.RestClusterStatsAction; +import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteSearchTemplateAction; +import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteStoredScriptAction; +import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetSearchTemplateAction; +import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetStoredScriptAction; +import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutSearchTemplateAction; +import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutStoredScriptAction; import org.elasticsearch.rest.action.admin.cluster.tasks.RestPendingClusterTasksAction; import org.elasticsearch.rest.action.admin.indices.alias.RestIndicesAliasesAction; import org.elasticsearch.rest.action.admin.indices.alias.delete.RestIndexDeleteAliasesAction; @@ -134,17 +137,11 @@ import org.elasticsearch.rest.action.ingest.RestGetPipelineAction; import org.elasticsearch.rest.action.ingest.RestPutPipelineAction; import org.elasticsearch.rest.action.ingest.RestSimulatePipelineAction; import org.elasticsearch.rest.action.main.RestMainAction; -import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteStoredScriptAction; -import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetStoredScriptAction; -import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutStoredScriptAction; import org.elasticsearch.rest.action.search.RestClearScrollAction; import org.elasticsearch.rest.action.search.RestMultiSearchAction; import org.elasticsearch.rest.action.search.RestSearchAction; import org.elasticsearch.rest.action.search.RestSearchScrollAction; import org.elasticsearch.rest.action.suggest.RestSuggestAction; -import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteSearchTemplateAction; -import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetSearchTemplateAction; -import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutSearchTemplateAction; import org.elasticsearch.rest.action.termvectors.RestMultiTermVectorsAction; import org.elasticsearch.rest.action.termvectors.RestTermVectorsAction; import org.elasticsearch.rest.action.update.RestUpdateAction; @@ -154,6 +151,9 @@ import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.local.LocalTransport; import org.elasticsearch.transport.netty.NettyTransport; +import java.util.Arrays; +import java.util.List; + /** * A module to handle registering and binding all network related classes. */ @@ -397,7 +397,7 @@ public class NetworkModule extends AbstractModule { * @param commandName the names under which the command should be parsed. The {@link ParseField#getPreferredName()} is special because * it is the name under which the command's reader is registered. */ - public void registerAllocationCommand(Writeable.Reader reader, AllocationCommand.Parser parser, + private void registerAllocationCommand(Writeable.Reader reader, AllocationCommand.Parser parser, ParseField commandName) { allocationCommandRegistry.register(parser, commandName); namedWriteableRegistry.register(AllocationCommand.class, commandName.getPreferredName(), reader); diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/reroute/RestClusterRerouteAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/reroute/RestClusterRerouteAction.java index b34c6726c09..a06466137a5 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/reroute/RestClusterRerouteAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/reroute/RestClusterRerouteAction.java @@ -25,12 +25,20 @@ import org.elasticsearch.client.Client; import org.elasticsearch.client.Requests; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.routing.allocation.command.AllocationCommandRegistry; +import org.elasticsearch.cluster.routing.allocation.command.AllocationCommands; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.ParseFieldMatcher; +import org.elasticsearch.common.ParseFieldMatcherSupplier; import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsFilter; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser.ValueType; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; @@ -43,12 +51,17 @@ import java.util.EnumSet; /** */ public class RestClusterRerouteAction extends BaseRestHandler { + private static final ObjectParser PARSER = new ObjectParser<>("cluster_reroute"); + static { + PARSER.declareField((p, v, c) -> v.commands(AllocationCommands.fromXContent(p, c.getParseFieldMatcher(), c.registry)), + new ParseField("commands"), ValueType.OBJECT_ARRAY); + PARSER.declareBoolean(ClusterRerouteRequest::dryRun, new ParseField("dry_run")); + } - private final SettingsFilter settingsFilter; - - private static String DEFAULT_METRICS = Strings + private static final String DEFAULT_METRICS = Strings .arrayToCommaDelimitedString(EnumSet.complementOf(EnumSet.of(ClusterState.Metric.METADATA)).toArray()); + private final SettingsFilter settingsFilter; private final AllocationCommandRegistry registry; @Inject @@ -62,16 +75,7 @@ public class RestClusterRerouteAction extends BaseRestHandler { @Override public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) throws Exception { - final ClusterRerouteRequest clusterRerouteRequest = Requests.clusterRerouteRequest(); - clusterRerouteRequest.dryRun(request.paramAsBoolean("dry_run", clusterRerouteRequest.dryRun())); - clusterRerouteRequest.setRetryFailed(request.paramAsBoolean("retry_failed", clusterRerouteRequest.isRetryFailed())); - clusterRerouteRequest.explain(request.paramAsBoolean("explain", clusterRerouteRequest.explain())); - clusterRerouteRequest.timeout(request.paramAsTime("timeout", clusterRerouteRequest.timeout())); - clusterRerouteRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterRerouteRequest.masterNodeTimeout())); - if (request.hasContent()) { - clusterRerouteRequest.source(request.content(), registry, parseFieldMatcher); - } - + ClusterRerouteRequest clusterRerouteRequest = createRequest(request, registry, parseFieldMatcher); client.admin().cluster().reroute(clusterRerouteRequest, new AcknowledgedRestListener(channel) { @Override protected void addCustomFields(XContentBuilder builder, ClusterRerouteResponse response) throws IOException { @@ -90,4 +94,35 @@ public class RestClusterRerouteAction extends BaseRestHandler { } }); } + + public static ClusterRerouteRequest createRequest(RestRequest request, AllocationCommandRegistry registry, + ParseFieldMatcher parseFieldMatcher) throws IOException { + ClusterRerouteRequest clusterRerouteRequest = Requests.clusterRerouteRequest(); + clusterRerouteRequest.dryRun(request.paramAsBoolean("dry_run", clusterRerouteRequest.dryRun())); + clusterRerouteRequest.explain(request.paramAsBoolean("explain", clusterRerouteRequest.explain())); + clusterRerouteRequest.timeout(request.paramAsTime("timeout", clusterRerouteRequest.timeout())); + clusterRerouteRequest.setRetryFailed(request.paramAsBoolean("retry_failed", clusterRerouteRequest.isRetryFailed())); + clusterRerouteRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterRerouteRequest.masterNodeTimeout())); + if (request.hasContent()) { + try (XContentParser parser = XContentHelper.createParser(request.content())) { + PARSER.parse(parser, clusterRerouteRequest, new ParseContext(registry, parseFieldMatcher)); + } + } + return clusterRerouteRequest; + } + + private static class ParseContext implements ParseFieldMatcherSupplier { + private final AllocationCommandRegistry registry; + private final ParseFieldMatcher parseFieldMatcher; + + private ParseContext(AllocationCommandRegistry registry, ParseFieldMatcher parseFieldMatcher) { + this.registry = registry; + this.parseFieldMatcher = parseFieldMatcher; + } + + @Override + public ParseFieldMatcher getParseFieldMatcher() { + return parseFieldMatcher; + } + } } diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequestTests.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequestTests.java new file mode 100644 index 00000000000..06ca3a4f869 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteRequestTests.java @@ -0,0 +1,214 @@ +/* + * 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.action.admin.cluster.reroute; + +import org.elasticsearch.action.support.master.AcknowledgedRequest; +import org.elasticsearch.action.support.master.MasterNodeRequest; +import org.elasticsearch.cluster.routing.allocation.command.AllocateEmptyPrimaryAllocationCommand; +import org.elasticsearch.cluster.routing.allocation.command.AllocateReplicaAllocationCommand; +import org.elasticsearch.cluster.routing.allocation.command.AllocateStalePrimaryAllocationCommand; +import org.elasticsearch.cluster.routing.allocation.command.AllocationCommand; +import org.elasticsearch.cluster.routing.allocation.command.AllocationCommandRegistry; +import org.elasticsearch.cluster.routing.allocation.command.CancelAllocationCommand; +import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand; +import org.elasticsearch.common.ParseFieldMatcher; +import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.network.NetworkModule; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.action.admin.cluster.reroute.RestClusterRerouteAction; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestRequest; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.unmodifiableList; +import static org.elasticsearch.common.unit.TimeValue.timeValueMillis; + +/** + * Test for serialization and parsing of {@link ClusterRerouteRequest} and its commands. See the superclass for, well, everything. + */ +public class ClusterRerouteRequestTests extends ESTestCase { + private static final int ROUNDS = 30; + private final List> RANDOM_COMMAND_GENERATORS = unmodifiableList(Arrays.asList( + () -> new AllocateReplicaAllocationCommand(randomAsciiOfLengthBetween(2, 10), between(0, 1000), + randomAsciiOfLengthBetween(2, 10)), + () -> new AllocateEmptyPrimaryAllocationCommand(randomAsciiOfLengthBetween(2, 10), between(0, 1000), + randomAsciiOfLengthBetween(2, 10), randomBoolean()), + () -> new AllocateStalePrimaryAllocationCommand(randomAsciiOfLengthBetween(2, 10), between(0, 1000), + randomAsciiOfLengthBetween(2, 10), randomBoolean()), + () -> new CancelAllocationCommand(randomAsciiOfLengthBetween(2, 10), between(0, 1000), + randomAsciiOfLengthBetween(2, 10), randomBoolean()), + () -> new MoveAllocationCommand(randomAsciiOfLengthBetween(2, 10), between(0, 1000), + randomAsciiOfLengthBetween(2, 10), randomAsciiOfLengthBetween(2, 10)))); + private final NamedWriteableRegistry namedWriteableRegistry; + private final AllocationCommandRegistry allocationCommandRegistry; + + public ClusterRerouteRequestTests() { + namedWriteableRegistry = new NamedWriteableRegistry(); + allocationCommandRegistry = new NetworkModule(null, null, true, namedWriteableRegistry).getAllocationCommandRegistry(); + } + + private ClusterRerouteRequest randomRequest() { + ClusterRerouteRequest request = new ClusterRerouteRequest(); + int commands = between(0, 10); + for (int i = 0; i < commands; i++) { + request.add(randomFrom(RANDOM_COMMAND_GENERATORS).get()); + } + request.dryRun(randomBoolean()); + request.explain(randomBoolean()); + request.setRetryFailed(randomBoolean()); + return request; + } + + public void testEqualsAndHashCode() { + for (int round = 0; round < ROUNDS; round++) { + ClusterRerouteRequest request = randomRequest(); + assertEquals(request, request); + assertEquals(request.hashCode(), request.hashCode()); + + ClusterRerouteRequest copy = new ClusterRerouteRequest() + .add(request.getCommands().commands().toArray(new AllocationCommand[0])); + copy.dryRun(request.dryRun()).explain(request.explain()).timeout(request.timeout()).setRetryFailed(request.isRetryFailed()); + copy.masterNodeTimeout(request.masterNodeTimeout()); + assertEquals(request, copy); + assertEquals(copy, request); // Commutative + assertEquals(request.hashCode(), copy.hashCode()); + + // Changing dryRun makes requests not equal + copy.dryRun(!copy.dryRun()); + assertNotEquals(request, copy); + assertNotEquals(request.hashCode(), copy.hashCode()); + copy.dryRun(!copy.dryRun()); + assertEquals(request, copy); + assertEquals(request.hashCode(), copy.hashCode()); + + // Changing explain makes requests not equal + copy.explain(!copy.explain()); + assertNotEquals(request, copy); + assertNotEquals(request.hashCode(), copy.hashCode()); + copy.explain(!copy.explain()); + assertEquals(request, copy); + assertEquals(request.hashCode(), copy.hashCode()); + + // Changing timeout makes requests not equal + copy.timeout(timeValueMillis(request.timeout().millis() + 1)); + assertNotEquals(request, copy); + assertNotEquals(request.hashCode(), copy.hashCode()); + copy.timeout(request.timeout()); + assertEquals(request, copy); + assertEquals(request.hashCode(), copy.hashCode()); + + // Changing masterNodeTime makes requests not equal + copy.masterNodeTimeout(timeValueMillis(request.masterNodeTimeout().millis() + 1)); + assertNotEquals(request, copy); + assertNotEquals(request.hashCode(), copy.hashCode()); + copy.masterNodeTimeout(request.masterNodeTimeout()); + assertEquals(request, copy); + assertEquals(request.hashCode(), copy.hashCode()); + + // Changing commands makes requests not equal + copy.add(randomFrom(RANDOM_COMMAND_GENERATORS).get()); + assertNotEquals(request, copy); + // Can't check hashCode because we can't be sure that changing commands changes the hashCode. It usually does but might not. + } + } + + public void testSerialization() throws IOException { + for (int round = 0; round < ROUNDS; round++) { + ClusterRerouteRequest request = randomRequest(); + ClusterRerouteRequest copy = roundTripThroughBytes(request); + assertEquals(request, copy); + assertEquals(request.hashCode(), copy.hashCode()); + assertNotSame(request, copy); + } + } + + public void testParsing() throws IOException { + for (int round = 0; round < ROUNDS; round++) { + ClusterRerouteRequest request = randomRequest(); + ClusterRerouteRequest copy = roundTripThroughRestRequest(request); + assertEquals(request, copy); + assertEquals(request.hashCode(), copy.hashCode()); + assertNotSame(request, copy); + } + } + + private ClusterRerouteRequest roundTripThroughBytes(ClusterRerouteRequest original) throws IOException { + try (BytesStreamOutput output = new BytesStreamOutput()) { + original.writeTo(output); + try (StreamInput in = new NamedWriteableAwareStreamInput(StreamInput.wrap(output.bytes()), namedWriteableRegistry)) { + ClusterRerouteRequest copy = new ClusterRerouteRequest(); + copy.readFrom(in); + return copy; + } + } + } + + private ClusterRerouteRequest roundTripThroughRestRequest(ClusterRerouteRequest original) throws IOException { + RestRequest restRequest = toRestRequest(original); + return RestClusterRerouteAction.createRequest(restRequest, allocationCommandRegistry, ParseFieldMatcher.STRICT); + } + + private static RestRequest toRestRequest(ClusterRerouteRequest original) throws IOException { + Map params = new HashMap<>(); + XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); + boolean hasBody = false; + if (randomBoolean()) { + builder.prettyPrint(); + } + builder.startObject(); + if (randomBoolean()) { + params.put("dry_run", Boolean.toString(original.dryRun())); + } else { + hasBody = true; + builder.field("dry_run", original.dryRun()); + } + params.put("explain", Boolean.toString(original.explain())); + if (false == original.timeout().equals(AcknowledgedRequest.DEFAULT_ACK_TIMEOUT) || randomBoolean()) { + params.put("timeout", original.timeout().toString()); + } + if (original.isRetryFailed() || randomBoolean()) { + params.put("retry_failed", Boolean.toString(original.isRetryFailed())); + } + if (false == original.masterNodeTimeout().equals(MasterNodeRequest.DEFAULT_MASTER_NODE_TIMEOUT) || randomBoolean()) { + params.put("master_timeout", original.masterNodeTimeout().toString()); + } + if (original.getCommands() != null) { + hasBody = true; + original.getCommands().toXContent(builder, ToXContent.EMPTY_PARAMS); + } + builder.endObject(); + + return new FakeRestRequest(emptyMap(), params, hasBody ? builder.bytes() : null); + } +} diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteTests.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteTests.java index 927f572487c..c11bf0b9ca6 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteTests.java +++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteTests.java @@ -59,7 +59,7 @@ public class ClusterRerouteTests extends ESAllocationTestCase { req.setRetryFailed(randomBoolean()); req.dryRun(randomBoolean()); req.explain(randomBoolean()); - req.commands(new AllocateEmptyPrimaryAllocationCommand("foo", 1, "bar", randomBoolean())); + req.add(new AllocateEmptyPrimaryAllocationCommand("foo", 1, "bar", randomBoolean())); req.timeout(TimeValue.timeValueMillis(randomIntBetween(0, 100))); BytesStreamOutput out = new BytesStreamOutput(); req.writeTo(out); diff --git a/docs/reference/migration/migrate_5_0/allocation.asciidoc b/docs/reference/migration/migrate_5_0/allocation.asciidoc index 1e095831381..d7affd8ff95 100644 --- a/docs/reference/migration/migrate_5_0/allocation.asciidoc +++ b/docs/reference/migration/migrate_5_0/allocation.asciidoc @@ -39,6 +39,11 @@ command corresponds to the old `allocate` command with `allow_primary` set to false. The new `allocate_empty_primary` command corresponds to the old `allocate` command with `allow_primary` set to true. +==== Custom Reroute Commands + +Elasticsearch no longer supports plugins registering custom allocation +commands. It was unused and hopefully unneeded. + ==== `index.shared_filesystem.recover_on_any_node` changes The behavior of `index.shared_filesystem.recover_on_any_node: true` has been