Skip to content

Commit

Permalink
Merge branch 'main' into feat/operator-java-opts
Browse files Browse the repository at this point in the history
  • Loading branch information
EricWittmann authored Feb 14, 2025
2 parents 0c72719 + 20b4c59 commit 42a32ca
Show file tree
Hide file tree
Showing 30 changed files with 765 additions and 304 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package io.apicurio.registry.operator;

import io.apicurio.registry.operator.api.v1.ApicurioRegistry3;
import io.apicurio.registry.operator.resource.LabelDiscriminators.AppDeploymentDiscriminator;
import io.apicurio.registry.operator.resource.app.*;
import io.apicurio.registry.operator.resource.studioui.*;
import io.apicurio.registry.operator.resource.ui.*;
import io.apicurio.registry.operator.status.OperatorErrorConditionManager;
import io.apicurio.registry.operator.status.StatusManager;
import io.apicurio.registry.operator.updater.IngressCRUpdater;
import io.apicurio.registry.operator.updater.KafkaSqlCRUpdater;
import io.apicurio.registry.operator.updater.SqlCRUpdater;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.javaoperatorsdk.operator.api.reconciler.*;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import org.slf4j.Logger;
Expand Down Expand Up @@ -127,26 +127,19 @@ public UpdateControl<ApicurioRegistry3> reconcile(ApicurioRegistry3 primary,
return UpdateControl.updateResource(primary);
}

var statusUpdater = new StatusUpdater(primary);

return context.getSecondaryResource(Deployment.class, AppDeploymentDiscriminator.INSTANCE)
.map(deployment -> {
statusUpdater.update(deployment);
return UpdateControl.patchStatus(primary);
}).orElseGet(UpdateControl::noUpdate);
return UpdateControl.patchStatus(StatusManager.get(primary).applyStatus(primary, context));
}

