Search in sources :

Example 1 with RerouteExplanation

use of org.opensearch.cluster.routing.allocation.RerouteExplanation in project OpenSearch by opensearch-project.

the class CancelAllocationCommand method execute.

@Override
public RerouteExplanation execute(RoutingAllocation allocation, boolean explain) {
    DiscoveryNode discoNode = allocation.nodes().resolveNode(node);
    ShardRouting shardRouting = null;
    RoutingNodes routingNodes = allocation.routingNodes();
    RoutingNode routingNode = routingNodes.node(discoNode.getId());
    IndexMetadata indexMetadata = null;
    if (routingNode != null) {
        indexMetadata = allocation.metadata().index(index());
        if (indexMetadata == null) {
            throw new IndexNotFoundException(index());
        }
        ShardId shardId = new ShardId(indexMetadata.getIndex(), shardId());
        shardRouting = routingNode.getByShardId(shardId);
    }
    if (shardRouting == null) {
        if (explain) {
            return new RerouteExplanation(this, allocation.decision(Decision.NO, "cancel_allocation_command", "can't cancel " + shardId + ", failed to find it on node " + discoNode));
        }
        throw new IllegalArgumentException("[cancel_allocation] can't cancel " + shardId + ", failed to find it on node " + discoNode);
    }
    if (shardRouting.primary() && allowPrimary == false) {
        if ((shardRouting.initializing() && shardRouting.relocatingNodeId() != null) == false) {
            // only allow cancelling initializing shard of primary relocation without allowPrimary flag
            if (explain) {
                return new RerouteExplanation(this, allocation.decision(Decision.NO, "cancel_allocation_command", "can't cancel " + shardId + " on node " + discoNode + ", shard is primary and " + shardRouting.state().name().toLowerCase(Locale.ROOT)));
            }
            throw new IllegalArgumentException("[cancel_allocation] can't cancel " + shardId + " on node " + discoNode + ", shard is primary and " + shardRouting.state().name().toLowerCase(Locale.ROOT));
        }
    }
    routingNodes.failShard(LogManager.getLogger(CancelAllocationCommand.class), shardRouting, new UnassignedInfo(UnassignedInfo.Reason.REROUTE_CANCELLED, null), indexMetadata, allocation.changes());
    // TODO: We don't have to remove a cancelled shard from in-sync set once we have a strict resync implementation.
    allocation.removeAllocationId(shardRouting);
    return new RerouteExplanation(this, allocation.decision(Decision.YES, "cancel_allocation_command", "shard " + shardId + " on node " + discoNode + " can be cancelled"));
}
Also used : ShardId(org.opensearch.index.shard.ShardId) DiscoveryNode(org.opensearch.cluster.node.DiscoveryNode) RoutingNode(org.opensearch.cluster.routing.RoutingNode) RoutingNodes(org.opensearch.cluster.routing.RoutingNodes) UnassignedInfo(org.opensearch.cluster.routing.UnassignedInfo) IndexNotFoundException(org.opensearch.index.IndexNotFoundException) RerouteExplanation(org.opensearch.cluster.routing.allocation.RerouteExplanation) ShardRouting(org.opensearch.cluster.routing.ShardRouting) IndexMetadata(org.opensearch.cluster.metadata.IndexMetadata)

Example 2 with RerouteExplanation

use of org.opensearch.cluster.routing.allocation.RerouteExplanation in project OpenSearch by opensearch-project.

the class MoveAllocationCommand method execute.

