Search in sources :

Example 1 with InvalidResourceException

use of io.strimzi.operator.cluster.model.InvalidResourceException in project strimzi by strimzi.

the class AbstractOperator method reconcile.

/**
 * Reconcile assembly resources in the given namespace having the given {@code name}.
 * Reconciliation works by getting the assembly resource (e.g. {@code KafkaUser})
 * in the given namespace with the given name and
 * comparing with the corresponding resource.
 * @param reconciliation The reconciliation.
 * @return A Future which is completed with the result of the reconciliation.
 */
@Override
@SuppressWarnings("unchecked")
public final Future<Void> reconcile(Reconciliation reconciliation) {
    String namespace = reconciliation.namespace();
    String name = reconciliation.name();
    reconciliationsCounter(reconciliation.namespace()).increment();
    Timer.Sample reconciliationTimerSample = Timer.start(metrics.meterRegistry());
    Future<Void> handler = withLock(reconciliation, LOCK_TIMEOUT_MS, () -> {
        T cr = resourceOperator.get(namespace, name);
        if (cr != null) {
            if (!Util.matchesSelector(selector(), cr)) {
                // When the labels matching the selector are removed from the custom resource, a DELETE event is
                // triggered by the watch even through the custom resource might not match the watch labels anymore
                // and might not be really deleted. We have to filter these situations out and ignore the
                // reconciliation because such resource might be already operated by another instance (where the
                // same change triggered ADDED event).
                LOGGER.debugCr(reconciliation, "{} {} in namespace {} does not match label selector {} and will be ignored", kind(), name, namespace, selector().get().getMatchLabels());
                return Future.succeededFuture();
            }
            Promise<Void> createOrUpdate = Promise.promise();
            if (Annotations.isReconciliationPausedWithAnnotation(cr)) {
                S status = createStatus();
                Set<Condition> conditions = validate(reconciliation, cr);
                conditions.add(StatusUtils.getPausedCondition());
                status.setConditions(new ArrayList<>(conditions));
                status.setObservedGeneration(cr.getStatus() != null ? cr.getStatus().getObservedGeneration() : 0);
                updateStatus(reconciliation, status).onComplete(statusResult -> {
                    if (statusResult.succeeded()) {
                        createOrUpdate.complete();
                    } else {
                        createOrUpdate.fail(statusResult.cause());
                    }
                });
                pausedResourceCounter(namespace).getAndIncrement();
                LOGGER.debugCr(reconciliation, "Reconciliation of {} {} is paused", kind, name);
                return createOrUpdate.future();
            } else if (cr.getSpec() == null) {
                InvalidResourceException exception = new InvalidResourceException("Spec cannot be null");
                S status = createStatus();
                Condition errorCondition = new ConditionBuilder().withLastTransitionTime(StatusUtils.iso8601Now()).withType("NotReady").withStatus("True").withReason(exception.getClass().getSimpleName()).withMessage(exception.getMessage()).build();
                status.setObservedGeneration(cr.getMetadata().getGeneration());
                status.addCondition(errorCondition);
                LOGGER.errorCr(reconciliation, "{} spec cannot be null", cr.getMetadata().getName());
                updateStatus(reconciliation, status).onComplete(notUsed -> {
                    createOrUpdate.fail(exception);
                });
                return createOrUpdate.future();
            }
            Set<Condition> unknownAndDeprecatedConditions = validate(reconciliation, cr);
            LOGGER.infoCr(reconciliation, "{} {} will be checked for creation or modification", kind, name);
            createOrUpdate(reconciliation, cr).onComplete(res -> {
                if (res.succeeded()) {
                    S status = res.result();
                    addWarningsToStatus(status, unknownAndDeprecatedConditions);
                    updateStatus(reconciliation, status).onComplete(statusResult -> {
                        if (statusResult.succeeded()) {
                            createOrUpdate.complete();
                        } else {
                            createOrUpdate.fail(statusResult.cause());
                        }
                    });
                } else {
                    if (res.cause() instanceof ReconciliationException) {
                        ReconciliationException e = (ReconciliationException) res.cause();
                        Status status = e.getStatus();
                        addWarningsToStatus(status, unknownAndDeprecatedConditions);
                        LOGGER.errorCr(reconciliation, "createOrUpdate failed", e.getCause());
                        updateStatus(reconciliation, (S) status).onComplete(statusResult -> {
                            createOrUpdate.fail(e.getCause());
                        });
                    } else {
                        LOGGER.errorCr(reconciliation, "createOrUpdate failed", res.cause());
                        createOrUpdate.fail(res.cause());
                    }
                }
            });
            return createOrUpdate.future();
        } else {
            LOGGER.infoCr(reconciliation, "{} {} should be deleted", kind, name);
            return delete(reconciliation).map(deleteResult -> {
                if (deleteResult) {
                    LOGGER.infoCr(reconciliation, "{} {} deleted", kind, name);
                } else {
                    LOGGER.infoCr(reconciliation, "Assembly {} or some parts of it will be deleted by garbage collection", name);
                }
                return (Void) null;
            }).recover(deleteResult -> {
                LOGGER.errorCr(reconciliation, "Deletion of {} {} failed", kind, name, deleteResult);
                return Future.failedFuture(deleteResult);
            });
        }
    });
    Promise<Void> result = Promise.promise();
    handler.onComplete(reconcileResult -> {
        try {
            handleResult(reconciliation, reconcileResult, reconciliationTimerSample);
        } finally {
            result.handle(reconcileResult);
        }
    });
    return result.future();
}
Also used : Condition(io.strimzi.api.kafka.model.status.Condition) ClusterRoleBinding(io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding) LabelSelector(io.fabric8.kubernetes.api.model.LabelSelector) Watch(io.fabric8.kubernetes.client.Watch) Callable(java.util.concurrent.Callable) ResourceVisitor(io.strimzi.operator.common.model.ResourceVisitor) ArrayList(java.util.ArrayList) WatcherException(io.fabric8.kubernetes.client.WatcherException) Timer(io.micrometer.core.instrument.Timer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) Status(io.strimzi.api.kafka.model.status.Status) ReconcileResult(io.strimzi.operator.common.operator.resource.ReconcileResult) AsyncResult(io.vertx.core.AsyncResult) LinkedHashSet(java.util.LinkedHashSet) 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) InvalidResourceException(io.strimzi.operator.cluster.model.InvalidResourceException) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ValidationVisitor(io.strimzi.operator.common.model.ValidationVisitor) Set(java.util.Set) Meter(io.micrometer.core.instrument.Meter) Spec(io.strimzi.api.kafka.model.Spec) Future(io.vertx.core.Future) Collectors(java.util.stream.Collectors) Util.async(io.strimzi.operator.common.Util.async) Consumer(java.util.function.Consumer) NamespaceAndName(io.strimzi.operator.common.model.NamespaceAndName) StatusDiff(io.strimzi.operator.cluster.model.StatusDiff) Labels(io.strimzi.operator.common.model.Labels) Lock(io.vertx.core.shareddata.Lock) ConditionBuilder(io.strimzi.api.kafka.model.status.ConditionBuilder) AbstractWatchableStatusedResourceOperator(io.strimzi.operator.common.operator.resource.AbstractWatchableStatusedResourceOperator) Optional(java.util.Optional) Condition(io.strimzi.api.kafka.model.status.Condition) Handler(io.vertx.core.Handler) Collections(java.util.Collections) CustomResource(io.fabric8.kubernetes.client.CustomResource) TimeoutException(io.strimzi.operator.common.operator.resource.TimeoutException) Status(io.strimzi.api.kafka.model.status.Status) InvalidResourceException(io.strimzi.operator.cluster.model.InvalidResourceException) ConditionBuilder(io.strimzi.api.kafka.model.status.ConditionBuilder) Timer(io.micrometer.core.instrument.Timer)

Example 2 with InvalidResourceException

use of io.strimzi.operator.cluster.model.InvalidResourceException in project strimzi by strimzi.

the class KafkaUserModelTest method testFromCrdScramShaUserWithEmptyPasswordThrows.

@Test
public void testFromCrdScramShaUserWithEmptyPasswordThrows() {
    KafkaUser emptyPassword = new KafkaUserBuilder(scramShaUser).editSpec().withNewKafkaUserScramSha512ClientAuthentication().withNewPassword().endPassword().endKafkaUserScramSha512ClientAuthentication().endSpec().build();
    InvalidResourceException e = assertThrows(InvalidResourceException.class, () -> {
        KafkaUserModel.fromCrd(emptyPassword, UserOperatorConfig.DEFAULT_SECRET_PREFIX, UserOperatorConfig.DEFAULT_STRIMZI_ACLS_ADMIN_API_SUPPORTED);
    });
    assertThat(e.getMessage(), is("Resource requests custom SCRAM-SHA-512 password but doesn't specify the secret name and/or key"));
}
Also used : InvalidResourceException(io.strimzi.operator.cluster.model.InvalidResourceException) KafkaUserBuilder(io.strimzi.api.kafka.model.KafkaUserBuilder) KafkaUser(io.strimzi.api.kafka.model.KafkaUser) Test(org.junit.jupiter.api.Test)