@Override
public ErrorStatusUpdateControl<ApicurioRegistry3> updateErrorStatus(ApicurioRegistry3 apicurioRegistry,
public ErrorStatusUpdateControl<ApicurioRegistry3> updateErrorStatus(ApicurioRegistry3 primary,
Context<ApicurioRegistry3> context, Exception ex) {
log.error("Status error", ex);
var statusUpdater = new StatusUpdater(apicurioRegistry);
statusUpdater.updateWithException(ex);
return ErrorStatusUpdateControl.updateStatus(apicurioRegistry);
StatusManager.get(primary).getConditionManager(OperatorErrorConditionManager.class).recordException(ex);
return ErrorStatusUpdateControl.updateStatus(StatusManager.get(primary).applyStatus(primary, context));
}

@Override
public DeleteControl cleanup(ApicurioRegistry3 primary, Context<ApicurioRegistry3> context) {
StatusManager.clean(primary);
return DeleteControl.defaultDelete();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.apicurio.registry.operator.resource;

import io.fabric8.kubernetes.api.model.HasMetadata;

import static io.apicurio.registry.operator.resource.Labels.getSelectorLabels;

public class ComponentLabelDiscriminator<R extends HasMetadata>
extends LabelDiscriminator<R> {

public ComponentLabelDiscriminator(String component) {
super(primary -> getSelectorLabels(primary, component));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,72 @@
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
import io.javaoperatorsdk.operator.processing.event.ResourceID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Optional;

import static io.javaoperatorsdk.operator.processing.event.ResourceID.fromResource;
import static java.lang.Long.parseLong;
import static java.util.Comparator.comparingLong;

public class LabelDiscriminator<R extends HasMetadata>
implements ResourceDiscriminator<R, ApicurioRegistry3> {

private final Map<String, String> labels;
private static final Logger log = LoggerFactory.getLogger(LabelDiscriminator.class);

private final LabelSupplier labelSupplier;

public LabelDiscriminator(LabelSupplier labelSupplier) {
this.labelSupplier = labelSupplier;
}

public LabelDiscriminator(Map<String, String> labels) {
this.labels = labels;
this(_ignored -> labels);
}

@Override
public Optional<R> distinguish(Class<R> resource, ApicurioRegistry3 primary,
Context<ApicurioRegistry3> context) {
var resources = context.getSecondaryResources(resource);
var filtered = resources.stream().filter(r -> {
for (var label : labels.entrySet()) {
var v = r.getMetadata().getLabels().get(label.getKey());
if (v == null || !v.equals(label.getValue())) {
return false;
Context<ApicurioRegistry3> context) {

var labels = labelSupplier.supply(primary);

var filtered = context.getSecondaryResources(resource).stream()
.filter(r -> {
for (var label : labels.entrySet()) {
var v = r.getMetadata().getLabels().get(label.getKey());
if (v == null || !v.equals(label.getValue())) {
return false;
}
}
return true;
}).toList();

switch (filtered.size()) {
case 0 -> {
return Optional.empty();
}
case 1 -> {
return Optional.of(filtered.get(0));
}
default -> {
var msg = "Expected at most one %s resource with labels %s but got more:\n%s"
.formatted(resource.getSimpleName(), labels, filtered.stream().map(ResourceID::fromResource).toList());
if (filtered.stream().allMatch(r -> fromResource(filtered.get(0)).equals(fromResource(r)))) {
log.warn(msg);
return filtered.stream().max(comparingLong(r -> parseLong(r.getMetadata().getResourceVersion())));
} else {
throw new OperatorException(msg);
}
}
return true;
}).toList();
if (filtered.size() > 1) {
throw new OperatorException("Expected at most one " + resource.getSimpleName()
+ " resource with labels " + labels + " but got more.");
}
return filtered.isEmpty() ? Optional.empty() : Optional.of(filtered.get(0));
}

@FunctionalInterface
public interface LabelSupplier {

Map<String, String> supply(ApicurioRegistry3 primary);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@
import io.fabric8.kubernetes.api.model.policy.v1.PodDisruptionBudget;
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;

import java.util.Map;

import static io.apicurio.registry.operator.resource.ResourceFactory.COMPONENT_APP;
import static io.apicurio.registry.operator.resource.ResourceFactory.COMPONENT_STUDIO_UI;
import static io.apicurio.registry.operator.resource.ResourceFactory.COMPONENT_UI;
import static io.apicurio.registry.operator.resource.ResourceFactory.*;

public class LabelDiscriminators {

Expand All @@ -21,200 +17,143 @@ private LabelDiscriminators() {

// ===== Registry App

public static class AppDeploymentDiscriminator extends LabelDiscriminator<Deployment> {
public static class AppDeploymentDiscriminator extends ComponentLabelDiscriminator<Deployment> {

public static final ResourceDiscriminator<Deployment, ApicurioRegistry3> INSTANCE = new AppDeploymentDiscriminator();

public AppDeploymentDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_APP
));
super(COMPONENT_APP);
}
}

public static class AppServiceDiscriminator extends LabelDiscriminator<Service> {
public static class AppServiceDiscriminator extends ComponentLabelDiscriminator<Service> {

public static final ResourceDiscriminator<Service, ApicurioRegistry3> INSTANCE = new AppServiceDiscriminator();

public AppServiceDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_APP
));
super(COMPONENT_APP);
}
}

public static class AppIngressDiscriminator extends LabelDiscriminator<Ingress> {
public static class AppIngressDiscriminator extends ComponentLabelDiscriminator<Ingress> {

public static final ResourceDiscriminator<Ingress, ApicurioRegistry3> INSTANCE = new AppIngressDiscriminator();

public AppIngressDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_APP
));
super(COMPONENT_APP);
}
}

public static class AppPodDisruptionBudgetDiscriminator extends LabelDiscriminator<PodDisruptionBudget> {
public static class AppPodDisruptionBudgetDiscriminator extends ComponentLabelDiscriminator<PodDisruptionBudget> {

public static final ResourceDiscriminator<PodDisruptionBudget, ApicurioRegistry3> INSTANCE = new AppPodDisruptionBudgetDiscriminator();

public AppPodDisruptionBudgetDiscriminator() {
// spotless:off
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_APP
));
// spotless:on
super(COMPONENT_APP);
}
}

public static class AppNetworkPolicyDiscriminator extends LabelDiscriminator<NetworkPolicy> {
public static class AppNetworkPolicyDiscriminator extends ComponentLabelDiscriminator<NetworkPolicy> {

public static final ResourceDiscriminator<NetworkPolicy, ApicurioRegistry3> INSTANCE = new AppNetworkPolicyDiscriminator();

public AppNetworkPolicyDiscriminator() {
// spotless:off
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_APP
));
// spotless:on
super(COMPONENT_APP);
}
}

// ===== Registry UI

public static class UIDeploymentDiscriminator extends LabelDiscriminator<Deployment> {
public static class UIDeploymentDiscriminator extends ComponentLabelDiscriminator<Deployment> {

public static final ResourceDiscriminator<Deployment, ApicurioRegistry3> INSTANCE = new UIDeploymentDiscriminator();

public UIDeploymentDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_UI
));
super(COMPONENT_UI);
}
}

public static class UIServiceDiscriminator extends LabelDiscriminator<Service> {
public static class UIServiceDiscriminator extends ComponentLabelDiscriminator<Service> {

public static ResourceDiscriminator<Service, ApicurioRegistry3> INSTANCE = new UIServiceDiscriminator();

public UIServiceDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_UI
));
super(COMPONENT_UI);
}
}

