Search in sources :

Example 1 with AlterPartitionReassignmentsResponse

use of org.apache.kafka.common.requests.AlterPartitionReassignmentsResponse in project kafka by apache.

the class KafkaAdminClientTest method testAlterPartitionReassignments.

@Test
public void testAlterPartitionReassignments() throws Exception {
    try (AdminClientUnitTestEnv env = mockClientEnv()) {
        env.kafkaClient().setNodeApiVersions(NodeApiVersions.create());
        TopicPartition tp1 = new TopicPartition("A", 0);
        TopicPartition tp2 = new TopicPartition("B", 0);
        Map<TopicPartition, Optional<NewPartitionReassignment>> reassignments = new HashMap<>();
        reassignments.put(tp1, Optional.empty());
        reassignments.put(tp2, Optional.of(new NewPartitionReassignment(Arrays.asList(1, 2, 3))));
        // 1. server returns less responses than number of partitions we sent
        AlterPartitionReassignmentsResponseData responseData1 = new AlterPartitionReassignmentsResponseData();
        ReassignablePartitionResponse normalPartitionResponse = new ReassignablePartitionResponse().setPartitionIndex(0);
        responseData1.setResponses(Collections.singletonList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(normalPartitionResponse))));
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(responseData1));
        AlterPartitionReassignmentsResult result1 = env.adminClient().alterPartitionReassignments(reassignments);
        Future<Void> future1 = result1.all();
        Future<Void> future2 = result1.values().get(tp1);
        TestUtils.assertFutureError(future1, UnknownServerException.class);
        TestUtils.assertFutureError(future2, UnknownServerException.class);
        // 2. NOT_CONTROLLER error handling
        AlterPartitionReassignmentsResponseData controllerErrResponseData = new AlterPartitionReassignmentsResponseData().setErrorCode(Errors.NOT_CONTROLLER.code()).setErrorMessage(Errors.NOT_CONTROLLER.message()).setResponses(Arrays.asList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(normalPartitionResponse)), new ReassignableTopicResponse().setName("B").setPartitions(Collections.singletonList(normalPartitionResponse))));
        MetadataResponse controllerNodeResponse = RequestTestUtils.metadataResponse(env.cluster().nodes(), env.cluster().clusterResource().clusterId(), 1, Collections.emptyList());
        AlterPartitionReassignmentsResponseData normalResponse = new AlterPartitionReassignmentsResponseData().setResponses(Arrays.asList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(normalPartitionResponse)), new ReassignableTopicResponse().setName("B").setPartitions(Collections.singletonList(normalPartitionResponse))));
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(controllerErrResponseData));
        env.kafkaClient().prepareResponse(controllerNodeResponse);
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(normalResponse));
        AlterPartitionReassignmentsResult controllerErrResult = env.adminClient().alterPartitionReassignments(reassignments);
        controllerErrResult.all().get();
        controllerErrResult.values().get(tp1).get();
        controllerErrResult.values().get(tp2).get();
        // 3. partition-level error
        AlterPartitionReassignmentsResponseData partitionLevelErrData = new AlterPartitionReassignmentsResponseData().setResponses(Arrays.asList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(new ReassignablePartitionResponse().setPartitionIndex(0).setErrorMessage(Errors.INVALID_REPLICA_ASSIGNMENT.message()).setErrorCode(Errors.INVALID_REPLICA_ASSIGNMENT.code()))), new ReassignableTopicResponse().setName("B").setPartitions(Collections.singletonList(normalPartitionResponse))));
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(partitionLevelErrData));
        AlterPartitionReassignmentsResult partitionLevelErrResult = env.adminClient().alterPartitionReassignments(reassignments);
        TestUtils.assertFutureError(partitionLevelErrResult.values().get(tp1), Errors.INVALID_REPLICA_ASSIGNMENT.exception().getClass());
        partitionLevelErrResult.values().get(tp2).get();
        // 4. top-level error
        String errorMessage = "this is custom error message";
        AlterPartitionReassignmentsResponseData topLevelErrResponseData = new AlterPartitionReassignmentsResponseData().setErrorCode(Errors.CLUSTER_AUTHORIZATION_FAILED.code()).setErrorMessage(errorMessage).setResponses(Arrays.asList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(normalPartitionResponse)), new ReassignableTopicResponse().setName("B").setPartitions(Collections.singletonList(normalPartitionResponse))));
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(topLevelErrResponseData));
        AlterPartitionReassignmentsResult topLevelErrResult = env.adminClient().alterPartitionReassignments(reassignments);
        assertEquals(errorMessage, TestUtils.assertFutureThrows(topLevelErrResult.all(), Errors.CLUSTER_AUTHORIZATION_FAILED.exception().getClass()).getMessage());
        assertEquals(errorMessage, TestUtils.assertFutureThrows(topLevelErrResult.values().get(tp1), Errors.CLUSTER_AUTHORIZATION_FAILED.exception().getClass()).getMessage());
        assertEquals(errorMessage, TestUtils.assertFutureThrows(topLevelErrResult.values().get(tp2), Errors.CLUSTER_AUTHORIZATION_FAILED.exception().getClass()).getMessage());
        // 5. unrepresentable topic name error
        TopicPartition invalidTopicTP = new TopicPartition("", 0);
        TopicPartition invalidPartitionTP = new TopicPartition("ABC", -1);
        Map<TopicPartition, Optional<NewPartitionReassignment>> invalidTopicReassignments = new HashMap<>();
        invalidTopicReassignments.put(invalidPartitionTP, Optional.of(new NewPartitionReassignment(Arrays.asList(1, 2, 3))));
        invalidTopicReassignments.put(invalidTopicTP, Optional.of(new NewPartitionReassignment(Arrays.asList(1, 2, 3))));
        invalidTopicReassignments.put(tp1, Optional.of(new NewPartitionReassignment(Arrays.asList(1, 2, 3))));
        AlterPartitionReassignmentsResponseData singlePartResponseData = new AlterPartitionReassignmentsResponseData().setResponses(Collections.singletonList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(normalPartitionResponse))));
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(singlePartResponseData));
        AlterPartitionReassignmentsResult unrepresentableTopicResult = env.adminClient().alterPartitionReassignments(invalidTopicReassignments);
        TestUtils.assertFutureError(unrepresentableTopicResult.values().get(invalidTopicTP), InvalidTopicException.class);
        TestUtils.assertFutureError(unrepresentableTopicResult.values().get(invalidPartitionTP), InvalidTopicException.class);
        unrepresentableTopicResult.values().get(tp1).get();
        // Test success scenario
        AlterPartitionReassignmentsResponseData noErrResponseData = new AlterPartitionReassignmentsResponseData().setErrorCode(Errors.NONE.code()).setErrorMessage(Errors.NONE.message()).setResponses(Arrays.asList(new ReassignableTopicResponse().setName("A").setPartitions(Collections.singletonList(normalPartitionResponse)), new ReassignableTopicResponse().setName("B").setPartitions(Collections.singletonList(normalPartitionResponse))));
        env.kafkaClient().prepareResponse(new AlterPartitionReassignmentsResponse(noErrResponseData));
        AlterPartitionReassignmentsResult noErrResult = env.adminClient().alterPartitionReassignments(reassignments);
        noErrResult.all().get();
        noErrResult.values().get(tp1).get();
        noErrResult.values().get(tp2).get();
    }
}
Also used : Optional(java.util.Optional) HashMap(java.util.HashMap) ReassignablePartitionResponse(org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData.ReassignablePartitionResponse) AlterPartitionReassignmentsResponse(org.apache.kafka.common.requests.AlterPartitionReassignmentsResponse) ReassignableTopicResponse(org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData.ReassignableTopicResponse) AlterPartitionReassignmentsResponseData(org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData) TopicPartition(org.apache.kafka.common.TopicPartition) MetadataResponse(org.apache.kafka.common.requests.MetadataResponse) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Test(org.junit.jupiter.api.Test)

