Upgrade Operator SDK version
This commit is contained in:
parent
42ad95af4d
commit
20fa75f677
7 changed files with 93 additions and 105 deletions
|
@ -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>
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue