Repository: FoundationDB/fdb-kubernetes-operator
Pull request #1142 (2022-03-28 16:31:32)

Fix role counts for versions prior to 7.0
# Description

This fixes the database configuration for version that doesn't support grr and commit proxies.

## Type of change

*Please select one of the options below.*

- Bug fix (non-breaking change which fixes an issue)
 
## Discussion

-

## Testing

Locally (cluster with `6.3.22`) + unit tests.

## Documentation

-

## Follow-up

Create a patch release.

foundationdb-ci: 
### AWS CodeBuild CI Report for Linux CentOS 7

* CodeBuild project: fdb-kubernetes-operator-pr
* Commit ID: 42cd513a02cb22f89e7e2fe81ff3d1780031c69f
* Result: FAILED
* Error: `Error while executing command: make -C tests -kj prOperator. Reason: exit status 2`
* [Build Logs](https://d1e0l78xbkh3xa.cloudfront.net/build-logs/fdb-kubernetes-operator/fdb-kubernetes-operator-pr/9b27e0c4-90db-4723-9bad-6b2d4e981f09.gz) (available for 30 days)


Patch:
diff --git a/api/v1beta2/foundationdb_database_configuration.go b/api/v1beta2/foundationdb_database_configuration.go
index 5e168f3f..d9a3d78e 100644
--- a/api/v1beta2/foundationdb_database_configuration.go
+++ b/api/v1beta2/foundationdb_database_configuration.go
@@ -236,7 +236,7 @@ func (configuration DatabaseConfiguration) getRegion(id string, priority int) Re
 // The default LogRouters value will be equal to 3 times the Logs value when
 // the UsableRegions is greater than 1. It will be equal to -1 when the
 // UsableRegions is less than or equal to 1.
-func (configuration *DatabaseConfiguration) GetRoleCountsWithDefaults(faultTolerance int) RoleCounts {
+func (configuration *DatabaseConfiguration) GetRoleCountsWithDefaults(version Version, faultTolerance int) RoleCounts {
 	counts := configuration.RoleCounts.DeepCopy()
 	if counts.Storage == 0 {
 		counts.Storage = 2*faultTolerance + 1
@@ -247,11 +247,13 @@ func (configuration *DatabaseConfiguration) GetRoleCountsWithDefaults(faultToler
 	if counts.Proxies == 0 {
 		counts.Proxies = 3
 	}
-	if counts.CommitProxies == 0 {
-		counts.CommitProxies = 2
-	}
-	if counts.GrvProxies == 0 {
-		counts.GrvProxies = 1
+	if version.HasSeparatedProxies() {
+		if counts.CommitProxies == 0 {
+			counts.CommitProxies = 2
+		}
+		if counts.GrvProxies == 0 {
+			counts.GrvProxies = 1
+		}
 	}
 	if counts.Resolvers == 0 {
 		counts.Resolvers = 1
@@ -528,7 +530,7 @@ func (configuration DatabaseConfiguration) AreSeparatedProxiesConfigured() bool
 // "proxies=%d" using the correct counts of the configuration object.
 //
 func (configuration DatabaseConfiguration) GetProxiesString(version Version) string {
-	counts := configuration.GetRoleCountsWithDefaults(DesiredFaultTolerance(configuration.RedundancyMode))
+	counts := configuration.GetRoleCountsWithDefaults(version, DesiredFaultTolerance(configuration.RedundancyMode))
 	if version.HasSeparatedProxies() && configuration.AreSeparatedProxiesConfigured() {
 		return fmt.Sprintf(" commit_proxies=%d grv_proxies=%d", counts.CommitProxies, counts.GrvProxies)
 	}
diff --git a/api/v1beta2/foundationdbcluster_types.go b/api/v1beta2/foundationdbcluster_types.go
index 37ba3327..96b2340c 100644
--- a/api/v1beta2/foundationdbcluster_types.go
+++ b/api/v1beta2/foundationdbcluster_types.go
@@ -943,7 +943,9 @@ func (cluster *FoundationDBCluster) GetProcessSettings(processClass ProcessClass
 // the UsableRegions is greater than 1. It will be equal to -1 when the
 // UsableRegions is less than or equal to 1.
 func (cluster *FoundationDBCluster) GetRoleCountsWithDefaults() RoleCounts {
-	return cluster.Spec.DatabaseConfiguration.GetRoleCountsWithDefaults(cluster.DesiredFaultTolerance())
+	// We can ignore the error here since the version will be validated in an earlier step.
+	version, _ := ParseFdbVersion(cluster.Spec.Version)
+	return cluster.Spec.DatabaseConfiguration.GetRoleCountsWithDefaults(version, cluster.DesiredFaultTolerance())
 }
 
 // calculateProcessCount determines the process count from a given role count.
@@ -1158,7 +1160,7 @@ func (cluster *FoundationDBCluster) CheckReconciliation(log logr.Logger) (bool,
 
 	desiredConfiguration := cluster.DesiredDatabaseConfiguration()
 	if !equality.Semantic.DeepEqual(cluster.Status.DatabaseConfiguration, desiredConfiguration) {
-		logger.Info("Pending database configuration change", "state", "NeedsConfigurationChange")
+		logger.Info("Pending database configuration change", "state", "NeedsConfigurationChange", "current", cluster.Status.DatabaseConfiguration, "desired", desiredConfiguration)
 		cluster.Status.Generations.NeedsConfigurationChange = cluster.ObjectMeta.Generation
 		reconciled = false
 	}
diff --git a/controllers/admin_client_mock.go b/controllers/admin_client_mock.go
index 32801d54..ffa5d052 100644
--- a/controllers/admin_client_mock.go
+++ b/controllers/admin_client_mock.go
@@ -315,11 +315,22 @@ func (client *mockAdminClient) GetStatus() (*fdbv1beta2.FoundationDBStatus, erro
 }
 
 // ConfigureDatabase changes the database configuration
-func (client *mockAdminClient) ConfigureDatabase(configuration fdbv1beta2.DatabaseConfiguration, _ bool, _ string) error {
+func (client *mockAdminClient) ConfigureDatabase(configuration fdbv1beta2.DatabaseConfiguration, _ bool, version string) error {
 	adminClientMutex.Lock()
 	defer adminClientMutex.Unlock()
 
 	client.DatabaseConfiguration = configuration.DeepCopy()
+
+	ver, err := fdbv1beta2.ParseFdbVersion(version)
+	if err != nil {
+		return err
+	}
+
+	if !ver.HasSeparatedProxies() {
+		client.DatabaseConfiguration.GrvProxies = 0
+		client.DatabaseConfiguration.CommitProxies = 0
+	}
+
 	return nil
 }
 


Test patch:
diff --git a/api/v1beta2/foundationdbcluster_types_test.go b/api/v1beta2/foundationdbcluster_types_test.go
index a355006c..90a9851a 100644
--- a/api/v1beta2/foundationdbcluster_types_test.go
+++ b/api/v1beta2/foundationdbcluster_types_test.go
@@ -41,110 +41,212 @@ var _ = Describe("[api] FoundationDBCluster", func() {
 	log := logf.Log.WithName("controller")
 
 	When("getting the default role counts", func() {
-		It("should return the default role counts", func() {
-			cluster := &FoundationDBCluster{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "foo",
-					Namespace: "default",
-				},
-				Spec: FoundationDBClusterSpec{
-					DatabaseConfiguration: DatabaseConfiguration{
-						RedundancyMode: RedundancyModeDouble,
+		When("the version does not supports grv and commit proxies", func() {
+			It("should return the default role counts", func() {
+				cluster := &FoundationDBCluster{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "default",
 					},
-				},
-			}
+					Spec: FoundationDBClusterSpec{
+						DatabaseConfiguration: DatabaseConfiguration{
+							RedundancyMode: RedundancyModeDouble,
+						},
+						Version: "6.3.24",
+					},
+				}
 
-			counts := cluster.GetRoleCountsWithDefaults()
-			Expect(counts).To(Equal(RoleCounts{
-				Storage:       3,
-				Logs:          3,
-				Proxies:       3,
-				CommitProxies: 2,
-				GrvProxies:    1,
-				Resolvers:     1,
-				RemoteLogs:    -1,
-				LogRouters:    -1,
-			}))
-			Expect(counts.Map()).To(Equal(map[ProcessClass]int{
-				"logs":           3,
-				"proxies":        3,
-				"resolvers":      1,
-				"remote_logs":    -1,
-				"log_routers":    -1,
-				"commit_proxies": 2,
-				"grv_proxies":    1,
-			}))
-			Expect(cluster.Spec.DatabaseConfiguration.RoleCounts).To(Equal(RoleCounts{}))
+				counts := cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:    3,
+					Logs:       3,
+					Proxies:    3,
+					Resolvers:  1,
+					RemoteLogs: -1,
+					LogRouters: -1,
+				}))
+				Expect(counts.Map()).To(Equal(map[ProcessClass]int{
+					"logs":           3,
+					"proxies":        3,
+					"resolvers":      1,
+					"commit_proxies": 0,
+					"grv_proxies":    0,
+					"remote_logs":    -1,
+					"log_routers":    -1,
+				}))
+				Expect(cluster.Spec.DatabaseConfiguration.RoleCounts).To(Equal(RoleCounts{}))
+
+				cluster.Spec.DatabaseConfiguration.UsableRegions = 2
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:    3,
+					Logs:       3,
+					Proxies:    3,
+					Resolvers:  1,
+					RemoteLogs: 3,
+					LogRouters: 3,
+				}))
+				Expect(counts.Map()).To(Equal(map[ProcessClass]int{
+					"logs":           3,
+					"proxies":        3,
+					"commit_proxies": 0,
+					"grv_proxies":    0,
+					"resolvers":      1,
+					"remote_logs":    3,
+					"log_routers":    3,
+				}))
 
-			cluster.Spec.DatabaseConfiguration.UsableRegions = 2
-			counts = cluster.GetRoleCountsWithDefaults()
-			Expect(counts).To(Equal(RoleCounts{
-				Storage:       3,
-				Logs:          3,
-				CommitProxies: 2,
-				GrvProxies:    1,
-				Proxies:       3,
-				Resolvers:     1,
-				RemoteLogs:    3,
-				LogRouters:    3,
-			}))
-			Expect(counts.Map()).To(Equal(map[ProcessClass]int{
-				"logs":           3,
-				"proxies":        3,
-				"resolvers":      1,
-				"remote_logs":    3,
-				"log_routers":    3,
-				"commit_proxies": 2,
-				"grv_proxies":    1,
-			}))
+				cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
+					Storage: 5,
+				}
 
-			cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
-				Storage: 5,
-			}
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:    5,
+					Logs:       3,
+					Proxies:    3,
+					Resolvers:  1,
+					RemoteLogs: 3,
+					LogRouters: 3,
+				}))
 
-			counts = cluster.GetRoleCountsWithDefaults()
-			Expect(counts).To(Equal(RoleCounts{
-				Storage:       5,
-				Logs:          3,
-				Proxies:       3,
-				GrvProxies:    1,
-				CommitProxies: 2,
-				Resolvers:     1,
-				RemoteLogs:    3,
-				LogRouters:    3,
-			}))
+				cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
+					Logs: 8,
+				}
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:    3,
+					Logs:       8,
+					Proxies:    3,
+					Resolvers:  1,
+					RemoteLogs: 8,
+					LogRouters: 8,
+				}))
 
-			cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
-				Logs: 8,
-			}
-			counts = cluster.GetRoleCountsWithDefaults()
-			Expect(counts).To(Equal(RoleCounts{
-				Storage:       3,
-				Logs:          8,
-				CommitProxies: 2,
-				GrvProxies:    1,
-				Proxies:       3,
-				Resolvers:     1,
-				RemoteLogs:    8,
-				LogRouters:    8,
-			}))
+				cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
+					Logs:       4,
+					RemoteLogs: 5,
+					LogRouters: 6,
+				}
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:    3,
+					Logs:       4,
+					Proxies:    3,
+					Resolvers:  1,
+					RemoteLogs: 5,
+					LogRouters: 6,
+				}))
+			})
+		})
 
