Repository: FoundationDB/fdb-kubernetes-operator
Pull request #1807 (2023-09-18 14:57:11)

Refactor code to make use of the process group directly without passing the class and id number down
# Description

This is a follow up to refactor the operator code and remove some old technical debts, e.g. there is no need to parse the process class and id number multiple times, we just can pass down the whole process group.

## Type of change

*Please select one of the options below.*

- Other

## Discussion

Most of the changes are adjustments for the test cases.

## Testing

Ran unit tests and e2e tests will be running with CI.

## Documentation

-

## Follow-up

-

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 3cfe0d608c7924ad930ecf67acc4665998c6c988
* Duration 4:07:14
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/e45e3bb0-2330-41f2-bedf-de88bfc195dd.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/e45e3bb0-2330-41f2-bedf-de88bfc195dd/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 3cfe0d608c7924ad930ecf67acc4665998c6c988
* Duration 3:32:13
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/0f667cbb-9aad-487d-9a81-2089ccde8307.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/0f667cbb-9aad-487d-9a81-2089ccde8307/workspace.zip) zip file of the working directory (available for 30 days)

johscheuer: > ### Result of fdb-kubernetes-operator-pr on Linux CentOS 7
> * Commit ID: [3cfe0d6](https://github.com/FoundationDB/fdb-kubernetes-operator/commit/3cfe0d608c7924ad930ecf67acc4665998c6c988)
> * Duration 3:32:13
> * Result: ❌ **FAILED**
> * Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
> * [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/0f667cbb-9aad-487d-9a81-2089ccde8307.gz) terminal output (available for 30 days)
> * [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/0f667cbb-9aad-487d-9a81-2089ccde8307/workspace.zip) zip file of the working directory (available for 30 days)

```text
Operator when we change the process group prefix [It] should add the prefix to all instances [e2e, pr]
/codebuild/output/src3645663570/src/github.com/FoundationDB/fdb-kubernetes-operator/e2e/test_operator/operator_test.go:757

  [FAILED] Expected
      <string>: log-1
  to have prefix
      <string>: banana
  In [It] at: /codebuild/output/src3645663570/src/github.com/FoundationDB/fdb-kubernetes-operator/e2e/test_operator/operator_test.go:760 @ 09/19/23 05:45:05.405
------------------------------
```
foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 54fe73d0f09ec530dd5c271f07c6a005e2bbcd00
* Duration 4:07:14
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/eae486b0-da50-49ec-9eee-c1a0a7baecdd.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/eae486b0-da50-49ec-9eee-c1a0a7baecdd/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: b2a100881fc42d843583efee435b69cd6693c58d
* Duration 3:38:27
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/0d6b534e-bb33-4b6e-ab89-2ebdb8e39e48.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/0d6b534e-bb33-4b6e-ab89-2ebdb8e39e48/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 3f116bdbf3063e5d275ff1b77ce3ab0b4b248c69
* Duration 2:39:31
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/8fab70a4-6bd9-4beb-a79d-c145e279a02a.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/8fab70a4-6bd9-4beb-a79d-c145e279a02a/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 53bafba94aa1dba533e88c028abfe66ea53f410b
* Duration 2:54:19
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/764bf03b-7970-492f-bbfb-b813a95ab3d2.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/764bf03b-7970-492f-bbfb-b813a95ab3d2/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 65e848086db7f9d3a6be310fe7962aa984ebe19f
* Duration 2:34:24
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/7d9dce7e-dc52-4882-8ba7-31bb41389568.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/7d9dce7e-dc52-4882-8ba7-31bb41389568/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 9cf27d9866ab16cb0412963257635e5a0702c8a8
* Duration 2:48:17
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/51bb4581-1583-48f3-8efd-f858471198ee.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/51bb4581-1583-48f3-8efd-f858471198ee/workspace.zip) zip file of the working directory (available for 30 days)

foundationdb-ci: 
### Result of fdb-kubernetes-operator-pr on Linux CentOS 7

