Upgrade Operator SDK version

This commit is contained in:
Václav Muzikář 2022-09-26 13:32:03 +02:00 committed by Václav Muzikář
parent 42ad95af4d
commit 20fa75f677
7 changed files with 93 additions and 105 deletions

View file

@ -21,11 +21,11 @@
See https://github.com/quarkusio/quarkus/blob/<versionTag>/bom/application/pom.xml
for reference
-->
<resteasy.version>4.7.5.Final</resteasy.version>
<resteasy.version>4.7.7.Final</resteasy.version>
<wildfly.common.version>1.5.4.Final-format-001</wildfly.common.version>
<jackson.version>2.13.3</jackson.version>
<jackson.databind.version>2.13.3</jackson.databind.version>
<kubernetes-client.version>5.12.2</kubernetes-client.version>
<kubernetes-client.version>5.12.3</kubernetes-client.version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
@ -34,8 +34,8 @@
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.operator.sdk.version>3.0.8</quarkus.operator.sdk.version>
<quarkus.version>2.7.6.Final</quarkus.version>
<quarkus.operator.sdk.version>4.0.1</quarkus.operator.sdk.version>
<quarkus.version>2.12.2.Final</quarkus.version>
<quarkus.container-image.group>keycloak</quarkus.container-image.group>
<quarkus.jib.base-jvm-image>registry.access.redhat.com/ubi8/openjdk-11-runtime</quarkus.jib.base-jvm-image>
</properties>
@ -71,10 +71,6 @@
<groupId>io.quarkiverse.operatorsdk</groupId>
<artifactId>quarkus-operator-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.operatorsdk</groupId>
<artifactId>quarkus-operator-sdk-csv-generator</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
@ -100,14 +96,6 @@
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
<!-- This dependency is needed only to ensure proper building order so that this module is build after the CSV extension -->
<dependency>
<groupId>io.quarkiverse.operatorsdk</groupId>
<artifactId>quarkus-operator-sdk-csv-generator-deployment</artifactId>
<scope>provided</scope>
</dependency>
<!-- Keycloak -->
<dependency>
<groupId>org.keycloak</groupId>

View file

@ -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<String, String> DEFAULT_DIST_CONFIG = Map.of(
"health-enabled","true",
"cache", "ispn",

View file

@ -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<Keycloak>, EventSourceInitializer<Keycloak>, ErrorStatusHandler<Keycloak> {
@Inject
@ -58,29 +56,35 @@ public class KeycloakController implements Reconciler<Keycloak>, EventSourceInit
Config config;
@Override
public List<EventSource> prepareEventSources(EventSourceContext<Keycloak> context) {
String namespace = context.getConfigurationService().getClientConfiguration().getNamespace();
public Map<String, EventSource> prepareEventSources(EventSourceContext<Keycloak> context) {
String namespace = context.getControllerConfiguration().getConfigurationService().getClientConfiguration().getNamespace();
SharedIndexInformer<StatefulSet> deploymentInformer =
client.apps().statefulSets().inNamespace(namespace)
.withLabels(Constants.DEFAULT_LABELS)
.runnableInformer(0);
InformerConfiguration<StatefulSet> statefulSetIC = InformerConfiguration
.from(StatefulSet.class)
.withLabelSelector(Constants.DEFAULT_LABELS_AS_STRING)
.withNamespaces(namespace)
.withSecondaryToPrimaryMapper(Mappers.fromOwnerReference())
.build();
SharedIndexInformer<Service> servicesInformer =
client.services().inNamespace(namespace)
.withLabels(Constants.DEFAULT_LABELS)
.runnableInformer(0);
InformerConfiguration<Service> servicesIC = InformerConfiguration
.from(Service.class)
.withLabelSelector(Constants.DEFAULT_LABELS_AS_STRING)
.withNamespaces(namespace)
.withSecondaryToPrimaryMapper(Mappers.fromOwnerReference())
.build();
SharedIndexInformer<Ingress> ingressesInformer =
client.network().v1().ingresses().inNamespace(namespace)
.withLabels(Constants.DEFAULT_LABELS)
.runnableInformer(0);
InformerConfiguration<Ingress> 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<Keycloak>, EventSourceInit
}
@Override
public Optional<Keycloak> updateErrorStatus(Keycloak kc, RetryInfo retryInfo, RuntimeException e) {
public ErrorStatusUpdateControl<Keycloak> updateErrorStatus(Keycloak kc, Context<Keycloak> 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<Keycloak>, EventSourceInit
kc.setStatus(status);
return Optional.of(kc);
return ErrorStatusUpdateControl.updateStatus(kc);
}
}

View file

@ -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<KeycloakRealmImport>, EventSourceInitializer<KeycloakRealmImport>, ErrorStatusHandler<KeycloakRealmImport> {
@Inject
@ -56,13 +54,15 @@ public class KeycloakRealmImportController implements Reconciler<KeycloakRealmIm
ObjectMapper jsonMapper;
@Override
public List<EventSource> prepareEventSources(EventSourceContext<KeycloakRealmImport> context) {
SharedIndexInformer<Job> jobInformer =
client.batch().v1().jobs().inNamespace(context.getConfigurationService().getClientConfiguration().getNamespace())
.withLabels(org.keycloak.operator.Constants.DEFAULT_LABELS)
.runnableInformer(0);
public Map<String, EventSource> prepareEventSources(EventSourceContext<KeycloakRealmImport> context) {
InformerConfiguration<Job> 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<KeycloakRealmIm
}
@Override
public Optional<KeycloakRealmImport> updateErrorStatus(KeycloakRealmImport realm, RetryInfo retryInfo, RuntimeException e) {
public ErrorStatusUpdateControl<KeycloakRealmImport> updateErrorStatus(KeycloakRealmImport realm, Context<KeycloakRealmImport> 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);
}
}

View file

@ -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<Secret> informer =
client.secrets()
.inNamespace(namespace)
.withLabel(Constants.COMPONENT_LABEL, COMPONENT)
.runnableInformer(0);
InformerConfiguration<Secret> 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<Secret> informer =
client.secrets()
.inNamespace(namespace)
.withLabel(Constants.KEYCLOAK_COMPONENT_LABEL, WATCHED_SECRETS_LABEL_VALUE)
.runnableInformer(0);
InformerConfiguration<Secret> informerConfiguration = InformerConfiguration
.from(Secret.class)
.withLabelSelector(Constants.KEYCLOAK_COMPONENT_LABEL + "=" + WATCHED_SECRETS_LABEL_VALUE)
.withNamespaces(namespace)
.withSecondaryToPrimaryMapper(secret -> {
// get all stores
List<Secret> stores = client.secrets().inNamespace(namespace).withLabel(Constants.COMPONENT_LABEL, COMPONENT).list().getItems();
return new InformerEventSource<>(informer, secret -> {
// get all stores
List<Secret> 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);
}
}

View file

@ -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()

View file

@ -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() {