-			cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
-				Logs:       4,
-				RemoteLogs: 5,
-				LogRouters: 6,
-			}
-			counts = cluster.GetRoleCountsWithDefaults()
-			Expect(counts).To(Equal(RoleCounts{
-				Storage:       3,
-				Logs:          4,
-				Proxies:       3,
-				GrvProxies:    1,
-				CommitProxies: 2,
-				Resolvers:     1,
-				RemoteLogs:    5,
-				LogRouters:    6,
-			}))
+		When("the version supports grv and commit proxies", func() {
+			It("should return the default role counts", func() {
+				cluster := &FoundationDBCluster{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "default",
+					},
+					Spec: FoundationDBClusterSpec{
+						DatabaseConfiguration: DatabaseConfiguration{
+							RedundancyMode: RedundancyModeDouble,
+						},
+						Version: "7.0.0",
+					},
+				}
+
+				counts := cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:       3,
+					Logs:          3,
+					Proxies:       3,
+					CommitProxies: 2,
+					GrvProxies:    1,
+					Resolvers:     1,
+					RemoteLogs:    -1,
+					LogRouters:    -1,
+				}))
+				Expect(counts.Map()).To(Equal(map[ProcessClass]int{
+					"logs":           3,
+					"proxies":        3,
+					"resolvers":      1,
+					"remote_logs":    -1,
+					"log_routers":    -1,
+					"commit_proxies": 2,
+					"grv_proxies":    1,
+				}))
+				Expect(cluster.Spec.DatabaseConfiguration.RoleCounts).To(Equal(RoleCounts{}))
+
+				cluster.Spec.DatabaseConfiguration.UsableRegions = 2
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:       3,
+					Logs:          3,
+					CommitProxies: 2,
+					GrvProxies:    1,
+					Proxies:       3,
+					Resolvers:     1,
+					RemoteLogs:    3,
+					LogRouters:    3,
+				}))
+				Expect(counts.Map()).To(Equal(map[ProcessClass]int{
+					"logs":           3,
+					"proxies":        3,
+					"resolvers":      1,
+					"remote_logs":    3,
+					"log_routers":    3,
+					"commit_proxies": 2,
+					"grv_proxies":    1,
+				}))
+
+				cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
+					Storage: 5,
+				}
+
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:       5,
+					Logs:          3,
+					Proxies:       3,
+					GrvProxies:    1,
+					CommitProxies: 2,
+					Resolvers:     1,
+					RemoteLogs:    3,
+					LogRouters:    3,
+				}))
+
+				cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
+					Logs: 8,
+				}
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:       3,
+					Logs:          8,
+					CommitProxies: 2,
+					GrvProxies:    1,
+					Proxies:       3,
+					Resolvers:     1,
+					RemoteLogs:    8,
+					LogRouters:    8,
+				}))
+
+				cluster.Spec.DatabaseConfiguration.RoleCounts = RoleCounts{
+					Logs:       4,
+					RemoteLogs: 5,
+					LogRouters: 6,
+				}
+				counts = cluster.GetRoleCountsWithDefaults()
+				Expect(counts).To(Equal(RoleCounts{
+					Storage:       3,
+					Logs:          4,
+					Proxies:       3,
+					GrvProxies:    1,
+					CommitProxies: 2,
+					Resolvers:     1,
+					RemoteLogs:    5,
+					LogRouters:    6,
+				}))
+			})
 		})
 	})
 
