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();
}
}
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));
}
Aggregations