From f8604913977c1bb5dd4edbea365a9b9e37991f3c Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Wed, 15 Oct 2025 09:31:20 -0400 Subject: [PATCH] fix: refining activation condition error handling closes: #43096 (cherry picked from commit 43ee41e8a82fc7f326cc74df462fe44a5f95de61) Signed-off-by: Steve Hawkins --- .github/workflows/operator-ci.yml | 1 + docs/guides/operator/installation.adoc | 2 + .../controllers/KeycloakController.java | 8 ++- .../KeycloakDeploymentDependentResource.java | 22 +++--- ...ycloakServiceMonitorDependentResource.java | 70 ++++++++++++++++--- .../operator/crds/v2alpha1/CRDUtils.java | 10 +-- operator/src/main/kubernetes/kubernetes.yml | 6 -- .../integration/ServiceMonitorTest.java | 34 ++++++--- .../ServiceMonitorUninstalledTest.java | 43 ++++++++++++ .../testsuite/unit/PodTemplateTest.java | 3 +- 10 files changed, 153 insertions(+), 46 deletions(-) create mode 100644 operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorUninstalledTest.java diff --git a/.github/workflows/operator-ci.yml b/.github/workflows/operator-ci.yml index 7daa016edc4..eea2cde3739 100644 --- a/.github/workflows/operator-ci.yml +++ b/.github/workflows/operator-ci.yml @@ -206,6 +206,7 @@ jobs: run: | kubectl apply -f src/test/resources/service-monitor-crds.yml ./scripts/check-crd-installed.sh servicemonitors + kubectl delete pod -l name=keycloak-operator - name: Deploy an example Keycloak with ServiceMonitor working-directory: operator/scripts diff --git a/docs/guides/operator/installation.adoc b/docs/guides/operator/installation.adoc index 65bb556f948..d633f0acdd0 100644 --- a/docs/guides/operator/installation.adoc +++ b/docs/guides/operator/installation.adoc @@ -125,6 +125,8 @@ execute the following commands: kubectl create namespace custom-namespace kubectl -n custom-namespace apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/{version}/kubernetes/kubernetes.yml kubectl patch clusterrolebinding keycloak-operator-clusterrole-binding --type='json' -p='[{"op": "replace", "path": "/subjects/0/namespace", "value":"custom-namespace"}]' +# if you have existing keycloaks, restart the operator after patching the clusterrolebinding +kubectl rollout restart -n custom-namespace Deployment/keycloak-operator ---- diff --git a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java index dcda20d8a26..47112f81b20 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java @@ -34,7 +34,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.api.reconciler.Workflow; import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; -import io.javaoperatorsdk.operator.processing.dependent.workflow.CRDPresentActivationCondition; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.quarkus.logging.Log; import jakarta.inject.Inject; @@ -67,8 +66,7 @@ import java.util.concurrent.TimeUnit; @Dependent(type = KeycloakNetworkPolicyDependentResource.class, reconcilePrecondition = KeycloakNetworkPolicyDependentResource.EnabledCondition.class), @Dependent( type = KeycloakServiceMonitorDependentResource.class, - activationCondition = CRDPresentActivationCondition.class, - reconcilePrecondition = KeycloakServiceMonitorDependentResource.ReconcilePrecondition.class + activationCondition = KeycloakServiceMonitorDependentResource.ActivationCondition.class ), }) public class KeycloakController implements Reconciler { @@ -230,6 +228,10 @@ public class KeycloakController implements Reconciler { } distConfigurator.validateOptions(keycloakCR, status); + + context.managedWorkflowAndDependentResourceContext() + .get(KeycloakServiceMonitorDependentResource.SERVICE_MONITOR_WARNING, String.class) + .ifPresent(status::addWarningMessage); } public static boolean isRolling(StatefulSet existingDeployment) { diff --git a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakDeploymentDependentResource.java b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakDeploymentDependentResource.java index 8dd455110f3..e64a6f72213 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakDeploymentDependentResource.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakDeploymentDependentResource.java @@ -75,6 +75,7 @@ import java.util.stream.Stream; import static org.keycloak.operator.Utils.addResources; import static org.keycloak.operator.controllers.KeycloakDistConfigurator.getKeycloakOptionEnvVarName; +import static org.keycloak.operator.crds.v2alpha1.CRDUtils.LEGACY_MANAGEMENT_ENABLED; import static org.keycloak.operator.crds.v2alpha1.CRDUtils.isTlsConfigured; import static org.keycloak.operator.crds.v2alpha1.deployment.spec.TracingSpec.convertTracingAttributesToString; @@ -83,7 +84,6 @@ import static org.keycloak.operator.crds.v2alpha1.deployment.spec.TracingSpec.co ) public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependentResource { - public static final String HTTP_MANAGEMENT_HEALTH_ENABLED = "http-management-health-enabled"; public static final String HTTP_MANAGEMENT_SCHEME = "http-management-scheme"; public static final String POD_IP = "POD_IP"; @@ -356,8 +356,7 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent // Set bind address as this is required for JGroups to form a cluster in IPv6 environments containerBuilder.addToArgs(0, "-Djgroups.bind.address=$(%s)".formatted(POD_IP)); - var healthEnabled = readConfigurationValue(HTTP_MANAGEMENT_HEALTH_ENABLED, keycloakCR, context).map(Boolean::valueOf).orElse(true); - ManagementEndpoint endpoint = managementEndpoint(keycloakCR, context, healthEnabled); + ManagementEndpoint endpoint = managementEndpoint(keycloakCR, context, true); // probes var readinessOptionalSpec = Optional.ofNullable(keycloakCR.getSpec().getReadinessProbeSpec()); @@ -592,7 +591,7 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent return keycloak.getMetadata().getName(); } - private static Optional readConfigurationValue(String key, Keycloak keycloakCR, Context context) { + static Optional readConfigurationValue(String key, Keycloak keycloakCR, Context context) { return Optional.ofNullable(keycloakCR.getSpec()).map(KeycloakSpec::getAdditionalOptions) .flatMap(l -> l.stream().filter(sc -> sc.getName().equals(key)).findFirst().map(serverConfigValue -> { if (serverConfigValue.getValue() != null) { @@ -644,20 +643,27 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent toUpdate.getMetadata().getAnnotations().put(Constants.KEYCLOAK_UPDATE_REVISION_ANNOTATION, revision); } - record ManagementEndpoint(String relativePath, String protocol, int port) {} + record ManagementEndpoint(String relativePath, String protocol, int port, String portName) {} - static ManagementEndpoint managementEndpoint(Keycloak keycloakCR, Context context, boolean useMgmtProtocolPort) { + static ManagementEndpoint managementEndpoint(Keycloak keycloakCR, Context context, boolean health) { boolean tls = isTlsConfigured(keycloakCR); String protocol = tls ? "HTTPS" : "HTTP"; int port; + String portName; - if (useMgmtProtocolPort) { + var legacy = readConfigurationValue(LEGACY_MANAGEMENT_ENABLED, keycloakCR, context).map(Boolean::valueOf).orElse(false); + + var healthManagementEnabled = readConfigurationValue(CRDUtils.HTTP_MANAGEMENT_HEALTH_ENABLED, keycloakCR, context).map(Boolean::valueOf).orElse(true); + + if (!legacy && (!health || healthManagementEnabled)) { port = HttpManagementSpec.managementPort(keycloakCR); + portName = Constants.KEYCLOAK_MANAGEMENT_PORT_NAME; if (readConfigurationValue(HTTP_MANAGEMENT_SCHEME, keycloakCR, context).filter("http"::equals).isPresent()) { protocol = "HTTP"; } } else { port = tls ? HttpSpec.httpsPort(keycloakCR) : HttpSpec.httpPort(keycloakCR); + portName = tls ? Constants.KEYCLOAK_HTTPS_PORT_NAME : Constants.KEYCLOAK_HTTP_PORT_NAME; } var relativePath = readConfigurationValue(Constants.KEYCLOAK_HTTP_MANAGEMENT_RELATIVE_PATH_KEY, keycloakCR, context) @@ -665,6 +671,6 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent .map(path -> !path.endsWith("/") ? path + "/" : path) .orElse("/"); - return new ManagementEndpoint(relativePath, protocol, port); + return new ManagementEndpoint(relativePath, protocol, port, portName); } } diff --git a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakServiceMonitorDependentResource.java b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakServiceMonitorDependentResource.java index 587cde735a6..fce42555b35 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakServiceMonitorDependentResource.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakServiceMonitorDependentResource.java @@ -1,16 +1,19 @@ package org.keycloak.operator.controllers; import static org.keycloak.operator.controllers.KeycloakDeploymentDependentResource.managementEndpoint; -import static org.keycloak.operator.crds.v2alpha1.CRDUtils.LEGACY_MANAGEMENT_ENABLED; import static org.keycloak.operator.crds.v2alpha1.CRDUtils.METRICS_ENABLED; import static org.keycloak.operator.crds.v2alpha1.CRDUtils.configuredOptions; +import java.net.HttpURLConnection; + import org.keycloak.operator.Constants; import org.keycloak.operator.Utils; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; import org.keycloak.operator.crds.v2alpha1.deployment.spec.ServiceMonitorSpec; -import io.fabric8.kubernetes.api.model.networking.v1.Ingress; +import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.WatcherException; import io.fabric8.openshift.api.model.monitoring.v1.ServiceMonitor; import io.fabric8.openshift.api.model.monitoring.v1.ServiceMonitorBuilder; import io.javaoperatorsdk.operator.api.config.informer.Informer; @@ -19,28 +22,75 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; +import io.quarkus.logging.Log; @KubernetesDependent( informer = @Informer(labelSelector = Constants.DEFAULT_LABELS_AS_STRING) ) public class KeycloakServiceMonitorDependentResource extends CRUDKubernetesDependentResource { - public static class ReconcilePrecondition implements Condition { + public static final String WARN_METRICS_NOT_ENABLED = "A ServiceMonitor will not be created because `metrics-enabled` is not true."; + public static final String WARN_CRD_NOT_INSTALLED = "A ServiceMonitor will not be created because the ServiceMonitor CRD is not installed."; + + static String SERVICE_MONITOR_WARNING = "ServiceMonitorWarning"; + + volatile Boolean crdInstalled; + + public static class ActivationCondition implements Condition { + @Override - public boolean isMet(DependentResource dependentResource, Keycloak primary, - Context context) { - var opts = configuredOptions(primary); - if (Boolean.parseBoolean(opts.get(LEGACY_MANAGEMENT_ENABLED)) || !Boolean.parseBoolean(opts.getOrDefault(METRICS_ENABLED, "false"))) { + public boolean isMet(DependentResource dependentResource, Keycloak primary, Context context) { + if (!ServiceMonitorSpec.get(primary).isEnabled()) { return false; } - return ServiceMonitorSpec.get(primary).isEnabled(); + var opts = configuredOptions(primary); + + if (!Boolean.parseBoolean(opts.getOrDefault(METRICS_ENABLED, "false"))) { + context.managedWorkflowAndDependentResourceContext().put(SERVICE_MONITOR_WARNING, WARN_METRICS_NOT_ENABLED); + return false; + } + + if (!isCRDInstalled(dependentResource, context, (KeycloakServiceMonitorDependentResource)dependentResource)) { + context.managedWorkflowAndDependentResourceContext().put(SERVICE_MONITOR_WARNING, WARN_CRD_NOT_INSTALLED); + return false; + } + + return true; + } + + private boolean isCRDInstalled(DependentResource dependentResource, + Context context, KeycloakServiceMonitorDependentResource serviceMonitorDependentResource) { + if (serviceMonitorDependentResource.crdInstalled != null) { + return serviceMonitorDependentResource.crdInstalled; + } + Watcher dummyWatcher = new Watcher() { + + @Override + public void eventReceived(Action action, ServiceMonitor resource) { + } + + @Override + public void onClose(WatcherException cause) { + } + }; + try (var watch = context.getClient().resources(dependentResource.resourceType()).watch(dummyWatcher)) { + serviceMonitorDependentResource.crdInstalled = true; + return true; + } catch (KubernetesClientException e) { + if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) { + Log.warn("ServiceMonitors will not be managed by the operator as the CRD for ServiceMonitors not installed. If the CRD is installed later, the operator will need to be restarted."); + serviceMonitorDependentResource.crdInstalled = false; + return false; + } + throw e; + } } } @Override protected ServiceMonitor desired(Keycloak primary, Context context) { - var endpoint = managementEndpoint(primary, context, true); + var endpoint = managementEndpoint(primary, context, false); var meta = primary.getMetadata(); var spec = ServiceMonitorSpec.get(primary); return new ServiceMonitorBuilder() @@ -60,7 +110,7 @@ public class KeycloakServiceMonitorDependentResource extends CRUDKubernetesDepen .addNewEndpoint() .withInterval(spec.getInterval()) .withPath(endpoint.relativePath() + "metrics") - .withPort(Constants.KEYCLOAK_MANAGEMENT_PORT_NAME) + .withPort(endpoint.portName()) .withScheme(endpoint.protocol().toLowerCase()) .withScrapeTimeout(spec.getScrapeTimeout()) .withNewTlsConfig() diff --git a/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/CRDUtils.java b/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/CRDUtils.java index 6c94327e2d4..0583c846c17 100644 --- a/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/CRDUtils.java +++ b/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/CRDUtils.java @@ -21,10 +21,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; -import java.util.stream.Stream; import org.keycloak.operator.Constants; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; @@ -47,6 +45,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; */ public final class CRDUtils { private static final String HEALTH_ENABLED = "health-enabled"; + public static final String HTTP_MANAGEMENT_HEALTH_ENABLED = "http-management-health-enabled"; public static final String METRICS_ENABLED = "metrics-enabled"; public static final String LEGACY_MANAGEMENT_ENABLED = "legacy-observability-interface"; @@ -71,11 +70,8 @@ public final class CRDUtils { return false; } - // Only metrics and health use the management endpoint. - return Stream.of(METRICS_ENABLED, HEALTH_ENABLED) - .map(options::get) - .filter(Objects::nonNull) - .anyMatch(Boolean::parseBoolean); + return Boolean.parseBoolean(options.get(METRICS_ENABLED)) || (Boolean.parseBoolean(options.get(HEALTH_ENABLED)) + && Boolean.parseBoolean(options.getOrDefault(HTTP_MANAGEMENT_HEALTH_ENABLED, Boolean.toString(true)))); } public static Map configuredOptions(Keycloak keycloak) { diff --git a/operator/src/main/kubernetes/kubernetes.yml b/operator/src/main/kubernetes/kubernetes.yml index cd3a7ee626a..aa280b6a9ef 100644 --- a/operator/src/main/kubernetes/kubernetes.yml +++ b/operator/src/main/kubernetes/kubernetes.yml @@ -93,12 +93,6 @@ metadata: labels: app.kubernetes.io/name: keycloak-operator rules: - - apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - get - apiGroups: - config.openshift.io resources: diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorTest.java b/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorTest.java index 9ed6f5dec70..62d05db9dbd 100644 --- a/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorTest.java +++ b/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorTest.java @@ -8,9 +8,12 @@ import org.awaitility.Awaitility; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.keycloak.operator.controllers.KeycloakServiceMonitorDependentResource; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; +import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition; import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret; import org.keycloak.operator.crds.v2alpha1.deployment.spec.ServiceMonitorSpecBuilder; +import org.keycloak.operator.testsuite.utils.CRAssert; import org.keycloak.operator.testsuite.utils.K8sUtils; import io.fabric8.kubernetes.client.KubernetesClient; @@ -24,18 +27,23 @@ public class ServiceMonitorTest extends BaseOperatorTest { @Test public void testServiceMonitorDisabledNoMetrics() { Assumptions.assumeTrue(isServiceMonitorAvailable(k8sclient)); - var kc = getTestKeycloakDeployment(true, false);; + var kc = getTestKeycloakDeployment(true, false); kc.getSpec().setAdditionalOptions(List.of(new ValueOrSecret("metrics-enabled", "false"))); K8sUtils.deployKeycloak(k8sclient, kc, true); ServiceMonitor sm = getServiceMonitor(kc); assertThat(sm).isNull(); + + CRAssert.assertKeycloakStatusCondition( + k8sclient.resources(Keycloak.class).withName(kc.getMetadata().getName()).get(), + KeycloakStatusCondition.HAS_ERRORS, false, + KeycloakServiceMonitorDependentResource.WARN_METRICS_NOT_ENABLED); } @Test public void testServiceMonitorCreatedWithMetricsEnabled() { Assumptions.assumeTrue(isServiceMonitorAvailable(k8sclient)); - var kc = getTestKeycloakDeployment(true, false);; + var kc = getTestKeycloakDeployment(true, false); K8sUtils.deployKeycloak(k8sclient, kc, true); Awaitility.await().untilAsserted(() -> { @@ -48,7 +56,7 @@ public class ServiceMonitorTest extends BaseOperatorTest { @Test public void testServiceMonitorDisabledExplicitly() { Assumptions.assumeTrue(isServiceMonitorAvailable(k8sclient)); - var kc = getTestKeycloakDeployment(true, false);; + var kc = getTestKeycloakDeployment(true, false); kc.getSpec().setServiceMonitorSpec( new ServiceMonitorSpecBuilder() .withEnabled(false) @@ -61,20 +69,24 @@ public class ServiceMonitorTest extends BaseOperatorTest { } @Test - public void testServiceMonitorDisabledLegacyManagement() { + public void testServiceMonitorLegacyManagement() { Assumptions.assumeTrue(isServiceMonitorAvailable(k8sclient)); - var kc = getTestKeycloakDeployment(true, false);; - kc.getSpec().setAdditionalOptions(List.of(new ValueOrSecret("legacy-observability-interface", "true"))); + var kc = getTestKeycloakDeployment(true, false); + kc.getSpec().getAdditionalOptions().add(new ValueOrSecret("legacy-observability-interface", "true")); K8sUtils.deployKeycloak(k8sclient, kc, true); - ServiceMonitor sm = getServiceMonitor(kc); - assertThat(sm).isNull(); + Awaitility.await().untilAsserted(() -> { + var sm = getServiceMonitor(kc); + assertThat(sm).isNotNull(); + assertThat(sm.getSpec().getEndpoints()).hasSize(1); + assertThat(sm.getSpec().getEndpoints().get(0).getPort()).isEqualTo("https"); + }); } @Test public void testServiceMonitorConfigProperties() { Assumptions.assumeTrue(isServiceMonitorAvailable(k8sclient)); - var kc = getTestKeycloakDeployment(true, false);; + var kc = getTestKeycloakDeployment(true, false); kc.getSpec().setServiceMonitorSpec( new ServiceMonitorSpecBuilder() .withInterval("1s") @@ -92,14 +104,14 @@ public class ServiceMonitorTest extends BaseOperatorTest { }); } - private ServiceMonitor getServiceMonitor(Keycloak kc) { + static ServiceMonitor getServiceMonitor(Keycloak kc) { return k8sclient.resources(ServiceMonitor.class) .inNamespace(kc.getMetadata().getNamespace()) .withName(kc.getMetadata().getName()) .get(); } - private boolean isServiceMonitorAvailable(KubernetesClient client) { + static boolean isServiceMonitorAvailable(KubernetesClient client) { return client .apiextensions() .v1() diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorUninstalledTest.java b/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorUninstalledTest.java new file mode 100644 index 00000000000..b71fe71ba89 --- /dev/null +++ b/operator/src/test/java/org/keycloak/operator/testsuite/integration/ServiceMonitorUninstalledTest.java @@ -0,0 +1,43 @@ +package org.keycloak.operator.testsuite.integration; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.keycloak.operator.controllers.KeycloakServiceMonitorDependentResource; +import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; +import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition; +import org.keycloak.operator.testsuite.utils.CRAssert; +import org.keycloak.operator.testsuite.utils.K8sUtils; + +import io.fabric8.openshift.api.model.monitoring.v1.ServiceMonitor; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class ServiceMonitorUninstalledTest extends BaseOperatorTest { + + @BeforeAll + public static void beforeAll() { + k8sclient.apiextensions().v1().customResourceDefinitions().withName(new ServiceMonitor().getFullResourceName()) + .withTimeout(10, TimeUnit.SECONDS).delete(); + } + + @Test + public void testServiceMonitorNoCRD() { + Assumptions.assumeFalse(ServiceMonitorTest.isServiceMonitorAvailable(k8sclient)); + var kc = getTestKeycloakDeployment(true, false); + K8sUtils.deployKeycloak(k8sclient, kc, true); + + ServiceMonitor sm = ServiceMonitorTest.getServiceMonitor(kc); + assertThat(sm).isNull(); + + CRAssert.assertKeycloakStatusCondition( + k8sclient.resources(Keycloak.class).withName(kc.getMetadata().getName()).get(), + KeycloakStatusCondition.HAS_ERRORS, false, + KeycloakServiceMonitorDependentResource.WARN_CRD_NOT_INSTALLED); + } + +} diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/unit/PodTemplateTest.java b/operator/src/test/java/org/keycloak/operator/testsuite/unit/PodTemplateTest.java index a7ce77031b7..24d5879159e 100644 --- a/operator/src/test/java/org/keycloak/operator/testsuite/unit/PodTemplateTest.java +++ b/operator/src/test/java/org/keycloak/operator/testsuite/unit/PodTemplateTest.java @@ -57,6 +57,7 @@ import org.keycloak.operator.controllers.KeycloakDistConfigurator; import org.keycloak.operator.controllers.KeycloakRealmImportJobDependentResource; import org.keycloak.operator.controllers.KeycloakUpdateJobDependentResource; import org.keycloak.operator.controllers.WatchedResources; +import org.keycloak.operator.crds.v2alpha1.CRDUtils; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakBuilder; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakSpecBuilder; @@ -416,7 +417,7 @@ public class PodTemplateTest { @Test public void testHealthOnMain() { var result = getDeployment(null, new StatefulSet(), - spec -> spec.withAdditionalOptions(new ValueOrSecret(KeycloakDeploymentDependentResource.HTTP_MANAGEMENT_HEALTH_ENABLED, "false"))) + spec -> spec.withAdditionalOptions(new ValueOrSecret(CRDUtils.HTTP_MANAGEMENT_HEALTH_ENABLED, "false"))) .getSpec() .getTemplate() .getSpec()