Merge "Revert "Update JOSDK to 5.1.0""
diff --git a/crd/current/gerritclusters.gerritoperator.google.com-v1.yml b/crd/current/gerritclusters.gerritoperator.google.com-v1.yml
index 3c38017..192598b 100644
--- a/crd/current/gerritclusters.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritclusters.gerritoperator.google.com-v1.yml
@@ -713,8 +713,6 @@
                                 properties:
                                   name:
                                     type: string
-                                  request:
-                                    type: string
                                 type: object
                               type: array
                             limits:
@@ -1482,8 +1480,6 @@
                               properties:
                                 name:
                                   type: string
-                                request:
-                                  type: string
                               type: object
                             type: array
                           limits:
@@ -1963,8 +1959,6 @@
                                         properties:
                                           name:
                                             type: string
-                                          request:
-                                            type: string
                                         type: object
                                       type: array
                                     limits:
@@ -2446,8 +2440,6 @@
                                     properties:
                                       name:
                                         type: string
-                                      request:
-                                        type: string
                                     type: object
                                   type: array
                                 limits:
diff --git a/crd/current/gerritindexers.gerritoperator.google.com-v1.yml b/crd/current/gerritindexers.gerritoperator.google.com-v1.yml
index e0c16a7..586531b 100644
--- a/crd/current/gerritindexers.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritindexers.gerritoperator.google.com-v1.yml
@@ -375,8 +375,6 @@
                       properties:
                         name:
                           type: string
-                        request:
-                          type: string
                       type: object
                     type: array
                   limits:
diff --git a/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml b/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml
index 5690b33..b633fb1 100644
--- a/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml
@@ -401,8 +401,6 @@
                                 properties:
                                   name:
                                     type: string
-                                  request:
-                                    type: string
                                 type: object
                               type: array
                             limits:
diff --git a/crd/current/gerrits.gerritoperator.google.com-v1.yml b/crd/current/gerrits.gerritoperator.google.com-v1.yml
index 5e857bd..bd20b5d 100644
--- a/crd/current/gerrits.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerrits.gerritoperator.google.com-v1.yml
@@ -705,8 +705,6 @@
                       properties:
                         name:
                           type: string
-                        request:
-                          type: string
                       type: object
                     type: array
                   limits:
diff --git a/crd/current/gitgcs.gerritoperator.google.com-v1.yml b/crd/current/gitgcs.gerritoperator.google.com-v1.yml
index 3c38ca8..a5756d3 100644
--- a/crd/current/gitgcs.gerritoperator.google.com-v1.yml
+++ b/crd/current/gitgcs.gerritoperator.google.com-v1.yml
@@ -366,8 +366,6 @@
                       properties:
                         name:
                           type: string
-                        request:
-                          type: string
                       type: object
                     type: array
                   limits:
diff --git a/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml b/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml
index dae9047..5fab4ad 100644
--- a/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml
+++ b/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml
@@ -412,8 +412,6 @@
                       properties:
                         name:
                           type: string
-                        request:
-                          type: string
                       type: object
                     type: array
                   limits:
diff --git a/crd/current/receivers.gerritoperator.google.com-v1.yml b/crd/current/receivers.gerritoperator.google.com-v1.yml
index 224fc54..ded8d2c 100644
--- a/crd/current/receivers.gerritoperator.google.com-v1.yml
+++ b/crd/current/receivers.gerritoperator.google.com-v1.yml
@@ -538,8 +538,6 @@
                       properties:
                         name:
                           type: string
-                        request:
-                          type: string
                       type: object
                     type: array
                   limits:
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml
index 8dca827..3010ba2 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml
@@ -3261,8 +3261,6 @@
                                   properties:
                                     name:
                                       type: string
-                                    request:
-                                      type: string
                                   type: object
                                 type: array
                               limits:
@@ -4030,8 +4028,6 @@
                                 properties:
                                   name:
                                     type: string
-                                  request:
-                                    type: string
                                 type: object
                               type: array
                             limits:
@@ -4499,8 +4495,6 @@
                                           properties:
                                             name:
                                               type: string
-                                            request:
-                                              type: string
                                           type: object
                                         type: array
                                       limits:
@@ -4982,8 +4976,6 @@
                                       properties:
                                         name:
                                           type: string
-                                        request:
-                                          type: string
                                       type: object
                                     type: array
                                   limits:
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml
index 19730c0..46f26d3 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml
@@ -375,8 +375,6 @@
                         properties:
                           name:
                             type: string
-                          request:
-                            type: string
                         type: object
                       type: array
                     limits:
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml
index bbcfd42..c038fe3 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml
@@ -401,8 +401,6 @@
                                   properties:
                                     name:
                                       type: string
-                                    request:
-                                      type: string
                                   type: object
                                 type: array
                               limits:
diff --git a/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml
index fc0e627..6a6da61 100644
--- a/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml
@@ -366,8 +366,6 @@
                         properties:
                           name:
                             type: string
-                          request:
-                            type: string
                         type: object
                       type: array
                     limits:
diff --git a/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml
index 5e2bc81..acf0b0c 100644
--- a/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml
@@ -412,8 +412,6 @@
                         properties:
                           name:
                             type: string
-                          request:
-                            type: string
                         type: object
                       type: array
                     limits:
diff --git a/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml
index 2182d31..baf05f4 100644
--- a/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml
@@ -538,8 +538,6 @@
                         properties:
                           name:
                             type: string
-                          request:
-                            type: string
                         type: object
                       type: array
                     limits:
diff --git a/operator/pom.xml b/operator/pom.xml
index ae73112..48b1a54 100644
--- a/operator/pom.xml
+++ b/operator/pom.xml
@@ -15,13 +15,12 @@
 	<properties>
 		<revision>1.0.0-SNAPSHOT</revision>
 
-		<fabric8.version>7.3.1</fabric8.version>
+		<fabric8.version>6.13.4</fabric8.version>
 		<flogger.version>0.8</flogger.version>
 		<guice.version>7.0.0</guice.version>
-		<javaoperatorsdk.version>5.1.0</javaoperatorsdk.version>
+		<javaoperatorsdk.version>4.9.7</javaoperatorsdk.version>
 		<jetty.version>11.0.25</jetty.version>
 		<log42.version>2.24.3</log42.version>
-		<sundrio.version>0.200.0</sundrio.version>
 		<lombok.version>1.18.38</lombok.version>
 		<maven.compiler.source>17</maven.compiler.source>
 		<maven.compiler.target>17</maven.compiler.target>
@@ -173,12 +172,6 @@
 			<version>${fabric8.version}</version>
 		</dependency>
 		<dependency>
-			<groupId>io.sundr</groupId>
-			<artifactId>builder-annotations</artifactId>
-			<scope>provided</scope>
-			<version>${sundrio.version}</version>
-		</dependency>
-		<dependency>
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
 			<scope>provided</scope>
@@ -238,7 +231,7 @@
 		<dependency>
 			<groupId>org.mockito</groupId>
 			<artifactId>mockito-core</artifactId>
-			<version>5.18.0</version>
+			<version>5.17.0</version>
 			<scope>test</scope>
 		</dependency>
 		<dependency>
@@ -255,7 +248,7 @@
 		<dependency>
 			<groupId>org.junit.jupiter</groupId>
 			<artifactId>junit-jupiter-params</artifactId>
-			<version>5.12.0</version>
+			<version>5.10.5</version>
 			<scope>test</scope>
 		</dependency>
 	</dependencies>
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMember.java b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMember.java
index ac39433..f1e7ed7 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMember.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMember.java
@@ -19,7 +19,7 @@
 
 public class NetworkMember {
   private String name;
-  private long httpPort = 8080L;
+  private int httpPort = 8080;
 
   public NetworkMember() {}
 
@@ -36,11 +36,11 @@
     this.name = name;
   }
 
-  public long getHttpPort() {
+  public int getHttpPort() {
     return httpPort;
   }
 
-  public void setHttpPort(long httpPort) {
+  public void setHttpPort(int httpPort) {
     this.httpPort = httpPort;
   }
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMemberWithSsh.java b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMemberWithSsh.java
index 530ece2..32f8b31 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMemberWithSsh.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/network/NetworkMemberWithSsh.java
@@ -18,7 +18,7 @@
 import java.util.Objects;
 
 public class NetworkMemberWithSsh extends NetworkMember {
-  private long sshPort = 29418L;
+  private int sshPort = 29418;
 
   public NetworkMemberWithSsh() {}
 
@@ -27,11 +27,11 @@
     this.sshPort = serviceConfig.getSshPort();
   }
 
-  public long getSshPort() {
+  public int getSshPort() {
     return sshPort;
   }
 
-  public void setSshPort(long sshPort) {
+  public void setSshPort(int sshPort) {
     this.sshPort = sshPort;
   }
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterMultisiteReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterMultisiteReconciler.java
index 8f9d297..5bcd914 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterMultisiteReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterMultisiteReconciler.java
@@ -14,36 +14,70 @@
 
 package com.google.gerrit.k8s.operator.cluster;
 
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterMultisiteReconciler.CLUSTER_MANAGED_GERRIT_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterMultisiteReconciler.CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE;
+
 import com.google.gerrit.k8s.operator.api.model.cluster.GerritCluster;
 import com.google.gerrit.k8s.operator.api.model.cluster.GerritClusterStatus;
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
 import com.google.gerrit.k8s.operator.api.model.gerrit.GerritTemplate;
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerrit;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerritCondition;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerritNetwork;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerritNetworkCondition;
 import com.google.inject.Singleton;
+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.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 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.event.source.EventSource;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = "gerrits",
           type = ClusterManagedGerrit.class,
-          reconcilePrecondition = ClusterManagedGerritCondition.class),
+          reconcilePrecondition = ClusterManagedGerritCondition.class,
+          useEventSourceWithName = CLUSTER_MANAGED_GERRIT_EVENT_SOURCE),
       @Dependent(
           type = ClusterManagedGerritNetwork.class,
-          reconcilePrecondition = ClusterManagedGerritNetworkCondition.class)
+          reconcilePrecondition = ClusterManagedGerritNetworkCondition.class,
+          useEventSourceWithName = CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE)
     })