Example 3 with InvalidResourceException

use of io.strimzi.operator.cluster.model.InvalidResourceException in project strimzi by strimzi.

the class KafkaUserModelTest method testGenerateSecretUseDesiredPasswordMissingKey.

@Test
public void testGenerateSecretUseDesiredPasswordMissingKey() {
    KafkaUser user = new KafkaUserBuilder(scramShaUser).editSpec().withNewKafkaUserScramSha512ClientAuthentication().withNewPassword().withNewValueFrom().withNewSecretKeyRef("my-password", "my-secret", false).endValueFrom().endPassword().endKafkaUserScramSha512ClientAuthentication().endSpec().build();
    Secret desiredPasswordSecret = new SecretBuilder().withNewMetadata().withName("my-secret").endMetadata().addToData("my-other-password", DESIRED_BASE64_PASSWORD).build();
    KafkaUserModel model = KafkaUserModel.fromCrd(user, UserOperatorConfig.DEFAULT_SECRET_PREFIX, UserOperatorConfig.DEFAULT_STRIMZI_ACLS_ADMIN_API_SUPPORTED);
    InvalidResourceException e = assertThrows(InvalidResourceException.class, () -> {
        model.maybeGeneratePassword(Reconciliation.DUMMY_RECONCILIATION, passwordGenerator, null, desiredPasswordSecret);
    });
    assertThat(e.getMessage(), is("Secret my-secret does not contain the key my-password with requested user password."));
}
Also used : Secret(io.fabric8.kubernetes.api.model.Secret) SecretBuilder(io.fabric8.kubernetes.api.model.SecretBuilder) InvalidResourceException(io.strimzi.operator.cluster.model.InvalidResourceException) KafkaUserBuilder(io.strimzi.api.kafka.model.KafkaUserBuilder) KafkaUser(io.strimzi.api.kafka.model.KafkaUser) Test(org.junit.jupiter.api.Test)

Example 4 with InvalidResourceException

use of io.strimzi.operator.cluster.model.InvalidResourceException in project strimzi by strimzi.

the class KafkaUserModelTest method testGenerateSecretUseDesiredPasswordSecretDoesNotExist.