@Override
public RerouteExplanation execute(RoutingAllocation allocation, boolean explain) {
    DiscoveryNode fromDiscoNode = allocation.nodes().resolveNode(fromNode);
    DiscoveryNode toDiscoNode = allocation.nodes().resolveNode(toNode);
    Decision decision = null;
    boolean found = false;
    RoutingNode fromRoutingNode = allocation.routingNodes().node(fromDiscoNode.getId());
    if (fromRoutingNode == null && !fromDiscoNode.isDataNode()) {
        throw new IllegalArgumentException("[move_allocation] can't move [" + index + "][" + shardId + "] from " + fromDiscoNode + " to " + toDiscoNode + ": source [" + fromDiscoNode.getName() + "] is not a data node.");
    }
    RoutingNode toRoutingNode = allocation.routingNodes().node(toDiscoNode.getId());
    if (toRoutingNode == null && !toDiscoNode.isDataNode()) {
        throw new IllegalArgumentException("[move_allocation] can't move [" + index + "][" + shardId + "] from " + fromDiscoNode + " to " + toDiscoNode + ": source [" + toDiscoNode.getName() + "] is not a data node.");
    }
    for (ShardRouting shardRouting : fromRoutingNode) {
        if (!shardRouting.shardId().getIndexName().equals(index)) {
            continue;
        }
        if (shardRouting.shardId().id() != shardId) {
            continue;
        }
        found = true;
        // TODO we can possibly support also relocating cases, where we cancel relocation and move...
        if (!shardRouting.started()) {
            if (explain) {
                return new RerouteExplanation(this, allocation.decision(Decision.NO, "move_allocation_command", "shard " + shardId + " has not been started"));
            }
            throw new IllegalArgumentException("[move_allocation] can't move " + shardId + ", shard is not started (state = " + shardRouting.state() + "]");
        }
        decision = allocation.deciders().canAllocate(shardRouting, toRoutingNode, allocation);
        if (decision.type() == Decision.Type.NO) {
            if (explain) {
                return new RerouteExplanation(this, decision);
            }
            throw new IllegalArgumentException("[move_allocation] can't move " + shardId + ", from " + fromDiscoNode + ", to " + toDiscoNode + ", since its not allowed, reason: " + decision);
        }
        if (decision.type() == Decision.Type.THROTTLE) {
        // its being throttled, maybe have a flag to take it into account and fail? for now, just do it since the "user" wants it...
        }
        allocation.routingNodes().relocateShard(shardRouting, toRoutingNode.nodeId(), allocation.clusterInfo().getShardSize(shardRouting, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE), allocation.changes());
    }
    if (!found) {
        if (explain) {
            return new RerouteExplanation(this, allocation.decision(Decision.NO, "move_allocation_command", "shard " + shardId + " not found"));
        }
        throw new IllegalArgumentException("[move_allocation] can't move " + shardId + ", failed to find it on node " + fromDiscoNode);
    }
    return new RerouteExplanation(this, decision);
}
Also used : DiscoveryNode(org.opensearch.cluster.node.DiscoveryNode) RoutingNode(org.opensearch.cluster.routing.RoutingNode) RerouteExplanation(org.opensearch.cluster.routing.allocation.RerouteExplanation) ShardRouting(org.opensearch.cluster.routing.ShardRouting) Decision(org.opensearch.cluster.routing.allocation.decider.Decision)

Example 3 with RerouteExplanation

use of org.opensearch.cluster.routing.allocation.RerouteExplanation in project OpenSearch by opensearch-project.

the class ClusterRerouteResponseTests method testToXContent.

