Search in sources :

Example 81 with KafkaTopic

use of io.strimzi.api.kafka.model.KafkaTopic in project strimzi-kafka-operator by strimzi.

the class TopicOperatorMockTest method testNotCreatedInKube.

void testNotCreatedInKube(VertxTestContext context, KafkaTopic kt) throws InterruptedException, ExecutionException {
    String kubeName = kt.getMetadata().getName();
    String kafkaName = kt.getSpec().getTopicName() != null ? kt.getSpec().getTopicName() : kubeName;
    int retention = (Integer) kt.getSpec().getConfig().get("retention.bytes");
    createInKube(kt);
    Thread.sleep(2000);
    LOGGER.info("Topic has not been created");
    Topic fromKafka = getFromKafka(kafkaName);
    context.verify(() -> assertThat(fromKafka, is(nullValue())));
    // Reconcile after no changes
    reconcile(context);
    // Check things still the same
    context.verify(() -> assertThat(fromKafka, is(nullValue())));
    // Config change + reconcile
    updateInKube(new KafkaTopicBuilder(kt).editSpec().addToConfig("retention.bytes", retention + 1).endSpec().build());
    // Another reconciliation
    reconcile(context);
    // Check things still the same
    context.verify(() -> {
        assertThat(getFromKafka(kafkaName), is(nullValue()));
        context.completeNow();
    });
}
Also used : KafkaTopicBuilder(io.strimzi.api.kafka.model.KafkaTopicBuilder) KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic) Checkpoint(io.vertx.junit5.Checkpoint)

Example 82 with KafkaTopic

use of io.strimzi.api.kafka.model.KafkaTopic in project strimzi-kafka-operator by strimzi.

the class TopicOperatorMockTest method testCreatedWithSameTopicNameInKube.

@Test
public void testCreatedWithSameTopicNameInKube(VertxTestContext context) throws InterruptedException, ExecutionException {
    int retention = 100_000_000;
    KafkaTopic kt = new KafkaTopicBuilder().withNewMetadata().withName("my-topic").withNamespace(NAMESPACE).addToLabels(Labels.STRIMZI_KIND_LABEL, "topic").endMetadata().withNewSpec().withTopicName(// the same as metadata.name
    "my-topic").withPartitions(1).withReplicas(1).addToConfig("retention.bytes", retention).endSpec().build();
    testCreatedInKube(context, kt);
}
Also used : KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic) KafkaTopicBuilder(io.strimzi.api.kafka.model.KafkaTopicBuilder) Checkpoint(io.vertx.junit5.Checkpoint) Test(org.junit.jupiter.api.Test)

Example 83 with KafkaTopic

use of io.strimzi.api.kafka.model.KafkaTopic in project strimzi-kafka-operator by strimzi.

the class TopicOperatorMockTest method testCreatedWithoutTopicNameInKube.

@Test
public void testCreatedWithoutTopicNameInKube(VertxTestContext context) throws InterruptedException, ExecutionException {
    LOGGER.info("Test started");
    int retention = 100_000_000;
    KafkaTopic kt = new KafkaTopicBuilder().withNewMetadata().withName("my-topic").withNamespace(NAMESPACE).addToLabels(Labels.STRIMZI_KIND_LABEL, "topic").addToLabels(Labels.KUBERNETES_NAME_LABEL, "topic-operator").endMetadata().withNewSpec().withPartitions(1).withReplicas(1).addToConfig("retention.bytes", retention).endSpec().build();
    testCreatedInKube(context, kt);
}
Also used : KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic) KafkaTopicBuilder(io.strimzi.api.kafka.model.KafkaTopicBuilder) Checkpoint(io.vertx.junit5.Checkpoint) Test(org.junit.jupiter.api.Test)

Example 84 with KafkaTopic

use of io.strimzi.api.kafka.model.KafkaTopic in project strimzi-kafka-operator by strimzi.

the class MockK8s method updateResource.

@Override
public Future<KafkaTopic> updateResource(KafkaTopic topicResource) {
    Promise<KafkaTopic> handler = Promise.promise();
    AsyncResult<Void> response = modifyResponse.apply(new ResourceName(topicResource));
    if (response.succeeded()) {
        AsyncResult<KafkaTopic> old = byName.put(new ResourceName(topicResource), Future.succeededFuture(topicResource));
        if (old == null) {
            handler.handle(Future.failedFuture("resource does not exist, cannot be updated: " + topicResource.getMetadata().getName()));
            return handler.future();
        }
    }
    if (response.succeeded()) {
        Long generation = topicResource.getMetadata().getGeneration();
        handler.complete(new KafkaTopicBuilder(topicResource).editMetadata().withGeneration(generation != null ? generation + 1 : 1).endMetadata().build());
    } else {
        handler.fail(response.cause());
    }
    return handler.future();
}
Also used : KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic) KafkaTopicBuilder(io.strimzi.api.kafka.model.KafkaTopicBuilder)

Example 85 with KafkaTopic