@Test
public void testGenerateSecretUseDesiredPasswordSecretDoesNotExist() {
    KafkaUser user = new KafkaUserBuilder(scramShaUser).editSpec().withNewKafkaUserScramSha512ClientAuthentication().withNewPassword().withNewValueFrom().withNewSecretKeyRef("my-password", "my-secret", false).endValueFrom().endPassword().endKafkaUserScramSha512ClientAuthentication().endSpec().build();
    KafkaUserModel model = KafkaUserModel.fromCrd(user, UserOperatorConfig.DEFAULT_SECRET_PREFIX, UserOperatorConfig.DEFAULT_STRIMZI_ACLS_ADMIN_API_SUPPORTED);
    InvalidResourceException e = assertThrows(InvalidResourceException.class, () -> {
        model.maybeGeneratePassword(Reconciliation.DUMMY_RECONCILIATION, passwordGenerator, null, null);
    });
    assertThat(e.getMessage(), is("Secret my-secret with requested user password does not exist."));
}
Also used : InvalidResourceException(io.strimzi.operator.cluster.model.InvalidResourceException) KafkaUserBuilder(io.strimzi.api.kafka.model.KafkaUserBuilder) KafkaUser(io.strimzi.api.kafka.model.KafkaUser) Test(org.junit.jupiter.api.Test)

Example 5 with InvalidResourceException

use of io.strimzi.operator.cluster.model.InvalidResourceException in project strimzi by strimzi.

the class KafkaUserModelTest method testFromCrdScramShaUserWithMissingPasswordKeyThrows.

@Test
public void testFromCrdScramShaUserWithMissingPasswordKeyThrows() {
    KafkaUser missingKey = new KafkaUserBuilder(scramShaUser).editSpec().withNewKafkaUserScramSha512ClientAuthentication().withNewPassword().withNewValueFrom().withNewSecretKeyRef(null, "my-secret", false).endValueFrom().endPassword().endKafkaUserScramSha512ClientAuthentication().endSpec().build();
    InvalidResourceException e = assertThrows(InvalidResourceException.class, () -> {
        KafkaUserModel.fromCrd(missingKey, UserOperatorConfig.DEFAULT_SECRET_PREFIX, UserOperatorConfig.DEFAULT_STRIMZI_ACLS_ADMIN_API_SUPPORTED);
    });
    assertThat(e.getMessage(), is("Resource requests custom SCRAM-SHA-512 password but doesn't specify the secret name and/or key"));
}
Also used : InvalidResourceException(io.strimzi.operator.cluster.model.InvalidResourceException) KafkaUserBuilder(io.strimzi.api.kafka.model.KafkaUserBuilder) KafkaUser(io.strimzi.api.kafka.model.KafkaUser) Test(org.junit.jupiter.api.Test)

Aggregations

InvalidResourceException (io.strimzi.operator.cluster.model.InvalidResourceException)28 Test (org.junit.jupiter.api.Test)12 KafkaUser (io.strimzi.api.kafka.model.KafkaUser)10 KafkaUserBuilder (io.strimzi.api.kafka.model.KafkaUserBuilder)10 Condition (io.strimzi.api.kafka.model.status.Condition)10 StatusUtils (io.strimzi.operator.common.operator.resource.StatusUtils)10 Future (io.vertx.core.Future)10 Promise (io.vertx.core.Promise)10 Vertx (io.vertx.core.Vertx)10 Collections (java.util.Collections)10 Map (java.util.Map)10 Collectors (java.util.stream.Collectors)10 Secret (io.fabric8.kubernetes.api.model.Secret)8 CustomResource (io.fabric8.kubernetes.client.CustomResource)8 KubernetesClient (io.fabric8.kubernetes.client.KubernetesClient)8 Resource (io.fabric8.kubernetes.client.dsl.Resource)8 PlatformFeaturesAvailability (io.strimzi.operator.PlatformFeaturesAvailability)8 ClusterOperatorConfig (io.strimzi.operator.cluster.ClusterOperatorConfig)8 ResourceOperatorSupplier (io.strimzi.operator.cluster.operator.resource.ResourceOperatorSupplier)8 Annotations (io.strimzi.operator.common.Annotations)8