@@ -567,56 +669,122 @@ var _ = Describe("[api] FoundationDBCluster", func() {
 	})
 
 	When("getting the cluster database configuration", func() {
-		It("should be parsed correctly", func() {
-			cluster := &FoundationDBCluster{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "foo",
-					Namespace: "default",
-				},
-				Spec: FoundationDBClusterSpec{
-					DatabaseConfiguration: DatabaseConfiguration{
-						RedundancyMode: RedundancyModeDouble,
-						StorageEngine:  "ssd",
-						RoleCounts: RoleCounts{
-							Storage: 5,
-							Logs:    4,
-							Proxies: 5,
+		var cluster *FoundationDBCluster
+
+		When("the version supports grv and commit proxies", func() {
+			BeforeEach(func() {
+				cluster = &FoundationDBCluster{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "default",
+					},
+					Spec: FoundationDBClusterSpec{
+						DatabaseConfiguration: DatabaseConfiguration{
+							RedundancyMode: RedundancyModeDouble,
+							StorageEngine:  "ssd",
+							RoleCounts: RoleCounts{
+								Storage: 5,
+								Logs:    4,
+								Proxies: 5,
+							},
 						},
+						Version: "7.0.0",
 					},
-				},
-			}
+				}
+			})
 
-			Expect(cluster.DesiredDatabaseConfiguration()).To(Equal(DatabaseConfiguration{
-				RedundancyMode: RedundancyModeDouble,
-				StorageEngine:  "ssd-2",
-				UsableRegions:  1,
-				RoleCounts: RoleCounts{
-					Logs:          4,
-					Proxies:       5,
-					CommitProxies: 2,
-					GrvProxies:    1,
-					Resolvers:     1,
-					LogRouters:    -1,
-					RemoteLogs:    -1,
-				},
-			}))
+			It("should be parsed correctly", func() {
+				Expect(cluster.DesiredDatabaseConfiguration()).To(Equal(DatabaseConfiguration{
+					RedundancyMode: RedundancyModeDouble,
+					StorageEngine:  "ssd-2",
+					UsableRegions:  1,
+					RoleCounts: RoleCounts{
+						Logs:          4,
+						Proxies:       5,
+						CommitProxies: 2,
+						GrvProxies:    1,
+						Resolvers:     1,
+						LogRouters:    -1,
+						RemoteLogs:    -1,
+					},
+				}))
 
-			cluster.Spec = FoundationDBClusterSpec{}
+				cluster.Spec = FoundationDBClusterSpec{
+					Version: "7.0.0",
+				}
 
-			Expect(cluster.DesiredDatabaseConfiguration()).To(Equal(DatabaseConfiguration{
-				RedundancyMode: RedundancyModeDouble,
-				StorageEngine:  "ssd-2",
-				UsableRegions:  1,
-				RoleCounts: RoleCounts{
-					Logs:          3,
-					Proxies:       3,
-					CommitProxies: 2,
-					GrvProxies:    1,
-					Resolvers:     1,
-					LogRouters:    -1,
-					RemoteLogs:    -1,
-				},
-			}))
+				Expect(cluster.DesiredDatabaseConfiguration()).To(Equal(DatabaseConfiguration{
+					RedundancyMode: RedundancyModeDouble,
+					StorageEngine:  "ssd-2",
+					UsableRegions:  1,
+					RoleCounts: RoleCounts{
+						Logs:          3,
+						Proxies:       3,
+						CommitProxies: 2,
+						GrvProxies:    1,
+						Resolvers:     1,
+						LogRouters:    -1,
+						RemoteLogs:    -1,
+					},
+				}))
+			})
+		})
+
+		When("the version supports grv and commit proxies", func() {
+			BeforeEach(func() {
+				cluster = &FoundationDBCluster{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "default",
+					},
+					Spec: FoundationDBClusterSpec{
+						DatabaseConfiguration: DatabaseConfiguration{
+							RedundancyMode: RedundancyModeDouble,
+							StorageEngine:  "ssd",
+							RoleCounts: RoleCounts{
+								Storage: 5,
+								Logs:    4,
+								Proxies: 5,
+							},
+						},
+						Version: "6.3.23",
+					},
+				}
+			})
+
+			It("should be parsed correctly", func() {
+				Expect(cluster.DesiredDatabaseConfiguration()).To(Equal(DatabaseConfiguration{
+					RedundancyMode: RedundancyModeDouble,
+					StorageEngine:  "ssd-2",
+					UsableRegions:  1,
+					RoleCounts: RoleCounts{
+						Logs:          4,
+						Proxies:       5,
+						CommitProxies: 0,
+						GrvProxies:    0,
+						Resolvers:     1,
+						LogRouters:    -1,
+						RemoteLogs:    -1,
+					},
+				}))
+
+				cluster.Spec = FoundationDBClusterSpec{}
+
+				Expect(cluster.DesiredDatabaseConfiguration()).To(Equal(DatabaseConfiguration{
+					RedundancyMode: RedundancyModeDouble,
+					StorageEngine:  "ssd-2",
+					UsableRegions:  1,
+					RoleCounts: RoleCounts{
+						Logs:          3,
+						Proxies:       3,
+						CommitProxies: 0,
+						GrvProxies:    0,
+						Resolvers:     1,
+						LogRouters:    -1,
+						RemoteLogs:    -1,
+					},
+				}))
+			})
 		})
 	})
 
@@ -2509,252 +2677,510 @@ var _ = Describe("[api] FoundationDBCluster", func() {
 	})
 
 	When("checking the reconciliation for a cluster", func() {
-		It("should return the correct status", func() {
-			createCluster := func() *FoundationDBCluster {
-				return &FoundationDBCluster{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:       "sample-cluster",
-						Namespace:  "default",
-						Generation: 2,
-					},
-					Spec: FoundationDBClusterSpec{
-						Version:               Versions.Default.String(),
-						DatabaseConfiguration: DatabaseConfiguration{},
-					},
-					Status: FoundationDBClusterStatus{
-						Health: ClusterHealth{
-							Available: true,
-							Healthy:   true,
+		var createCluster func() *FoundationDBCluster
+
+		When("the cluster supports grv and commit proxies", func() {
+			BeforeEach(func() {
+				createCluster = func() *FoundationDBCluster {
+					return &FoundationDBCluster{
+						ObjectMeta: metav1.ObjectMeta{
+							Name:       "sample-cluster",
+							Namespace:  "default",
+							Generation: 2,
 						},
-						RequiredAddresses: RequiredAddressSet{
-							NonTLS: true,
+						Spec: FoundationDBClusterSpec{
+							Version:               "7.0.0",
+							DatabaseConfiguration: DatabaseConfiguration{},
+						},
+						Status: FoundationDBClusterStatus{
+							Health: ClusterHealth{
+								Available: true,
+								Healthy:   true,
+							},
+							RequiredAddresses: RequiredAddressSet{
+								NonTLS: true,
+							},
+							DatabaseConfiguration: DatabaseConfiguration{
+								RedundancyMode: RedundancyModeDouble,
+								StorageEngine:  "ssd-2",
+								UsableRegions:  1,
+								RoleCounts: RoleCounts{
+									Logs:          3,
+									Proxies:       3,
+									GrvProxies:    1,
+									CommitProxies: 2,
+									Resolvers:     1,
+									LogRouters:    -1,
+									RemoteLogs:    -1,
+								},
+							},
+							Generations: ClusterGenerationStatus{
+								Reconciled: 1,
+							},
+							ProcessGroups: []*ProcessGroupStatus{
+								{ProcessGroupID: "storage-1", ProcessClass: "storage"},
+								{ProcessGroupID: "storage-2", ProcessClass: "storage"},
+								{ProcessGroupID: "storage-3", ProcessClass: "storage"},
+								{ProcessGroupID: "stateless-1", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-2", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-3", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-4", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-5", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-6", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-7", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-8", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-9", ProcessClass: "stateless"},
+								{ProcessGroupID: "log-1", ProcessClass: "log"},
+								{ProcessGroupID: "log-2", ProcessClass: "log"},
+								{ProcessGroupID: "log-3", ProcessClass: "log"},
+								{ProcessGroupID: "log-4", ProcessClass: "log"},
+							},
+							Configured: true,
+						},
+					}
+				}
+			})
+
+			It("should return the correct status", func() {
+				cluster := createCluster()
+
+				result, err := cluster.CheckReconciliation(log)
+				Expect(result).To(BeTrue())
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.Configured = false
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:               1,
+					NeedsConfigurationChange: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.ProcessGroups = append(cluster.Status.ProcessGroups, &ProcessGroupStatus{ProcessGroupID: "storage-5", ProcessClass: "storage"})
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:  1,
+					NeedsShrink: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.ProcessGroups = cluster.Status.ProcessGroups[1:]
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 1,
+					NeedsGrow:  2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.Health.Available = false
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:          1,
+					DatabaseUnavailable: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.DatabaseConfiguration.StorageEngine = "ssd-1"
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:               1,
+					NeedsConfigurationChange: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.HasIncorrectConfigMap = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:             1,
+					NeedsMonitorConfUpdate: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.RequiredAddresses.TLS = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:        1,
+					HasExtraListeners: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.ProcessCounts.Storage = 2
+				cluster.Status.ProcessGroups[0].MarkForRemoval()
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:  1,
+					NeedsShrink: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.ProcessCounts.Storage = 2
+				cluster.Status.ProcessGroups[0].MarkForRemoval()
+				cluster.Status.ProcessGroups[0].UpdateCondition(ResourcesTerminating, true, nil, "")
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:        2,
+					HasPendingRemoval: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.ProcessCounts.Storage = 2
+				cluster.Status.ProcessGroups[0].MarkForRemoval()
+				cluster.Status.ProcessGroups[0].SetExclude()
+				cluster.Status.ProcessGroups[0].UpdateCondition(IncorrectCommandLine, true, nil, "")
+				cluster.Status.ProcessGroups[0].UpdateCondition(ResourcesTerminating, true, nil, "")
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:        2,
+					HasPendingRemoval: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.HasIncorrectServiceConfig = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:         1,
+					NeedsServiceUpdate: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.NeedsNewCoordinators = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:             1,
+					NeedsCoordinatorChange: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Status.ProcessGroups[0].UpdateCondition(IncorrectCommandLine, true, nil, "")
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:          1,
+					HasUnhealthyProcess: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1"})
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:                    1,
+					NeedsLockConfigurationChanges: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1"})
+				cluster.Status.Locks.DenyList = []string{"dc1", "dc2"}
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1", Allow: true})
+				cluster.Status.Locks.DenyList = []string{"dc1", "dc2"}
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:                    1,
+					NeedsLockConfigurationChanges: 2,
+				}))
+
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1", Allow: true})
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 2,
+				}))
+			})
+		})
+
+		When("the cluster does not support grv and commit proxies", func() {
+			BeforeEach(func() {
+				createCluster = func() *FoundationDBCluster {
+					return &FoundationDBCluster{
+						ObjectMeta: metav1.ObjectMeta{
+							Name:       "sample-cluster",
+							Namespace:  "default",
+							Generation: 2,
 						},
-						DatabaseConfiguration: DatabaseConfiguration{
-							RedundancyMode: RedundancyModeDouble,
-							StorageEngine:  "ssd-2",
-							UsableRegions:  1,
-							RoleCounts: RoleCounts{
-								Logs:          3,
-								Proxies:       3,
-								GrvProxies:    1,
-								CommitProxies: 2,
-								Resolvers:     1,
-								LogRouters:    -1,
-								RemoteLogs:    -1,
-							},
-						},
-						Generations: ClusterGenerationStatus{
-							Reconciled: 1,
-						},
-						ProcessGroups: []*ProcessGroupStatus{
-							{ProcessGroupID: "storage-1", ProcessClass: "storage"},
-							{ProcessGroupID: "storage-2", ProcessClass: "storage"},
-							{ProcessGroupID: "storage-3", ProcessClass: "storage"},
-							{ProcessGroupID: "stateless-1", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-2", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-3", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-4", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-5", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-6", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-7", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-8", ProcessClass: "stateless"},
-							{ProcessGroupID: "stateless-9", ProcessClass: "stateless"},
-							{ProcessGroupID: "log-1", ProcessClass: "log"},
-							{ProcessGroupID: "log-2", ProcessClass: "log"},
-							{ProcessGroupID: "log-3", ProcessClass: "log"},
-							{ProcessGroupID: "log-4", ProcessClass: "log"},
-						},
-						Configured: true,
-					},
+						Spec: FoundationDBClusterSpec{
+							Version:               Versions.Default.String(),
+							DatabaseConfiguration: DatabaseConfiguration{},
+						},
+						Status: FoundationDBClusterStatus{
+							Health: ClusterHealth{
+								Available: true,
+								Healthy:   true,
+							},
+							RequiredAddresses: RequiredAddressSet{
+								NonTLS: true,
+							},
+							DatabaseConfiguration: DatabaseConfiguration{
+								RedundancyMode: RedundancyModeDouble,
+								StorageEngine:  "ssd-2",
+								UsableRegions:  1,
+								RoleCounts: RoleCounts{
+									Logs:          3,
+									Proxies:       3,
+									GrvProxies:    0,
+									CommitProxies: 0,
+									Resolvers:     1,
+									LogRouters:    -1,
+									RemoteLogs:    -1,
+								},
+							},
+							Generations: ClusterGenerationStatus{
+								Reconciled: 1,
+							},
+							ProcessGroups: []*ProcessGroupStatus{
+								{ProcessGroupID: "storage-1", ProcessClass: "storage"},
+								{ProcessGroupID: "storage-2", ProcessClass: "storage"},
+								{ProcessGroupID: "storage-3", ProcessClass: "storage"},
+								{ProcessGroupID: "stateless-1", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-2", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-3", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-4", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-5", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-6", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-7", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-8", ProcessClass: "stateless"},
+								{ProcessGroupID: "stateless-9", ProcessClass: "stateless"},
+								{ProcessGroupID: "log-1", ProcessClass: "log"},
+								{ProcessGroupID: "log-2", ProcessClass: "log"},
+								{ProcessGroupID: "log-3", ProcessClass: "log"},
+								{ProcessGroupID: "log-4", ProcessClass: "log"},
+							},
+							Configured: true,
+						},
+					}
 				}
-			}
+			})
 
-			cluster := createCluster()
+			It("should return the correct status", func() {
+				cluster := createCluster()
 
-			result, err := cluster.CheckReconciliation(log)
-			Expect(result).To(BeTrue())
-			Expect(err).NotTo(HaveOccurred())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled: 2,
-			}))
+				result, err := cluster.CheckReconciliation(log)
+				Expect(result).To(BeTrue())
+				Expect(err).NotTo(HaveOccurred())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.Configured = false
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:               1,
-				NeedsConfigurationChange: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.Configured = false
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:               1,
+					NeedsConfigurationChange: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.ProcessGroups = append(cluster.Status.ProcessGroups, &ProcessGroupStatus{ProcessGroupID: "storage-5", ProcessClass: "storage"})
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:  1,
-				NeedsShrink: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.ProcessGroups = append(cluster.Status.ProcessGroups, &ProcessGroupStatus{ProcessGroupID: "storage-5", ProcessClass: "storage"})
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:  1,
+					NeedsShrink: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.ProcessGroups = cluster.Status.ProcessGroups[1:]
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled: 1,
-				NeedsGrow:  2,
-			}))
+				cluster = createCluster()
+				cluster.Status.ProcessGroups = cluster.Status.ProcessGroups[1:]
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 1,
+					NeedsGrow:  2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.Health.Available = false
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:          1,
-				DatabaseUnavailable: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.Health.Available = false
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:          1,
+					DatabaseUnavailable: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.DatabaseConfiguration.StorageEngine = "ssd-1"
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:               1,
-				NeedsConfigurationChange: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.DatabaseConfiguration.StorageEngine = "ssd-1"
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:               1,
+					NeedsConfigurationChange: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.HasIncorrectConfigMap = true
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:             1,
-				NeedsMonitorConfUpdate: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.HasIncorrectConfigMap = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:             1,
+					NeedsMonitorConfUpdate: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.RequiredAddresses.TLS = true
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:        1,
-				HasExtraListeners: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.RequiredAddresses.TLS = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:        1,
+					HasExtraListeners: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.ProcessCounts.Storage = 2
-			cluster.Status.ProcessGroups[0].MarkForRemoval()
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:  1,
-				NeedsShrink: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.ProcessCounts.Storage = 2
+				cluster.Status.ProcessGroups[0].MarkForRemoval()
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:  1,
+					NeedsShrink: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.ProcessCounts.Storage = 2
-			cluster.Status.ProcessGroups[0].MarkForRemoval()
-			cluster.Status.ProcessGroups[0].UpdateCondition(ResourcesTerminating, true, nil, "")
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeTrue())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:        2,
-				HasPendingRemoval: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.ProcessCounts.Storage = 2
+				cluster.Status.ProcessGroups[0].MarkForRemoval()
+				cluster.Status.ProcessGroups[0].UpdateCondition(ResourcesTerminating, true, nil, "")
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:        2,
+					HasPendingRemoval: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.ProcessCounts.Storage = 2
-			cluster.Status.ProcessGroups[0].MarkForRemoval()
-			cluster.Status.ProcessGroups[0].SetExclude()
-			cluster.Status.ProcessGroups[0].UpdateCondition(IncorrectCommandLine, true, nil, "")
-			cluster.Status.ProcessGroups[0].UpdateCondition(ResourcesTerminating, true, nil, "")
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeTrue())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:        2,
-				HasPendingRemoval: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.ProcessCounts.Storage = 2
+				cluster.Status.ProcessGroups[0].MarkForRemoval()
+				cluster.Status.ProcessGroups[0].SetExclude()
+				cluster.Status.ProcessGroups[0].UpdateCondition(IncorrectCommandLine, true, nil, "")
+				cluster.Status.ProcessGroups[0].UpdateCondition(ResourcesTerminating, true, nil, "")
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:        2,
+					HasPendingRemoval: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.HasIncorrectServiceConfig = true
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:         1,
-				NeedsServiceUpdate: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.HasIncorrectServiceConfig = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:         1,
+					NeedsServiceUpdate: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.NeedsNewCoordinators = true
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:             1,
-				NeedsCoordinatorChange: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.NeedsNewCoordinators = true
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:             1,
+					NeedsCoordinatorChange: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Status.ProcessGroups[0].UpdateCondition(IncorrectCommandLine, true, nil, "")
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:          1,
-				HasUnhealthyProcess: 2,
-			}))
+				cluster = createCluster()
+				cluster.Status.ProcessGroups[0].UpdateCondition(IncorrectCommandLine, true, nil, "")
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:          1,
+					HasUnhealthyProcess: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1"})
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:                    1,
-				NeedsLockConfigurationChanges: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1"})
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:                    1,
+					NeedsLockConfigurationChanges: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1"})
-			cluster.Status.Locks.DenyList = []string{"dc1", "dc2"}
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeTrue())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1"})
+				cluster.Status.Locks.DenyList = []string{"dc1", "dc2"}
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1", Allow: true})
-			cluster.Status.Locks.DenyList = []string{"dc1", "dc2"}
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeFalse())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled:                    1,
-				NeedsLockConfigurationChanges: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1", Allow: true})
+				cluster.Status.Locks.DenyList = []string{"dc1", "dc2"}
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeFalse())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled:                    1,
+					NeedsLockConfigurationChanges: 2,
+				}))
 