public void testToXContent() throws IOException {
    DiscoveryNode node0 = new DiscoveryNode("node0", new TransportAddress(TransportAddress.META_ADDRESS, 9000), Version.CURRENT);
    DiscoveryNodes nodes = new DiscoveryNodes.Builder().add(node0).masterNodeId(node0.getId()).build();
    IndexMetadata indexMetadata = IndexMetadata.builder("index").settings(Settings.builder().put(IndexSettings.INDEX_CHECK_ON_STARTUP.getKey(), true).put(IndexSettings.MAX_SCRIPT_FIELDS_SETTING.getKey(), 10).put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT).build()).build();
    ImmutableOpenMap.Builder<String, IndexMetadata> openMapBuilder = ImmutableOpenMap.builder();
    openMapBuilder.put("index", indexMetadata);
    Metadata metadata = Metadata.builder().indices(openMapBuilder.build()).build();
    ClusterState clusterState = ClusterState.builder(new ClusterName("test")).nodes(nodes).metadata(metadata).build();
    RoutingExplanations routingExplanations = new RoutingExplanations();
    routingExplanations.add(new RerouteExplanation(new AllocateReplicaAllocationCommand("index", 0, "node0"), Decision.YES));
    ClusterRerouteResponse clusterRerouteResponse = new ClusterRerouteResponse(true, clusterState, routingExplanations);
    {
        XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint();
        clusterRerouteResponse.toXContent(builder, ToXContent.EMPTY_PARAMS);
        assertEquals("{\n" + "  \"acknowledged\" : true,\n" + "  \"state\" : {\n" + "    \"cluster_uuid\" : \"_na_\",\n" + "    \"version\" : 0,\n" + "    \"state_uuid\" : \"" + clusterState.stateUUID() + "\",\n" + "    \"master_node\" : \"node0\",\n" + "    \"blocks\" : { },\n" + "    \"nodes\" : {\n" + "      \"node0\" : {\n" + "        \"name\" : \"\",\n" + "        \"ephemeral_id\" : \"" + node0.getEphemeralId() + "\",\n" + "        \"transport_address\" : \"0.0.0.0:9000\",\n" + "        \"attributes\" : { }\n" + "      }\n" + "    },\n" + "    \"metadata\" : {\n" + "      \"cluster_uuid\" : \"_na_\",\n" + "      \"cluster_uuid_committed\" : false,\n" + "      \"cluster_coordination\" : {\n" + "        \"term\" : 0,\n" + "        \"last_committed_config\" : [ ],\n" + "        \"last_accepted_config\" : [ ],\n" + "        \"voting_config_exclusions\" : [ ]\n" + "      },\n" + "      \"templates\" : { },\n" + "      \"indices\" : {\n" + "        \"index\" : {\n" + "          \"version\" : 1,\n" + "          \"mapping_version\" : 1,\n" + "          \"settings_version\" : 1,\n" + "          \"aliases_version\" : 1,\n" + "          \"routing_num_shards\" : 1,\n" + "          \"state\" : \"open\",\n" + "          \"settings\" : {\n" + "            \"index\" : {\n" + "              \"shard\" : {\n" + "                \"check_on_startup\" : \"true\"\n" + "              },\n" + "              \"number_of_shards\" : \"1\",\n" + "              \"number_of_replicas\" : \"0\",\n" + "              \"version\" : {\n" + "                \"created\" : \"" + Version.CURRENT.id + "\"\n" + "              },\n" + "              \"max_script_fields\" : \"10\"\n" + "            }\n" + "          },\n" + "          \"mappings\" : { },\n" + "          \"aliases\" : [ ],\n" + "          \"primary_terms\" : {\n" + "            \"0\" : 0\n" + "          },\n" + "          \"in_sync_allocations\" : {\n" + "            \"0\" : [ ]\n" + "          },\n" + "          \"rollover_info\" : { },\n" + "          \"system\" : false\n" + "        }\n" + "      },\n" + "      \"index-graveyard\" : {\n" + "        \"tombstones\" : [ ]\n" + "      }\n" + "    },\n" + "    \"routing_table\" : {\n" + "      \"indices\" : { }\n" + "    },\n" + "    \"routing_nodes\" : {\n" + "      \"unassigned\" : [ ],\n" + "      \"nodes\" : {\n" + "        \"node0\" : [ ]\n" + "      }\n" + "    }\n" + "  }\n" + "}", Strings.toString(builder));
    }
    {
        XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint();
        Map<String, String> params = new HashMap<>();
        params.put("explain", "true");
        params.put("metric", "version,master_node");
        clusterRerouteResponse.toXContent(builder, new ToXContent.MapParams(params));
        assertEquals("{\n" + "  \"acknowledged\" : true,\n" + "  \"state\" : {\n" + "    \"cluster_uuid\" : \"_na_\",\n" + "    \"version\" : 0,\n" + "    \"state_uuid\" : \"" + clusterState.stateUUID() + "\",\n" + "    \"master_node\" : \"node0\"\n" + "  },\n" + "  \"explanations\" : [\n" + "    {\n" + "      \"command\" : \"allocate_replica\",\n" + "      \"parameters\" : {\n" + "        \"index\" : \"index\",\n" + "        \"shard\" : 0,\n" + "        \"node\" : \"node0\"\n" + "      },\n" + "      \"decisions\" : [\n" + "        {\n" + "          \"decider\" : null,\n" + "          \"decision\" : \"YES\",\n" + "          \"explanation\" : \"none\"\n" + "        }\n" + "      ]\n" + "    }\n" + "  ]\n" + "}", Strings.toString(builder));
    }
    {
        XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint();
        Map<String, String> params = new HashMap<>();
        params.put("metric", "metadata");
        params.put("settings_filter", "index.number*,index.version.created");
        clusterRerouteResponse.toXContent(builder, new ToXContent.MapParams(params));
        assertEquals("{\n" + "  \"acknowledged\" : true,\n" + "  \"state\" : {\n" + "    \"cluster_uuid\" : \"_na_\",\n" + "    \"metadata\" : {\n" + "      \"cluster_uuid\" : \"_na_\",\n" + "      \"cluster_uuid_committed\" : false,\n" + "      \"cluster_coordination\" : {\n" + "        \"term\" : 0,\n" + "        \"last_committed_config\" : [ ],\n" + "        \"last_accepted_config\" : [ ],\n" + "        \"voting_config_exclusions\" : [ ]\n" + "      },\n" + "      \"templates\" : { },\n" + "      \"indices\" : {\n" + "        \"index\" : {\n" + "          \"version\" : 1,\n" + "          \"mapping_version\" : 1,\n" + "          \"settings_version\" : 1,\n" + "          \"aliases_version\" : 1,\n" + "          \"routing_num_shards\" : 1,\n" + "          \"state\" : \"open\",\n" + "          \"settings\" : {\n" + "            \"index\" : {\n" + "              \"max_script_fields\" : \"10\",\n" + "              \"shard\" : {\n" + "                \"check_on_startup\" : \"true\"\n" + "              }\n" + "            }\n" + "          },\n" + "          \"mappings\" : { },\n" + "          \"aliases\" : [ ],\n" + "          \"primary_terms\" : {\n" + "            \"0\" : 0\n" + "          },\n" + "          \"in_sync_allocations\" : {\n" + "            \"0\" : [ ]\n" + "          },\n" + "          \"rollover_info\" : { },\n" + "          \"system\" : false\n" + "        }\n" + "      },\n" + "      \"index-graveyard\" : {\n" + "        \"tombstones\" : [ ]\n" + "      }\n" + "    }\n" + "  }\n" + "}", Strings.toString(builder));
    }
}
Also used : ClusterState(org.opensearch.cluster.ClusterState) RoutingExplanations(org.opensearch.cluster.routing.allocation.RoutingExplanations) DiscoveryNode(org.opensearch.cluster.node.DiscoveryNode) TransportAddress(org.opensearch.common.transport.TransportAddress) Metadata(org.opensearch.cluster.metadata.Metadata) IndexMetadata(org.opensearch.cluster.metadata.IndexMetadata) AllocateReplicaAllocationCommand(org.opensearch.cluster.routing.allocation.command.AllocateReplicaAllocationCommand) RerouteExplanation(org.opensearch.cluster.routing.allocation.RerouteExplanation) ImmutableOpenMap(org.opensearch.common.collect.ImmutableOpenMap) ClusterName(org.opensearch.cluster.ClusterName) IndexMetadata(org.opensearch.cluster.metadata.IndexMetadata) ImmutableOpenMap(org.opensearch.common.collect.ImmutableOpenMap) HashMap(java.util.HashMap) Map(java.util.Map) DiscoveryNodes(org.opensearch.cluster.node.DiscoveryNodes) XContentBuilder(org.opensearch.common.xcontent.XContentBuilder)