Example 2 with AlterPartitionReassignmentsResponse

use of org.apache.kafka.common.requests.AlterPartitionReassignmentsResponse in project kafka by apache.

the class KafkaAdminClient method alterPartitionReassignments.

@Override
public AlterPartitionReassignmentsResult alterPartitionReassignments(Map<TopicPartition, Optional<NewPartitionReassignment>> reassignments, AlterPartitionReassignmentsOptions options) {
    final Map<TopicPartition, KafkaFutureImpl<Void>> futures = new HashMap<>();
    final Map<String, Map<Integer, Optional<NewPartitionReassignment>>> topicsToReassignments = new TreeMap<>();
    for (Map.Entry<TopicPartition, Optional<NewPartitionReassignment>> entry : reassignments.entrySet()) {
        String topic = entry.getKey().topic();
        int partition = entry.getKey().partition();
        TopicPartition topicPartition = new TopicPartition(topic, partition);
        Optional<NewPartitionReassignment> reassignment = entry.getValue();
        KafkaFutureImpl<Void> future = new KafkaFutureImpl<>();
        futures.put(topicPartition, future);
        if (topicNameIsUnrepresentable(topic)) {
            future.completeExceptionally(new InvalidTopicException("The given topic name '" + topic + "' cannot be represented in a request."));
        } else if (topicPartition.partition() < 0) {
            future.completeExceptionally(new InvalidTopicException("The given partition index " + topicPartition.partition() + " is not valid."));
        } else {
            Map<Integer, Optional<NewPartitionReassignment>> partitionReassignments = topicsToReassignments.get(topicPartition.topic());
            if (partitionReassignments == null) {
                partitionReassignments = new TreeMap<>();
                topicsToReassignments.put(topic, partitionReassignments);
            }
            partitionReassignments.put(partition, reassignment);
        }
    }
    final long now = time.milliseconds();
    Call call = new Call("alterPartitionReassignments", calcDeadlineMs(now, options.timeoutMs()), new ControllerNodeProvider()) {

        @Override
        public AlterPartitionReassignmentsRequest.Builder createRequest(int timeoutMs) {
            AlterPartitionReassignmentsRequestData data = new AlterPartitionReassignmentsRequestData();
            for (Map.Entry<String, Map<Integer, Optional<NewPartitionReassignment>>> entry : topicsToReassignments.entrySet()) {
                String topicName = entry.getKey();
                Map<Integer, Optional<NewPartitionReassignment>> partitionsToReassignments = entry.getValue();
                List<ReassignablePartition> reassignablePartitions = new ArrayList<>();
                for (Map.Entry<Integer, Optional<NewPartitionReassignment>> partitionEntry : partitionsToReassignments.entrySet()) {
                    int partitionIndex = partitionEntry.getKey();
                    Optional<NewPartitionReassignment> reassignment = partitionEntry.getValue();
                    ReassignablePartition reassignablePartition = new ReassignablePartition().setPartitionIndex(partitionIndex).setReplicas(reassignment.map(NewPartitionReassignment::targetReplicas).orElse(null));
                    reassignablePartitions.add(reassignablePartition);
                }
                ReassignableTopic reassignableTopic = new ReassignableTopic().setName(topicName).setPartitions(reassignablePartitions);
                data.topics().add(reassignableTopic);
            }
            data.setTimeoutMs(timeoutMs);
            return new AlterPartitionReassignmentsRequest.Builder(data);
        }

        @Override
        public void handleResponse(AbstractResponse abstractResponse) {
            AlterPartitionReassignmentsResponse response = (AlterPartitionReassignmentsResponse) abstractResponse;
            Map<TopicPartition, ApiException> errors = new HashMap<>();
            int receivedResponsesCount = 0;
            Errors topLevelError = Errors.forCode(response.data().errorCode());
            switch(topLevelError) {
                case NONE:
                    receivedResponsesCount += validateTopicResponses(response.data().responses(), errors);
                    break;
                case NOT_CONTROLLER:
                    handleNotControllerError(topLevelError);
                    break;
                default:
                    for (ReassignableTopicResponse topicResponse : response.data().responses()) {
                        String topicName = topicResponse.name();
                        for (ReassignablePartitionResponse partition : topicResponse.partitions()) {
                            errors.put(new TopicPartition(topicName, partition.partitionIndex()), new ApiError(topLevelError, response.data().errorMessage()).exception());
                            receivedResponsesCount += 1;
                        }
                    }
                    break;
            }
            assertResponseCountMatch(errors, receivedResponsesCount);
            for (Map.Entry<TopicPartition, ApiException> entry : errors.entrySet()) {
                ApiException exception = entry.getValue();
                if (exception == null)
                    futures.get(entry.getKey()).complete(null);
                else
                    futures.get(entry.getKey()).completeExceptionally(exception);
            }
        }

        private void assertResponseCountMatch(Map<TopicPartition, ApiException> errors, int receivedResponsesCount) {
            int expectedResponsesCount = topicsToReassignments.values().stream().mapToInt(Map::size).sum();
            if (errors.values().stream().noneMatch(Objects::nonNull) && receivedResponsesCount != expectedResponsesCount) {
                String quantifier = receivedResponsesCount > expectedResponsesCount ? "many" : "less";
                throw new UnknownServerException("The server returned too " + quantifier + " results." + "Expected " + expectedResponsesCount + " but received " + receivedResponsesCount);
            }
        }

        private int validateTopicResponses(List<ReassignableTopicResponse> topicResponses, Map<TopicPartition, ApiException> errors) {
            int receivedResponsesCount = 0;
            for (ReassignableTopicResponse topicResponse : topicResponses) {
                String topicName = topicResponse.name();
                for (ReassignablePartitionResponse partResponse : topicResponse.partitions()) {
                    Errors partitionError = Errors.forCode(partResponse.errorCode());
                    TopicPartition tp = new TopicPartition(topicName, partResponse.partitionIndex());
                    if (partitionError == Errors.NONE) {
                        errors.put(tp, null);
                    } else {
                        errors.put(tp, new ApiError(partitionError, partResponse.errorMessage()).exception());
                    }
                    receivedResponsesCount += 1;
                }
            }
            return receivedResponsesCount;
        }

        @Override
        void handleFailure(Throwable throwable) {
            for (KafkaFutureImpl<Void> future : futures.values()) {
                future.completeExceptionally(throwable);
            }
        }
    };
    if (!topicsToReassignments.isEmpty()) {
        runnable.call(call, now);
    }
    return new AlterPartitionReassignmentsResult(new HashMap<>(futures));
}
Also used : ReassignablePartition(org.apache.kafka.common.message.AlterPartitionReassignmentsRequestData.ReassignablePartition) HashMap(java.util.HashMap) ReassignableTopic(org.apache.kafka.common.message.AlterPartitionReassignmentsRequestData.ReassignableTopic) ChannelBuilder(org.apache.kafka.common.network.ChannelBuilder) ArrayList(java.util.ArrayList) AlterPartitionReassignmentsResponse(org.apache.kafka.common.requests.AlterPartitionReassignmentsResponse) ReassignableTopicResponse(org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData.ReassignableTopicResponse) LinkedList(java.util.LinkedList) ArrayList(java.util.ArrayList) List(java.util.List) AlterPartitionReassignmentsRequest(org.apache.kafka.common.requests.AlterPartitionReassignmentsRequest) Optional(java.util.Optional) AbstractResponse(org.apache.kafka.common.requests.AbstractResponse) ReassignablePartitionResponse(org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData.ReassignablePartitionResponse) AlterPartitionReassignmentsRequestData(org.apache.kafka.common.message.AlterPartitionReassignmentsRequestData) KafkaFutureImpl(org.apache.kafka.common.internals.KafkaFutureImpl) TreeMap(java.util.TreeMap) UnknownServerException(org.apache.kafka.common.errors.UnknownServerException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Errors(org.apache.kafka.common.protocol.Errors) TopicPartition(org.apache.kafka.common.TopicPartition) InvalidTopicException(org.apache.kafka.common.errors.InvalidTopicException) ApiError(org.apache.kafka.common.requests.ApiError) Map(java.util.Map) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap) ApiException(org.apache.kafka.common.errors.ApiException)

