From 20fa75f677b365c719f013cb59accda0170f627a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Muzik=C3=A1=C5=99?= Date: Mon, 26 Sep 2022 13:32:03 +0200 Subject: [PATCH] Upgrade Operator SDK version --- operator/pom.xml | 20 +---- .../java/org/keycloak/operator/Constants.java | 5 ++ .../controllers/KeycloakController.java | 56 +++++++------- .../KeycloakRealmImportController.java | 30 ++++---- .../controllers/WatchedSecretsStore.java | 74 +++++++++---------- .../KeycloakRealmImportStatus.java | 3 + .../integration/BaseOperatorTest.java | 10 +-- 7 files changed, 93 insertions(+), 105 deletions(-) diff --git a/operator/pom.xml b/operator/pom.xml index 1fdecc1cd7..7adb25f416 100644 --- a/operator/pom.xml +++ b/operator/pom.xml @@ -21,11 +21,11 @@ See https://github.com/quarkusio/quarkus/blob//bom/application/pom.xml for reference --> - 4.7.5.Final + 4.7.7.Final 1.5.4.Final-format-001 2.13.3 2.13.3 - 5.12.2 + 5.12.3 3.8.1 true @@ -34,8 +34,8 @@ 11 UTF-8 UTF-8 - 3.0.8 - 2.7.6.Final + 4.0.1 + 2.12.2.Final keycloak registry.access.redhat.com/ubi8/openjdk-11-runtime @@ -71,10 +71,6 @@ io.quarkiverse.operatorsdk quarkus-operator-sdk - - io.quarkiverse.operatorsdk - quarkus-operator-sdk-csv-generator - io.quarkus quarkus-resteasy-jackson @@ -100,14 +96,6 @@ quarkus-kubernetes-client - - - - io.quarkiverse.operatorsdk - quarkus-operator-sdk-csv-generator-deployment - provided - - org.keycloak diff --git a/operator/src/main/java/org/keycloak/operator/Constants.java b/operator/src/main/java/org/keycloak/operator/Constants.java index f22ae89922..080e37055a 100644 --- a/operator/src/main/java/org/keycloak/operator/Constants.java +++ b/operator/src/main/java/org/keycloak/operator/Constants.java @@ -17,6 +17,7 @@ package org.keycloak.operator; import java.util.Map; +import java.util.stream.Collectors; public final class Constants { public static final String CRDS_GROUP = "k8s.keycloak.org"; @@ -34,6 +35,10 @@ public final class Constants { MANAGED_BY_LABEL, MANAGED_BY_VALUE ); + public static final String DEFAULT_LABELS_AS_STRING = DEFAULT_LABELS.entrySet().stream() + .map(e -> e.getKey() + "=" + e.getValue()) + .collect(Collectors.joining(",")); + public static final Map DEFAULT_DIST_CONFIG = Map.of( "health-enabled","true", "cache", "ispn", 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 6e5adc5fc0..057c60d650 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java @@ -20,14 +20,14 @@ import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.StatefulSet; import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.informers.SharedIndexInformer; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -41,14 +41,12 @@ import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusBuilder; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition; import javax.inject.Inject; -import java.util.List; -import java.util.Optional; +import java.util.Map; 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) +@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE) public class KeycloakController implements Reconciler, EventSourceInitializer, ErrorStatusHandler { @Inject @@ -58,29 +56,35 @@ public class KeycloakController implements Reconciler, EventSourceInit Config config; @Override - public List prepareEventSources(EventSourceContext context) { - String namespace = context.getConfigurationService().getClientConfiguration().getNamespace(); + public Map prepareEventSources(EventSourceContext context) { + String namespace = context.getControllerConfiguration().getConfigurationService().getClientConfiguration().getNamespace(); - SharedIndexInformer deploymentInformer = - client.apps().statefulSets().inNamespace(namespace) - .withLabels(Constants.DEFAULT_LABELS) - .runnableInformer(0); + InformerConfiguration statefulSetIC = InformerConfiguration + .from(StatefulSet.class) + .withLabelSelector(Constants.DEFAULT_LABELS_AS_STRING) + .withNamespaces(namespace) + .withSecondaryToPrimaryMapper(Mappers.fromOwnerReference()) + .build(); - SharedIndexInformer servicesInformer = - client.services().inNamespace(namespace) - .withLabels(Constants.DEFAULT_LABELS) - .runnableInformer(0); + InformerConfiguration servicesIC = InformerConfiguration + .from(Service.class) + .withLabelSelector(Constants.DEFAULT_LABELS_AS_STRING) + .withNamespaces(namespace) + .withSecondaryToPrimaryMapper(Mappers.fromOwnerReference()) + .build(); - SharedIndexInformer ingressesInformer = - client.network().v1().ingresses().inNamespace(namespace) - .withLabels(Constants.DEFAULT_LABELS) - .runnableInformer(0); + InformerConfiguration ingressesIC = InformerConfiguration + .from(Ingress.class) + .withLabelSelector(Constants.DEFAULT_LABELS_AS_STRING) + .withNamespaces(namespace) + .withSecondaryToPrimaryMapper(Mappers.fromOwnerReference()) + .build(); - EventSource deploymentEvent = new InformerEventSource<>(deploymentInformer, Mappers.fromOwnerReference()); - EventSource servicesEvent = new InformerEventSource<>(servicesInformer, Mappers.fromOwnerReference()); - EventSource ingressesEvent = new InformerEventSource<>(ingressesInformer, Mappers.fromOwnerReference()); + EventSource statefulSetEvent = new InformerEventSource<>(statefulSetIC, context); + EventSource servicesEvent = new InformerEventSource<>(servicesIC, context); + EventSource ingressesEvent = new InformerEventSource<>(ingressesIC, context); - return List.of(deploymentEvent, + return EventSourceInitializer.nameEventSources(statefulSetEvent, servicesEvent, ingressesEvent, WatchedSecretsStore.getStoreEventSource(client, namespace), @@ -146,7 +150,7 @@ public class KeycloakController implements Reconciler, EventSourceInit } @Override - public Optional updateErrorStatus(Keycloak kc, RetryInfo retryInfo, RuntimeException e) { + public ErrorStatusUpdateControl updateErrorStatus(Keycloak kc, Context context, Exception e) { Log.error("--- Error reconciling", e); KeycloakStatus status = new KeycloakStatusBuilder() .addErrorMessage("Error performing operations:\n" + e.getMessage()) @@ -154,6 +158,6 @@ public class KeycloakController implements Reconciler, EventSourceInit kc.setStatus(status); - return Optional.of(kc); + return ErrorStatusUpdateControl.updateStatus(kc); } } diff --git a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakRealmImportController.java b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakRealmImportController.java index b899370edb..2bb59a1f42 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/KeycloakRealmImportController.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/KeycloakRealmImportController.java @@ -19,34 +19,32 @@ package org.keycloak.operator.controllers; import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.api.model.batch.v1.Job; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.informers.SharedIndexInformer; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; 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.Constants; 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 javax.inject.Inject; - -import java.util.List; -import java.util.Optional; +import java.util.Map; 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) +@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE) public class KeycloakRealmImportController implements Reconciler, EventSourceInitializer, ErrorStatusHandler { @Inject @@ -56,13 +54,15 @@ public class KeycloakRealmImportController implements Reconciler prepareEventSources(EventSourceContext context) { - SharedIndexInformer jobInformer = - client.batch().v1().jobs().inNamespace(context.getConfigurationService().getClientConfiguration().getNamespace()) - .withLabels(org.keycloak.operator.Constants.DEFAULT_LABELS) - .runnableInformer(0); + public Map prepareEventSources(EventSourceContext context) { + InformerConfiguration jobIC = InformerConfiguration + .from(Job.class) + .withLabelSelector(Constants.DEFAULT_LABELS_AS_STRING) + .withNamespaces(context.getControllerConfiguration().getConfigurationService().getClientConfiguration().getNamespace()) + .withSecondaryToPrimaryMapper(Mappers.fromOwnerReference()) + .build(); - return List.of(new InformerEventSource<>(jobInformer, Mappers.fromOwnerReference())); + return EventSourceInitializer.nameEventSources(new InformerEventSource<>(jobIC, context)); } @Override @@ -104,13 +104,13 @@ public class KeycloakRealmImportController implements Reconciler updateErrorStatus(KeycloakRealmImport realm, RetryInfo retryInfo, RuntimeException e) { + public ErrorStatusUpdateControl updateErrorStatus(KeycloakRealmImport realm, Context context, Exception e) { Log.error("--- Error reconciling", e); KeycloakRealmImportStatus status = new KeycloakRealmImportStatusBuilder() .addErrorMessage("Error performing operations:\n" + e.getMessage()) .build(); realm.setStatus(status); - return Optional.of(realm); + return ErrorStatusUpdateControl.updateStatus(realm); } } diff --git a/operator/src/main/java/org/keycloak/operator/controllers/WatchedSecretsStore.java b/operator/src/main/java/org/keycloak/operator/controllers/WatchedSecretsStore.java index 521aa379f0..daeb09140a 100644 --- a/operator/src/main/java/org/keycloak/operator/controllers/WatchedSecretsStore.java +++ b/operator/src/main/java/org/keycloak/operator/controllers/WatchedSecretsStore.java @@ -21,8 +21,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.informers.SharedIndexInformer; import io.fabric8.kubernetes.client.utils.Serialization; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -183,18 +183,14 @@ public class WatchedSecretsStore extends OperatorManagedResource { } public static EventSource getStoreEventSource(KubernetesClient client, String namespace) { - SharedIndexInformer informer = - client.secrets() - .inNamespace(namespace) - .withLabel(Constants.COMPONENT_LABEL, COMPONENT) - .runnableInformer(0); + InformerConfiguration informerConfiguration = InformerConfiguration + .from(Secret.class) + .withLabelSelector(Constants.COMPONENT_LABEL + "=" + COMPONENT) + .withNamespaces(namespace) + .withSecondaryToPrimaryMapper(Mappers.fromOwnerReference()) + .build(); - return new InformerEventSource<>(informer, Mappers.fromOwnerReference()) { - @Override - public String name() { - return "watchedResourcesStoreEventSource"; - } - }; + return new InformerEventSource<>(informerConfiguration, client); } private static void cleanObsoleteLabelFromSecret(KubernetesClient client, Secret secret) { @@ -203,38 +199,34 @@ public class WatchedSecretsStore extends OperatorManagedResource { } public static EventSource getWatchedSecretsEventSource(KubernetesClient client, String namespace) { - SharedIndexInformer informer = - client.secrets() - .inNamespace(namespace) - .withLabel(Constants.KEYCLOAK_COMPONENT_LABEL, WATCHED_SECRETS_LABEL_VALUE) - .runnableInformer(0); + InformerConfiguration informerConfiguration = InformerConfiguration + .from(Secret.class) + .withLabelSelector(Constants.KEYCLOAK_COMPONENT_LABEL + "=" + WATCHED_SECRETS_LABEL_VALUE) + .withNamespaces(namespace) + .withSecondaryToPrimaryMapper(secret -> { + // get all stores + List stores = client.secrets().inNamespace(namespace).withLabel(Constants.COMPONENT_LABEL, COMPONENT).list().getItems(); - return new InformerEventSource<>(informer, secret -> { - // get all stores - List stores = client.secrets().inNamespace(namespace).withLabel(Constants.COMPONENT_LABEL, COMPONENT).list().getItems(); + // find all CR names that are watching this Secret + var ret = stores.stream() + // check if any of the stores tracks this secret + .filter(store -> store.getData().containsKey(secret.getMetadata().getName())) + .map(store -> { + String crName = store.getMetadata().getName().split(STORE_SUFFIX)[0]; + return new ResourceID(crName, namespace); + }) + .collect(Collectors.toSet()); - // find all CR names that are watching this Secret - var ret = stores.stream() - // check if any of the stores tracks this secret - .filter(store -> store.getData().containsKey(secret.getMetadata().getName())) - .map(store -> { - String crName = store.getMetadata().getName().split(STORE_SUFFIX)[0]; - return new ResourceID(crName, namespace); - }) - .collect(Collectors.toSet()); + if (ret.isEmpty()) { + Log.infof("No CRs watching \"%s\" Secret, cleaning up labels", secret.getMetadata().getName()); + cleanObsoleteLabelFromSecret(client, secret); + Log.debug("Labels removed"); + } - if (ret.isEmpty()) { - Log.infof("No CRs watching \"%s\" Secret, cleaning up labels", secret.getMetadata().getName()); - cleanObsoleteLabelFromSecret(client, secret); - Log.debug("Labels removed"); - } + return ret; + }) + .build(); - return ret; - }) { - @Override - public String name() { - return "watchedSecretsEventSource"; - } - }; + return new InformerEventSource<>(informerConfiguration, client); } } diff --git a/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/realmimport/KeycloakRealmImportStatus.java b/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/realmimport/KeycloakRealmImportStatus.java index 0617255cf1..c0c97d07e8 100644 --- a/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/realmimport/KeycloakRealmImportStatus.java +++ b/operator/src/main/java/org/keycloak/operator/crds/v2alpha1/realmimport/KeycloakRealmImportStatus.java @@ -16,6 +16,8 @@ */ package org.keycloak.operator.crds.v2alpha1.realmimport; +import com.fasterxml.jackson.annotation.JsonIgnore; + import java.util.List; import java.util.Objects; @@ -32,6 +34,7 @@ public class KeycloakRealmImportStatus { this.conditions = conditions; } + @JsonIgnore public boolean isDone() { return conditions .stream() diff --git a/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java b/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java index 2b36ebee77..93534231d9 100644 --- a/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java +++ b/operator/src/test/java/org/keycloak/operator/testsuite/integration/BaseOperatorTest.java @@ -46,7 +46,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.time.Duration; -import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -143,17 +142,14 @@ public abstract class BaseOperatorTest { Log.info("Registering reconcilers for operator : " + operator + " [" + operatorDeployment + "]"); for (Reconciler reconciler : reconcilers) { - final var config = configuration.getConfigurationFor(reconciler); - if (!config.isRegistrationDelayed()) { - Log.info("Register and apply : " + reconciler.getClass().getName()); - OperatorProducer.applyCRDIfNeededAndRegister(operator, reconciler, configuration); - } + Log.info("Register and apply : " + reconciler.getClass().getName()); + OperatorProducer.applyCRDAndRegister(operator, reconciler, configuration); } } private static void createOperator() { + configuration.getClientConfiguration().setNamespace(namespace); operator = new Operator(k8sclient, configuration); - operator.getConfigurationService().getClientConfiguration().setNamespace(namespace); } private static void createNamespace() {