Search in sources :

Example 1 with Spec

use of io.strimzi.api.kafka.model.Spec 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 Spec

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

the class OperatorMetricsTest method resourceOperatorWithExistingPausedResource.

private AbstractWatchableStatusedResourceOperator resourceOperatorWithExistingPausedResource() {
    return new AbstractWatchableStatusedResourceOperator(vertx, null, "TestResource") {

        @Override
        public Future updateStatusAsync(Reconciliation reconciliation, HasMetadata resource) {
            return Future.succeededFuture();
        }

        @Override
        protected MixedOperation operation() {
            return null;
        }

        @Override
        public CustomResource get(String namespace, String name) {
            @Group("strimzi")
            @Version("v1")
            class Foo extends MyResource {

                @Override
                public ObjectMeta getMetadata() {
                    ObjectMeta md = new ObjectMeta();
                    md.setAnnotations(singletonMap("strimzi.io/pause-reconciliation", "true"));
                    return md;
                }

                @Override
                public void setMetadata(ObjectMeta objectMeta) {
                }

                @Override
                public String getKind() {
                    return "TestResource";
                }

                @Override
                public String getApiVersion() {
                    return "v1";
                }

                @Override
                public void setApiVersion(String s) {
                }

                @Override
                public Spec getSpec() {
                    return new Spec() {
                    };
                }

                @Override
                public void setSpec(Object spec) {
                }

                @Override
                public Status getStatus() {
                    return null;
                }

                @Override
                public void setStatus(Object status) {
                }
            }
            return new Foo();
        }

        @Override
        public Future getAsync(String namespace, String name) {
            @Group("strimzi")
            @Version("v1")
            class Foo extends MyResource {

                @Override
                public ObjectMeta getMetadata() {
                    ObjectMeta md = new ObjectMeta();
                    md.setAnnotations(singletonMap("strimzi.io/pause-reconciliation", "true"));
                    return md;
                }

                @Override
                public void setMetadata(ObjectMeta objectMeta) {
                }

                @Override
                public String getKind() {
                    return "TestResource";
                }

                @Override
                public String getApiVersion() {
                    return "v1";
                }

                @Override
                public void setApiVersion(String s) {
                }

                @Override
                public Spec getSpec() {
                    return new Spec() {
                    };
                }

                @Override
                public void setSpec(Object spec) {
                }

                @Override
                public Status getStatus() {
                    return null;
                }

                @Override
                public void setStatus(Object status) {
                }
            }
            return Future.succeededFuture(new Foo());
        }
    };
}
Also used : Group(io.fabric8.kubernetes.model.annotation.Group) ObjectMeta(io.fabric8.kubernetes.api.model.ObjectMeta) HasMetadata(io.fabric8.kubernetes.api.model.HasMetadata) Version(io.fabric8.kubernetes.model.annotation.Version) AbstractWatchableStatusedResourceOperator(io.strimzi.operator.common.operator.resource.AbstractWatchableStatusedResourceOperator) Spec(io.strimzi.api.kafka.model.Spec)

Example 3 with Spec

use of io.strimzi.api.kafka.model.Spec in project strimzi by strimzi.

the class OperatorMetricsTest method resourceOperatorWithExistingPausedResource.

private AbstractWatchableStatusedResourceOperator resourceOperatorWithExistingPausedResource() {
    return new AbstractWatchableStatusedResourceOperator(vertx, null, "TestResource") {

        @Override
        public Future updateStatusAsync(Reconciliation reconciliation, HasMetadata resource) {
            return Future.succeededFuture();
        }

        @Override
        protected MixedOperation operation() {
            return null;
        }

        @Override
        public CustomResource get(String namespace, String name) {
            @Group("strimzi")
            @Version("v1")
            class Foo extends MyResource {

                @Override
                public ObjectMeta getMetadata() {
                    ObjectMeta md = new ObjectMeta();
                    md.setAnnotations(singletonMap("strimzi.io/pause-reconciliation", "true"));
                    return md;
                }

                @Override
                public void setMetadata(ObjectMeta objectMeta) {
                }

                @Override
                public String getKind() {
                    return "TestResource";
                }

                @Override
                public String getApiVersion() {
                    return "v1";
                }

                @Override
                public void setApiVersion(String s) {
                }

                @Override
                public Spec getSpec() {
                    return new Spec() {
                    };
                }

                @Override
                public void setSpec(Object spec) {
                }

                @Override
                public Status getStatus() {
                    return null;
                }

                @Override
                public void setStatus(Object status) {
                }
            }
            return new Foo();
        }

        @Override
        public Future getAsync(String namespace, String name) {
            @Group("strimzi")
            @Version("v1")
            class Foo extends MyResource {

                @Override
                public ObjectMeta getMetadata() {
                    ObjectMeta md = new ObjectMeta();
                    md.setAnnotations(singletonMap("strimzi.io/pause-reconciliation", "true"));
                    return md;
                }

                @Override
                public void setMetadata(ObjectMeta objectMeta) {
                }

                @Override
                public String getKind() {
                    return "TestResource";
                }

                @Override
                public String getApiVersion() {
                    return "v1";
                }

                @Override
                public void setApiVersion(String s) {
                }

                @Override
                public Spec getSpec() {
                    return new Spec() {
                    };
                }

                @Override
                public void setSpec(Object spec) {
                }

                @Override
                public Status getStatus() {
                    return null;
                }

                @Override
                public void setStatus(Object status) {
                }
            }
            return Future.succeededFuture(new Foo());
        }
    };
}
Also used : Group(io.fabric8.kubernetes.model.annotation.Group) ObjectMeta(io.fabric8.kubernetes.api.model.ObjectMeta) HasMetadata(io.fabric8.kubernetes.api.model.HasMetadata) Version(io.fabric8.kubernetes.model.annotation.Version) AbstractWatchableStatusedResourceOperator(io.strimzi.operator.common.operator.resource.AbstractWatchableStatusedResourceOperator) Spec(io.strimzi.api.kafka.model.Spec)

Example 4 with Spec

use of io.strimzi.api.kafka.model.Spec in project strimzi-kafka-operator 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)

Aggregations

Spec (io.strimzi.api.kafka.model.Spec)4 AbstractWatchableStatusedResourceOperator (io.strimzi.operator.common.operator.resource.AbstractWatchableStatusedResourceOperator)4 HasMetadata (io.fabric8.kubernetes.api.model.HasMetadata)2 LabelSelector (io.fabric8.kubernetes.api.model.LabelSelector)2 ObjectMeta (io.fabric8.kubernetes.api.model.ObjectMeta)2 ClusterRoleBinding (io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding)2 CustomResource (io.fabric8.kubernetes.client.CustomResource)2 Watch (io.fabric8.kubernetes.client.Watch)2 WatcherException (io.fabric8.kubernetes.client.WatcherException)2 Group (io.fabric8.kubernetes.model.annotation.Group)2 Version (io.fabric8.kubernetes.model.annotation.Version)2 Counter (io.micrometer.core.instrument.Counter)2 Meter (io.micrometer.core.instrument.Meter)2 Tag (io.micrometer.core.instrument.Tag)2 Tags (io.micrometer.core.instrument.Tags)2 Timer (io.micrometer.core.instrument.Timer)2 Condition (io.strimzi.api.kafka.model.status.Condition)2 ConditionBuilder (io.strimzi.api.kafka.model.status.ConditionBuilder)2 Status (io.strimzi.api.kafka.model.status.Status)2 InvalidResourceException (io.strimzi.operator.cluster.model.InvalidResourceException)2