* Commit ID: 3b7aa88e2c36f320702a1378c14fa9fb0b0e2c34
* Duration 2:47:23
* Result: :x: **FAILED**
* Error: `Error while executing command: if $fail_test; then exit 1; fi. Reason: exit status 1`
* [Build Log](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/57b56b00-f201-4da5-98c3-3d69c53efd93.gz) terminal output (available for 30 days)
* [Build Workspace](https://d1e0l78xbkh3xa.cloudfront.net/fdb-kubernetes-operator-pr/57b56b00-f201-4da5-98c3-3d69c53efd93/workspace.zip) zip file of the working directory (available for 30 days)


Patch:
diff --git a/api/v1beta2/foundationdbcluster_types.go b/api/v1beta2/foundationdbcluster_types.go
index de5344ee..9551fae6 100644
--- a/api/v1beta2/foundationdbcluster_types.go
+++ b/api/v1beta2/foundationdbcluster_types.go
@@ -594,17 +594,20 @@ func (processGroupStatus *ProcessGroupStatus) AllAddressesExcluded(logger logr.L
 
 // NewProcessGroupStatus returns a new GroupStatus for the given processGroupID and processClass.
 func NewProcessGroupStatus(processGroupID ProcessGroupID, processClass ProcessClass, addresses []string) *ProcessGroupStatus {
+	initialConditions := []*ProcessGroupCondition{
+		NewProcessGroupCondition(MissingProcesses),
+		NewProcessGroupCondition(MissingPod),
+	}
+
+	if processClass.IsStateful() {
+		initialConditions = append(initialConditions, NewProcessGroupCondition(MissingPVC))
+	}
+
 	return &ProcessGroupStatus{
-		ProcessGroupID: processGroupID,
-		ProcessClass:   processClass,
-		Addresses:      addresses,
-		ProcessGroupConditions: []*ProcessGroupCondition{
-			NewProcessGroupCondition(MissingProcesses),
-			NewProcessGroupCondition(MissingPod),
-			NewProcessGroupCondition(MissingPVC),
-			// TODO(johscheuer): currently we never set this condition
-			// NewProcessGroupCondition(MissingService),
-		},
+		ProcessGroupID:         processGroupID,
+		ProcessClass:           processClass,
+		Addresses:              addresses,
+		ProcessGroupConditions: initialConditions,
 	}
 }
 
diff --git a/controllers/add_pods.go b/controllers/add_pods.go
index 6a239be3..334c7897 100644
--- a/controllers/add_pods.go
+++ b/controllers/add_pods.go
@@ -78,14 +78,9 @@ func (a addPods) reconcile(ctx context.Context, r *FoundationDBClusterReconciler
 			continue
 		}
 
-		idNum, err := processGroup.ProcessGroupID.GetIDNumber()
+		pod, err := internal.GetPod(cluster, processGroup)
 		if err != nil {
-			return &requeue{curError: err}
-		}
-
-		pod, err := internal.GetPod(cluster, processGroup.ProcessClass, idNum)
-		if err != nil {
-			r.Recorder.Event(cluster, corev1.EventTypeWarning, "GetPod", fmt.Sprintf("failed to get the PodSpec for %s/%d with error: %s", processGroup.ProcessClass, idNum, err))
+			r.Recorder.Event(cluster, corev1.EventTypeWarning, "GetPod", fmt.Sprintf("failed to get the PodSpec for %s with error: %s", processGroup.ProcessGroupID, err))
 			return &requeue{curError: err}
 		}
 
diff --git a/controllers/add_pvcs.go b/controllers/add_pvcs.go
index 22da8a46..a3ce78a5 100644
--- a/controllers/add_pvcs.go
+++ b/controllers/add_pvcs.go
@@ -43,12 +43,7 @@ func (a addPVCs) reconcile(ctx context.Context, r *FoundationDBClusterReconciler
 			continue
 		}
 
-		idNum, err := processGroup.ProcessGroupID.GetIDNumber()
-		if err != nil {
-			return &requeue{curError: err}
-		}
-
-		pvc, err := internal.GetPvc(cluster, processGroup.ProcessClass, idNum)
+		pvc, err := internal.GetPvc(cluster, processGroup)
 		if err != nil {
 			return &requeue{curError: err}
 		}
@@ -61,7 +56,7 @@ func (a addPVCs) reconcile(ctx context.Context, r *FoundationDBClusterReconciler
 		err = r.Get(ctx, client.ObjectKey{Namespace: pvc.Namespace, Name: pvc.Name}, existingPVC)
 		if err != nil {
 			if !k8serrors.IsNotFound(err) {
-				return &requeue{curError: err}
+				return &requeue{curError: err, delayedRequeue: true}
 			}
 
 			owner := internal.BuildOwnerReference(cluster.TypeMeta, cluster.ObjectMeta)
@@ -69,11 +64,7 @@ func (a addPVCs) reconcile(ctx context.Context, r *FoundationDBClusterReconciler
 			logger.V(1).Info("Creating PVC", "name", pvc.Name)
 			err = r.Create(ctx, pvc)
 			if err != nil {
-				if internal.IsQuotaExceeded(err) {
-					return &requeue{curError: err, delayedRequeue: true}
-				}
-
-				return &requeue{curError: err}
+				return &requeue{curError: err, delayedRequeue: true}
 			}
 		}
 	}
diff --git a/controllers/add_services.go b/controllers/add_services.go
index 29e90c29..e4787712 100644
--- a/controllers/add_services.go
+++ b/controllers/add_services.go
@@ -38,23 +38,23 @@ type addServices struct{}
 
 // reconcile runs the reconciler's work.
 func (a addServices) reconcile(ctx context.Context, r *FoundationDBClusterReconciler, cluster *fdbv1beta2.FoundationDBCluster, _ *fdbv1beta2.FoundationDBStatus, logger logr.Logger) *requeue {
-	service := internal.GetHeadlessService(cluster)
-	if service != nil {
+	headlessService := internal.GetHeadlessService(cluster)
+	if headlessService != nil {
 		existingService := &corev1.Service{}
 		err := r.Get(ctx, client.ObjectKey{Namespace: cluster.Namespace, Name: cluster.Name}, existingService)
 		if err == nil {
-			err = updateService(ctx, logger, cluster, r, existingService, service)
+			err = updateService(ctx, logger, cluster, r, existingService, headlessService)
 			if err != nil {
-				return &requeue{curError: err}
+				return &requeue{curError: err, delayedRequeue: true}
 			}
 		} else {
 			if !k8serrors.IsNotFound(err) {
 				return &requeue{curError: err}
 			}
 			owner := internal.BuildOwnerReference(cluster.TypeMeta, cluster.ObjectMeta)
-			service.ObjectMeta.OwnerReferences = owner
-			logger.V(1).Info("Creating service", "name", service.Name)
-			err = r.Create(ctx, service)
+			headlessService.ObjectMeta.OwnerReferences = owner
+			logger.V(1).Info("Creating service", "name", headlessService.Name)
+			err = r.Create(ctx, headlessService)
 			if err != nil {
 				return &requeue{curError: err, delayedRequeue: true}
 			}
@@ -67,36 +67,26 @@ func (a addServices) reconcile(ctx context.Context, r *FoundationDBClusterReconc
 				continue
 			}
 
-			idNum, err := processGroup.ProcessGroupID.GetIDNumber()
-			if err != nil {
-				return &requeue{curError: err}
-			}
-
-			serviceName, _ := cluster.GetProcessGroupID(processGroup.ProcessClass, idNum)
-			service, err := internal.GetService(cluster, processGroup.ProcessClass, idNum)
+			service, err := internal.GetService(cluster, processGroup)
 			if err != nil {
-				return &requeue{curError: err}
+				return &requeue{curError: err, delayedRequeue: true}
 			}
 
 			existingService := &corev1.Service{}
-			err = r.Get(ctx, client.ObjectKey{Namespace: cluster.Namespace, Name: serviceName}, existingService)
+			err = r.Get(ctx, client.ObjectKey{Namespace: cluster.Namespace, Name: service.Name}, existingService)
 			if err == nil {
 				err = updateService(ctx, logger, cluster, r, existingService, service)
 				if err != nil {
-					return &requeue{curError: err}
+					return &requeue{curError: err, delayedRequeue: true}
 				}
 			} else if k8serrors.IsNotFound(err) {
 				logger.V(1).Info("Creating service", "name", service.Name)
 				err = r.Create(ctx, service)
 				if err != nil {
-					if internal.IsQuotaExceeded(err) {
-						return &requeue{curError: err, delayedRequeue: true}
-					}
-
-					return &requeue{curError: err}
+					return &requeue{curError: err, delayedRequeue: true}
 				}
 			} else {
-				return &requeue{curError: err}
+				return &requeue{curError: err, delayedRequeue: true}
 			}
 		}
 	}
diff --git a/controllers/update_pods.go b/controllers/update_pods.go
index d565ca7f..ed53a391 100644
--- a/controllers/update_pods.go
+++ b/controllers/update_pods.go
@@ -175,15 +175,7 @@ func getPodsToUpdate(ctx context.Context, logger logr.Logger, reconciler *Founda
 			return nil, fmt.Errorf("cluster has Pod %s that is pending deletion", pod.Name)
 		}
 
-		idNum, err := processGroup.ProcessGroupID.GetIDNumber()
-		if err != nil {
-			logger.Info("Skipping Pod due to error parsing Process Group ID",
-				"processGroupID", processGroup.ProcessGroupID,
-				"error", err.Error())
-			continue
-		}
-
-		specHash, err := internal.GetPodSpecHash(cluster, processGroup.ProcessClass, idNum, nil)
+		specHash, err := internal.GetPodSpecHash(cluster, processGroup, nil)
 		if err != nil {
 			logger.Info("Skipping Pod due to error generating spec hash",
 				"processGroupID", processGroup.ProcessGroupID,
diff --git a/controllers/update_status.go b/controllers/update_status.go
index c92ddb02..4f9ca0c1 100644
--- a/controllers/update_status.go
+++ b/controllers/update_status.go
@@ -544,12 +544,7 @@ func validateProcessGroup(ctx context.Context, r *FoundationDBClusterReconciler,
 		return nil
 	}
 
-	idNum, err := processGroupStatus.ProcessGroupID.GetIDNumber()
-	if err != nil {
-		return err
-	}
-
-	specHash, err := internal.GetPodSpecHash(cluster, processGroupStatus.ProcessClass, idNum, nil)
+	specHash, err := internal.GetPodSpecHash(cluster, processGroupStatus, nil)
 	if err != nil {
 		return err
 	}
@@ -582,7 +577,7 @@ func validateProcessGroup(ctx context.Context, r *FoundationDBClusterReconciler,
 
 	processGroupStatus.UpdateCondition(fdbv1beta2.IncorrectConfigMap, !synced)
 
-	desiredPvc, err := internal.GetPvc(cluster, processGroupStatus.ProcessClass, idNum)
+	desiredPvc, err := internal.GetPvc(cluster, processGroupStatus)
 	if err != nil {
 		return err
 	}
diff --git a/internal/pod_helper.go b/internal/pod_helper.go
index d7ca4903..bffd5061 100644
--- a/internal/pod_helper.go
+++ b/internal/pod_helper.go
@@ -99,10 +99,10 @@ func GetProcessGroupIDFromMeta(cluster *fdbv1beta2.FoundationDBCluster, metadata
 }
 
 // GetPodSpecHash builds the hash of the expected spec for a pod.
-func GetPodSpecHash(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, id int, spec *corev1.PodSpec) (string, error) {
+func GetPodSpecHash(cluster *fdbv1beta2.FoundationDBCluster, processGroup *fdbv1beta2.ProcessGroupStatus, spec *corev1.PodSpec) (string, error) {
 	var err error
 	if spec == nil {
-		spec, err = GetPodSpec(cluster, processClass, id)
+		spec, err = GetPodSpec(cluster, processGroup)
 		if err != nil {
 			return "", err
 		}
@@ -197,6 +197,7 @@ func GetPvcMetadata(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1b
 	} else {
 		customMetadata = nil
 	}
+
 	return GetObjectMetadata(cluster, customMetadata, processClass, id)
 }
 
diff --git a/internal/pod_models.go b/internal/pod_models.go
index 530e9647..7f19137e 100644
--- a/internal/pod_models.go
+++ b/internal/pod_models.go
@@ -72,16 +72,14 @@ func generateServicePorts(processesPerPod int) []corev1.ServicePort {
 }
 
 // GetService builds a service for a new process group
-func GetService(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, idNum int) (*corev1.Service, error) {
-	name, id := cluster.GetProcessGroupID(processClass, idNum)
-
+func GetService(cluster *fdbv1beta2.FoundationDBCluster, processGroup *fdbv1beta2.ProcessGroupStatus) (*corev1.Service, error) {
 	owner := BuildOwnerReference(cluster.TypeMeta, cluster.ObjectMeta)
-	metadata := GetObjectMetadata(cluster, nil, processClass, id)
-	metadata.Name = name
+	metadata := GetObjectMetadata(cluster, nil, processGroup.ProcessClass, processGroup.ProcessGroupID)
+	metadata.Name = processGroup.GetPodName(cluster)
 	metadata.OwnerReferences = owner
 
 	processesPerPod := 1
-	if processClass == fdbv1beta2.ProcessClassStorage {
+	if processGroup.ProcessClass == fdbv1beta2.ProcessClassStorage {
 		processesPerPod = cluster.GetStorageServersPerPod()
 	}
 
@@ -95,29 +93,27 @@ func GetService(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2
 			Type:                     corev1.ServiceTypeClusterIP,
 			Ports:                    generateServicePorts(processesPerPod),
 			PublishNotReadyAddresses: true,
-			Selector:                 GetPodMatchLabels(cluster, "", string(id)),
+			Selector:                 GetPodMatchLabels(cluster, "", string(processGroup.ProcessGroupID)),
 			IPFamilies:               ipFamilies,
 		},
 	}, nil
 }
 
 // GetPod builds a pod for a new process group
-func GetPod(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, idNum int) (*corev1.Pod, error) {
-	name, id := cluster.GetProcessGroupID(processClass, idNum)
-
+func GetPod(cluster *fdbv1beta2.FoundationDBCluster, processGroup *fdbv1beta2.ProcessGroupStatus) (*corev1.Pod, error) {
 	owner := BuildOwnerReference(cluster.TypeMeta, cluster.ObjectMeta)
-	spec, err := GetPodSpec(cluster, processClass, idNum)
+	spec, err := GetPodSpec(cluster, processGroup)
 	if err != nil {
 		return nil, err
 	}
 
-	specHash, err := GetPodSpecHash(cluster, processClass, idNum, spec)
+	specHash, err := GetPodSpecHash(cluster, processGroup, spec)
 	if err != nil {
 		return nil, err
 	}
 
-	metadata := GetPodMetadata(cluster, processClass, id, specHash)
-	metadata.Name = name
+	metadata := GetPodMetadata(cluster, processGroup.ProcessClass, processGroup.ProcessGroupID, specHash)
+	metadata.Name = processGroup.GetPodName(cluster)
 	metadata.OwnerReferences = owner
 
 	return &corev1.Pod{
@@ -389,8 +385,8 @@ func configureNoSchedule(podSpec *corev1.PodSpec, processGroupID fdbv1beta2.Proc
 }
 
 // GetPodSpec builds a pod spec for a FoundationDB pod
-func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, idNum int) (*corev1.PodSpec, error) {
-	processSettings := cluster.GetProcessSettings(processClass)
+func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processGroup *fdbv1beta2.ProcessGroupStatus) (*corev1.PodSpec, error) {
+	processSettings := cluster.GetProcessSettings(processGroup.ProcessClass)
 	podSpec := processSettings.PodTemplate.Spec.DeepCopy()
 	useUnifiedImages := pointer.BoolDeref(cluster.Spec.UseUnifiedImage, false)
 
@@ -404,7 +400,6 @@ func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2
 		return nil, err
 	}
 
-	podName, processGroupID := cluster.GetProcessGroupID(processClass, idNum)
 	desiredVersion := cluster.GetRunningVersion()
 	if cluster.VersionCompatibleUpgradeInProgress() {
 		desiredVersion = cluster.Spec.Version
@@ -427,8 +422,9 @@ func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2
 		logGroup = cluster.Name
 	}
 
+	podName := processGroup.GetPodName(cluster)
 	if useUnifiedImages {
-		err = configureContainersForUnifiedImages(cluster, mainContainer, sidecarContainer, processGroupID, processClass)
+		err = configureContainersForUnifiedImages(cluster, mainContainer, sidecarContainer, processGroup.ProcessGroupID, processGroup.ProcessClass)
 		if err != nil {
 			return nil, err
 		}
@@ -442,7 +438,7 @@ func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2
 
 		for _, crashObjs := range cluster.Spec.Buggify.CrashLoopContainers {
 			for _, pid := range crashObjs.Targets {
-				if (pid == processGroupID || pid == "*") && crashObjs.ContainerName == mainContainer.Name {
+				if (pid == processGroup.ProcessGroupID || pid == "*") && crashObjs.ContainerName == mainContainer.Name {
 					args = "crash-loop"
 					break
 				}
@@ -456,27 +452,27 @@ func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2
 			corev1.VolumeMount{Name: "fdb-trace-logs", MountPath: "/var/log/fdb-trace-logs"},
 		)
 
-		err = configureSidecarContainerForCluster(cluster, podName, initContainer, true, processGroupID, desiredVersion)
+		err = configureSidecarContainerForCluster(cluster, podName, initContainer, true, processGroup.ProcessGroupID, desiredVersion)
 		if err != nil {
 			return nil, err
 		}
 
-		err = configureSidecarContainerForCluster(cluster, podName, sidecarContainer, false, processGroupID, desiredVersion)
+		err = configureSidecarContainerForCluster(cluster, podName, sidecarContainer, false, processGroup.ProcessGroupID, desiredVersion)
 		if err != nil {
 			return nil, err
 		}
 
-		serversPerPod := cluster.GetDesiredServersPerPod(processClass)
+		serversPerPod := cluster.GetDesiredServersPerPod(processGroup.ProcessClass)
 		if serversPerPod > 1 {
-			sidecarContainer.Env = append(sidecarContainer.Env, corev1.EnvVar{Name: processClass.GetServersPerPodEnvName(), Value: strconv.Itoa(serversPerPod)})
+			sidecarContainer.Env = append(sidecarContainer.Env, corev1.EnvVar{Name: processGroup.ProcessClass.GetServersPerPodEnvName(), Value: strconv.Itoa(serversPerPod)})
 		}
 	}
 
 	ensureSecurityContextIsPresent(mainContainer)
 	ensureSecurityContextIsPresent(sidecarContainer)
-	setAffinityForFaultDomain(cluster, podSpec, processClass)
-	configureVolumesForContainers(cluster, podSpec, processSettings.VolumeClaimTemplate, podName, processClass)
-	configureNoSchedule(podSpec, processGroupID, cluster.Spec.Buggify.NoSchedule)
+	setAffinityForFaultDomain(cluster, podSpec, processGroup.ProcessClass)
+	configureVolumesForContainers(cluster, podSpec, processSettings.VolumeClaimTemplate, podName, processGroup.ProcessClass)
+	configureNoSchedule(podSpec, processGroup.ProcessGroupID, cluster.Spec.Buggify.NoSchedule)
 
 	if !useUnifiedImages {
 		replaceContainers(podSpec.InitContainers, initContainer)
@@ -741,13 +737,12 @@ func usePvc(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.Pro
 }
 
 // GetPvc builds a persistent volume claim for a FoundationDB process group.
-func GetPvc(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, idNum int) (*corev1.PersistentVolumeClaim, error) {
-	if !usePvc(cluster, processClass) {
+func GetPvc(cluster *fdbv1beta2.FoundationDBCluster, processGroup *fdbv1beta2.ProcessGroupStatus) (*corev1.PersistentVolumeClaim, error) {
+	if !usePvc(cluster, processGroup.ProcessClass) {
 		return nil, nil
 	}
-	name, id := cluster.GetProcessGroupID(processClass, idNum)
 
-	processSettings := cluster.GetProcessSettings(processClass)
+	processSettings := cluster.GetProcessSettings(processGroup.ProcessClass)
 	var pvc *corev1.PersistentVolumeClaim
 	if processSettings.VolumeClaimTemplate != nil {
 		pvc = processSettings.VolumeClaimTemplate.DeepCopy()
@@ -755,7 +750,8 @@ func GetPvc(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.Pro
 		pvc = &corev1.PersistentVolumeClaim{}
 	}
 
-	pvc.ObjectMeta = GetPvcMetadata(cluster, processClass, id)
+	pvc.ObjectMeta = GetPvcMetadata(cluster, processGroup.ProcessClass, processGroup.ProcessGroupID)
+	name := processGroup.GetPodName(cluster)
 	if pvc.ObjectMeta.Name == "" {
 		pvc.ObjectMeta.Name = fmt.Sprintf("%s-data", name)
 	} else {
diff --git a/internal/replacements/replacements.go b/internal/replacements/replacements.go
index 0e5e5dea..0ce7195a 100644
--- a/internal/replacements/replacements.go
+++ b/internal/replacements/replacements.go
@@ -57,7 +57,7 @@ func ReplaceMisconfiguredProcessGroups(ctx context.Context, podManager podmanage
 		pvc, hasPVC := pvcMap[processGroup.ProcessGroupID]
 		pod, podErr := podManager.GetPod(ctx, client, cluster, processGroup.GetPodName(cluster))
 		if hasPVC {
-			needsPVCRemoval, err := processGroupNeedsRemovalForPVC(cluster, pvc, log)
+			needsPVCRemoval, err := processGroupNeedsRemovalForPVC(cluster, pvc, log, processGroup)
 			if err != nil {
 				return hasReplacements, err
 			}
@@ -94,7 +94,7 @@ func ReplaceMisconfiguredProcessGroups(ctx context.Context, podManager podmanage
 	return hasReplacements, nil
 }
 
-func processGroupNeedsRemovalForPVC(cluster *fdbv1beta2.FoundationDBCluster, pvc corev1.PersistentVolumeClaim, log logr.Logger) (bool, error) {
+func processGroupNeedsRemovalForPVC(cluster *fdbv1beta2.FoundationDBCluster, pvc corev1.PersistentVolumeClaim, log logr.Logger, processGroup *fdbv1beta2.ProcessGroupStatus) (bool, error) {
 	processGroupID := internal.GetProcessGroupIDFromMeta(cluster, pvc.ObjectMeta)
 	logger := log.WithValues("namespace", cluster.Namespace, "cluster", cluster.Name, "pvc", pvc.Name, "processGroupID", processGroupID, "reconciler", "replaceMisconfiguredProcessGroups")
 
@@ -112,12 +112,7 @@ func processGroupNeedsRemovalForPVC(cluster *fdbv1beta2.FoundationDBCluster, pvc
 		return false, nil
 	}
 
-	idNum, err := processGroupID.GetIDNumber()
-	if err != nil {
-		return false, err
-	}
-	processClass := internal.GetProcessClassFromMeta(cluster, pvc.ObjectMeta)
-	desiredPVC, err := internal.GetPvc(cluster, processClass, idNum)
+	desiredPVC, err := internal.GetPvc(cluster, processGroup)
 	if err != nil {
 		return false, err
 	}
@@ -189,7 +184,7 @@ func processGroupNeedsRemoval(cluster *fdbv1beta2.FoundationDBCluster, pod *core
 
 	expectedNodeSelector := cluster.GetProcessSettings(processGroupStatus.ProcessClass).PodTemplate.Spec.NodeSelector
 	if !equality.Semantic.DeepEqual(pod.Spec.NodeSelector, expectedNodeSelector) {
-		specHash, err := internal.GetPodSpecHash(cluster, processGroupStatus.ProcessClass, idNum, nil)
+		specHash, err := internal.GetPodSpecHash(cluster, processGroupStatus, nil)
 		if err != nil {
 			return false, err
 		}
@@ -202,12 +197,12 @@ func processGroupNeedsRemoval(cluster *fdbv1beta2.FoundationDBCluster, pod *core
 	}
 
 	if cluster.NeedsReplacement(processGroupStatus) {
-		spec, err := internal.GetPodSpec(cluster, processGroupStatus.ProcessClass, idNum)
+		spec, err := internal.GetPodSpec(cluster, processGroupStatus)
 		if err != nil {
 			return false, err
 		}
 
-		specHash, err := internal.GetPodSpecHash(cluster, processGroupStatus.ProcessClass, idNum, spec)
+		specHash, err := internal.GetPodSpecHash(cluster, processGroupStatus, spec)
 		if err != nil {
 			return false, err
 		}
@@ -229,7 +224,7 @@ func processGroupNeedsRemoval(cluster *fdbv1beta2.FoundationDBCluster, pod *core
 	}
 
 	if pointer.BoolDeref(cluster.Spec.ReplaceInstancesWhenResourcesChange, false) {
-		desiredSpec, err := internal.GetPodSpec(cluster, processGroupStatus.ProcessClass, idNum)
+		desiredSpec, err := internal.GetPodSpec(cluster, processGroupStatus)
 		if err != nil {
 			return false, err
 		}
diff --git a/pkg/podmanager/pod_lifecycle_manager.go b/pkg/podmanager/pod_lifecycle_manager.go
index 8705b63a..47d258cf 100644
--- a/pkg/podmanager/pod_lifecycle_manager.go
+++ b/pkg/podmanager/pod_lifecycle_manager.go
@@ -183,7 +183,11 @@ func (manager StandardPodLifecycleManager) PodIsUpdated(context.Context, client.
 // GetPodSpec provides an external interface for the internal GetPodSpec method
 // This is necessary for compatibility reasons.
 func GetPodSpec(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, idNum int) (*corev1.PodSpec, error) {
-	return internal.GetPodSpec(cluster, processClass, idNum)
+	_, processGroupID := cluster.GetProcessGroupID(processClass, idNum)
+	return internal.GetPodSpec(cluster, &fdbv1beta2.ProcessGroupStatus{
+		ProcessClass:   processClass,
+		ProcessGroupID: processGroupID,
+	})
 }
 
 // GetDeletionMode returns the PodUpdateMode of the cluster if set or the default value Zone.


Test patch:
diff --git a/api/v1beta2/foundationdbcluster_types_test.go b/api/v1beta2/foundationdbcluster_types_test.go
index 9b14f87d..747cc6f5 100644
--- a/api/v1beta2/foundationdbcluster_types_test.go
+++ b/api/v1beta2/foundationdbcluster_types_test.go
@@ -5547,4 +5547,42 @@ var _ = Describe("[api] FoundationDBCluster", func() {
 				},
 			}, "testing"),
 	)
+
+	When("creating a new ProcessGroup", func() {
+		var processGroupID ProcessGroupID
+		var processClass ProcessClass
+		var processGroup *ProcessGroupStatus
+
+		JustBeforeEach(func() {
+			processGroup = NewProcessGroupStatus(processGroupID, processClass, nil)
+		})
+
+		When("the ProcessGroup is stateful", func() {
+			BeforeEach(func() {
+				processGroupID = "storage-1"
+				processClass = ProcessClassStorage
+			})
+
+			It("should create the new ProcessGroup with the initial conditions", func() {
+				Expect(processGroup).NotTo(BeNil())
+				Expect(processGroup.ProcessGroupConditions).To(HaveLen(3))
+				Expect(processGroup.ProcessClass).To(Equal(processClass))
+				Expect(processGroup.ProcessGroupID).To(Equal(processGroupID))
+			})
+		})
+
+		When("the ProcessGroup is stateless", func() {
+			BeforeEach(func() {
+				processGroupID = "stateless-1"
+				processClass = ProcessClassStateless
+			})
+
+			It("should create the new ProcessGroup with the initial conditions", func() {
+				Expect(processGroup).NotTo(BeNil())
+				Expect(processGroup.ProcessGroupConditions).To(HaveLen(2))
+				Expect(processGroup.ProcessClass).To(Equal(processClass))
+				Expect(processGroup.ProcessGroupID).To(Equal(processGroupID))
+			})
+		})
+	})
 })
diff --git a/controllers/cluster_controller_test.go b/controllers/cluster_controller_test.go
index 98e40ee8..633cfa53 100644
--- a/controllers/cluster_controller_test.go
+++ b/controllers/cluster_controller_test.go
@@ -1336,10 +1336,10 @@ var _ = Describe("cluster_controller", func() {
 				Expect(err).NotTo(HaveOccurred())
 
 				for _, item := range pods.Items {
-					id, err := fdbv1beta2.ProcessGroupID(item.Labels[fdbv1beta2.FDBProcessGroupIDLabel]).GetIDNumber()
-					Expect(err).NotTo(HaveOccurred())
-
-					hash, err := internal.GetPodSpecHash(cluster, internal.ProcessClassFromLabels(cluster, item.Labels), id, nil)
+					hash, err := internal.GetPodSpecHash(cluster, &fdbv1beta2.ProcessGroupStatus{
+						ProcessGroupID: fdbv1beta2.ProcessGroupID(item.Labels[fdbv1beta2.FDBProcessGroupIDLabel]),
+						ProcessClass:   internal.ProcessClassFromLabels(cluster, item.Labels),
+					}, nil)
 					Expect(err).NotTo(HaveOccurred())
 
 					configMapHash, err := getConfigMapHash(cluster, internal.GetProcessClassFromMeta(cluster, item.ObjectMeta), &item)
@@ -1477,10 +1477,10 @@ var _ = Describe("cluster_controller", func() {
 					err = k8sClient.List(context.TODO(), pods, getListOptions(cluster)...)
 					Expect(err).NotTo(HaveOccurred())
 					for _, item := range pods.Items {
-						id, err := fdbv1beta2.ProcessGroupID(item.Labels[fdbv1beta2.FDBProcessGroupIDLabel]).GetIDNumber()
-						Expect(err).NotTo(HaveOccurred())
-
-						hash, err := internal.GetPodSpecHash(cluster, internal.ProcessClassFromLabels(cluster, item.Labels), id, nil)
+						hash, err := internal.GetPodSpecHash(cluster, &fdbv1beta2.ProcessGroupStatus{
+							ProcessGroupID: fdbv1beta2.ProcessGroupID(item.Labels[fdbv1beta2.FDBProcessGroupIDLabel]),
+							ProcessClass:   internal.ProcessClassFromLabels(cluster, item.Labels),
+						}, nil)
 						Expect(err).NotTo(HaveOccurred())
 
 						configMapHash, err := getConfigMapHash(cluster, internal.GetProcessClassFromMeta(cluster, item.ObjectMeta), &item)
@@ -1586,10 +1586,10 @@ var _ = Describe("cluster_controller", func() {
 				Expect(err).NotTo(HaveOccurred())
 
 				for _, item := range pods.Items {
-					id, err := fdbv1beta2.ProcessGroupID(item.Labels[fdbv1beta2.FDBProcessGroupIDLabel]).GetIDNumber()
-					Expect(err).NotTo(HaveOccurred())
-
-					hash, err := internal.GetPodSpecHash(cluster, internal.ProcessClassFromLabels(cluster, item.Labels), id, nil)
+					hash, err := internal.GetPodSpecHash(cluster, &fdbv1beta2.ProcessGroupStatus{
+						ProcessGroupID: fdbv1beta2.ProcessGroupID(item.Labels[fdbv1beta2.FDBProcessGroupIDLabel]),
+						ProcessClass:   internal.ProcessClassFromLabels(cluster, item.Labels),
+					}, nil)
 					Expect(err).NotTo(HaveOccurred())
 
 					configMapHash, err := getConfigMapHash(cluster, internal.GetProcessClassFromMeta(cluster, item.ObjectMeta), &item)
@@ -2569,8 +2569,7 @@ var _ = Describe("cluster_controller", func() {
 		Context("with a change to the process group ID prefix", func() {
 			BeforeEach(func() {
 				cluster.Spec.ProcessGroupIDPrefix = "dev"
-				err = k8sClient.Update(context.TODO(), cluster)
-				Expect(err).NotTo(HaveOccurred())
+				Expect(k8sClient.Update(context.TODO(), cluster)).NotTo(HaveOccurred())
 			})
 
 			It("should replace the process groups", func() {
@@ -2593,8 +2592,7 @@ var _ = Describe("cluster_controller", func() {
 
 			It("should generate process group IDs with the new prefix", func() {
 				pods := &corev1.PodList{}
-				err = k8sClient.List(context.TODO(), pods, getListOptions(cluster)...)
-				Expect(err).NotTo(HaveOccurred())
+				Expect(k8sClient.List(context.TODO(), pods, getListOptions(cluster)...)).NotTo(HaveOccurred())
 
 				sortPodsByName(pods)
 				Expect(pods.Items[0].Labels[fdbv1beta2.FDBProcessGroupIDLabel]).To(Equal("dev-cluster_controller-2"))
@@ -3671,7 +3669,10 @@ var _ = Describe("cluster_controller", func() {
 		Context("with a default pod", func() {
 			BeforeEach(func() {
 				var err error
-				pod, err = internal.GetPod(cluster, "storage", 1)
+				pod, err = internal.GetPod(cluster, &fdbv1beta2.ProcessGroupStatus{
+					ProcessClass:   fdbv1beta2.ProcessClassStorage,
+					ProcessGroupID: "storage-1",
+				})
 				Expect(err).NotTo(HaveOccurred())
 				pod.Status.PodIP = "1.1.1.1"
 				pod.Status.PodIPs = []corev1.PodIP{
@@ -3690,7 +3691,10 @@ var _ = Describe("cluster_controller", func() {
 			BeforeEach(func() {
 				var err error
 				cluster.Spec.Routing.PodIPFamily = pointer.Int(6)
-				pod, err = internal.GetPod(cluster, "storage", 1)
+				pod, err = internal.GetPod(cluster, &fdbv1beta2.ProcessGroupStatus{
+					ProcessClass:   fdbv1beta2.ProcessClassStorage,
+					ProcessGroupID: "storage-1",
+				})
 				Expect(err).NotTo(HaveOccurred())
 				pod.Status.PodIP = "1.1.1.1"
 				pod.Status.PodIPs = []corev1.PodIP{
@@ -3707,7 +3711,10 @@ var _ = Describe("cluster_controller", func() {
 			Context("with no matching IPs in the Pod IP list", func() {
 				BeforeEach(func() {
 					var err error
-					pod, err = internal.GetPod(cluster, "storage", 1)
+					pod, err = internal.GetPod(cluster, &fdbv1beta2.ProcessGroupStatus{
+						ProcessClass:   fdbv1beta2.ProcessClassStorage,
+						ProcessGroupID: "storage-1",
+					})
 					Expect(err).NotTo(HaveOccurred())
 					pod.Status.PodIPs = []corev1.PodIP{
 						{IP: "1.1.1.2"},
@@ -3725,7 +3732,10 @@ var _ = Describe("cluster_controller", func() {
 			BeforeEach(func() {
 				var err error
 				cluster.Spec.Routing.PodIPFamily = pointer.Int(4)
-				pod, err = internal.GetPod(cluster, "storage", 1)
+				pod, err = internal.GetPod(cluster, &fdbv1beta2.ProcessGroupStatus{
+					ProcessClass:   fdbv1beta2.ProcessClassStorage,
+					ProcessGroupID: "storage-1",
+				})
 				Expect(err).NotTo(HaveOccurred())
 				pod.Status.PodIP = "1.1.1.2"
 				pod.Status.PodIPs = []corev1.PodIP{
diff --git a/e2e/fixtures/fdb_cluster.go b/e2e/fixtures/fdb_cluster.go
index 590a9b6e..7dab4f3c 100644
--- a/e2e/fixtures/fdb_cluster.go
+++ b/e2e/fixtures/fdb_cluster.go
@@ -228,6 +228,14 @@ func (fdbCluster *FdbCluster) waitForReconciliationToGeneration(
 		fdbCluster.cluster.Name,
 	)
 
+	if minimumGeneration > 0 {
+		log.Printf(
+			"waiting for generation %d, current generation: %d",
+			minimumGeneration,
+			fdbCluster.cluster.Generation,
+		)
+	}
+
 	var creationTracker *fdbClusterCreationTracker
 	if creationTrackerLogger != nil {
 		creationTracker = newFdbClusterCreationTracker(
diff --git a/e2e/test_operator/operator_test.go b/e2e/test_operator/operator_test.go
index 94f7bf04..19161312 100644
--- a/e2e/test_operator/operator_test.go
+++ b/e2e/test_operator/operator_test.go
@@ -781,15 +781,29 @@ var _ = Describe("Operator", Label("e2e", "pr"), func() {
 		prefix := "banana"
 
 		BeforeEach(func() {
+			currentGeneration := fdbCluster.GetCluster().Generation
 			Expect(fdbCluster.SetProcessGroupPrefix(prefix)).NotTo(HaveOccurred())
-			Expect(fdbCluster.WaitForReconciliation())
+			Expect(fdbCluster.WaitForReconciliation(fixtures.MinimumGenerationOption(currentGeneration+1), fixtures.SoftReconcileOption(false)))
 		})
 
 		It("should add the prefix to all instances", func() {
-			pods := fdbCluster.GetPods()
-			for _, pod := range pods.Items {
-				Expect(string(fixtures.GetProcessGroupID(pod))).To(HavePrefix(prefix))
-			}
+			log.Println("DEBUGGING: Cluster is reconciled, current generation:", fdbCluster.GetCluster().Generation)
+			Eventually(func(g Gomega) bool {
+				for _, processGroup := range fdbCluster.GetCluster().Status.ProcessGroups {
+					g.Expect(string(processGroup.ProcessGroupID)).To(HavePrefix(prefix))
+				}
+
+				return true
+			}).WithTimeout(10 * time.Minute).WithPolling(5 * time.Second).Should(BeTrue())
+
+			Eventually(func(g Gomega) bool {
+				pods := fdbCluster.GetPods()
+				for _, pod := range pods.Items {
+					g.Expect(string(fixtures.GetProcessGroupID(pod))).To(HavePrefix(prefix))
+				}
+
+				return true
+			}).WithTimeout(5 * time.Minute).WithPolling(5 * time.Second).Should(BeTrue())
 		})
 	})
 
diff --git a/internal/monitor_conf_test.go b/internal/monitor_conf_test.go
index 4af58ae5..b89ae350 100644
--- a/internal/monitor_conf_test.go
+++ b/internal/monitor_conf_test.go
@@ -434,7 +434,10 @@ var _ = Describe("monitor_conf", func() {
 		var processGroupID = "storage-1"
 
 		BeforeEach(func() {
-			pod, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+			pod, err = GetPod(cluster, &fdbv1beta2.ProcessGroupStatus{
+				ProcessClass:   processClass,
+				ProcessGroupID: fdbv1beta2.ProcessGroupID(processGroupID),
+			})
 			Expect(err).NotTo(HaveOccurred())
 			address = pod.Status.PodIP
 		})
diff --git a/internal/pod_client_test.go b/internal/pod_client_test.go
index 0a25cc42..8b03e786 100644
--- a/internal/pod_client_test.go
+++ b/internal/pod_client_test.go
@@ -46,7 +46,7 @@ var _ = Describe("pod_client", func() {
 		})
 
 		It("should not have TLS sidecar TLS", func() {
-			pod, err := GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+			pod, err := GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			Expect(err).NotTo(HaveOccurred())
 			Expect(podHasSidecarTLS(pod)).To(BeFalse())
 		})
@@ -58,7 +58,7 @@ var _ = Describe("pod_client", func() {
 		})
 
 		It("should have TLS sidecar TLS", func() {
-			pod, err := GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+			pod, err := GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			Expect(err).NotTo(HaveOccurred())
 			Expect(podHasSidecarTLS(pod)).To(BeTrue())
 		})
diff --git a/internal/pod_models_test.go b/internal/pod_models_test.go
index 80b380d8..c2b26e14 100644
--- a/internal/pod_models_test.go
+++ b/internal/pod_models_test.go
@@ -47,7 +47,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with a basic storage process group", func() {
 			BeforeEach(func() {
-				pod, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pod, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -62,7 +62,7 @@ var _ = Describe("pod_models", func() {
 			})
 
 			It("should contain the process group's pod spec", func() {
-				spec, err := GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err := GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 				Expect(pod.Spec).To(Equal(*spec))
 			})
@@ -82,7 +82,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				pod, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pod, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -101,7 +101,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with a cluster controller process group", func() {
 			BeforeEach(func() {
-				pod, err = GetPod(cluster, fdbv1beta2.ProcessClassClusterController, 1)
+				pod, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassClusterController, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -115,7 +115,7 @@ var _ = Describe("pod_models", func() {
 			})
 
 			It("should contain the process group's pod spec", func() {
-				spec, err := GetPodSpec(cluster, fdbv1beta2.ProcessClassClusterController, 1)
+				spec, err := GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassClusterController, 1))
 				Expect(err).NotTo(HaveOccurred())
 				Expect(pod.Spec).To(Equal(*spec))
 			})
@@ -129,17 +129,17 @@ var _ = Describe("pod_models", func() {
 					},
 				}
 
-				pod, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pod, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
 			It("should add the annotations to the metadata", func() {
-				hash, err := GetPodSpecHash(cluster, ProcessClassFromLabels(cluster, pod.Labels), 1, &pod.Spec)
+				hash, err := GetPodSpecHash(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1), &pod.Spec)
 				Expect(err).NotTo(HaveOccurred())
 				Expect(pod.ObjectMeta.Annotations).To(Equal(map[string]string{
-					"fdb-annotation":                     "value1",
-					"foundationdb.org/last-applied-spec": hash,
-					"foundationdb.org/public-ip-source":  "pod",
+					"fdb-annotation":                    "value1",
+					fdbv1beta2.LastSpecKey:              hash,
+					fdbv1beta2.PublicIPSourceAnnotation: "pod",
 				}))
 			})
 		})
@@ -157,7 +157,7 @@ var _ = Describe("pod_models", func() {
 				err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				pod, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pod, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -178,7 +178,7 @@ var _ = Describe("pod_models", func() {
 		Context("with a version compatible upgrade in progress", func() {
 			BeforeEach(func() {
 				cluster.Spec.Version = fdbv1beta2.Versions.NextPatchVersion.String()
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -197,7 +197,7 @@ var _ = Describe("pod_models", func() {
 		Context("with a version incompatible upgrade in progress", func() {
 			BeforeEach(func() {
 				cluster.Spec.Version = fdbv1beta2.Versions.NextMajorVersion.String()
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -215,7 +215,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with a basic storage process group", func() {
 			BeforeEach(func() {
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -405,7 +405,7 @@ var _ = Describe("pod_models", func() {
 						Value: "",
 						Key:   "kubernetes.io/hostname",
 					}
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -418,7 +418,7 @@ var _ = Describe("pod_models", func() {
 				BeforeEach(func() {
 					enabled := true
 					cluster.Spec.SidecarContainer.EnableLivenessProbe = &enabled
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -439,7 +439,7 @@ var _ = Describe("pod_models", func() {
 				BeforeEach(func() {
 					enabled := false
 					cluster.Spec.SidecarContainer.EnableReadinessProbe = &enabled
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -460,7 +460,7 @@ var _ = Describe("pod_models", func() {
 				BeforeEach(func() {
 					enabled := true
 					cluster.Spec.SidecarContainer.EnableReadinessProbe = &enabled
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -488,7 +488,7 @@ var _ = Describe("pod_models", func() {
 			})
 			When("running one storage server per disk", func() {
 				BeforeEach(func() {
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -606,7 +606,7 @@ var _ = Describe("pod_models", func() {
 			When("running multiple storage servers per disk", func() {
 				BeforeEach(func() {
 					cluster.Spec.StorageServersPerPod = 2
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -662,7 +662,7 @@ var _ = Describe("pod_models", func() {
 			When("creating a log with multiple storage servers per disk", func() {
 				BeforeEach(func() {
 					cluster.Spec.StorageServersPerPod = 2
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassLog, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassLog, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -716,7 +716,7 @@ var _ = Describe("pod_models", func() {
 			When("running multiple log servers per disk", func() {
 				BeforeEach(func() {
 					cluster.Spec.LogServersPerPod = 2
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassLog, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassLog, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -774,7 +774,7 @@ var _ = Describe("pod_models", func() {
 					cluster.Spec.Buggify.CrashLoop = []fdbv1beta2.ProcessGroupID{"storage-1"}
 					err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 					Expect(err).NotTo(HaveOccurred())
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -795,7 +795,7 @@ var _ = Describe("pod_models", func() {
 					}
 					err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 					Expect(err).NotTo(HaveOccurred())
-					spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+					spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 					Expect(err).NotTo(HaveOccurred())
 				})
 
@@ -817,7 +817,7 @@ var _ = Describe("pod_models", func() {
 			BeforeEach(func() {
 				family := 6
 				cluster.Spec.Routing.PodIPFamily = &family
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -904,7 +904,7 @@ var _ = Describe("pod_models", func() {
 		When("enabling DNS in the cluster file", func() {
 			BeforeEach(func() {
 				cluster.Spec.Routing.UseDNSInClusterFile = pointer.Bool(true)
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			})
 
 			It("should set an additional environment variable on the init container", func() {
@@ -988,7 +988,7 @@ var _ = Describe("pod_models", func() {
 		When("enabling DNS in the locality fields", func() {
 			BeforeEach(func() {
 				cluster.Spec.Routing.DefineDNSLocalityFields = pointer.Bool(true)
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			})
 
 			It("should set an additional environment variable on the init container", func() {
@@ -1093,7 +1093,7 @@ var _ = Describe("pod_models", func() {
 					Value: "",
 					Key:   "kubernetes.io/hostname",
 				}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1108,7 +1108,7 @@ var _ = Describe("pod_models", func() {
 				cluster.Spec.Buggify.CrashLoop = []fdbv1beta2.ProcessGroupID{"storage-1"}
 				err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1124,7 +1124,7 @@ var _ = Describe("pod_models", func() {
 				cluster.Spec.Buggify.CrashLoop = []fdbv1beta2.ProcessGroupID{"*"}
 				err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1140,7 +1140,7 @@ var _ = Describe("pod_models", func() {
 				cluster.Spec.Buggify.CrashLoop = []fdbv1beta2.ProcessGroupID{"storage-2"}
 				err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1164,7 +1164,7 @@ var _ = Describe("pod_models", func() {
 						Targets:       []fdbv1beta2.ProcessGroupID{"storage-2"},
 					},
 				}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1188,7 +1188,7 @@ var _ = Describe("pod_models", func() {
 						Targets:       []fdbv1beta2.ProcessGroupID{"storage-1"},
 					},
 				}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1213,7 +1213,7 @@ var _ = Describe("pod_models", func() {
 						Targets:       []fdbv1beta2.ProcessGroupID{"storage-1"},
 					},
 				}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1233,7 +1233,7 @@ var _ = Describe("pod_models", func() {
 		Context("with an process group with scheduling broken", func() {
 			BeforeEach(func() {
 				cluster.Spec.Buggify.NoSchedule = []fdbv1beta2.ProcessGroupID{"storage-1"}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1252,7 +1252,7 @@ var _ = Describe("pod_models", func() {
 		Context("with a basic storage process group with multiple storage servers per disk", func() {
 			BeforeEach(func() {
 				cluster.Spec.StorageServersPerPod = 2
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1425,7 +1425,7 @@ var _ = Describe("pod_models", func() {
 			BeforeEach(func() {
 				var source = fdbv1beta2.PublicIPSourcePod
 				cluster.Spec.Routing.PublicIPSource = &source
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1493,7 +1493,7 @@ var _ = Describe("pod_models", func() {
 				cluster.Spec.Routing.PublicIPSource = &source
 				enabled := true
 				cluster.Spec.UseExplicitListenAddress = &enabled
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1563,7 +1563,7 @@ var _ = Describe("pod_models", func() {
 			BeforeEach(func() {
 				var source = fdbv1beta2.PublicIPSourceService
 				cluster.Spec.Routing.PublicIPSource = &source
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1633,7 +1633,7 @@ var _ = Describe("pod_models", func() {
 			BeforeEach(func() {
 				var enabled = true
 				cluster.Spec.Routing.HeadlessService = &enabled
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1647,7 +1647,7 @@ var _ = Describe("pod_models", func() {
 			BeforeEach(func() {
 				var enabled = false
 				cluster.Spec.Routing.HeadlessService = &enabled
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1682,7 +1682,7 @@ var _ = Describe("pod_models", func() {
 				err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1710,7 +1710,7 @@ var _ = Describe("pod_models", func() {
 				err := NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1725,7 +1725,7 @@ var _ = Describe("pod_models", func() {
 		Context("with a host-based fault domain", func() {
 			BeforeEach(func() {
 				cluster.Spec.FaultDomain = fdbv1beta2.FoundationDBClusterFaultDomain{}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			})
 
 			It("should set the fault domain information in the sidecar environment", func() {
@@ -1781,7 +1781,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1815,7 +1815,7 @@ var _ = Describe("pod_models", func() {
 					Key:       "rack",
 					ValueFrom: "$RACK",
 				}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1865,7 +1865,7 @@ var _ = Describe("pod_models", func() {
 					Key:   "foundationdb.org/kubernetes-cluster",
 					Value: "kc2",
 				}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1912,7 +1912,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -1970,7 +1970,7 @@ var _ = Describe("pod_models", func() {
 			})
 
 			It("should return an error since a tag is specified", func() {
-				_, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				_, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).To(HaveOccurred())
 			})
 		})
@@ -2006,7 +2006,7 @@ var _ = Describe("pod_models", func() {
 					},
 				}}}
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2066,7 +2066,7 @@ var _ = Describe("pod_models", func() {
 				cluster.Spec.SidecarContainer.EnableTLS = true
 				cluster.Spec.SidecarContainer.PeerVerificationRules = "S.CN=foundationdb.org"
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2169,7 +2169,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2238,7 +2238,7 @@ var _ = Describe("pod_models", func() {
 				}
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2291,7 +2291,7 @@ var _ = Describe("pod_models", func() {
 					},
 				}}}
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2318,7 +2318,7 @@ var _ = Describe("pod_models", func() {
 		Context("with an process group ID prefix", func() {
 			BeforeEach(func() {
 				cluster.Spec.ProcessGroupIDPrefix = "dc1"
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2345,7 +2345,7 @@ var _ = Describe("pod_models", func() {
 		Context("with custom map", func() {
 			BeforeEach(func() {
 				cluster.Spec.ConfigMap = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "config1"}}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2356,7 +2356,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with no custom map", func() {
 			BeforeEach(func() {
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 			It("adds config-map volume that refers to custom map", func() {
@@ -2370,7 +2370,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2381,7 +2381,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with no custom pvc", func() {
 			BeforeEach(func() {
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 			It("adds data volume that refers to default pvc", func() {
@@ -2392,7 +2392,7 @@ var _ = Describe("pod_models", func() {
 		Context("with a custom CA", func() {
 			BeforeEach(func() {
 				cluster.Spec.TrustedCAs = []string{"Test"}
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			})
 
 			It("should pass the CA file to the main container", func() {
@@ -2498,7 +2498,7 @@ var _ = Describe("pod_models", func() {
 				}
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).ToNot(HaveOccurred())
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).ToNot(HaveOccurred())
 			})
 
@@ -2533,7 +2533,7 @@ var _ = Describe("pod_models", func() {
 				}
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).ToNot(HaveOccurred())
-				spec, err = GetPodSpec(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				spec, err = GetPodSpec(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).ToNot(HaveOccurred())
 			})
 
@@ -2559,7 +2559,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with a basic storage process group", func() {
 			BeforeEach(func() {
-				service, err = GetService(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				service, err = GetService(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2594,7 +2594,7 @@ var _ = Describe("pod_models", func() {
 		Context("with podIPFamily 6", func() {
 			BeforeEach(func() {
 				cluster.Spec.Routing.PodIPFamily = pointer.Int(6)
-				service, err = GetService(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				service, err = GetService(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2630,7 +2630,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				service, err = GetService(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				service, err = GetService(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2669,7 +2669,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with a basic storage process group", func() {
 			BeforeEach(func() {
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2704,7 +2704,7 @@ var _ = Describe("pod_models", func() {
 				err = NormalizeClusterSpec(cluster, DeprecationOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2732,7 +2732,7 @@ var _ = Describe("pod_models", func() {
 						},
 					},
 				}}}
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2757,7 +2757,7 @@ var _ = Describe("pod_models", func() {
 						},
 					},
 				}}}
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2788,7 +2788,7 @@ var _ = Describe("pod_models", func() {
 						},
 					},
 				}}}
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2806,7 +2806,7 @@ var _ = Describe("pod_models", func() {
 						StorageClassName: &class,
 					},
 				}}}
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2817,7 +2817,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("for a stateless process group", func() {
 			BeforeEach(func() {
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStateless, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStateless, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2829,7 +2829,7 @@ var _ = Describe("pod_models", func() {
 		Context("with an process group ID prefix", func() {
 			BeforeEach(func() {
 				cluster.Spec.ProcessGroupIDPrefix = "dc1"
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2846,7 +2846,7 @@ var _ = Describe("pod_models", func() {
 		Context("with an process group ID prefix", func() {
 			BeforeEach(func() {
 				cluster.Spec.ProcessGroupIDPrefix = "dc1"
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2865,7 +2865,7 @@ var _ = Describe("pod_models", func() {
 				cluster.Spec.Processes = map[fdbv1beta2.ProcessClass]fdbv1beta2.ProcessSettings{fdbv1beta2.ProcessClassGeneral: {VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
 					ObjectMeta: metav1.ObjectMeta{Name: "pvc1"},
 				}}}
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -2876,7 +2876,7 @@ var _ = Describe("pod_models", func() {
 
 		Context("with default name in the suffix", func() {
 			BeforeEach(func() {
-				pvc, err = GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err = GetPvc(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -3539,10 +3539,11 @@ var _ = Describe("pod_models", func() {
 
 	Describe("ContainsPod", func() {
 		var pod1, pod2 *corev1.Pod
+
 		BeforeEach(func() {
-			pod1, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 1)
+			pod1, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 1))
 			Expect(err).NotTo(HaveOccurred())
-			pod2, err = GetPod(cluster, fdbv1beta2.ProcessClassStorage, 2)
+			pod2, err = GetPod(cluster, GetProcessGroup(cluster, fdbv1beta2.ProcessClassStorage, 2))
 			Expect(err).NotTo(HaveOccurred())
 			pod2.Labels[fdbv1beta2.FDBClusterLabel] = "incorrect-cluster-name"
 		})
diff --git a/internal/replacements/replacements_test.go b/internal/replacements/replacements_test.go
index d40336d3..b6519616 100644
--- a/internal/replacements/replacements_test.go
+++ b/internal/replacements/replacements_test.go
@@ -59,35 +59,35 @@ var _ = Describe("replace_misconfigured_pods", func() {
 
 	When("checking process groups for replacements", func() {
 		var pod *corev1.Pod
-		var status *fdbv1beta2.ProcessGroupStatus
+		var processGroup *fdbv1beta2.ProcessGroupStatus
 		var pClass fdbv1beta2.ProcessClass
 		var remove bool
 
 		JustBeforeEach(func() {
 			processGroupName := fmt.Sprintf("%s-%d", pClass, 1337)
-			status = &fdbv1beta2.ProcessGroupStatus{
+			processGroup = &fdbv1beta2.ProcessGroupStatus{
 				ProcessGroupID: fdbv1beta2.ProcessGroupID(processGroupName),
 				ProcessClass:   pClass,
 			}
 
 			if remove {
-				status.MarkForRemoval()
+				processGroup.MarkForRemoval()
 			}
 
 			pod = &corev1.Pod{
 				ObjectMeta: metav1.ObjectMeta{
 					Labels: map[string]string{
 						fdbv1beta2.FDBProcessGroupIDLabel: processGroupName,
-						fdbv1beta2.FDBProcessClassLabel:   string(status.ProcessClass),
+						fdbv1beta2.FDBProcessClassLabel:   string(processGroup.ProcessClass),
 					},
 					Annotations: map[string]string{},
 				},
 			}
 
-			spec, err := internal.GetPodSpec(cluster, status.ProcessClass, 1337)
+			spec, err := internal.GetPodSpec(cluster, processGroup)
 			Expect(err).NotTo(HaveOccurred())
 
-			pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey], err = internal.GetPodSpecHash(cluster, status.ProcessClass, 1337, spec)
+			pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey], err = internal.GetPodSpecHash(cluster, processGroup, spec)
 			Expect(err).NotTo(HaveOccurred())
 
 			pod.Spec = *spec
@@ -111,7 +111,7 @@ var _ = Describe("replace_misconfigured_pods", func() {
 				})
 
 				It("should not need a removal", func() {
-					needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+					needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 					Expect(needsRemoval).To(BeFalse())
 					Expect(err).NotTo(HaveOccurred())
 				})
@@ -125,13 +125,13 @@ var _ = Describe("replace_misconfigured_pods", func() {
 					})
 
 					It("should need a removal", func() {
-						needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+						needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 						Expect(needsRemoval).To(BeFalse())
 						Expect(err).NotTo(HaveOccurred())
 
 						// Change the process group ID should trigger a removal
 						cluster.Spec.ProcessGroupIDPrefix = "test"
-						needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+						needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 						Expect(needsRemoval).To(BeTrue())
 						Expect(err).NotTo(HaveOccurred())
 					})
@@ -144,13 +144,13 @@ var _ = Describe("replace_misconfigured_pods", func() {
 					})
 
 					It("should need a removal", func() {
-						needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+						needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 						Expect(needsRemoval).To(BeFalse())
 						Expect(err).NotTo(HaveOccurred())
 
 						// Change the process group ID should trigger a removal
 						cluster.Spec.ProcessGroupIDPrefix = "test"
-						needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+						needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 						Expect(needsRemoval).To(BeTrue())
 						Expect(err).NotTo(HaveOccurred())
 					})
@@ -164,13 +164,13 @@ var _ = Describe("replace_misconfigured_pods", func() {
 				})
 
 				It("should need a removal", func() {
-					needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+					needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 					Expect(needsRemoval).To(BeFalse())
 					Expect(err).NotTo(HaveOccurred())
 
 					ipSource := fdbv1beta2.PublicIPSourceService
 					cluster.Spec.Routing.PublicIPSource = &ipSource
-					needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+					needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 					Expect(needsRemoval).To(BeTrue())
 					Expect(err).NotTo(HaveOccurred())
 				})
@@ -191,12 +191,12 @@ var _ = Describe("replace_misconfigured_pods", func() {
 				ipSource := fdbv1beta2.PublicIPSourceService
 				cluster.Spec.Routing.PublicIPSource = &ipSource
 
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 
 				cluster.Spec.Routing.PublicIPSource = nil
-				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeTrue())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -209,13 +209,13 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			})
 
 			It("should not need a removal", func() {
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 
 				ipSource := fdbv1beta2.PublicIPSourcePod
 				cluster.Spec.Routing.PublicIPSource = &ipSource
-				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -228,12 +228,12 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			})
 
 			It("should need a removal", func() {
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 
 				cluster.Spec.StorageServersPerPod = 2
-				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeTrue())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -246,12 +246,12 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			})
 
 			It("should not need a removal", func() {
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 
 				cluster.Spec.StorageServersPerPod = 2
-				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -264,14 +264,14 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			})
 
 			It("should need a removal", func() {
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 
 				cluster.Spec.Processes[fdbv1beta2.ProcessClassGeneral].PodTemplate.Spec.NodeSelector = map[string]string{
 					"dummy": "test",
 				}
-				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err = processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeTrue())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -284,16 +284,13 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			})
 
 			It("should not need a removal", func() {
-				processClass := internal.GetProcessClassFromMeta(cluster, pod.ObjectMeta)
-				processGroupID := internal.GetProcessGroupIDFromMeta(cluster, pod.ObjectMeta)
-				idNum, err := processGroupID.GetIDNumber()
-				Expect(err).NotTo(HaveOccurred())
-				pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey], err = internal.GetPodSpecHash(cluster, processClass, idNum, nil)
+				var err error
+				pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey], err = internal.GetPodSpecHash(cluster, processGroup, nil)
 				Expect(err).NotTo(HaveOccurred())
 				pod.Spec.NodeSelector = map[string]string{
 					"dummy": "test",
 				}
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -309,7 +306,7 @@ var _ = Describe("replace_misconfigured_pods", func() {
 				pod.Spec = corev1.PodSpec{
 					Containers: []corev1.Container{{}},
 				}
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -324,7 +321,7 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			It("should need a removal", func() {
 				pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey] = "-1"
 				cluster.Spec.AutomationOptions.PodUpdateStrategy = fdbv1beta2.PodUpdateStrategyReplacement
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeTrue())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -339,7 +336,7 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			It("should not need a removal", func() {
 				pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey] = "-1"
 				cluster.Spec.AutomationOptions.PodUpdateStrategy = fdbv1beta2.PodUpdateStrategyTransactionReplacement
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeFalse())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -354,7 +351,7 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			It("should need a removal", func() {
 				pod.ObjectMeta.Annotations[fdbv1beta2.LastSpecKey] = "-1"
 				cluster.Spec.AutomationOptions.PodUpdateStrategy = fdbv1beta2.PodUpdateStrategyTransactionReplacement
-				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, status, log)
+				needsRemoval, err := processGroupNeedsRemoval(cluster, pod, processGroup, log)
 				Expect(needsRemoval).To(BeTrue())
 				Expect(err).NotTo(HaveOccurred())
 			})
@@ -362,10 +359,10 @@ var _ = Describe("replace_misconfigured_pods", func() {
 
 		When("PVC name doesn't match", func() {
 			It("should need a removal", func() {
-				pvc, err := internal.GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err := internal.GetPvc(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				pvc.Name = "Test-storage"
-				needsRemoval, err := processGroupNeedsRemovalForPVC(cluster, *pvc, log)
+				needsRemoval, err := processGroupNeedsRemovalForPVC(cluster, *pvc, log, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				Expect(needsRemoval).To(BeTrue())
 			})
@@ -373,9 +370,9 @@ var _ = Describe("replace_misconfigured_pods", func() {
 
 		When("PVC name and PVC spec match", func() {
 			It("should not need a removal", func() {
-				pvc, err := internal.GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err := internal.GetPvc(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
-				needsRemoval, err := processGroupNeedsRemovalForPVC(cluster, *pvc, log)
+				needsRemoval, err := processGroupNeedsRemovalForPVC(cluster, *pvc, log, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				Expect(needsRemoval).To(BeFalse())
 			})
@@ -383,10 +380,10 @@ var _ = Describe("replace_misconfigured_pods", func() {
 
 		When("PVC hash doesn't match", func() {
 			It("should need a removal", func() {
-				pvc, err := internal.GetPvc(cluster, fdbv1beta2.ProcessClassStorage, 1)
+				pvc, err := internal.GetPvc(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				pvc.Annotations[fdbv1beta2.LastSpecKey] = "1"
-				needsRemoval, err := processGroupNeedsRemovalForPVC(cluster, *pvc, log)
+				needsRemoval, err := processGroupNeedsRemovalForPVC(cluster, *pvc, log, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				Expect(needsRemoval).To(BeTrue())
 			})
@@ -399,7 +396,7 @@ var _ = Describe("replace_misconfigured_pods", func() {
 			BeforeEach(func() {
 				err := internal.NormalizeClusterSpec(cluster, internal.DeprecationOptions{UseFutureDefaults: true})
 				Expect(err).NotTo(HaveOccurred())
-				pod, err = internal.GetPod(cluster, fdbv1beta2.ProcessClassStorage, 0)
+				pod, err = internal.GetPod(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				status = &fdbv1beta2.ProcessGroupStatus{
 					ProcessGroupID: fdbv1beta2.ProcessGroupID(fmt.Sprintf("%s-%d", fdbv1beta2.ProcessClassStorage, 1337)),
@@ -598,10 +595,14 @@ var _ = Describe("replace_misconfigured_pods", func() {
 
 			for i := 0; i < 10; i++ {
 				_, id := cluster.GetProcessGroupID(fdbv1beta2.ProcessClassStorage, i)
-				newPVC, err := internal.GetPvc(cluster, fdbv1beta2.ProcessClassStorage, i)
+				processGroup := &fdbv1beta2.ProcessGroupStatus{
+					ProcessClass:   fdbv1beta2.ProcessClassStorage,
+					ProcessGroupID: id,
+				}
+				newPVC, err := internal.GetPvc(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				pvcMap[id] = *newPVC
-				newPod, err := internal.GetPod(cluster, fdbv1beta2.ProcessClassStorage, i)
+				newPod, err := internal.GetPod(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				Expect(k8sClient.Create(context.Background(), newPod)).NotTo(HaveOccurred())
 				// Populate process groups
@@ -610,10 +611,15 @@ var _ = Describe("replace_misconfigured_pods", func() {
 
 			for i := 0; i < 1; i++ {
 				_, id := cluster.GetProcessGroupID(fdbv1beta2.ProcessClassTransaction, i)
-				newPVC, err := internal.GetPvc(cluster, fdbv1beta2.ProcessClassTransaction, i)
+				processGroup := &fdbv1beta2.ProcessGroupStatus{
+					ProcessClass:   fdbv1beta2.ProcessClassTransaction,
+					ProcessGroupID: id,
+				}
+
+				newPVC, err := internal.GetPvc(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				pvcMap[id] = *newPVC
-				newPod, err := internal.GetPod(cluster, fdbv1beta2.ProcessClassTransaction, i)
+				newPod, err := internal.GetPod(cluster, processGroup)
 				Expect(err).NotTo(HaveOccurred())
 				Expect(k8sClient.Create(context.Background(), newPod)).NotTo(HaveOccurred())
 				// Populate process groups
diff --git a/internal/test_helper.go b/internal/test_helper.go
index 4c9474fe..e4df4890 100644
--- a/internal/test_helper.go
+++ b/internal/test_helper.go
@@ -94,3 +94,13 @@ func CreateDefaultBackup(cluster *fdbv1beta2.FoundationDBCluster) *fdbv1beta2.Fo
 		Status: fdbv1beta2.FoundationDBBackupStatus{},
 	}
 }
+
+// GetProcessGroup is a helper method that creates a ProcessGroup based on the provided process class and id number.
+func GetProcessGroup(cluster *fdbv1beta2.FoundationDBCluster, processClass fdbv1beta2.ProcessClass, idNum int) *fdbv1beta2.ProcessGroupStatus {
+	_, processGroupID := cluster.GetProcessGroupID(processClass, idNum)
+
+	return &fdbv1beta2.ProcessGroupStatus{
+		ProcessClass:   processClass,
+		ProcessGroupID: processGroupID,
+	}
+}