Example 4 with RerouteExplanation

use of org.opensearch.cluster.routing.allocation.RerouteExplanation in project OpenSearch by opensearch-project.

the class ClusterRerouteIT method testRerouteExplain.

public void testRerouteExplain() {
    Settings commonSettings = Settings.builder().build();
    logger.info("--> starting a node");
    String node_1 = internalCluster().startNode(commonSettings);
    assertThat(cluster().size(), equalTo(1));
    ClusterHealthResponse healthResponse = client().admin().cluster().prepareHealth().setWaitForNodes("1").execute().actionGet();
    assertThat(healthResponse.isTimedOut(), equalTo(false));
    logger.info("--> create an index with 1 shard");
    createIndex("test", Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).build());
    if (randomBoolean()) {
        assertAcked(client().admin().indices().prepareClose("test"));
    }
    ensureGreen("test");
    logger.info("--> disable allocation");
    Settings newSettings = Settings.builder().put(CLUSTER_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), Allocation.NONE.name()).build();
    client().admin().cluster().prepareUpdateSettings().setTransientSettings(newSettings).execute().actionGet();
    logger.info("--> starting a second node");
    String node_2 = internalCluster().startNode(commonSettings);
    assertThat(cluster().size(), equalTo(2));
    healthResponse = client().admin().cluster().prepareHealth().setWaitForNodes("2").execute().actionGet();
    assertThat(healthResponse.isTimedOut(), equalTo(false));
    logger.info("--> try to move the shard from node1 to node2");
    MoveAllocationCommand cmd = new MoveAllocationCommand("test", 0, node_1, node_2);
    ClusterRerouteResponse resp = client().admin().cluster().prepareReroute().add(cmd).setExplain(true).execute().actionGet();
    RoutingExplanations e = resp.getExplanations();
    assertThat(e.explanations().size(), equalTo(1));
    RerouteExplanation explanation = e.explanations().get(0);
    assertThat(explanation.command().name(), equalTo(cmd.name()));
    assertThat(((MoveAllocationCommand) explanation.command()).shardId(), equalTo(cmd.shardId()));
    assertThat(((MoveAllocationCommand) explanation.command()).fromNode(), equalTo(cmd.fromNode()));
    assertThat(((MoveAllocationCommand) explanation.command()).toNode(), equalTo(cmd.toNode()));
    assertThat(explanation.decisions().type(), equalTo(Decision.Type.YES));
}
Also used : RoutingExplanations(org.opensearch.cluster.routing.allocation.RoutingExplanations) ClusterHealthResponse(org.opensearch.action.admin.cluster.health.ClusterHealthResponse) MoveAllocationCommand(org.opensearch.cluster.routing.allocation.command.MoveAllocationCommand) Matchers.containsString(org.hamcrest.Matchers.containsString) RerouteExplanation(org.opensearch.cluster.routing.allocation.RerouteExplanation) Settings(org.opensearch.common.settings.Settings) ClusterRerouteResponse(org.opensearch.action.admin.cluster.reroute.ClusterRerouteResponse)