-public class GerritClusterMultisiteReconciler implements Reconciler<GerritCluster> {
+public class GerritClusterMultisiteReconciler
+    implements Reconciler<GerritCluster>, EventSourceInitializer<GerritCluster> {
+  public static final String CLUSTER_MANAGED_GERRIT_EVENT_SOURCE = "cluster-managed-gerrit";
+
+  public static final String CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE =
+      "cluster-managed-gerrit-network";
+
+  @Override
+  public Map<String, EventSource> prepareEventSources(EventSourceContext<GerritCluster> context) {
+    InformerEventSource<Gerrit, GerritCluster> clusterManagedGerritEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(Gerrit.class, context).build(), context);
+
+    InformerEventSource<GerritNetwork, GerritCluster> clusterManagedGerritNetworkEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(GerritNetwork.class, context).build(), context);
+
+    Map<String, EventSource> eventSources = new HashMap<>();
+    eventSources.put(CLUSTER_MANAGED_GERRIT_EVENT_SOURCE, clusterManagedGerritEventSource);
+    eventSources.put(
+        CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE, clusterManagedGerritNetworkEventSource);
+    return eventSources;
+  }
 
   @Override
   public UpdateControl<GerritCluster> reconcile(
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterReconciler.java
index 8d759c9..6419232 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/GerritClusterReconciler.java
@@ -14,10 +14,23 @@
 
 package com.google.gerrit.k8s.operator.cluster;
 
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CLUSTER_MANAGED_GERRIT_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CLUSTER_MANAGED_GERRIT_MAINTENANCE_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CLUSTER_MANAGED_INC_REPL_TASK_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CLUSTER_MANAGED_RECEIVER_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CM_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.PVC_EVENT_SOURCE;
+
 import com.google.gerrit.k8s.operator.api.model.cluster.GerritCluster;
 import com.google.gerrit.k8s.operator.api.model.cluster.GerritClusterStatus;
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
 import com.google.gerrit.k8s.operator.api.model.gerrit.GerritTemplate;
+import com.google.gerrit.k8s.operator.api.model.maintenance.GerritMaintenance;
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import com.google.gerrit.k8s.operator.api.model.receiver.Receiver;
 import com.google.gerrit.k8s.operator.api.model.receiver.ReceiverTemplate;
+import com.google.gerrit.k8s.operator.api.model.tasks.incomingrepl.IncomingReplicationTask;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerrit;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerritCondition;
 import com.google.gerrit.k8s.operator.cluster.dependent.ClusterManagedGerritMaintenance;
@@ -32,43 +45,117 @@
 import com.google.gerrit.k8s.operator.cluster.dependent.SharedPVC;
 import com.google.gerrit.k8s.operator.cluster.dependent.SharedPVCCondition;
 import com.google.inject.Singleton;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.PersistentVolumeClaim;
+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.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 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.event.source.EventSource;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = "shared-pvc",
           type = SharedPVC.class,
-          reconcilePrecondition = SharedPVCCondition.class),
+          reconcilePrecondition = SharedPVCCondition.class,
+          useEventSourceWithName = PVC_EVENT_SOURCE),
       @Dependent(
           type = NfsIdmapdConfigMap.class,
-          reconcilePrecondition = NfsWorkaroundCondition.class),
+          reconcilePrecondition = NfsWorkaroundCondition.class,
+          useEventSourceWithName = CM_EVENT_SOURCE),
       @Dependent(
           name = "gerrits",
           type = ClusterManagedGerrit.class,
-          reconcilePrecondition = ClusterManagedGerritCondition.class),
+          reconcilePrecondition = ClusterManagedGerritCondition.class,
+          useEventSourceWithName = CLUSTER_MANAGED_GERRIT_EVENT_SOURCE),
       @Dependent(
           name = "receiver",
           type = ClusterManagedReceiver.class,
-          reconcilePrecondition = ClusterManagedReceiverCondition.class),
+          reconcilePrecondition = ClusterManagedReceiverCondition.class,
+          useEventSourceWithName = CLUSTER_MANAGED_RECEIVER_EVENT_SOURCE),
       @Dependent(
           type = ClusterManagedGerritNetwork.class,
-          reconcilePrecondition = ClusterManagedGerritNetworkCondition.class),
-      @Dependent(type = ClusterManagedIncomingReplicationTask.class),
+          reconcilePrecondition = ClusterManagedGerritNetworkCondition.class,
+          useEventSourceWithName = CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE),
+      @Dependent(
+          type = ClusterManagedIncomingReplicationTask.class,
+          useEventSourceWithName = CLUSTER_MANAGED_INC_REPL_TASK_EVENT_SOURCE),
       @Dependent(
           type = ClusterManagedGerritMaintenance.class,
-          reconcilePrecondition = ClusterManagedGerritMaintenanceCondition.class),
+          reconcilePrecondition = ClusterManagedGerritMaintenanceCondition.class,
+          useEventSourceWithName = CLUSTER_MANAGED_GERRIT_MAINTENANCE_EVENT_SOURCE),
     })