public static class UIIngressDiscriminator extends LabelDiscriminator<Ingress> {
public static class UIIngressDiscriminator extends ComponentLabelDiscriminator<Ingress> {

public static ResourceDiscriminator<Ingress, ApicurioRegistry3> INSTANCE = new UIIngressDiscriminator();

public UIIngressDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_UI
));
super(COMPONENT_UI);
}
}

public static class UiPodDisruptionBudgetDiscriminator extends LabelDiscriminator<PodDisruptionBudget> {
public static class UiPodDisruptionBudgetDiscriminator extends ComponentLabelDiscriminator<PodDisruptionBudget> {

public static final ResourceDiscriminator<PodDisruptionBudget, ApicurioRegistry3> INSTANCE = new AppPodDisruptionBudgetDiscriminator();

public UiPodDisruptionBudgetDiscriminator() {
// spotless:off
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_UI
));
// spotless:on
super(COMPONENT_UI);
}
}

public static class UINetworkPolicyDiscriminator extends LabelDiscriminator<NetworkPolicy> {
public static class UINetworkPolicyDiscriminator extends ComponentLabelDiscriminator<NetworkPolicy> {

public static final ResourceDiscriminator<NetworkPolicy, ApicurioRegistry3> INSTANCE = new AppNetworkPolicyDiscriminator();

public UINetworkPolicyDiscriminator() {
// spotless:off
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_UI
));
// spotless:on
super(COMPONENT_UI);
}
}

// ===== Studio UI

public static class StudioUIDeploymentDiscriminator extends LabelDiscriminator<Deployment> {
public static class StudioUIDeploymentDiscriminator extends ComponentLabelDiscriminator<Deployment> {

public static final ResourceDiscriminator<Deployment, ApicurioRegistry3> INSTANCE = new StudioUIDeploymentDiscriminator();

public StudioUIDeploymentDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_STUDIO_UI
));
super(COMPONENT_STUDIO_UI);
}
}

public static class StudioUIServiceDiscriminator extends LabelDiscriminator<Service> {
public static class StudioUIServiceDiscriminator extends ComponentLabelDiscriminator<Service> {

public static ResourceDiscriminator<Service, ApicurioRegistry3> INSTANCE = new StudioUIServiceDiscriminator();

public StudioUIServiceDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_STUDIO_UI
));
super(COMPONENT_STUDIO_UI);
}
}

public static class StudioUIIngressDiscriminator extends LabelDiscriminator<Ingress> {
public static class StudioUIIngressDiscriminator extends ComponentLabelDiscriminator<Ingress> {

public static ResourceDiscriminator<Ingress, ApicurioRegistry3> INSTANCE = new StudioUIIngressDiscriminator();

public StudioUIIngressDiscriminator() {
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_STUDIO_UI
));
super(COMPONENT_STUDIO_UI);
}
}

public static class StudioUiPodDisruptionBudgetDiscriminator
extends LabelDiscriminator<PodDisruptionBudget> {
extends ComponentLabelDiscriminator<PodDisruptionBudget> {

public static final ResourceDiscriminator<PodDisruptionBudget, ApicurioRegistry3> INSTANCE = new AppPodDisruptionBudgetDiscriminator();

public StudioUiPodDisruptionBudgetDiscriminator() {
// spotless:off
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_STUDIO_UI
));
// spotless:on
super(COMPONENT_STUDIO_UI);
}
}

public static class StudioUINetworkPolicyDiscriminator extends LabelDiscriminator<NetworkPolicy> {
public static class StudioUINetworkPolicyDiscriminator extends ComponentLabelDiscriminator<NetworkPolicy> {

public static final ResourceDiscriminator<NetworkPolicy, ApicurioRegistry3> INSTANCE = new AppNetworkPolicyDiscriminator();

public StudioUINetworkPolicyDiscriminator() {
// spotless:off
super(Map.of(
"app.kubernetes.io/name", "apicurio-registry",
"app.kubernetes.io/component", COMPONENT_STUDIO_UI
));
// spotless:on
super(COMPONENT_STUDIO_UI);
}
}
}
Loading

0 comments on commit 42a32ca

Please sign in to comment.