Example 5 with RerouteExplanation

use of org.opensearch.cluster.routing.allocation.RerouteExplanation in project OpenSearch by opensearch-project.

the class AllocateEmptyPrimaryAllocationCommand method execute.

@Override
public RerouteExplanation execute(RoutingAllocation allocation, boolean explain) {
    final DiscoveryNode discoNode;
    try {
        discoNode = allocation.nodes().resolveNode(node);
    } catch (IllegalArgumentException e) {
        return explainOrThrowRejectedCommand(explain, allocation, e);
    }
    final RoutingNodes routingNodes = allocation.routingNodes();
    RoutingNode routingNode = routingNodes.node(discoNode.getId());
    if (routingNode == null) {
        return explainOrThrowMissingRoutingNode(allocation, explain, discoNode);
    }
    try {
        allocation.routingTable().shardRoutingTable(index, shardId).primaryShard();
    } catch (IndexNotFoundException | ShardNotFoundException e) {
        return explainOrThrowRejectedCommand(explain, allocation, e);
    }
    ShardRouting shardRouting = null;
    for (ShardRouting shard : allocation.routingNodes().unassigned()) {
        if (shard.getIndexName().equals(index) && shard.getId() == shardId && shard.primary()) {
            shardRouting = shard;
            break;
        }
    }
    if (shardRouting == null) {
        return explainOrThrowRejectedCommand(explain, allocation, "primary [" + index + "][" + shardId + "] is already assigned");
    }
    if (shardRouting.recoverySource().getType() != RecoverySource.Type.EMPTY_STORE && acceptDataLoss == false) {
        String dataLossWarning = "allocating an empty primary for [" + index + "][" + shardId + "] can result in data loss. Please confirm by setting the accept_data_loss parameter to true";
        return explainOrThrowRejectedCommand(explain, allocation, dataLossWarning);
    }
    UnassignedInfo unassignedInfoToUpdate = null;
    if (shardRouting.unassignedInfo().getReason() != UnassignedInfo.Reason.FORCED_EMPTY_PRIMARY) {
        String unassignedInfoMessage = "force empty allocation from previous reason " + shardRouting.unassignedInfo().getReason() + ", " + shardRouting.unassignedInfo().getMessage();
        unassignedInfoToUpdate = new UnassignedInfo(UnassignedInfo.Reason.FORCED_EMPTY_PRIMARY, unassignedInfoMessage, shardRouting.unassignedInfo().getFailure(), 0, System.nanoTime(), System.currentTimeMillis(), false, shardRouting.unassignedInfo().getLastAllocationStatus(), Collections.emptySet());
    }
    initializeUnassignedShard(allocation, routingNodes, routingNode, shardRouting, unassignedInfoToUpdate, EmptyStoreRecoverySource.INSTANCE);
    return new RerouteExplanation(this, allocation.decision(Decision.YES, name() + " (allocation command)", "ignore deciders"));
}
Also used : DiscoveryNode(org.opensearch.cluster.node.DiscoveryNode) RoutingNode(org.opensearch.cluster.routing.RoutingNode) ShardNotFoundException(org.opensearch.index.shard.ShardNotFoundException) RoutingNodes(org.opensearch.cluster.routing.RoutingNodes) UnassignedInfo(org.opensearch.cluster.routing.UnassignedInfo) IndexNotFoundException(org.opensearch.index.IndexNotFoundException) RerouteExplanation(org.opensearch.cluster.routing.allocation.RerouteExplanation) ShardRouting(org.opensearch.cluster.routing.ShardRouting)

Aggregations

RerouteExplanation (org.opensearch.cluster.routing.allocation.RerouteExplanation)7 DiscoveryNode (org.opensearch.cluster.node.DiscoveryNode)6 RoutingNode (org.opensearch.cluster.routing.RoutingNode)5 ShardRouting (org.opensearch.cluster.routing.ShardRouting)5 RoutingNodes (org.opensearch.cluster.routing.RoutingNodes)4 IndexNotFoundException (org.opensearch.index.IndexNotFoundException)4 ShardNotFoundException (org.opensearch.index.shard.ShardNotFoundException)3 IndexMetadata (org.opensearch.cluster.metadata.IndexMetadata)2 UnassignedInfo (org.opensearch.cluster.routing.UnassignedInfo)2 RoutingExplanations (org.opensearch.cluster.routing.allocation.RoutingExplanations)2 Decision (org.opensearch.cluster.routing.allocation.decider.Decision)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Matchers.containsString (org.hamcrest.Matchers.containsString)1 ClusterHealthResponse (org.opensearch.action.admin.cluster.health.ClusterHealthResponse)1 ClusterRerouteResponse (org.opensearch.action.admin.cluster.reroute.ClusterRerouteResponse)1 ClusterName (org.opensearch.cluster.ClusterName)1 ClusterState (org.opensearch.cluster.ClusterState)1 Metadata (org.opensearch.cluster.metadata.Metadata)1