-public class GerritClusterReconciler implements Reconciler<GerritCluster> {
+public class GerritClusterReconciler
+    implements Reconciler<GerritCluster>, EventSourceInitializer<GerritCluster> {
+  public static final String CM_EVENT_SOURCE = "cm-event-source";
+  public static final String PVC_EVENT_SOURCE = "pvc-event-source";
+  public static final String CLUSTER_MANAGED_GERRIT_EVENT_SOURCE = "cluster-managed-gerrit";
+  public static final String CLUSTER_MANAGED_RECEIVER_EVENT_SOURCE = "cluster-managed-receiver";
+  public static final String CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE =
+      "cluster-managed-gerrit-network";
+  public static final String CLUSTER_MANAGED_INC_REPL_TASK_EVENT_SOURCE =
+      "cluster-managed-incoming-repl-task";
+  public static final String CLUSTER_MANAGED_GERRIT_MAINTENANCE_EVENT_SOURCE =
+      "cluster-managed-gerrit-maintenance";
+
+  @Override
+  public Map<String, EventSource> prepareEventSources(EventSourceContext<GerritCluster> context) {
+    InformerEventSource<ConfigMap, GerritCluster> cmEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(ConfigMap.class, context).build(), context);
+
+    InformerEventSource<PersistentVolumeClaim, GerritCluster> pvcEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(PersistentVolumeClaim.class, context).build(), context);
+
+    InformerEventSource<Gerrit, GerritCluster> clusterManagedGerritEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(Gerrit.class, context).build(), context);
+
+    InformerEventSource<Receiver, GerritCluster> clusterManagedReceiverEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(Receiver.class, context).build(), context);
+
+    InformerEventSource<GerritNetwork, GerritCluster> clusterManagedGerritNetworkEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(GerritNetwork.class, context).build(), context);
+
+    InformerEventSource<IncomingReplicationTask, GerritCluster>
+        clusterManagedIncomingReplTaskEventSource =
+            new InformerEventSource<>(
+                InformerConfiguration.from(IncomingReplicationTask.class, context).build(),
+                context);
+
+    InformerEventSource<GerritMaintenance, GerritCluster>
+        clusterManagedGerritMaintenanceEventSource =
+            new InformerEventSource<>(
+                InformerConfiguration.from(GerritMaintenance.class, context).build(), context);
+
+    Map<String, EventSource> eventSources = new HashMap<>();
+    eventSources.put(CM_EVENT_SOURCE, cmEventSource);
+    eventSources.put(PVC_EVENT_SOURCE, pvcEventSource);
+    eventSources.put(CLUSTER_MANAGED_GERRIT_EVENT_SOURCE, clusterManagedGerritEventSource);
+    eventSources.put(CLUSTER_MANAGED_RECEIVER_EVENT_SOURCE, clusterManagedReceiverEventSource);
+    eventSources.put(
+        CLUSTER_MANAGED_GERRIT_NETWORK_EVENT_SOURCE, clusterManagedGerritNetworkEventSource);
+    eventSources.put(
+        CLUSTER_MANAGED_INC_REPL_TASK_EVENT_SOURCE, clusterManagedIncomingReplTaskEventSource);
+    eventSources.put(
+        CLUSTER_MANAGED_GERRIT_MAINTENANCE_EVENT_SOURCE,
+        clusterManagedGerritMaintenanceEventSource);
+    return eventSources;
+  }
 
   @Override
   public UpdateControl<GerritCluster> reconcile(
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMap.java b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMap.java
index fe0b44d..8e63d16 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMap.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMap.java
@@ -23,7 +23,7 @@
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import java.util.Map;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = NfsIdmapdConfigMapDiscriminator.class)
 public class NfsIdmapdConfigMap
     extends CRUDReconcileAddKubernetesDependentResource<ConfigMap, GerritCluster> {
   public static final String NFS_IDMAPD_CM_NAME = "nfs-idmapd-config";
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMapDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMapDiscriminator.java
new file mode 100644
index 0000000..52ca139
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/NfsIdmapdConfigMapDiscriminator.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.cluster.dependent;
+
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.CM_EVENT_SOURCE;
+
+import com.google.gerrit.k8s.operator.api.model.cluster.GerritCluster;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class NfsIdmapdConfigMapDiscriminator
+    implements ResourceDiscriminator<ConfigMap, GerritCluster> {
+  @Override
+  public Optional<ConfigMap> distinguish(
+      Class<ConfigMap> resource, GerritCluster primary, Context<GerritCluster> context) {
+    InformerEventSource<ConfigMap, GerritCluster> ies =
+        (InformerEventSource<ConfigMap, GerritCluster>)
+            context
+                .eventSourceRetriever()
+                .getResourceEventSourceFor(ConfigMap.class, CM_EVENT_SOURCE);
+
+    return ies.get(
+        new ResourceID(
+            NfsIdmapdConfigMap.NFS_IDMAPD_CM_NAME, primary.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVC.java b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVC.java
index ca869cb..a0cca49 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVC.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVC.java
@@ -25,7 +25,7 @@
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import java.util.Map;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = SharedPVCDiscriminator.class)
 public class SharedPVC extends CRUDKubernetesDependentPVCResource<GerritCluster> {
 
   public static final String SHARED_PVC_NAME = "shared-pvc";
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVCDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVCDiscriminator.java
new file mode 100644
index 0000000..83d5295
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/cluster/dependent/SharedPVCDiscriminator.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.cluster.dependent;
+
+import static com.google.gerrit.k8s.operator.cluster.GerritClusterReconciler.PVC_EVENT_SOURCE;
+
+import com.google.gerrit.k8s.operator.api.model.cluster.GerritCluster;
+import io.fabric8.kubernetes.api.model.PersistentVolumeClaim;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class SharedPVCDiscriminator
+    implements ResourceDiscriminator<PersistentVolumeClaim, GerritCluster> {
+  @Override
+  public Optional<PersistentVolumeClaim> distinguish(
+      Class<PersistentVolumeClaim> resource,
+      GerritCluster primary,
+      Context<GerritCluster> context) {
+    InformerEventSource<PersistentVolumeClaim, GerritCluster> ies =
+        (InformerEventSource<PersistentVolumeClaim, GerritCluster>)
+            context
+                .eventSourceRetriever()
+                .getResourceEventSourceFor(PersistentVolumeClaim.class, PVC_EVENT_SOURCE);
+
+    return ies.get(new ResourceID(SharedPVC.SHARED_PVC_NAME, primary.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritReconciler.java
index 4ee4d99..abc0d87 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritReconciler.java
@@ -32,21 +32,20 @@
 import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.api.model.Service;
 import io.fabric8.kubernetes.client.KubernetesClient;
-import io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration;
+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.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 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.WorkflowReconcileResult;
 import io.javaoperatorsdk.operator.processing.event.ResourceID;
 import io.javaoperatorsdk.operator.processing.event.source.EventSource;
 import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper;
 import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -54,7 +53,7 @@
 import java.util.stream.Collectors;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = "fluentbit-configmap",
@@ -83,7 +82,7 @@
           useEventSourceWithName = GERRIT_SERVICE_EVENT_SOURCE,
           dependsOn = {"gerrit-statefulset"})
     })
-public class GerritReconciler implements Reconciler<Gerrit> {
+public class GerritReconciler implements Reconciler<Gerrit>, EventSourceInitializer<Gerrit> {
   public static final String GERRIT_SECRET_EVENT_SOURCE = "gerrit-secret-event-source";
   public static final String CONFIG_MAP_EVENT_SOURCE = "configmap-event-source";
   public static final String GERRIT_SERVICE_EVENT_SOURCE = "gerrit-service-event-source";
@@ -97,34 +96,27 @@
   }
 
   @Override
-  public List<EventSource<?, Gerrit>> prepareEventSources(EventSourceContext<Gerrit> context) {
-    List<EventSource<?, Gerrit>> eventSources = new ArrayList<>();
+  public Map<String, EventSource> prepareEventSources(EventSourceContext<Gerrit> context) {
+    Map<String, EventSource> eventSources = new HashMap<>();
 
     InformerEventSource<ConfigMap, Gerrit> configmapEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(ConfigMap.class, Gerrit.class)
-                .withName(CONFIG_MAP_EVENT_SOURCE)
-                .build(),
-            context);
-    eventSources.add(configmapEventSource);
+            InformerConfiguration.from(ConfigMap.class, context).build(), context);
+    eventSources.put(CONFIG_MAP_EVENT_SOURCE, configmapEventSource);
 
     InformerEventSource<Service, Gerrit> gerritServiceEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(Service.class, Gerrit.class)
-                .withName(GERRIT_SERVICE_EVENT_SOURCE)
-                .build(),
-            context);
-    eventSources.add(gerritServiceEventSource);
+            InformerConfiguration.from(Service.class, context).build(), context);
+    eventSources.put(GERRIT_SERVICE_EVENT_SOURCE, gerritServiceEventSource);
 
     SecondaryToPrimaryMapper<Secret> secretMapper = new SecretToGerritMapper(context);
     InformerEventSource<Secret, Gerrit> moduleMetaDataEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(Secret.class, Gerrit.class)
-                .withName(GERRIT_SECRET_EVENT_SOURCE)
+            InformerConfiguration.from(Secret.class, context)
                 .withSecondaryToPrimaryMapper(secretMapper)
                 .build(),
             context);
-    eventSources.add(moduleMetaDataEventSource);
+    eventSources.put(GERRIT_SECRET_EVENT_SOURCE, moduleMetaDataEventSource);
     return eventSources;
   }
 
@@ -139,7 +131,7 @@
       status = new GerritStatus();
     }
     Optional<WorkflowReconcileResult> result =
-        context.managedWorkflowAndDependentResourceContext().getWorkflowReconcileResult();
+        context.managedDependentResourceContext().getWorkflowReconcileResult();
     if (result.isPresent()) {
       status.setReady(result.get().allDependentResourcesReady());
     } else {
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMap.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMap.java
index 43e77bf..fc46634 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMap.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMap.java
@@ -25,7 +25,7 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = FluentBitConfigMapDiscriminator.class)
 public class FluentBitConfigMap extends CRUDKubernetesDependentResource<ConfigMap, Gerrit> {
   private static final String FLUENT_BIT_SERVICE_CONFIG =
       """
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMapDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMapDiscriminator.java
new file mode 100644
index 0000000..88e8255
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/FluentBitConfigMapDiscriminator.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.gerrit.dependent;
+
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class FluentBitConfigMapDiscriminator implements ResourceDiscriminator<ConfigMap, Gerrit> {
+  @Override
+  public Optional<ConfigMap> distinguish(
+      Class<ConfigMap> resource, Gerrit primary, Context<Gerrit> context) {
+    InformerEventSource<ConfigMap, Gerrit> ies =
+        (InformerEventSource<ConfigMap, Gerrit>)
+            context.eventSourceRetriever().getResourceEventSourceFor(ConfigMap.class);
+
+    return ies.get(
+        new ResourceID(FluentBitConfigMap.getName(primary), primary.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMap.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMap.java
index 0286a89..9e9771a 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMap.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMap.java
@@ -33,7 +33,7 @@
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import java.util.Map;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritConfigMapDiscriminator.class)
 public class GerritConfigMap
     extends CRUDReconcileAddKubernetesDependentResource<ConfigMap, Gerrit> {
   private static final String DEFAULT_HEALTHCHECK_CONFIG =
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMapDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMapDiscriminator.java
new file mode 100644
index 0000000..17edc62
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritConfigMapDiscriminator.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.gerrit.dependent;
+
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritConfigMapDiscriminator implements ResourceDiscriminator<ConfigMap, Gerrit> {
+  @Override
+  public Optional<ConfigMap> distinguish(
+      Class<ConfigMap> resource, Gerrit primary, Context<Gerrit> context) {
+    InformerEventSource<ConfigMap, Gerrit> ies =
+        (InformerEventSource<ConfigMap, Gerrit>)
+            context.eventSourceRetriever().getResourceEventSourceFor(ConfigMap.class);
+
+    return ies.get(
+        new ResourceID(GerritConfigMap.getName(primary), primary.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessService.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessService.java
index 17b0f20..585f2d0 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessService.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessService.java
@@ -25,7 +25,7 @@
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import java.util.concurrent.TimeUnit;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritHeadlessServiceDiscriminator.class)
 public class GerritHeadlessService extends GerritAbstractService {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessServiceDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessServiceDiscriminator.java
new file mode 100644
index 0000000..7064f3d
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritHeadlessServiceDiscriminator.java
@@ -0,0 +1,41 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.gerrit.dependent;
+
+import static com.google.gerrit.k8s.operator.gerrit.GerritReconciler.GERRIT_SERVICE_EVENT_SOURCE;
+
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
+import io.fabric8.kubernetes.api.model.Service;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritHeadlessServiceDiscriminator implements ResourceDiscriminator<Service, Gerrit> {
+  @Override
+  public Optional<Service> distinguish(
+      Class<Service> aClass, Gerrit gerrit, Context<Gerrit> context) {
+    InformerEventSource<Service, Gerrit> ies =
+        (InformerEventSource<Service, Gerrit>)
+            context
+                .eventSourceRetriever()
+                .getResourceEventSourceFor(Service.class, GERRIT_SERVICE_EVENT_SOURCE);
+
+    return ies.get(
+        new ResourceID(
+            new GerritHeadlessService().getName(gerrit), gerrit.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMap.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMap.java
index dbc41ed..7b3d183 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMap.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMap.java
@@ -36,7 +36,7 @@
 import java.util.Locale;
 import java.util.Map;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritInitConfigMapDiscriminator.class)
 public class GerritInitConfigMap
     extends CRUDReconcileAddKubernetesDependentResource<ConfigMap, Gerrit> {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMapDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMapDiscriminator.java
new file mode 100644
index 0000000..e5b2f8e
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritInitConfigMapDiscriminator.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.gerrit.dependent;
+
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritInitConfigMapDiscriminator implements ResourceDiscriminator<ConfigMap, Gerrit> {
+  @Override
+  public Optional<ConfigMap> distinguish(
+      Class<ConfigMap> resource, Gerrit primary, Context<Gerrit> context) {
+    InformerEventSource<ConfigMap, Gerrit> ies =
+        (InformerEventSource<ConfigMap, Gerrit>)
+            context.eventSourceRetriever().getResourceEventSourceFor(ConfigMap.class);
+
+    return ies.get(
+        new ResourceID(GerritInitConfigMap.getName(primary), primary.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritService.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritService.java
index 80edcf2..25c94bb 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritService.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritService.java
@@ -19,7 +19,7 @@
 import io.fabric8.kubernetes.api.model.ServiceSpecBuilder;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritServiceDiscriminator.class)
 public class GerritService extends GerritAbstractService {
   private static final String SERVICE_SUFFIX = "-service";
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritServiceDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritServiceDiscriminator.java
new file mode 100644
index 0000000..f832835
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritServiceDiscriminator.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.gerrit.dependent;
+
+import static com.google.gerrit.k8s.operator.gerrit.GerritReconciler.GERRIT_SERVICE_EVENT_SOURCE;
+
+import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
+import io.fabric8.kubernetes.api.model.Service;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritServiceDiscriminator implements ResourceDiscriminator<Service, Gerrit> {
+  @Override
+  public Optional<Service> distinguish(
+      Class<Service> aClass, Gerrit gerrit, Context<Gerrit> context) {
+    InformerEventSource<Service, Gerrit> ies =
+        (InformerEventSource<Service, Gerrit>)
+            context
+                .eventSourceRetriever()
+                .getResourceEventSourceFor(Service.class, GERRIT_SERVICE_EVENT_SOURCE);
+
+    return ies.get(
+        new ResourceID(new GerritService().getName(gerrit), gerrit.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gitgc/GitGarbageCollectionReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gitgc/GitGarbageCollectionReconciler.java
index e372493..39182d0 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gitgc/GitGarbageCollectionReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gitgc/GitGarbageCollectionReconciler.java
@@ -23,26 +23,30 @@
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import io.fabric8.kubernetes.client.KubernetesClient;
-import io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration;
+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.EventSourceUtils;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
 import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
 import io.javaoperatorsdk.operator.processing.event.ResourceID;
 import io.javaoperatorsdk.operator.processing.event.source.EventSource;
 import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper;
 import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
-import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Singleton
 @ControllerConfiguration
 @Deprecated
-public class GitGarbageCollectionReconciler implements Reconciler<GitGarbageCollection> {
+public class GitGarbageCollectionReconciler
+    implements Reconciler<GitGarbageCollection>,
+        EventSourceInitializer<GitGarbageCollection>,
+        ErrorStatusHandler<GitGarbageCollection> {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
   private final KubernetesClient client;
 
@@ -55,11 +59,8 @@
   }
 
   @Override
-  public List<EventSource<?, GitGarbageCollection>> prepareEventSources(
+  public Map<String, EventSource> prepareEventSources(
       EventSourceContext<GitGarbageCollection> context) {
-    List<EventSource<?, GitGarbageCollection>> eventSources = new ArrayList<>();
-    eventSources.addAll(EventSourceUtils.dependentEventSources(context, dependentCronJob));
-
     final SecondaryToPrimaryMapper<GitGarbageCollection> specificProjectGitGcMapper =
         (GitGarbageCollection gc) ->
             context
@@ -70,12 +71,10 @@
 
     InformerEventSource<GitGarbageCollection, GitGarbageCollection> gitGcEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(
-                    GitGarbageCollection.class, GitGarbageCollection.class)
+            InformerConfiguration.from(GitGarbageCollection.class, context)
                 .withSecondaryToPrimaryMapper(specificProjectGitGcMapper)
                 .build(),
             context);
-    eventSources.add(gitGcEventSource);
 
     final SecondaryToPrimaryMapper<GerritCluster> gerritClusterMapper =
         (GerritCluster cluster) ->
@@ -87,12 +86,13 @@
 
     InformerEventSource<GerritCluster, GitGarbageCollection> gerritClusterEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(GerritCluster.class, GitGarbageCollection.class)
+            InformerConfiguration.from(GerritCluster.class, context)
                 .withSecondaryToPrimaryMapper(gerritClusterMapper)
                 .build(),
             context);
-    eventSources.add(gerritClusterEventSource);
-    return eventSources;
+
+    return EventSourceInitializer.nameEventSources(
+        gitGcEventSource, gerritClusterEventSource, dependentCronJob.initEventSource(context));
   }
 
   @Override
@@ -103,7 +103,7 @@
     }
 
     dependentCronJob.reconcile(gitGc, context);
-    return UpdateControl.patchStatus(updateGitGcStatus(gitGc));
+    return UpdateControl.updateStatus(updateGitGcStatus(gitGc));
   }
 
   private GitGarbageCollection updateGitGcStatus(GitGarbageCollection gitGc) {
@@ -147,6 +147,6 @@
     }
     gitGc.setStatus(status);
 
-    return ErrorStatusUpdateControl.patchStatus(gitGc);
+    return ErrorStatusUpdateControl.updateStatus(gitGc);
   }
 }
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/indexer/GerritIndexerReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/indexer/GerritIndexerReconciler.java
index a4dc41b..3431381 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/indexer/GerritIndexerReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/indexer/GerritIndexerReconciler.java
@@ -19,13 +19,13 @@
 import com.google.gerrit.k8s.operator.indexer.dependent.GerritIndexerJob;
 import com.google.inject.Singleton;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
 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;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(name = "gerrit-indexer-configmap", type = GerritIndexerConfigMap.class),
       @Dependent(
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/maintenance/GerritMaintenanceReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/maintenance/GerritMaintenanceReconciler.java
index eeb4357..8b95011 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/maintenance/GerritMaintenanceReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/maintenance/GerritMaintenanceReconciler.java
@@ -18,13 +18,13 @@
 import com.google.gerrit.k8s.operator.maintenance.dependent.GerritMaintenanceCronJobs;
 import com.google.inject.Singleton;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
 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;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(name = "gerrit-maintenance-cronjobs", type = GerritMaintenanceCronJobs.class)
     })
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/GerritAmbassadorReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/GerritAmbassadorReconciler.java
index ee0ab23..b67760a 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/GerritAmbassadorReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/GerritAmbassadorReconciler.java
@@ -41,17 +41,18 @@
 import com.google.gerrit.k8s.operator.network.ambassador.dependent.TLSContextCondition;
 import com.google.inject.Singleton;
 import io.getambassador.v2.Mapping;
-import io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration;
+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.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 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.event.source.EventSource;
 import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Provides an Ambassador-based implementation for GerritNetworkReconciler.
@@ -100,7 +101,7 @@
  * https://gerrit.googlesource.com/plugins/replication/+/refs/heads/master/src/main/resources/Documentation/config.md
  */
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = GERRIT_MAPPING,
@@ -143,22 +144,21 @@
           type = GerritClusterHost.class,
           reconcilePrecondition = CreateHostCondition.class),
     })
-public class GerritAmbassadorReconciler implements Reconciler<GerritNetwork> {
+public class GerritAmbassadorReconciler
+    implements Reconciler<GerritNetwork>, EventSourceInitializer<GerritNetwork> {
 
   public static final String MAPPING_EVENT_SOURCE = "mapping-event-source";
 
   // Because we have multiple dependent resources of the same type `Mapping`, we need to specify
   // a named event source.
   @Override
-  public List<EventSource<?, GerritNetwork>> prepareEventSources(
-      EventSourceContext<GerritNetwork> context) {
+  public Map<String, EventSource> prepareEventSources(EventSourceContext<GerritNetwork> context) {
     InformerEventSource<Mapping, GerritNetwork> mappingEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(Mapping.class, GerritNetwork.class).build(),
-            context);
+            InformerConfiguration.from(Mapping.class, context).build(), context);
 
-    List<EventSource<?, GerritNetwork>> eventSources = new ArrayList<>();
-    eventSources.add(mappingEventSource);
+    Map<String, EventSource> eventSources = new HashMap<>();
+    eventSources.put(MAPPING_EVENT_SOURCE, mappingEventSource);
     return eventSources;
   }
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMapping.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMapping.java
index 05a6f4f..ec4974a 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMapping.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMapping.java
@@ -21,7 +21,7 @@
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritClusterMappingDiscriminator.class)
 public class GerritClusterMapping extends AbstractAmbassadorDependentResource<Mapping>
     implements MappingDependentResourceInterface {
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingDiscriminator.java
new file mode 100644
index 0000000..7dfc5c4
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingDiscriminator.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.network.ambassador.dependent;
+
+import static com.google.gerrit.k8s.operator.network.ambassador.dependent.GerritClusterMapping.GERRIT_MAPPING;
+
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import io.getambassador.v2.Mapping;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritClusterMappingDiscriminator
+    implements ResourceDiscriminator<Mapping, GerritNetwork> {
+  @Override
+  public Optional<Mapping> distinguish(
+      Class<Mapping> resource, GerritNetwork network, Context<GerritNetwork> context) {
+    InformerEventSource<Mapping, GerritNetwork> ies =
+        (InformerEventSource<Mapping, GerritNetwork>)
+            context.eventSourceRetriever().getResourceEventSourceFor(Mapping.class);
+    return ies.get(new ResourceID(GERRIT_MAPPING, network.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplica.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplica.java
index 4ebd448..0698f81 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplica.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplica.java
@@ -24,7 +24,7 @@
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import java.util.HashMap;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritClusterMappingGETReplicaDiscriminator.class)
 public class GerritClusterMappingGETReplica extends AbstractAmbassadorDependentResource<Mapping>
     implements MappingDependentResourceInterface {
 
@@ -53,7 +53,7 @@
             .withNewQueryParameters()
             .withAdditionalProperties(
                 new HashMap<String, Object>(ImmutableMap.of("service", "git-upload-pack")))
-            .endQueryParameters()
+            .endV2QueryParameters()
             .withMethod("GET")
             .withPrefix(INFO_REFS_PATTERN)
             .withPrefixRegex(true)
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplicaDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplicaDiscriminator.java
new file mode 100644
index 0000000..2aa4b37
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingGETReplicaDiscriminator.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.network.ambassador.dependent;
+
+import static com.google.gerrit.k8s.operator.network.ambassador.dependent.GerritClusterMappingGETReplica.GERRIT_MAPPING_GET_REPLICA;
+
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import io.getambassador.v2.Mapping;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritClusterMappingGETReplicaDiscriminator
+    implements ResourceDiscriminator<Mapping, GerritNetwork> {
+  @Override
+  public Optional<Mapping> distinguish(
+      Class<Mapping> resource, GerritNetwork network, Context<GerritNetwork> context) {
+    InformerEventSource<Mapping, GerritNetwork> ies =
+        (InformerEventSource<Mapping, GerritNetwork>)
+            context.eventSourceRetriever().getResourceEventSourceFor(Mapping.class);
+    return ies.get(
+        new ResourceID(GERRIT_MAPPING_GET_REPLICA, network.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplica.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplica.java
index 8fba245..eea964d 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplica.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplica.java
@@ -22,7 +22,7 @@
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritClusterMappingPOSTReplicaDiscriminator.class)
 public class GerritClusterMappingPOSTReplica extends AbstractAmbassadorDependentResource<Mapping>
     implements MappingDependentResourceInterface {
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplicaDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplicaDiscriminator.java
new file mode 100644
index 0000000..bb09abd
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPOSTReplicaDiscriminator.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.network.ambassador.dependent;
+
+import static com.google.gerrit.k8s.operator.network.ambassador.dependent.GerritClusterMappingPOSTReplica.GERRIT_MAPPING_POST_REPLICA;
+
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import io.getambassador.v2.Mapping;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritClusterMappingPOSTReplicaDiscriminator
+    implements ResourceDiscriminator<Mapping, GerritNetwork> {
+  @Override
+  public Optional<Mapping> distinguish(
+      Class<Mapping> resource, GerritNetwork network, Context<GerritNetwork> context) {
+    InformerEventSource<Mapping, GerritNetwork> ies =
+        (InformerEventSource<Mapping, GerritNetwork>)
+            context.eventSourceRetriever().getResourceEventSourceFor(Mapping.class);
+    return ies.get(
+        new ResourceID(GERRIT_MAPPING_POST_REPLICA, network.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimary.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimary.java
index 816f654..f17ce20 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimary.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimary.java
@@ -20,7 +20,7 @@
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritClusterMappingPrimaryDiscriminator.class)
 public class GerritClusterMappingPrimary extends AbstractAmbassadorDependentResource<Mapping>
     implements MappingDependentResourceInterface {
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimaryDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimaryDiscriminator.java
new file mode 100644
index 0000000..6dd38d0
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingPrimaryDiscriminator.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.network.ambassador.dependent;
+
+import static com.google.gerrit.k8s.operator.network.ambassador.dependent.GerritClusterMappingPrimary.GERRIT_MAPPING_PRIMARY;
+
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import io.getambassador.v2.Mapping;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritClusterMappingPrimaryDiscriminator
+    implements ResourceDiscriminator<Mapping, GerritNetwork> {
+  @Override
+  public Optional<Mapping> distinguish(
+      Class<Mapping> resource, GerritNetwork network, Context<GerritNetwork> context) {
+    InformerEventSource<Mapping, GerritNetwork> ies =
+        (InformerEventSource<Mapping, GerritNetwork>)
+            context.eventSourceRetriever().getResourceEventSourceFor(Mapping.class);
+    return ies.get(new ResourceID(GERRIT_MAPPING_PRIMARY, network.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiver.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiver.java
index 124f38c..ac56422 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiver.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiver.java
@@ -24,7 +24,7 @@
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritClusterMappingReceiverDiscriminator.class)
 public class GerritClusterMappingReceiver extends AbstractAmbassadorDependentResource<Mapping>
     implements MappingDependentResourceInterface {
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverDiscriminator.java
new file mode 100644
index 0000000..d59fadb
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverDiscriminator.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.network.ambassador.dependent;
+
+import static com.google.gerrit.k8s.operator.network.ambassador.dependent.GerritClusterMappingReceiver.GERRIT_MAPPING_RECEIVER;
+
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import io.getambassador.v2.Mapping;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritClusterMappingReceiverDiscriminator
+    implements ResourceDiscriminator<Mapping, GerritNetwork> {
+  @Override
+  public Optional<Mapping> distinguish(
+      Class<Mapping> resource, GerritNetwork network, Context<GerritNetwork> context) {
+    InformerEventSource<Mapping, GerritNetwork> ies =
+        (InformerEventSource<Mapping, GerritNetwork>)
+            context.eventSourceRetriever().getResourceEventSourceFor(Mapping.class);
+    return ies.get(new ResourceID(GERRIT_MAPPING_RECEIVER, network.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGET.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGET.java
index 3675af8..da3815c 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGET.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGET.java
@@ -25,7 +25,7 @@
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import java.util.HashMap;
 
-@KubernetesDependent
+@KubernetesDependent(resourceDiscriminator = GerritClusterMappingReceiverGETDiscriminator.class)
 public class GerritClusterMappingReceiverGET extends AbstractAmbassadorDependentResource<Mapping>
     implements MappingDependentResourceInterface {
 
@@ -53,7 +53,7 @@
             .withNewQueryParameters()
             .withAdditionalProperties(
                 new HashMap<String, Object>(ImmutableMap.of("service", "git-receive-pack")))
-            .endQueryParameters()
+            .endV2QueryParameters()
             .withMethod("GET")
             .withPrefix(INFO_REFS_PATTERN)
             .withPrefixRegex(true)
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGETDiscriminator.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGETDiscriminator.java
new file mode 100644
index 0000000..3128be9
--- /dev/null
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ambassador/dependent/GerritClusterMappingReceiverGETDiscriminator.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.k8s.operator.network.ambassador.dependent;
+
+import static com.google.gerrit.k8s.operator.network.ambassador.dependent.GerritClusterMappingReceiverGET.GERRIT_MAPPING_RECEIVER_GET;
+
+import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
+import io.getambassador.v2.Mapping;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
+import io.javaoperatorsdk.operator.processing.event.ResourceID;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.Optional;
+
+public class GerritClusterMappingReceiverGETDiscriminator
+    implements ResourceDiscriminator<Mapping, GerritNetwork> {
+  @Override
+  public Optional<Mapping> distinguish(
+      Class<Mapping> resource, GerritNetwork network, Context<GerritNetwork> context) {
+    InformerEventSource<Mapping, GerritNetwork> ies =
+        (InformerEventSource<Mapping, GerritNetwork>)
+            context.eventSourceRetriever().getResourceEventSourceFor(Mapping.class);
+    return ies.get(
+        new ResourceID(GERRIT_MAPPING_RECEIVER_GET, network.getMetadata().getNamespace()));
+  }
+}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/GerritIngressReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/GerritIngressReconciler.java
index afe71e8..48ec5fd 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/GerritIngressReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/GerritIngressReconciler.java
@@ -19,13 +19,13 @@
 import com.google.gerrit.k8s.operator.network.ingress.dependent.GerritClusterIngress;
 import com.google.inject.Singleton;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
 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;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = "gerrit-ingress",
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/GerritIstioReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/GerritIstioReconciler.java
index a45aa71..9d0a509 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/GerritIstioReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/GerritIstioReconciler.java
@@ -14,6 +14,10 @@
 
 package com.google.gerrit.k8s.operator.network.istio;
 
+import static com.google.gerrit.k8s.operator.network.istio.GerritIstioReconciler.ISTIO_DESTINATION_RULE_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.network.istio.GerritIstioReconciler.ISTIO_SERVICE_ENTRIES_EVENT_SOURCE;
+import static com.google.gerrit.k8s.operator.network.istio.GerritIstioReconciler.ISTIO_VIRTUAL_SERVICE_EVENT_SOURCE;
+
 import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
 import com.google.gerrit.k8s.operator.network.GerritClusterIngressCondition;
 import com.google.gerrit.k8s.operator.network.istio.dependent.GerritClusterIstioGateway;
@@ -21,23 +25,35 @@
 import com.google.gerrit.k8s.operator.network.istio.dependent.GerritIstioServiceEntries;
 import com.google.gerrit.k8s.operator.network.istio.dependent.GerritIstioVirtualService;
 import com.google.inject.Singleton;
+import io.fabric8.istio.api.networking.v1beta1.DestinationRule;
+import io.fabric8.istio.api.networking.v1beta1.ServiceEntry;
+import io.fabric8.istio.api.networking.v1beta1.VirtualService;
+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.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 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.event.source.EventSource;
+import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
+import java.util.HashMap;
+import java.util.Map;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = "gerrit-destination-rules",
           type = GerritIstioDestinationRule.class,
-          reconcilePrecondition = GerritClusterIngressCondition.class),
+          reconcilePrecondition = GerritClusterIngressCondition.class,
+          useEventSourceWithName = ISTIO_DESTINATION_RULE_EVENT_SOURCE),
       @Dependent(
           name = "gerrit-service-entries",
           type = GerritIstioServiceEntries.class,
-          reconcilePrecondition = GerritClusterIngressCondition.class),
+          reconcilePrecondition = GerritClusterIngressCondition.class,
+          useEventSourceWithName = ISTIO_SERVICE_ENTRIES_EVENT_SOURCE),
       @Dependent(
           name = "gerrit-istio-gateway",
           type = GerritClusterIstioGateway.class,
@@ -46,9 +62,38 @@
           name = "gerrit-istio-virtual-service",
           type = GerritIstioVirtualService.class,
           reconcilePrecondition = GerritClusterIngressCondition.class,
-          dependsOn = {"gerrit-istio-gateway"})
+          dependsOn = {"gerrit-istio-gateway"},
+          useEventSourceWithName = ISTIO_VIRTUAL_SERVICE_EVENT_SOURCE)
     })
-public class GerritIstioReconciler implements Reconciler<GerritNetwork> {
+public class GerritIstioReconciler
+    implements Reconciler<GerritNetwork>, EventSourceInitializer<GerritNetwork> {
+  public static final String ISTIO_DESTINATION_RULE_EVENT_SOURCE =
+      "gerrit-cluster-istio-destination-rule";
+  public static final String ISTIO_SERVICE_ENTRIES_EVENT_SOURCE =
+      "gerrit-cluster-istio-service-entries";
+  public static final String ISTIO_VIRTUAL_SERVICE_EVENT_SOURCE =
+      "gerrit-cluster-istio-virtual-service";
+
+  @Override
+  public Map<String, EventSource> prepareEventSources(EventSourceContext<GerritNetwork> context) {
+    InformerEventSource<DestinationRule, GerritNetwork> gerritIstioDestinationRuleEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(DestinationRule.class, context).build(), context);
+
+    InformerEventSource<ServiceEntry, GerritNetwork> gerritIstioServiceEntriesEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(ServiceEntry.class, context).build(), context);
+
+    InformerEventSource<VirtualService, GerritNetwork> virtualServiceEventSource =
+        new InformerEventSource<>(
+            InformerConfiguration.from(VirtualService.class, context).build(), context);
+
+    Map<String, EventSource> eventSources = new HashMap<>();
+    eventSources.put(ISTIO_DESTINATION_RULE_EVENT_SOURCE, gerritIstioDestinationRuleEventSource);
+    eventSources.put(ISTIO_SERVICE_ENTRIES_EVENT_SOURCE, gerritIstioServiceEntriesEventSource);
+    eventSources.put(ISTIO_VIRTUAL_SERVICE_EVENT_SOURCE, virtualServiceEventSource);
+    return eventSources;
+  }
 
   @Override
   public UpdateControl<GerritNetwork> reconcile(
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritClusterIstioGateway.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritClusterIstioGateway.java
index 3130ff0..e4cc3d7 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritClusterIstioGateway.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritClusterIstioGateway.java
@@ -17,11 +17,11 @@
 import com.google.gerrit.k8s.operator.api.model.network.GerritNetwork;
 import com.google.gerrit.k8s.operator.cluster.GerritClusterLabelFactory;
 import com.google.gerrit.k8s.operator.util.CRUDReconcileAddKubernetesDependentResource;
-import io.fabric8.istio.api.api.networking.v1alpha3.Server;
-import io.fabric8.istio.api.api.networking.v1alpha3.ServerBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.ServerTLSSettingsTLSmode;
 import io.fabric8.istio.api.networking.v1beta1.Gateway;
 import io.fabric8.istio.api.networking.v1beta1.GatewayBuilder;
+import io.fabric8.istio.api.networking.v1beta1.Server;
+import io.fabric8.istio.api.networking.v1beta1.ServerBuilder;
+import io.fabric8.istio.api.networking.v1beta1.ServerTLSSettingsTLSmode;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import java.util.ArrayList;
 import java.util.List;
@@ -59,7 +59,7 @@
         new ServerBuilder()
             .withNewPort()
             .withName("http")
-            .withNumber(80L)
+            .withNumber(80)
             .withProtocol("HTTP")
             .endPort()
             .withHosts(gerritClusterHost)
@@ -73,7 +73,7 @@
           new ServerBuilder()
               .withNewPort()
               .withName("https")
-              .withNumber(443L)
+              .withNumber(443)
               .withProtocol("HTTPS")
               .endPort()
               .withHosts(gerritClusterHost)
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java
index b875b8e..4158d79 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java
@@ -19,11 +19,11 @@
 import com.google.gerrit.k8s.operator.cluster.GerritClusterLabelFactory;
 import com.google.gerrit.k8s.operator.gerrit.dependent.GerritService;
 import com.google.gerrit.k8s.operator.util.CRUDReconcileAddKubernetesDependentResource;
-import io.fabric8.istio.api.api.networking.v1alpha3.LoadBalancerSettingsSimpleLB;
-import io.fabric8.istio.api.api.networking.v1alpha3.TrafficPolicy;
-import io.fabric8.istio.api.api.networking.v1alpha3.TrafficPolicyBuilder;
 import io.fabric8.istio.api.networking.v1beta1.DestinationRule;
 import io.fabric8.istio.api.networking.v1beta1.DestinationRuleBuilder;
+import io.fabric8.istio.api.networking.v1beta1.LoadBalancerSettingsSimpleLB;
+import io.fabric8.istio.api.networking.v1beta1.TrafficPolicy;
+import io.fabric8.istio.api.networking.v1beta1.TrafficPolicyBuilder;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter;
 import io.javaoperatorsdk.operator.processing.dependent.BulkDependentResource;
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioServiceEntries.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioServiceEntries.java
index 3795472..aa57362 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioServiceEntries.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioServiceEntries.java
@@ -25,11 +25,11 @@
 import com.google.gerrit.k8s.operator.gerrit.dependent.GerritService;
 import com.google.gerrit.k8s.operator.gerrit.dependent.GerritStatefulSet;
 import com.google.gerrit.k8s.operator.util.CRUDReconcileAddKubernetesDependentResource;
-import io.fabric8.istio.api.api.networking.v1alpha3.ServiceEntryLocation;
-import io.fabric8.istio.api.api.networking.v1alpha3.ServiceEntryResolution;
-import io.fabric8.istio.api.api.networking.v1alpha3.ServicePortBuilder;
 import io.fabric8.istio.api.networking.v1beta1.ServiceEntry;
 import io.fabric8.istio.api.networking.v1beta1.ServiceEntryBuilder;
+import io.fabric8.istio.api.networking.v1beta1.ServiceEntryLocation;
+import io.fabric8.istio.api.networking.v1beta1.ServiceEntryResolution;
+import io.fabric8.istio.api.networking.v1beta1.ServicePortBuilder;
 import io.fabric8.kubernetes.api.model.apps.StatefulSet;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter;
@@ -66,17 +66,17 @@
             List.of(
                 new ServicePortBuilder()
                     .withName("ssh-primary")
-                    .withNumber(Integer.toUnsignedLong(SSH_PORT))
+                    .withNumber(SSH_PORT)
                     .withProtocol("TCP")
                     .build(),
                 new ServicePortBuilder()
                     .withName("http")
-                    .withNumber(Integer.toUnsignedLong(HTTP_PORT))
+                    .withNumber(HTTP_PORT)
                     .withProtocol("HTTP")
                     .build(),
                 new ServicePortBuilder()
                     .withName("jgroups")
-                    .withNumber(Integer.toUnsignedLong(JGROUPS_PORT))
+                    .withNumber(JGROUPS_PORT)
                     .withProtocol("TCP")
                     .build()))
         .endSpec()
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioVirtualService.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioVirtualService.java
index 554c8ec..dff1a91 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioVirtualService.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioVirtualService.java
@@ -29,18 +29,18 @@
 import com.google.gerrit.k8s.operator.gerrit.dependent.GerritService;
 import com.google.gerrit.k8s.operator.receiver.dependent.ReceiverService;
 import com.google.gerrit.k8s.operator.util.CRUDReconcileAddKubernetesDependentResource;
-import io.fabric8.istio.api.api.networking.v1alpha3.HTTPMatchRequest;
-import io.fabric8.istio.api.api.networking.v1alpha3.HTTPMatchRequestBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.HTTPRoute;
-import io.fabric8.istio.api.api.networking.v1alpha3.HTTPRouteBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.HTTPRouteDestination;
-import io.fabric8.istio.api.api.networking.v1alpha3.HTTPRouteDestinationBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.L4MatchAttributesBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.RouteDestination;
-import io.fabric8.istio.api.api.networking.v1alpha3.RouteDestinationBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.StringMatchBuilder;
-import io.fabric8.istio.api.api.networking.v1alpha3.TCPRoute;
-import io.fabric8.istio.api.api.networking.v1alpha3.TCPRouteBuilder;
+import io.fabric8.istio.api.networking.v1beta1.HTTPMatchRequest;
+import io.fabric8.istio.api.networking.v1beta1.HTTPMatchRequestBuilder;
+import io.fabric8.istio.api.networking.v1beta1.HTTPRoute;
+import io.fabric8.istio.api.networking.v1beta1.HTTPRouteBuilder;
+import io.fabric8.istio.api.networking.v1beta1.HTTPRouteDestination;
+import io.fabric8.istio.api.networking.v1beta1.HTTPRouteDestinationBuilder;
+import io.fabric8.istio.api.networking.v1beta1.L4MatchAttributesBuilder;
+import io.fabric8.istio.api.networking.v1beta1.RouteDestination;
+import io.fabric8.istio.api.networking.v1beta1.RouteDestinationBuilder;
+import io.fabric8.istio.api.networking.v1beta1.StringMatchBuilder;
+import io.fabric8.istio.api.networking.v1beta1.TCPRoute;
+import io.fabric8.istio.api.networking.v1beta1.TCPRouteBuilder;
 import io.fabric8.istio.api.networking.v1beta1.VirtualService;
 import io.fabric8.istio.api.networking.v1beta1.VirtualServiceBuilder;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/receiver/ReceiverReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/receiver/ReceiverReconciler.java
index e15f542..25502bd 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/receiver/ReceiverReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/receiver/ReceiverReconciler.java
@@ -23,23 +23,24 @@
 import com.google.inject.Singleton;
 import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.client.KubernetesClient;
-import io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration;
+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.EventSourceContext;
+import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
 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.event.ResourceID;
 import io.javaoperatorsdk.operator.processing.event.source.EventSource;
 import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper;
 import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(name = "receiver-deployment", type = ReceiverDeployment.class),
       @Dependent(
@@ -47,7 +48,7 @@
           type = ReceiverService.class,
           dependsOn = {"receiver-deployment"})
     })
-public class ReceiverReconciler implements Reconciler<Receiver> {
+public class ReceiverReconciler implements Reconciler<Receiver>, EventSourceInitializer<Receiver> {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
   private static final String SECRET_EVENT_SOURCE_NAME = "secret-event-source";
   private final KubernetesClient client;
@@ -58,8 +59,7 @@
   }
 
   @Override
-  public List<EventSource<?, Receiver>> prepareEventSources(EventSourceContext<Receiver> context) {
-    List<EventSource<?, Receiver>> eventSources = new ArrayList<>();
+  public Map<String, EventSource> prepareEventSources(EventSourceContext<Receiver> context) {
     final SecondaryToPrimaryMapper<Secret> secretMapper =
         (Secret secret) ->
             context
@@ -75,12 +75,13 @@
 
     InformerEventSource<Secret, Receiver> secretEventSource =
         new InformerEventSource<>(
-            InformerEventSourceConfiguration.from(Secret.class, Receiver.class)
+            InformerConfiguration.from(Secret.class, context)
                 .withSecondaryToPrimaryMapper(secretMapper)
                 .build(),
             context);
 
-    eventSources.add(secretEventSource);
+    Map<String, EventSource> eventSources = new HashMap<>();
+    eventSources.put(SECRET_EVENT_SOURCE_NAME, secretEventSource);
     return eventSources;
   }
 
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/IncomingReplicationTaskReconciler.java b/operator/src/main/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/IncomingReplicationTaskReconciler.java
index 8fc92b1..48d7abb 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/IncomingReplicationTaskReconciler.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/IncomingReplicationTaskReconciler.java
@@ -19,13 +19,13 @@
 import com.google.gerrit.k8s.operator.tasks.incomingrepl.dependent.IncomingReplicationTaskCronJob;
 import com.google.inject.Singleton;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
 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;
 
 @Singleton
-@Workflow(
+@ControllerConfiguration(
     dependents = {
       @Dependent(
           name = "incoming-repl-task-configmap",
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/util/CRUDReconcileAddKubernetesDependentResource.java b/operator/src/main/java/com/google/gerrit/k8s/operator/util/CRUDReconcileAddKubernetesDependentResource.java
index aec8a0f..6e1cd79 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/util/CRUDReconcileAddKubernetesDependentResource.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/util/CRUDReconcileAddKubernetesDependentResource.java
@@ -35,6 +35,7 @@
 
   @Override
   public Result<R> match(R actualResource, R desired, P primary, Context<P> context) {
-    return GenericKubernetesResourceMatcher.match(desired, actualResource, false, true, context);
+    return GenericKubernetesResourceMatcher.match(
+        desired, actualResource, false, false, true, context);
   }
 }
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/util/KubernetesDependentCustomResource.java b/operator/src/main/java/com/google/gerrit/k8s/operator/util/KubernetesDependentCustomResource.java
index 946e9ce..9b2f516 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/util/KubernetesDependentCustomResource.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/util/KubernetesDependentCustomResource.java
@@ -39,7 +39,8 @@
 
   @Override
   public Result<R> match(R actualResource, R desired, P primary, Context<P> context) {
-    return GenericKubernetesResourceMatcher.match(desired, actualResource, false, true, context);
+    return GenericKubernetesResourceMatcher.match(
+        desired, actualResource, true, false, true, context);
   }
 
   @Override
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java
index 6fa4f27..86179a7 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java
@@ -21,7 +21,7 @@
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.Service;
 import io.fabric8.kubernetes.api.model.apps.StatefulSet;
-import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
 import io.javaoperatorsdk.operator.ReconcilerUtils;
 import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
@@ -33,6 +33,7 @@
 import java.util.Map;
 import java.util.stream.Stream;
 import org.junit.Rule;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.TestInstance.Lifecycle;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -41,7 +42,12 @@
 
 @TestInstance(Lifecycle.PER_CLASS)
 public class GerritTest {
-  @Rule public KubernetesMockServer kubernetesServer = new KubernetesMockServer();
+  @Rule public KubernetesServer kubernetesServer = new KubernetesServer();
+
+  @BeforeAll
+  public void setup() throws Exception {
+    kubernetesServer.before();
+  }
 
   @ParameterizedTest
   @MethodSource("provideYamlManifests")
@@ -54,7 +60,7 @@
       String expectedHeadlessServiceOutputFile) {
     Gerrit gerrit = ReconcilerUtils.loadYaml(Gerrit.class, this.getClass(), inputFile);
     Context<Gerrit> context =
-        getContext(new GerritReconciler(kubernetesServer.createClient()), gerrit);
+        getContext(new GerritReconciler(kubernetesServer.getClient()), gerrit);
 
     ConfigMap expectedGerritCm =
         ReconcilerUtils.loadYaml(
@@ -100,7 +106,7 @@
         new Controller<Gerrit>(
             reconciler,
             new BaseConfigurationService().getConfigurationFor(reconciler),
-            kubernetesServer.createClient());
+            kubernetesServer.getClient());
 
     return new DefaultContext<Gerrit>(
         new GenericRetryExecution(new GenericRetry()), controller, primary);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/gitgc/dependent/GitGarbageCollectionTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/gitgc/dependent/GitGarbageCollectionTest.java
index bafcb24..f175256 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/gitgc/dependent/GitGarbageCollectionTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/gitgc/dependent/GitGarbageCollectionTest.java
@@ -21,7 +21,7 @@
 import com.google.gerrit.k8s.operator.gitgc.GitGarbageCollectionReconciler;
 import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.fabric8.kubernetes.api.model.batch.v1.CronJob;
-import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
 import io.javaoperatorsdk.operator.ReconcilerUtils;
 import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
@@ -33,6 +33,7 @@
 import java.net.HttpURLConnection;
 import java.util.stream.Stream;
 import org.junit.Rule;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.TestInstance.Lifecycle;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -46,7 +47,12 @@
           "/apis/%s/namespaces/gerrit/%s/gerrit",
           HasMetadata.getApiVersion(GerritCluster.class),
           HasMetadata.getPlural(GerritCluster.class));
-  @Rule public KubernetesMockServer kubernetesServer = new KubernetesMockServer();
+  @Rule public KubernetesServer kubernetesServer = new KubernetesServer();
+
+  @BeforeAll
+  public void setup() throws Exception {
+    kubernetesServer.before();
+  }
 
   @ParameterizedTest
   @MethodSource("provideYamlManifests")
@@ -66,7 +72,7 @@
         .once();
 
     Context<GitGarbageCollection> context =
-        getContext(new GitGarbageCollectionReconciler(kubernetesServer.createClient()), input);
+        getContext(new GitGarbageCollectionReconciler(kubernetesServer.getClient()), input);
     GitGarbageCollectionCronJob dependentCronjob = new GitGarbageCollectionCronJob();
     assertThat(dependentCronjob.desired(input, context))
         .isEqualTo(ReconcilerUtils.loadYaml(CronJob.class, this.getClass(), expectedCronJob));
@@ -78,7 +84,7 @@
         new Controller<GitGarbageCollection>(
             reconciler,
             new BaseConfigurationService().getConfigurationFor(reconciler),
-            kubernetesServer.createClient());
+            kubernetesServer.getClient());
 
     return new DefaultContext<GitGarbageCollection>(
         new GenericRetryExecution(new GenericRetry()), controller, primary);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/indexer/dependent/GerritIndexerTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/indexer/dependent/GerritIndexerTest.java
index 0058c1e..21579e7 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/indexer/dependent/GerritIndexerTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/indexer/dependent/GerritIndexerTest.java
@@ -25,7 +25,7 @@
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.fabric8.kubernetes.api.model.batch.v1.Job;
-import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
 import io.javaoperatorsdk.operator.ReconcilerUtils;
 import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
@@ -56,11 +56,12 @@
       String.format(
           "/apis/%s/namespaces/gerrit/%s/gerrit",
           HasMetadata.getApiVersion(Gerrit.class), HasMetadata.getPlural(Gerrit.class));
-  @Rule public KubernetesMockServer kubernetesServer = new KubernetesMockServer();
+  @Rule public KubernetesServer kubernetesServer = new KubernetesServer();
 
   @BeforeAll
   public void setup() throws Exception {
     OperatorContext.createInstance(ClusterMode.HIGH_AVAILABILITY, "cluster.local");
+    kubernetesServer.before();
   }
 
   @ParameterizedTest
@@ -109,7 +110,7 @@
         new Controller<GerritIndexer>(
             reconciler,
             new BaseConfigurationService().getConfigurationFor(reconciler),
-            kubernetesServer.createClient());
+            kubernetesServer.getClient());
 
     return new DefaultContext<GerritIndexer>(
         new GenericRetryExecution(new GenericRetry()), controller, primary);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/server/AdmissionWebhookAbstractTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/server/AdmissionWebhookAbstractTest.java
index 91c2202..49ee9ea 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/server/AdmissionWebhookAbstractTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/server/AdmissionWebhookAbstractTest.java
@@ -35,7 +35,7 @@
 import io.fabric8.kubernetes.api.model.admission.v1.AdmissionRequest;
 import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
 import io.fabric8.kubernetes.client.CustomResource;
-import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
@@ -65,12 +65,14 @@
           NAMESPACE,
           HasMetadata.getPlural(GerritCluster.class));
 
-  @Rule protected KubernetesMockServer kubernetesServer = new KubernetesMockServer();
+  @Rule protected KubernetesServer kubernetesServer = new KubernetesServer();
 
   @BeforeAll
   public void setup() throws Exception {
     server = new TestAdmissionWebhookServer();
 
+    kubernetesServer.before();
+
     OperatorContext.createInstance(getClusterMode(), "cluster.local");
     server.registerWebhook(new GerritClusterAdmissionWebhook(getClusterMode()));
     server.registerWebhook(new GerritAdmissionWebhook(getClusterMode()));
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritClusterAdmissionWebhookTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritClusterAdmissionWebhookTest.java
index 7524ee8..76c6fbf 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritClusterAdmissionWebhookTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritClusterAdmissionWebhookTest.java
@@ -48,7 +48,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
     GerritTemplate gerrit1 = TestGerrit.createGerritTemplate("gerrit1", GerritMode.PRIMARY, cfg);
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     gerritCluster.addGerrit(gerrit1);
     GerritCluster cluster = gerritCluster.build();
 
@@ -80,7 +80,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
     GerritTemplate gerrit = TestGerrit.createGerritTemplate("gerrit1", GerritMode.PRIMARY, cfg);
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     gerritCluster.addGerrit(gerrit);
 
     ReceiverTemplate receiver = new ReceiverTemplate();
@@ -110,7 +110,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
     GerritTemplate gerrit1 = TestGerrit.createGerritTemplate("gerrit1", GerritMode.PRIMARY, cfg);
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     gerritCluster.addGerrit(gerrit1);
 
     HttpURLConnection http = sendAdmissionRequest(gerritCluster.build());
@@ -138,7 +138,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
 
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     GerritTemplate primary = TestGerrit.createGerritTemplate("gerrit", GerritMode.PRIMARY, cfg);
     GerritTemplate replica = TestGerrit.createGerritTemplate("gerrit", GerritMode.REPLICA, cfg);
     gerritCluster.addGerrit(primary);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritMultisiteClusterAdmissionWebhookTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritMultisiteClusterAdmissionWebhookTest.java
index b0cef7e..de97552 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritMultisiteClusterAdmissionWebhookTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/server/GerritMultisiteClusterAdmissionWebhookTest.java
@@ -43,7 +43,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
 
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     GerritTemplate primary = TestGerrit.createGerritTemplate("gerrit", GerritMode.PRIMARY, cfg);
     GerritTemplate replica = TestGerrit.createGerritTemplate("gerrit", GerritMode.REPLICA, cfg);
     gerritCluster.addGerrit(primary);
@@ -68,7 +68,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
 
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     GerritTemplate replica = TestGerrit.createGerritTemplate("gerrit", GerritMode.REPLICA, cfg);
     gerritCluster.addGerrit(replica);
 
@@ -92,7 +92,7 @@
     cfg.fromText(TestGerrit.DEFAULT_GERRIT_CONFIG);
 
     TestGerritCluster gerritCluster =
-        new TestGerritCluster(kubernetesServer.createClient(), NAMESPACE);
+        new TestGerritCluster(kubernetesServer.getClient(), NAMESPACE);
     GerritTemplate primary = TestGerrit.createGerritTemplate("gerrit", GerritMode.PRIMARY, cfg);
     primary.getSpec().setReplicas(1);
     gerritCluster.addGerrit(primary);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/server/GitGcAdmissionWebhookTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/server/GitGcAdmissionWebhookTest.java
index 358e22b..0fc1407 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/server/GitGcAdmissionWebhookTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/server/GitGcAdmissionWebhookTest.java
@@ -30,7 +30,7 @@
 import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
 import io.fabric8.kubernetes.api.model.admission.v1.AdmissionRequest;
 import io.fabric8.kubernetes.api.model.admission.v1.AdmissionReview;
-import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
 import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -60,13 +60,15 @@
           HasMetadata.getPlural(GitGarbageCollection.class));
   private TestAdmissionWebhookServer server;
 
-  @Rule public KubernetesMockServer kubernetesServer = new KubernetesMockServer();
+  @Rule public KubernetesServer kubernetesServer = new KubernetesServer();
 
   @BeforeAll
   public void setup() throws Exception {
     server = new TestAdmissionWebhookServer();
 
-    GitGcAdmissionWebhook webhook = new GitGcAdmissionWebhook(kubernetesServer.createClient());
+    kubernetesServer.before();
+
+    GitGcAdmissionWebhook webhook = new GitGcAdmissionWebhook(kubernetesServer.getClient());
     server.registerWebhook(webhook);
     server.start();
   }
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/dependent/IncomingReplicationTaskTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/dependent/IncomingReplicationTaskTest.java
index ec805ec..4c9cf7e 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/dependent/IncomingReplicationTaskTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/tasks/incomingrepl/dependent/IncomingReplicationTaskTest.java
@@ -24,7 +24,7 @@
 import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.api.model.SecretBuilder;
 import io.fabric8.kubernetes.api.model.batch.v1.CronJob;
-import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
 import io.javaoperatorsdk.operator.ReconcilerUtils;
 import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
@@ -37,6 +37,7 @@
 import java.util.Map;
 import java.util.stream.Stream;
 import org.junit.Rule;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.TestInstance.Lifecycle;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -45,7 +46,12 @@
 
 @TestInstance(Lifecycle.PER_CLASS)
 public class IncomingReplicationTaskTest {
-  @Rule public KubernetesMockServer kubernetesServer = new KubernetesMockServer();
+  @Rule public KubernetesServer kubernetesServer = new KubernetesServer();
+
+  @BeforeAll
+  public void setup() throws Exception {
+    kubernetesServer.before();
+  }
 
   @ParameterizedTest
   @MethodSource("provideYamlManifests")
@@ -107,7 +113,7 @@
         new Controller<IncomingReplicationTask>(
             reconciler,
             new BaseConfigurationService().getConfigurationFor(reconciler),
-            kubernetesServer.createClient());
+            kubernetesServer.getClient());
 
     return new DefaultContext<IncomingReplicationTask>(
         new GenericRetryExecution(new GenericRetry()), controller, primary);
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_es_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_es_primary.yaml
index 3c797c9..b1b5da8 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_es_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_es_primary.yaml
@@ -158,21 +158,21 @@
       serviceAccount: gerrit
       terminationGracePeriodSeconds: 30
       volumes:
-      - name: tmp
-        emptyDir:
-          sizeLimit: 500Mi
-      - configMap:
-          name: gerrit-init-configmap
-        name: gerrit-init-config
-      - configMap:
-          name: gerrit-configmap
-        name: gerrit-config
-      - name: gerrit-secure-config
-        secret:
-          secretName: gerrit-secure-config
       - name: shared
         persistentVolumeClaim:
           claimName: shared-pvc
+      - name: tmp
+        emptyDir:
+          sizeLimit: 500Mi
+      - name: gerrit-secure-config
+        secret:
+          secretName: gerrit-secure-config
+      - configMap:
+          name: gerrit-configmap
+        name: gerrit-config
+      - configMap:
+          name: gerrit-init-configmap
+        name: gerrit-init-config
   updateStrategy:
     rollingUpdate:
       partition: 0
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_ha_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_ha_primary.yaml
index 67800cf..28b366b 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_ha_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_ha_primary.yaml
@@ -152,21 +152,21 @@
       serviceAccount: gerrit
       terminationGracePeriodSeconds: 30
       volumes:
-      - name: tmp
-        emptyDir:
-          sizeLimit: 500Mi
-      - configMap:
-          name: gerrit-init-configmap
-        name: gerrit-init-config
-      - configMap:
-          name: gerrit-configmap
-        name: gerrit-config
-      - name: gerrit-secure-config
-        secret:
-          secretName: gerrit-secure-config
       - name: shared
         persistentVolumeClaim:
           claimName: shared-pvc
+      - name: tmp
+        emptyDir:
+          sizeLimit: 500Mi
+      - name: gerrit-secure-config
+        secret:
+          secretName: gerrit-secure-config
+      - configMap:
+          name: gerrit-configmap
+        name: gerrit-config
+      - configMap:
+          name: gerrit-init-configmap
+        name: gerrit-init-config
   updateStrategy:
     rollingUpdate:
       partition: 0
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_single_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_single_primary.yaml
index 31a82c8..7086159 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_single_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_single_primary.yaml
@@ -140,21 +140,21 @@
       serviceAccount: gerrit
       terminationGracePeriodSeconds: 30
       volumes:
-      - name: tmp
-        emptyDir:
-          sizeLimit: 500Mi
-      - configMap:
-          name: gerrit-init-configmap
-        name: gerrit-init-config
-      - configMap:
-          name: gerrit-configmap
-        name: gerrit-config
-      - name: gerrit-secure-config
-        secret:
-          secretName: gerrit-secure-config
       - name: shared
         persistentVolumeClaim:
           claimName: shared-pvc
+      - name: tmp
+        emptyDir:
+          sizeLimit: 500Mi
+      - name: gerrit-secure-config
+        secret:
+          secretName: gerrit-secure-config
+      - configMap:
+          name: gerrit-configmap
+        name: gerrit-config
+      - configMap:
+          name: gerrit-init-configmap
+        name: gerrit-init-config
   updateStrategy:
     rollingUpdate:
       partition: 0
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment.yaml
index 801c0b7..08f8270 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment.yaml
@@ -120,12 +120,12 @@
           mountPath: /var/apache/credentials/.htpasswd
           subPath: .htpasswd
       volumes:
-      - name: apache-credentials
-        secret:
-          secretName: apache-credentials
       - name: shared
         persistentVolumeClaim:
           claimName: shared-pvc
+      - name: apache-credentials
+        secret:
+          secretName: apache-credentials
       - name: apache-run-dir
         emptyDir:
           sizeLimit: 50Mi
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment_minimal.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment_minimal.yaml
index c2e6024..c282acf 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment_minimal.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/dependent/deployment_minimal.yaml
@@ -81,12 +81,12 @@
           mountPath: /var/apache/credentials/.htpasswd
           subPath: .htpasswd
       volumes:
-      - name: apache-credentials
-        secret:
-          secretName: apache-credentials
       - name: shared
         persistentVolumeClaim:
           claimName: shared-pvc
+      - name: apache-credentials
+        secret:
+          secretName: apache-credentials
       - name: apache-run-dir
         emptyDir:
           sizeLimit: 50Mi