-			cluster = createCluster()
-			cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1", Allow: true})
-			result, err = cluster.CheckReconciliation(log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(result).To(BeTrue())
-			Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
-				Reconciled: 2,
-			}))
+				cluster = createCluster()
+				cluster.Spec.LockOptions.DenyList = append(cluster.Spec.LockOptions.DenyList, LockDenyListEntry{ID: "dc1", Allow: true})
+				result, err = cluster.CheckReconciliation(log)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(result).To(BeTrue())
+				Expect(cluster.Status.Generations).To(Equal(ClusterGenerationStatus{
+					Reconciled: 2,
+				}))
+			})
 		})
+
 	})
 
 	When("getting the process settings", func() {
diff --git a/controllers/admin_client_test.go b/controllers/admin_client_test.go
index d9ab6ded..70ea5c13 100644
--- a/controllers/admin_client_test.go
+++ b/controllers/admin_client_test.go
@@ -65,48 +65,109 @@ var _ = Describe("admin_client_test", func() {
 		})
 
 		Context("with a basic cluster", func() {
-			It("should generate the status", func() {
-				Expect(status.Cluster.DatabaseConfiguration).To(Equal(fdbv1beta2.DatabaseConfiguration{
-					RedundancyMode: fdbv1beta2.RedundancyModeDouble,
-					StorageEngine:  "ssd-2",
-					UsableRegions:  1,
-					RoleCounts: fdbv1beta2.RoleCounts{
-						Logs:          3,
-						Proxies:       3,
-						CommitProxies: 2,
-						GrvProxies:    1,
-						Resolvers:     1,
-						LogRouters:    -1,
-						RemoteLogs:    -1,
-					},
-					VersionFlags: fdbv1beta2.VersionFlags{
-						LogSpill: 2,
-					},
-				}))
+			When("the version supports grv and commit proxies", func() {
+				BeforeEach(func() {
+					cluster.Spec.Version = fdbv1beta2.Versions.NextMajorVersion.String()
+					err = k8sClient.Update(context.TODO(), cluster)
+					Expect(err).NotTo(HaveOccurred())
 
-				address := cluster.Status.ProcessGroups[13].Addresses[0]
-				Expect(status.Cluster.Processes).To(HaveLen(len(cluster.Status.ProcessGroups)))
-				Expect(status.Cluster.Processes["operator-test-1-storage-1-1"]).To(Equal(fdbv1beta2.FoundationDBStatusProcessInfo{
-					Address: fdbv1beta2.ProcessAddress{
-						IPAddress: net.ParseIP(address),
-						Port:      4501,
-					},
-					ProcessClass: fdbv1beta2.ProcessClassStorage,
-					CommandLine:  fmt.Sprintf("/usr/bin/fdbserver --class=storage --cluster_file=/var/fdb/data/fdb.cluster --datadir=/var/fdb/data --listen_address=%s:4501 --locality_instance_id=storage-1 --locality_machineid=operator-test-1-storage-1 --locality_zoneid=operator-test-1-storage-1 --logdir=/var/log/fdb-trace-logs --loggroup=operator-test-1 --public_address=%s:4501 --seed_cluster_file=/var/dynamic-conf/fdb.cluster", address, address),
-					Excluded:     false,
-					Locality: map[string]string{
-						"instance_id": "storage-1",
-						"zoneid":      "operator-test-1-storage-1",
-						"dcid":        "",
-					},
-					Version:       "6.2.20",
-					UptimeSeconds: 60000,
-					Roles: []fdbv1beta2.FoundationDBStatusProcessRoleInfo{
-						{
-							Role: string(fdbv1beta2.ProcessRoleCoordinator),
+					result, err := reconcileCluster(cluster)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(result.Requeue).To(BeFalse())
+
+					generation, err := reloadCluster(cluster)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(generation).NotTo(Equal(int64(0)))
+
+					client, err = newMockAdminClientUncast(cluster, k8sClient)
+					Expect(err).NotTo(HaveOccurred())
+				})
+
+				It("should generate the status", func() {
+					Expect(status.Cluster.DatabaseConfiguration).To(Equal(fdbv1beta2.DatabaseConfiguration{
+						RedundancyMode: fdbv1beta2.RedundancyModeDouble,
+						StorageEngine:  "ssd-2",
+						UsableRegions:  1,
+						RoleCounts: fdbv1beta2.RoleCounts{
+							Logs:          3,
+							Proxies:       3,
+							CommitProxies: 2,
+							GrvProxies:    1,
+							Resolvers:     1,
+							LogRouters:    -1,
+							RemoteLogs:    -1,
 						},
-					},
-				}))
+						VersionFlags: fdbv1beta2.VersionFlags{
+							LogSpill: 2,
+						},
+					}))
+
+					address := cluster.Status.ProcessGroups[13].Addresses[0]
+					Expect(status.Cluster.Processes).To(HaveLen(len(cluster.Status.ProcessGroups)))
+					Expect(status.Cluster.Processes["operator-test-1-storage-1-1"]).To(Equal(fdbv1beta2.FoundationDBStatusProcessInfo{
+						Address: fdbv1beta2.ProcessAddress{
+							IPAddress: net.ParseIP(address),
+							Port:      4501,
+						},
+						ProcessClass: fdbv1beta2.ProcessClassStorage,
+						CommandLine:  fmt.Sprintf("/usr/bin/fdbserver --class=storage --cluster_file=/var/fdb/data/fdb.cluster --datadir=/var/fdb/data --listen_address=%s:4501 --locality_instance_id=storage-1 --locality_machineid=operator-test-1-storage-1 --locality_zoneid=operator-test-1-storage-1 --logdir=/var/log/fdb-trace-logs --loggroup=operator-test-1 --public_address=%s:4501 --seed_cluster_file=/var/dynamic-conf/fdb.cluster", address, address),
+						Excluded:     false,
+						Locality: map[string]string{
+							"instance_id": "storage-1",
+							"zoneid":      "operator-test-1-storage-1",
+							"dcid":        "",
+						},
+						Version:       fdbv1beta2.Versions.NextMajorVersion.String(),
+						UptimeSeconds: 60000,
+						Roles:         nil,
+					}))
+				})
+			})
+
+			When("the version does not supports grv and commit proxies", func() {
+				It("should generate the status", func() {
+					Expect(status.Cluster.DatabaseConfiguration).To(Equal(fdbv1beta2.DatabaseConfiguration{
+						RedundancyMode: fdbv1beta2.RedundancyModeDouble,
+						StorageEngine:  "ssd-2",
+						UsableRegions:  1,
+						RoleCounts: fdbv1beta2.RoleCounts{
+							Logs:          3,
+							Proxies:       3,
+							CommitProxies: 0,
+							GrvProxies:    0,
+							Resolvers:     1,
+							LogRouters:    -1,
+							RemoteLogs:    -1,
+						},
+						VersionFlags: fdbv1beta2.VersionFlags{
+							LogSpill: 2,
+						},
+					}))
+
+					address := cluster.Status.ProcessGroups[13].Addresses[0]
+					Expect(status.Cluster.Processes).To(HaveLen(len(cluster.Status.ProcessGroups)))
+					Expect(status.Cluster.Processes["operator-test-1-storage-1-1"]).To(Equal(fdbv1beta2.FoundationDBStatusProcessInfo{
+						Address: fdbv1beta2.ProcessAddress{
+							IPAddress: net.ParseIP(address),
+							Port:      4501,
+						},
+						ProcessClass: fdbv1beta2.ProcessClassStorage,
+						CommandLine:  fmt.Sprintf("/usr/bin/fdbserver --class=storage --cluster_file=/var/fdb/data/fdb.cluster --datadir=/var/fdb/data --listen_address=%s:4501 --locality_instance_id=storage-1 --locality_machineid=operator-test-1-storage-1 --locality_zoneid=operator-test-1-storage-1 --logdir=/var/log/fdb-trace-logs --loggroup=operator-test-1 --public_address=%s:4501 --seed_cluster_file=/var/dynamic-conf/fdb.cluster", address, address),
+						Excluded:     false,
+						Locality: map[string]string{
+							"instance_id": "storage-1",
+							"zoneid":      "operator-test-1-storage-1",
+							"dcid":        "",
+						},
+						Version:       "6.2.20",
+						UptimeSeconds: 60000,
+						Roles: []fdbv1beta2.FoundationDBStatusProcessRoleInfo{
+							{
+								Role: string(fdbv1beta2.ProcessRoleCoordinator),
+							},
+						},
+					}))
+				})
 			})
 		})
 
diff --git a/controllers/cluster_controller_test.go b/controllers/cluster_controller_test.go
index 9f00d655..9af0eda7 100644
--- a/controllers/cluster_controller_test.go
+++ b/controllers/cluster_controller_test.go
@@ -228,14 +228,29 @@ var _ = Describe("cluster_controller", func() {
 				Expect(adminClient.DatabaseConfiguration.RoleCounts).To(Equal(fdbv1beta2.RoleCounts{
 					Logs:          3,
 					Proxies:       3,
-					CommitProxies: 2,
-					GrvProxies:    1,
+					CommitProxies: 0,
+					GrvProxies:    0,
 					Resolvers:     1,
 					RemoteLogs:    -1,
 					LogRouters:    -1,
 				}))
 			})
 
+			It("should send the configuration to the cluster", func() {
+				adminClient, err := newMockAdminClientUncast(cluster, k8sClient)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(adminClient).NotTo(BeNil())
+				Expect(adminClient.DatabaseConfiguration.RedundancyMode).To(Equal(fdbv1beta2.RedundancyModeDouble))
+				Expect(adminClient.DatabaseConfiguration.StorageEngine).To(Equal(fdbv1beta2.StorageEngineSSD2))
+				Expect(adminClient.DatabaseConfiguration.RoleCounts).To(Equal(fdbv1beta2.RoleCounts{
+					Logs:       3,
+					Proxies:    3,
+					Resolvers:  1,
+					RemoteLogs: -1,
+					LogRouters: -1,
+				}))
+			})
+
 			It("should update the status with the reconciliation result", func() {
 				adminClient, err := newMockAdminClientUncast(cluster, k8sClient)
 				Expect(err).NotTo(HaveOccurred())