use of io.strimzi.api.kafka.model.KafkaTopic in project strimzi-kafka-operator by strimzi.

the class TopicOperator method update3Way.

private Future<Void> update3Way(Reconciliation reconciliation, LogContext logContext, HasMetadata involvedObject, Topic k8sTopic, Topic kafkaTopic, Topic privateTopic) {
    final Future<Void> reconciliationResultHandler;
    if (!privateTopic.getResourceName().equals(k8sTopic.getResourceName())) {
        return Future.failedFuture(new OperatorException(involvedObject, "Topic '" + kafkaTopic.getTopicName() + "' is already managed via KafkaTopic '" + privateTopic.getResourceName() + "' it cannot also be managed via the KafkaTopic '" + k8sTopic.getResourceName() + "'"));
    }
    TopicDiff oursKafka = TopicDiff.diff(privateTopic, kafkaTopic);
    LOGGER.debugCr(logContext.toReconciliation(), "topicStore->kafkaTopic: {}", oursKafka);
    TopicDiff oursK8s = TopicDiff.diff(privateTopic, k8sTopic);
    LOGGER.debugCr(logContext.toReconciliation(), "topicStore->k8sTopic: {}", oursK8s);
    String conflict = oursKafka.conflict(oursK8s);
    if (conflict != null) {
        final String message = "KafkaTopic resource and Kafka topic both changed in a conflicting way: " + conflict;
        LOGGER.errorCr(logContext.toReconciliation(), "{}", message);
        enqueue(logContext, new Event(logContext, involvedObject, message, EventType.INFO, eventResult -> {
        }));
        reconciliationResultHandler = Future.failedFuture(new ConflictingChangesException(involvedObject, message));
    } else {
        TopicDiff merged = oursKafka.merge(oursK8s);
        LOGGER.debugCr(logContext.toReconciliation(), "Diffs do not conflict, merged diff: {}", merged);
        if (merged.isEmpty()) {
            LOGGER.infoCr(logContext.toReconciliation(), "All three topics are identical");
            reconciliationResultHandler = Future.succeededFuture();
        } else {
            Topic result = merged.apply(privateTopic);
            int partitionsDelta = merged.numPartitionsDelta();
            if (partitionsDelta < 0) {
                final String message = "Number of partitions cannot be decreased";
                LOGGER.errorCr(logContext.toReconciliation(), "{}", message);
                enqueue(logContext, new Event(logContext, involvedObject, message, EventType.INFO, eventResult -> {
                }));
                reconciliationResultHandler = Future.failedFuture(new PartitionDecreaseException(involvedObject, message));
            } else if (oursK8s.changesReplicationFactor() && !oursKafka.changesReplicationFactor()) {
                reconciliationResultHandler = Future.failedFuture(new ReplicationFactorChangeException(involvedObject, "Changing 'spec.replicas' is not supported. " + "This KafkaTopic's 'spec.replicas' should be reverted to " + kafkaTopic.getNumReplicas() + " and then the replication should be changed directly in Kafka."));
            } else {
                // TODO What if we increase min.in.sync.replicas and the number of replicas,
                // such that the old number of replicas < the new min isr? But likewise
                // we could decrease, so order of tasks in the queue will need to change
                // depending on what the diffs are.
                LOGGER.debugCr(logContext.toReconciliation(), "Updating KafkaTopic, kafka topic and topicStore");
                TopicDiff kubeDiff = TopicDiff.diff(k8sTopic, result);
                reconciliationResultHandler = Future.succeededFuture().compose(updatedKafkaTopic -> {
                    Future<Void> configFuture;
                    TopicDiff kafkaDiff = TopicDiff.diff(kafkaTopic, result);
                    if (merged.changesConfig() && !kafkaDiff.isEmpty()) {
                        Promise<Void> promise = Promise.promise();
                        configFuture = promise.future();
                        LOGGER.debugCr(logContext.toReconciliation(), "Updating kafka config with {}", kafkaDiff);
                        enqueue(logContext, new UpdateKafkaConfig(logContext, result, involvedObject, promise));
                    } else {
                        LOGGER.debugCr(logContext.toReconciliation(), "No need to update kafka topic with {}", kafkaDiff);
                        configFuture = Future.succeededFuture();
                    }
                    return configFuture;
                }).compose(ignored -> {
                    Future<KafkaTopic> resourceFuture;
                    if (!kubeDiff.isEmpty()) {
                        LOGGER.debugCr(logContext.toReconciliation(), "Updating KafkaTopic with {}", kubeDiff);
                        resourceFuture = updateResource(logContext, result).map(updatedKafkaTopic -> {
                            reconciliation.observedTopicFuture(updatedKafkaTopic);
                            return updatedKafkaTopic;
                        });
                    } else {
                        LOGGER.debugCr(logContext.toReconciliation(), "No need to update KafkaTopic {}", kubeDiff);
                        resourceFuture = Future.succeededFuture();
                    }
                    return resourceFuture;
                }).compose(ignored -> {
                    if (partitionsDelta > 0 && // Kafka throws an error if we attempt a noop change #partitions
                    result.getNumPartitions() > kafkaTopic.getNumPartitions()) {
                        Promise<Void> partitionsPromise = Promise.promise();
                        enqueue(logContext, new IncreaseKafkaPartitions(logContext, result, involvedObject, partitionsPromise));
                        return partitionsPromise.future();
                    } else {
                        return Future.succeededFuture();
                    }
                }).compose(ignored -> {
                    Promise<Void> topicStorePromise = Promise.promise();
                    enqueue(logContext, new UpdateInTopicStore(logContext, result, involvedObject, topicStorePromise));
                    return topicStorePromise.future();
                });
            }
        }
    }
    return reconciliationResultHandler;
}
Also used : BackOff(io.strimzi.operator.common.BackOff) ZonedDateTime(java.time.ZonedDateTime) BiFunction(java.util.function.BiFunction) Collections.disjoint(java.util.Collections.disjoint) Watcher(io.fabric8.kubernetes.client.Watcher) Annotations(io.strimzi.operator.common.Annotations) InvalidReplicationFactorException(org.apache.kafka.common.errors.InvalidReplicationFactorException) HashMap(java.util.HashMap) MaxAttemptsExceededException(io.strimzi.operator.common.MaxAttemptsExceededException) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayList(java.util.ArrayList) Collections.singletonList(java.util.Collections.singletonList) HashSet(java.util.HashSet) CompositeFuture(io.vertx.core.CompositeFuture) Timer(io.micrometer.core.instrument.Timer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) AsyncResult(io.vertx.core.AsyncResult) Counter(io.micrometer.core.instrument.Counter) StatusUtils(io.strimzi.operator.common.operator.resource.StatusUtils) Tag(io.micrometer.core.instrument.Tag) Tags(io.micrometer.core.instrument.Tags) KafkaTopicStatus(io.strimzi.api.kafka.model.status.KafkaTopicStatus) ReconciliationLogger(io.strimzi.operator.common.ReconciliationLogger) Collections.emptyList(java.util.Collections.emptyList) Promise(io.vertx.core.Promise) MetricsProvider(io.strimzi.operator.common.MetricsProvider) Vertx(io.vertx.core.Vertx) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) Meter(io.micrometer.core.instrument.Meter) HasMetadata(io.fabric8.kubernetes.api.model.HasMetadata) Future(io.vertx.core.Future) Collectors(java.util.stream.Collectors) EventBuilder(io.fabric8.kubernetes.api.model.EventBuilder) TopicExistsException(org.apache.kafka.common.errors.TopicExistsException) List(java.util.List) KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic) StatusDiff(io.strimzi.operator.cluster.model.StatusDiff) Util(io.strimzi.operator.common.Util) Logger(org.apache.logging.log4j.Logger) ObjectMeta(io.fabric8.kubernetes.api.model.ObjectMeta) KafkaTopicBuilder(io.strimzi.api.kafka.model.KafkaTopicBuilder) DateTimeFormatter(java.time.format.DateTimeFormatter) Optional(java.util.Optional) Handler(io.vertx.core.Handler) LogManager(org.apache.logging.log4j.LogManager) Collections.disjoint(java.util.Collections.disjoint) Promise(io.vertx.core.Promise) KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic) CompositeFuture(io.vertx.core.CompositeFuture) Future(io.vertx.core.Future) KafkaTopic(io.strimzi.api.kafka.model.KafkaTopic)

Aggregations

KafkaTopic (io.strimzi.api.kafka.model.KafkaTopic)187 Test (org.junit.jupiter.api.Test)92 KafkaTopicBuilder (io.strimzi.api.kafka.model.KafkaTopicBuilder)80 Checkpoint (io.vertx.junit5.Checkpoint)46 ObjectMetaBuilder (io.fabric8.kubernetes.api.model.ObjectMetaBuilder)38 HashMap (java.util.HashMap)32 ObjectMeta (io.fabric8.kubernetes.api.model.ObjectMeta)30 CountDownLatch (java.util.concurrent.CountDownLatch)28 NewTopic (org.apache.kafka.clients.admin.NewTopic)28 List (java.util.List)26 Map (java.util.Map)26 MeterRegistry (io.micrometer.core.instrument.MeterRegistry)22 KafkaTopicStatus (io.strimzi.api.kafka.model.status.KafkaTopicStatus)22 AsyncResult (io.vertx.core.AsyncResult)22 MaxAttemptsExceededException (io.strimzi.operator.common.MaxAttemptsExceededException)20 Vertx (io.vertx.core.Vertx)20 Matchers.containsString (org.hamcrest.Matchers.containsString)20 Watcher (io.fabric8.kubernetes.client.Watcher)18 KafkaClients (io.strimzi.systemtest.kafkaclients.internalClients.KafkaClients)18 KafkaClientsBuilder (io.strimzi.systemtest.kafkaclients.internalClients.KafkaClientsBuilder)18