diff --git a/operator/pom.xml b/operator/pom.xml index 2827889048..457190b95f 100644 --- a/operator/pom.xml +++ b/operator/pom.xml @@ -32,8 +32,8 @@ 11 UTF-8 UTF-8 - 3.0.2 - 2.6.1.Final + 3.0.4 + 2.7.3.Final keycloak eclipse-temurin:11 Never diff --git a/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakController.java b/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakController.java index e27a47a468..24365a5100 100644 --- a/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakController.java +++ b/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakController.java @@ -37,15 +37,18 @@ import org.keycloak.operator.Constants; import org.keycloak.operator.v2alpha1.crds.Keycloak; import org.keycloak.operator.v2alpha1.crds.KeycloakStatus; import org.keycloak.operator.v2alpha1.crds.KeycloakStatusBuilder; +import org.keycloak.operator.v2alpha1.crds.KeycloakStatusCondition; import javax.inject.Inject; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_CURRENT_NAMESPACE; -@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE, finalizerName = NO_FINALIZER) +// TODO: remove "generationAwareEventProcessing = false" when the race condition is fixed +@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE, finalizerName = NO_FINALIZER, generationAwareEventProcessing = false) public class KeycloakController implements Reconciler, EventSourceInitializer, ErrorStatusHandler { @Inject @@ -98,13 +101,23 @@ public class KeycloakController implements Reconciler, EventSourceInit Log.info("--- Reconciliation finished successfully"); + UpdateControl updateControl; if (status.equals(kc.getStatus())) { - return UpdateControl.noUpdate(); + updateControl = UpdateControl.noUpdate(); } else { kc.setStatus(status); - return UpdateControl.updateStatus(kc); + updateControl = UpdateControl.updateStatus(kc); } + + if (status + .getConditions() + .stream() + .anyMatch(c -> c.getType().equals(KeycloakStatusCondition.READY) && !c.getStatus())) { + updateControl.rescheduleAfter(10, TimeUnit.SECONDS); + } + + return updateControl; } @Override diff --git a/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakDeployment.java b/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakDeployment.java index e823aeb46c..84c3a47492 100644 --- a/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakDeployment.java +++ b/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakDeployment.java @@ -510,6 +510,7 @@ public class KeycloakDeployment extends OperatorManagedResource implements Statu || existingDeployment.getStatus().getReadyReplicas() == null || existingDeployment.getStatus().getReadyReplicas() < keycloakCR.getSpec().getInstances()) { status.addNotReadyMessage("Waiting for more replicas"); + return; } } diff --git a/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakRealmImportController.java b/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakRealmImportController.java index 085537313e..f046fe9329 100644 --- a/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakRealmImportController.java +++ b/operator/src/main/java/org/keycloak/operator/v2alpha1/KeycloakRealmImportController.java @@ -32,19 +32,24 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; import io.quarkus.logging.Log; +import org.keycloak.operator.v2alpha1.crds.Keycloak; import org.keycloak.operator.v2alpha1.crds.KeycloakRealmImport; import org.keycloak.operator.v2alpha1.crds.KeycloakRealmImportStatus; import org.keycloak.operator.v2alpha1.crds.KeycloakRealmImportStatusBuilder; +import org.keycloak.operator.v2alpha1.crds.KeycloakRealmImportStatusCondition; +import org.keycloak.operator.v2alpha1.crds.KeycloakStatusCondition; import javax.inject.Inject; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_CURRENT_NAMESPACE; -@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE, finalizerName = NO_FINALIZER) +// TODO: remove "generationAwareEventProcessing = false" when the race condition is fixed +@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE, finalizerName = NO_FINALIZER, generationAwareEventProcessing = false) public class KeycloakRealmImportController implements Reconciler, EventSourceInitializer, ErrorStatusHandler { @Inject @@ -83,12 +88,22 @@ public class KeycloakRealmImportController implements Reconciler updateControl; if (status.equals(realm.getStatus())) { - return UpdateControl.noUpdate(); + updateControl = UpdateControl.noUpdate(); } else { realm.setStatus(status); - return UpdateControl.updateStatus(realm); + updateControl = UpdateControl.updateStatus(realm); } + + if (status + .getConditions() + .stream() + .anyMatch(c -> c.getType().equals(KeycloakRealmImportStatusCondition.DONE) && !c.getStatus())) { + updateControl.rescheduleAfter(10, TimeUnit.SECONDS); + } + + return updateControl; } @Override diff --git a/operator/src/test/java/org/keycloak/operator/utils/K8sUtils.java b/operator/src/test/java/org/keycloak/operator/utils/K8sUtils.java index 30fc9d1090..7813bb3a0a 100644 --- a/operator/src/test/java/org/keycloak/operator/utils/K8sUtils.java +++ b/operator/src/test/java/org/keycloak/operator/utils/K8sUtils.java @@ -34,8 +34,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.UUID; - -import static java.util.concurrent.TimeUnit.MINUTES; +import java.util.concurrent.TimeUnit; /** * @author Vaclav Muzikar @@ -75,8 +74,8 @@ public final class K8sUtils { public static void waitForKeycloakToBeReady(KubernetesClient client, Keycloak kc) { Log.infof("Waiting for Keycloak \"%s\"", kc.getMetadata().getName()); Awaitility.await() - .pollInterval(Duration.ofSeconds(1)) - .timeout(Duration.ofMinutes(5)) + .pollInterval(1, TimeUnit.SECONDS) + .timeout(5, TimeUnit.MINUTES) .ignoreExceptions() .untilAsserted(() -> { var currentKc = client @@ -106,7 +105,7 @@ public final class K8sUtils { .build()) .done(); Log.info("Waiting for curl Pod to finish running"); - Awaitility.await().atMost(3, MINUTES) + Awaitility.await().atMost(3, TimeUnit.MINUTES) .until(() -> { String phase = k8sclient.pods().inNamespace(namespace).withName(podName).get() @@ -124,7 +123,7 @@ public final class K8sUtils { } finally { Log.info("Deleting curl Pod"); k8sclient.pods().inNamespace(namespace).withName(podName).delete(); - Awaitility.await().atMost(2, MINUTES) + Awaitility.await().atMost(2, TimeUnit.MINUTES) .until(() -> k8sclient.pods().inNamespace(namespace).withName(podName) .get() == null); }