fix: adding debug logging for the KeycloakRealmImport (#42102)

also simplifying status logic

closes: #42019

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2025-08-29 06:57:00 -04:00 committed by GitHub
parent 1eba022149
commit ec0f64b4cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 52 deletions

View File

@ -33,7 +33,6 @@ import org.keycloak.operator.ContextUtils;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatus;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusBuilder;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@ -84,10 +83,7 @@ public class KeycloakRealmImportController implements Reconciler<KeycloakRealmIm
updateControl = UpdateControl.patchStatus(realm);
}
if (status
.getConditions()
.stream()
.anyMatch(c -> c.getType().equals(KeycloakRealmImportStatusCondition.DONE) && !Boolean.TRUE.equals(c.getStatus()))) {
if (!status.isDone()) {
updateControl.rescheduleAfter(10, TimeUnit.SECONDS);
}
@ -111,35 +107,34 @@ public class KeycloakRealmImportController implements Reconciler<KeycloakRealmIm
return;
}
if (getReadyReplicas(existingDeployment) < 1) {
status.addErrorMessage("Deployment not yet ready, waiting for it to be ready");
return;
}
if (existingJob == null) {
Log.info("Job about to start");
status.addStartedMessage("Import Job will start soon");
} else {
Log.info("Job already executed - not recreating");
var oldStatus = existingJob.getStatus();
var lastReportedStatus = realmCR.getStatus();
if (oldStatus == null) {
Log.info("Job started");
status.addStartedMessage("Import Job started");
} else if (oldStatus.getSucceeded() != null && oldStatus.getSucceeded() > 0) {
if (!lastReportedStatus.isDone()) {
// no need to restart Keycloak as we're only importing new realms and are not overwriting existing realms
Log.info("Job finished");
}
status.addDone();
} else if (oldStatus.getFailed() != null && oldStatus.getFailed() > 0) {
Log.info("Job Failed");
status.addErrorMessage("Import Job failed");
} else {
Log.info("Job running");
status.addStartedMessage("Import Job running");
if (getReadyReplicas(existingDeployment) < 1) {
status.addErrorMessage("Deployment not yet ready");
}
return;
}
Log.info("Job already executed - not recreating");
var oldStatus = existingJob.getStatus();
var lastReportedStatus = realmCR.getStatus();
if (oldStatus == null) {
Log.info("Job started");
status.addStartedMessage("Import Job started");
} else if (oldStatus.getSucceeded() != null && oldStatus.getSucceeded() > 0) {
if (!lastReportedStatus.isDone()) {
// no need to restart Keycloak as we're only importing new realms and are not overwriting existing realms
Log.info("Job finished");
}
status.addDone();
} else if (oldStatus.getFailed() != null && oldStatus.getFailed() > 0) {
Log.info("Job Failed");
status.addErrorMessage("Import Job failed");
} else {
Log.info("Job running");
status.addStartedMessage("Import Job running");
}
}

View File

@ -63,6 +63,7 @@ import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakSpecBuilder;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatus;
import org.keycloak.operator.testsuite.apiserver.ApiServerHelper;
import org.keycloak.operator.testsuite.apiserver.DisabledIfApiServerTest;
import org.keycloak.operator.testsuite.utils.K8sUtils;
@ -345,9 +346,8 @@ public class BaseOperatorTest implements QuarkusTestAfterEachCallback {
logEvents();
savePodLogs();
// provide some helpful entries in the main log as well
logFailedKeycloaks();
k8sclient.resources(Keycloak.class).list().getItems()
.forEach(keycloak -> Log.infof("Keycloak '%s' status:%n%s", keycloak.getMetadata().getName(), Serialization.asYaml(keycloak.getStatus())));
logKeycloaks();
logKeycloakRealmImports();
if (operatorDeployment == OperatorDeployment.remote) {
log(k8sclient.apps().deployments().withName("keycloak-operator"), Deployment::getStatus, false);
}
@ -395,26 +395,43 @@ public class BaseOperatorTest implements QuarkusTestAfterEachCallback {
log(resource, statusExtractor, true);
}
private void logFailedKeycloaks() {
k8sclient.resources(Keycloak.class).list().getItems().stream()
.filter(kc -> !Optional.ofNullable(kc.getStatus()).map(KeycloakStatus::isReady).orElse(false))
.forEach(kc -> {
Log.warnf("Keycloak failed to become ready \"%s\" %s", kc.getMetadata().getName(), Serialization.asYaml(kc.getStatus()));
var statefulSet = k8sclient.apps().statefulSets().withName(KeycloakDeploymentDependentResource.getName(kc)).get();
if (statefulSet != null) {
Log.warnf("Keycloak \"%s\" StatefulSet status %s", kc.getMetadata().getName(), Serialization.asYaml(statefulSet.getStatus()));
k8sclient.pods().withLabels(statefulSet.getSpec().getSelector().getMatchLabels()).list()
.getItems().stream().map(pod -> k8sclient.pods().resource(pod)).forEach(p -> {
logFailed(p, Pod::getStatus);
threadDump(p);
});
private void logKeycloakRealmImports() {
k8sclient.resources(KeycloakRealmImport.class).list().getItems().stream()
.forEach(kcri -> {
if (Optional.ofNullable(kcri.getStatus()).map(KeycloakRealmImportStatus::isDone).orElse(false)) {
Log.infof("Keycloak realm import '%s' status: %s", kcri.getMetadata().getName(), Serialization.asYaml(kcri.getStatus()));
} else {
Log.warnf("Keycloak realm import failed to be done \"%s\": %s", kcri.getMetadata().getName(), Serialization.asYaml(kcri.getStatus()));
Keycloak kc = k8sclient.resources(Keycloak.class).withName(kcri.getSpec().getKeycloakCRName()).get();
var job = k8sclient.batch().v1().jobs()
.inNamespace(kcri.getMetadata().getNamespace())
.withName(KeycloakUpdateJobDependentResource.jobName(kc))
.get();
if (job != null) {
Log.warnf("Keycloak Update Job \"%s\" %s", job.getMetadata().getName(), Serialization.asYaml(job.getStatus()));
}
}
var job = k8sclient.batch().v1().jobs()
.inNamespace(kc.getMetadata().getNamespace())
.withName(KeycloakUpdateJobDependentResource.jobName(kc))
.get();
if (job != null) {
Log.warnf("Keycloak Update Job \"%s\" %s", job.getMetadata().getName(), Serialization.asYaml(job.getStatus()));
});
}
private void logKeycloaks() {
k8sclient.resources(Keycloak.class).list().getItems().stream()
.forEach(kc -> {
if (Optional.ofNullable(kc.getStatus()).map(KeycloakStatus::isReady).orElse(false)) {
Log.infof("Keycloak '%s' status: %s", kc.getMetadata().getName(), Serialization.asYaml(kc.getStatus()));
} else {
Log.warnf("Keycloak failed to become ready \"%s\": %s", kc.getMetadata().getName(), Serialization.asYaml(kc.getStatus()));
var statefulSet = k8sclient.apps().statefulSets().withName(KeycloakDeploymentDependentResource.getName(kc)).get();
if (statefulSet != null) {
Log.warnf("Keycloak \"%s\" StatefulSet status %s", kc.getMetadata().getName(), Serialization.asYaml(statefulSet.getStatus()));
k8sclient.pods().withLabels(statefulSet.getSpec().getSelector().getMatchLabels()).list()
.getItems().stream().map(pod -> k8sclient.pods().resource(pod)).forEach(p -> {
logFailed(p, Pod::getStatus);
threadDump(p);
});
}
}
});
}