Aggregations

HashMap (java.util.HashMap)2 Optional (java.util.Optional)2 TopicPartition (org.apache.kafka.common.TopicPartition)2 ReassignablePartitionResponse (org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData.ReassignablePartitionResponse)2 ReassignableTopicResponse (org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData.ReassignableTopicResponse)2 AlterPartitionReassignmentsResponse (org.apache.kafka.common.requests.AlterPartitionReassignmentsResponse)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1 TreeMap (java.util.TreeMap)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 ApiException (org.apache.kafka.common.errors.ApiException)1 InvalidTopicException (org.apache.kafka.common.errors.InvalidTopicException)1 UnknownServerException (org.apache.kafka.common.errors.UnknownServerException)1 KafkaFutureImpl (org.apache.kafka.common.internals.KafkaFutureImpl)1 AlterPartitionReassignmentsRequestData (org.apache.kafka.common.message.AlterPartitionReassignmentsRequestData)1 ReassignablePartition (org.apache.kafka.common.message.AlterPartitionReassignmentsRequestData.ReassignablePartition)1 ReassignableTopic (org.apache.kafka.common.message.AlterPartitionReassignmentsRequestData.ReassignableTopic)1 AlterPartitionReassignmentsResponseData (org.apache.kafka.common.message.AlterPartitionReassignmentsResponseData)1