Repository: FoundationDB/fdb-kubernetes-operator
Pull request #1131 (2022-03-22 14:52:18)

Document failover with plugin and allow to update config
# Description

Document the configuration sub command in the kubectl plugin and allow the plugin to update a cluster directly.

## Type of change

*Please select one of the options below.*

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)

## Discussion

-

## Testing

locally.

## Documentation

Added.

## Follow-up

-


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

* CodeBuild project: fdb-kubernetes-operator-pr
* Commit ID: 9ddd1fffc0b4665cc08eae88e40d1b1444a3bcc9
* Result: FAILED
* Error: `Unexpected EC2 error: InvalidGroup.NotFound`
* [Build Logs](https://d1e0l78xbkh3xa.cloudfront.net) (available for 30 days)

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

* CodeBuild project: fdb-kubernetes-operator-pr
* Commit ID: c5f52a88fc8113041fda750807ca381a77a816b1
* 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/c4872344-a8c2-445f-beb8-2401da204729.gz) (available for 30 days)

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

* CodeBuild project: fdb-kubernetes-operator-pr
* Commit ID: f1499fa6f6a3d64aaad1bd61420b88e2090c5838
* 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/f878f73f-0e82-4406-9ce6-ed917e6ded38.gz) (available for 30 days)

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

* CodeBuild project: fdb-kubernetes-operator-pr
* Commit ID: 780a06876951313cea4788e882dceb70d64959a2
* 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/5cdf9275-7f20-4ae8-997c-76381e015df9.gz) (available for 30 days)


Patch:
diff --git a/api/v1beta2/foundationdb_database_configuration.go b/api/v1beta2/foundationdb_database_configuration.go
index d9a3d78e..328f2f67 100644
--- a/api/v1beta2/foundationdb_database_configuration.go
+++ b/api/v1beta2/foundationdb_database_configuration.go
@@ -1,5 +1,5 @@
 /*
- * foundationdb_labels.go
+ * foundationdb_database_configuration.go
  *
  * This source file is part of the FoundationDB open source project
  *
@@ -67,7 +67,7 @@ type Region struct {
 	SatelliteLogs int `json:"satellite_logs,omitempty"`
 
 	// The replication strategy for satellite logs.
-	SatelliteRedundancyMode string `json:"satellite_redundancy_mode,omitempty"`
+	SatelliteRedundancyMode RedundancyMode `json:"satellite_redundancy_mode,omitempty"`
 }
 
 // DataCenter represents a data center in the region configuration
@@ -110,10 +110,12 @@ func (configuration *DatabaseConfiguration) FailOver() DatabaseConfiguration {
 	}
 
 	for _, region := range newConfiguration.Regions {
-		// In order to trigger a fail over we have to change the priority
-		// of the main and remote dc
+		// In order to trigger a fail-over we have to change the priority of the main and remote dc
 		newRegion := Region{}
 		for _, dc := range region.DataCenters {
+			newRegion.SatelliteRedundancyMode = region.SatelliteRedundancyMode
+			newRegion.SatelliteLogs = region.SatelliteLogs
+
 			// Don't change the Satellite config
 			if dc.Satellite == 1 {
 				newRegion.DataCenters = append(newRegion.DataCenters, dc)
@@ -661,6 +663,10 @@ const (
 	RedundancyModeDouble RedundancyMode = "double"
 	// RedundancyModeTriple defines the replication factor 3.
 	RedundancyModeTriple RedundancyMode = "triple"
+	// RedundancyModeOneSatelliteSingle defines the replication factor one_satellite_single.
+	RedundancyModeOneSatelliteSingle RedundancyMode = "one_satellite_single"
+	// RedundancyModeOneSatelliteDouble  defines the replication factor one_satellite_double.
+	RedundancyModeOneSatelliteDouble RedundancyMode = "one_satellite_double"
 	// RedundancyModeUnset defines the replication factor unset.
 	RedundancyModeUnset RedundancyMode = ""
 )
diff --git a/config/crd/bases/apps.foundationdb.org_foundationdbclusters.yaml b/config/crd/bases/apps.foundationdb.org_foundationdbclusters.yaml
index 6e139e2f..e3aee542 100644
--- a/config/crd/bases/apps.foundationdb.org_foundationdbclusters.yaml
+++ b/config/crd/bases/apps.foundationdb.org_foundationdbclusters.yaml
@@ -9463,6 +9463,7 @@ spec:
                         satellite_logs:
                           type: integer
                         satellite_redundancy_mode:
+                          maxLength: 100
                           type: string
                       type: object
                     type: array
@@ -12855,6 +12856,7 @@ spec:
                         satellite_logs:
                           type: integer
                         satellite_redundancy_mode:
+                          maxLength: 100
                           type: string
                       type: object
                     type: array
diff --git a/docs/cluster_spec.md b/docs/cluster_spec.md
index 08bae706..42d023e3 100644
--- a/docs/cluster_spec.md
+++ b/docs/cluster_spec.md
@@ -483,7 +483,7 @@ Region represents a region in the database configuration
 | ----- | ----------- | ------ | -------- |
 | datacenters | The data centers in this region. | [][DataCenter](#datacenter) | false |
 | satellite_logs | The number of satellite logs that we should recruit. | int | false |
-| satellite_redundancy_mode | The replication strategy for satellite logs. | string | false |
+| satellite_redundancy_mode | The replication strategy for satellite logs. | [RedundancyMode](#redundancymode) | false |
 
 [Back to TOC](#table-of-contents)
 
diff --git a/docs/manual/debugging.md b/docs/manual/debugging.md
index a5322ffd..bbc36765 100644
--- a/docs/manual/debugging.md
+++ b/docs/manual/debugging.md
@@ -7,8 +7,8 @@ You can use the [kubectl-fdb](/kubectl-fdb) plugin when investigating issues and
 If a cluster is stuck in a reconciliation you can use the `kubectl-fdb` plugin to analyze the issue:
 
 ```bash
-$ kubectl fdb analyze example-cluster
-Checking cluster: default/example-cluster
+$ kubectl fdb analyze sample-cluster
+Checking cluster: default/sample-cluster
 ✔ Cluster is available
 ✔ Cluster is fully replicated
 ✖ Cluster is not reconciled
@@ -17,19 +17,19 @@ Checking cluster: default/example-cluster
 ✖ ProcessGroup: storage-2 has the following condition: PodFailing since 2021-03-25 18:23:22 +0000 GMT
 ✖ ProcessGroup: storage-2 has the following condition: IncorrectConfigMap since 2021-03-26 19:20:56 +0000 GMT
 ✖ ProcessGroup: transaction-5 has the following condition: MissingProcesses since 2021-04-27 02:57:24 +0100 BST
-✖ Pod default/example-cluster-storage-2 has unexpected Phase Pending with Reason:
-✖ Pod default/example-cluster-storage-2 has an unready container: foundationdb
-✖ Pod default/example-cluster-storage-2 has an unready container: foundationdb-kubernetes-sidecar
-✖ Pod default/example-cluster-storage-2 has an unready container: trace-log-forwarder
+✖ Pod default/sample-cluster-storage-2 has unexpected Phase Pending with Reason:
+✖ Pod default/sample-cluster-storage-2 has an unready container: foundationdb
+✖ Pod default/sample-cluster-storage-2 has an unready container: foundationdb-kubernetes-sidecar
+✖ Pod default/sample-cluster-storage-2 has an unready container: trace-log-forwarder
 Error:
-found issues for cluster example-cluster. Please check them
+found issues for cluster sample-cluster. Please check them
 ```
 
 The plugin can also resolve most of these issues automatically:
 
 ```bash
-$ kubectl fdb analyze example-cluster --auto-fix
-Checking cluster: default/example-cluster
+$ kubectl fdb analyze sample-cluster --auto-fix
+Checking cluster: default/sample-cluster
 ✔ Cluster is available
 ✔ Cluster is fully replicated
 ✖ Cluster is not reconciled
@@ -38,13 +38,13 @@ Checking cluster: default/example-cluster
 ✖ ProcessGroup: storage-2 has the following condition: PodFailing since 2021-03-25 18:23:22 +0000 GMT
 ✖ ProcessGroup: storage-2 has the following condition: IncorrectConfigMap since 2021-03-26 19:20:56 +0000 GMT
 ✖ ProcessGroup: transaction-5 has the following condition: MissingProcesses since 2021-04-27 02:57:24 +0100 BST
-✖ Pod default/example-cluster-storage-2 has unexpected Phase Pending with Reason:
-✖ Pod default/example-cluster-storage-2 has an unready container: foundationdb
-✖ Pod default/example-cluster-storage-2 has an unready container: foundationdb-kubernetes-sidecar
-✖ Pod default/example-cluster-storage-2 has an unready container: trace-log-forwarder
-Replace process groups [stateless-5 storage-2 transaction-5] in cluster default/example-cluster [y/n]: y
+✖ Pod default/sample-cluster-storage-2 has unexpected Phase Pending with Reason:
+✖ Pod default/sample-cluster-storage-2 has an unready container: foundationdb
+✖ Pod default/examsampleple-cluster-storage-2 has an unready container: foundationdb-kubernetes-sidecar
+✖ Pod default/sample-cluster-storage-2 has an unready container: trace-log-forwarder
+Replace process groups [stateless-5 storage-2 transaction-5] in cluster default/sample-cluster [y/n]: y
 Error:
-found issues for cluster example-cluster. Please check them
+found issues for cluster sample-cluster. Please check them
 ```
 
 When using this feature, read carefully what the plugin wants to do and only confirm the dialog when you are sure that you want to do these actions.
@@ -56,11 +56,11 @@ You can do that using a [plugin command](#replacing-pods-with-the-kubectl-plugin
 
 ## Replacing Pods with the kubectl plugin
 
-Let's assume we are working with the cluster `example-cluster`, and the pod `example-cluster-storage-1` is failing to launch.
+Let's assume we are working with the cluster `sample-cluster`, and the pod `sample-cluster-storage-1` is failing to launch.
 
 ```bash
-$ kubectl fdb remove process-groups -c example-cluster example-cluster-storage-1
-Remove [storage-1] from cluster default/example-cluster with exclude: true and shrink: false [y/n]:
+$ kubectl fdb remove process-groups -c sample-cluster sample-cluster-storage-1
+Remove [storage-1] from cluster default/sample-cluster with exclude: true and shrink: false [y/n]:
 # Confirm with 'y' if the excluded Pod is the correct one
 ```
 
@@ -74,8 +74,8 @@ If this happens, you will see an error of the form `Cannot check the exclusion s
 When this happens, the only way to finish the replacement is to skip the exclusion:
 
 ```bash
-$ kubectl fdb remove process-groups --exclusion=false -c example-cluster example-cluster-storage-1
-Remove [storage-1] from cluster default/example-cluster with exclude: false and shrink: false [y/n]:
+$ kubectl fdb remove process-groups --exclusion=false -c sample-cluster sample-cluster-storage-1
+Remove [storage-1] from cluster default/sample-cluster with exclude: false and shrink: false [y/n]:
 # Confirm with 'y' if the excluded Pod is the correct one
 ```
 
@@ -138,7 +138,7 @@ To simplify this process, the kubectl-fdb plugin has a command that encapsulates
 If you want to open up a shell or run a CLI, you can use the [plugin](#kubectl-fdb-plugin):
 
 ```bash
- kubectl fdb exec -c example-cluster -- bash
+ kubectl fdb exec -c sample-cluster -- bash
 ```
 
 Or if you want to check a specific pod:
@@ -151,6 +151,19 @@ This will open up a shell inside the container. You can use this shell to examin
 
 When running the CLI on Kubernetes, you can simply run `fdbcli` with no additional arguments. The shell path, cluster file, TLS certificates, and any other required configuration will be supplied through the environment.
 
+## Get the configuration string
+
+The kubectl plugin supports to generate the configuration string from a FoundationDB cluster spec:
+
+```bash
+kubectl fdb get configuration sample-cluster
+```
+
+When the `--fail-over` flag is provided the resulting configuration string will change the priority for the primary and the remote dc.
+You can also update the config directly by providing the `--update` flag to the command.
+Per default a diff of the new changes will be shown before updating the cluster spec.
+For an HA cluster you have to update all clusters that are managed by the operator with the same command to ensure that all operator instance want to converge to the same configuration. 
+
 ## Next
 
 You can continue on to the [next section](more.md) or go back to the [table of contents](index.md).
diff --git a/kubectl-fdb/cmd/analyze.go b/kubectl-fdb/cmd/analyze.go
index 4c872cba..2597ebb0 100644
--- a/kubectl-fdb/cmd/analyze.go
+++ b/kubectl-fdb/cmd/analyze.go
@@ -44,7 +44,7 @@ func newAnalyzeCmd(streams genericclioptions.IOStreams) *cobra.Command {
 		Short: "Analyze if the given clusters have any issues",
 		Long:  "Analyze if the given clusters have any issues",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			force, err := cmd.Root().Flags().GetBool("force")
+			wait, err := cmd.Root().Flags().GetBool("wait")
 			if err != nil {
 				return err
 			}
@@ -108,7 +108,7 @@ func newAnalyzeCmd(streams genericclioptions.IOStreams) *cobra.Command {
 
 			var errs []error
 			for _, cluster := range clusters {
-				err := analyzeCluster(cmd, kubeClient, cluster, namespace, autoFix, force, ignoreConditions)
+				err := analyzeCluster(cmd, kubeClient, cluster, namespace, autoFix, wait, ignoreConditions)
 				if err != nil {
 					errs = append(errs, err)
 				}
@@ -208,7 +208,7 @@ func printStatement(cmd *cobra.Command, line string, mesType messageType) {
 	color.Unset()
 }
 
-func analyzeCluster(cmd *cobra.Command, kubeClient client.Client, clusterName string, namespace string, autoFix bool, force bool, ignoreConditions []string) error {
+func analyzeCluster(cmd *cobra.Command, kubeClient client.Client, clusterName string, namespace string, autoFix bool, wait bool, ignoreConditions []string) error {
 	foundIssues := false
 	cluster, err := loadCluster(kubeClient, namespace, clusterName)
 
@@ -372,14 +372,14 @@ func analyzeCluster(cmd *cobra.Command, kubeClient client.Client, clusterName st
 		confirmed := false
 
 		if len(failedProcessGroups) > 0 {
-			err := replaceProcessGroups(kubeClient, cluster.Name, failedProcessGroups, namespace, true, false, force, false)
+			err := replaceProcessGroups(kubeClient, cluster.Name, failedProcessGroups, namespace, true, false, wait, false)
 			if err != nil {
 				return err
 			}
 		}
 
 		pods := filterDeletePods(failedProcessGroups, killPods)
-		if !force && len(pods) > 0 {
+		if wait && len(pods) > 0 {
 			podNames := make([]string, 0, len(killPods))
 			for _, pod := range killPods {
 				podNames = append(podNames, pod.Name)
@@ -388,7 +388,7 @@ func analyzeCluster(cmd *cobra.Command, kubeClient client.Client, clusterName st
 			confirmed = confirmAction(fmt.Sprintf("Delete Pods %v in cluster %s/%s", strings.Join(podNames, ","), namespace, clusterName))
 		}
 
-		if force || confirmed {
+		if !wait || confirmed {
 			for _, pod := range pods {
 				cmd.Printf("Delete Pod: %s/%s\n", pod.Namespace, pod.Name)
 				err := kubeClient.Delete(context.Background(), &pod)
diff --git a/kubectl-fdb/cmd/configuration.go b/kubectl-fdb/cmd/configuration.go
index 126a59d0..e3cda9b8 100644
--- a/kubectl-fdb/cmd/configuration.go
+++ b/kubectl-fdb/cmd/configuration.go
@@ -21,6 +21,9 @@
 package cmd
 
 import (
+	ctx "context"
+	"fmt"
+
 	"github.com/spf13/cobra"
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -34,11 +37,21 @@ func newConfigurationCmd(streams genericclioptions.IOStreams) *cobra.Command {
 		Short: "Get the configuration string based on the database configuration of the cluster spec.",
 		Long:  "Get the configuration string based on the database configuration of the cluster spec.",
 		RunE: func(cmd *cobra.Command, args []string) error {
+			wait, err := cmd.Root().Flags().GetBool("wait")
+			if err != nil {
+				return err
+			}
+
 			failOver, err := cmd.Flags().GetBool("fail-over")
 			if err != nil {
 				return err
 			}
 
+			update, err := cmd.Flags().GetBool("update")
+			if err != nil {
+				return err
+			}
+
 			kubeClient, err := getKubeClient(o)
 			if err != nil {
 				return err
@@ -50,6 +63,10 @@ func newConfigurationCmd(streams genericclioptions.IOStreams) *cobra.Command {
 			}
 
 			for _, clusterName := range args {
+				if update {
+					return updateConfig(kubeClient, clusterName, namespace, failOver, wait)
+				}
+
 				configuration, err := getConfigurationString(kubeClient, clusterName, namespace, failOver)
 				if err != nil {
 					return err
@@ -73,6 +90,9 @@ kubectl fdb -n default get configuration c1
 
 # Get the configuration string from cluster c1 and change the priority for an HA cluster
 kubectl fdb get configuration --fail-over c1
+
+# Change the priority for an HA cluster named c1 and apply these changes
+kubectl fdb get configuration --fail-over --update c1
 `,
 	}
 	cmd.SetOut(o.Out)
@@ -80,12 +100,41 @@ kubectl fdb get configuration --fail-over c1
 	cmd.SetIn(o.In)
 
 	cmd.Flags().Bool("fail-over", false, "defines if the configuration should be changed to issue a fail over")
+	cmd.Flags().Bool("update", false, "defines if the configuration should be updated in the cluster spec")
 	o.configFlags.AddFlags(cmd.Flags())
 
 	return cmd
 }
 
-// printConfiguration
+func updateConfig(kubeClient client.Client, clusterName string, namespace string, failOver bool, wait bool) error {
+	cluster, err := loadCluster(kubeClient, namespace, clusterName)
+	if err != nil {
+		return err
+	}
+
+	config := cluster.Spec.DatabaseConfiguration
+	if failOver {
+		config = config.FailOver()
+	}
+
+	if wait {
+		diff, err := getDiff(cluster.Spec.DatabaseConfiguration, config)
+		if err != nil {
+			return err
+		}
+
+		confirmed := confirmAction(fmt.Sprintf("The following changes will be made:\n%s", diff))
+		if !confirmed {
+			return fmt.Errorf("user aborted the change")
+		}
+	}
+
+	cluster.Spec.DatabaseConfiguration = config
+
+	return kubeClient.Update(ctx.Background(), cluster)
+}
+
+// getConfigurationString returns the configuration string
 func getConfigurationString(kubeClient client.Client, clusterName string, namespace string, failOver bool) (string, error) {
 	cluster, err := loadCluster(kubeClient, namespace, clusterName)
 	if err != nil {
diff --git a/kubectl-fdb/cmd/cordon.go b/kubectl-fdb/cmd/cordon.go
index d7f51600..2dd4ea53 100644
--- a/kubectl-fdb/cmd/cordon.go
+++ b/kubectl-fdb/cmd/cordon.go
@@ -47,7 +47,7 @@ func newCordonCmd(streams genericclioptions.IOStreams) *cobra.Command {
 		Short: "Adds all process groups (or multiple) that run on a node to the remove list of the given cluster",
 		Long:  "Adds all process groups (or multiple) that run on a node to the remove list of the given cluster",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			force, err := cmd.Root().Flags().GetBool("force")
+			wait, err := cmd.Root().Flags().GetBool("wait")
 			if err != nil {
 				return err
 			}
@@ -89,10 +89,10 @@ func newCordonCmd(streams genericclioptions.IOStreams) *cobra.Command {
 					return err
 				}
 
-				return cordonNode(kubeClient, cluster, nodes, namespace, withExclusion, force)
+				return cordonNode(kubeClient, cluster, nodes, namespace, withExclusion, wait)
 			}
 
-			return cordonNode(kubeClient, cluster, args, namespace, withExclusion, force)
+			return cordonNode(kubeClient, cluster, args, namespace, withExclusion, wait)
 		},
 		Example: `
 # Evacuate all process groups for a cluster in the current namespace that are hosted on node-1
@@ -123,7 +123,7 @@ kubectl fdb cordon -c cluster --node-selector machine=a,disk=fast
 }
 
 // cordonNode gets all process groups of this cluster that run on the given nodes and add them to the remove list
-func cordonNode(kubeClient client.Client, cluster *fdbv1beta2.FoundationDBCluster, nodes []string, namespace string, withExclusion bool, force bool) error {
+func cordonNode(kubeClient client.Client, cluster *fdbv1beta2.FoundationDBCluster, nodes []string, namespace string, withExclusion bool, wait bool) error {
 	fmt.Printf("Start to cordon %d nodes\n", len(nodes))
 	if len(nodes) == 0 {
 		return nil
@@ -161,5 +161,5 @@ func cordonNode(kubeClient client.Client, cluster *fdbv1beta2.FoundationDBCluste
 		}
 	}
 
-	return replaceProcessGroups(kubeClient, cluster.Name, processGroups, namespace, withExclusion, false, force, false)
+	return replaceProcessGroups(kubeClient, cluster.Name, processGroups, namespace, withExclusion, false, wait, false)
 }
diff --git a/kubectl-fdb/cmd/deprecation.go b/kubectl-fdb/cmd/deprecation.go
index e7ca19e6..fefe1920 100644
--- a/kubectl-fdb/cmd/deprecation.go
+++ b/kubectl-fdb/cmd/deprecation.go
@@ -156,6 +156,9 @@ func checkDeprecation(cmd *cobra.Command, kubeClient client.Client, inputCluster
 		}
 
 		diff := cmp.Diff(originalYAML, normalizedYAML)
+		if err != nil {
+			return err
+		}
 		if diff == "" {
 			if !showClusterSpec {
 				cmd.Printf("Cluster %s has no deprecation\n", cluster.Name)
@@ -182,6 +185,20 @@ func checkDeprecation(cmd *cobra.Command, kubeClient client.Client, inputCluster
 	return nil
 }
 
+func getDiff(objectA interface{}, objectB interface{}) (string, error) {
+	aYaml, err := getMinimalYAML(objectA)
+	if err != nil {
+		return "", err
+	}
+
+	bYaml, err := getMinimalYAML(objectB)
+	if err != nil {
+		return "", err
+	}
+
+	return cmp.Diff(aYaml, bYaml), nil
+}
+
 func getMinimalYAML(object interface{}) ([]byte, error) {
 	rawYAML, err := yaml.Marshal(object)
 	if err != nil {
diff --git a/kubectl-fdb/cmd/remove_process_group.go b/kubectl-fdb/cmd/remove_process_group.go
index 79cbd747..1511799a 100644
--- a/kubectl-fdb/cmd/remove_process_group.go
+++ b/kubectl-fdb/cmd/remove_process_group.go
@@ -42,7 +42,7 @@ func newRemoveProcessGroupCmd(streams genericclioptions.IOStreams) *cobra.Comman
 		Short: "Adds a process group (or multiple) to the remove list of the given cluster",
 		Long:  "Adds a process group (or multiple) to the remove list field of the given cluster",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			force, err := cmd.Root().Flags().GetBool("force")
+			wait, err := cmd.Root().Flags().GetBool("wait")
 			if err != nil {
 				return err
 			}
@@ -85,21 +85,21 @@ func newRemoveProcessGroupCmd(streams genericclioptions.IOStreams) *cobra.Comman
 				}
 			}
 
-			return replaceProcessGroups(kubeClient, cluster, processGroups, namespace, withExclusion, withShrink, force, removeAllFailed)
+			return replaceProcessGroups(kubeClient, cluster, processGroups, namespace, withExclusion, withShrink, wait, removeAllFailed)
 		},
 		Example: `
 # Remove process groups for a cluster in the current namespace
 kubectl fdb remove process-group -c cluster pod-1 -i pod-2
 
 # Remove process groups for a cluster in the namespace default
-kubectl fdb -n default remove process-group  -c cluster pod-1 pod-2
+kubectl fdb -n default remove process-group -c cluster pod-1 pod-2
 
 # Remove process groups for a cluster with the process group ID.
 # The process group ID of a Pod can be fetched with "kubectl get po -L foundationdb.org/fdb-process-group-id"
 kubectl fdb -n default remove process-group --use-process-group-id -c cluster storage-1 storage-2
 
 # Remove all failed process groups for a cluster (all process groups that have a missing process)
-kubectl fdb -n default remove process-group  -c cluster --remove-all-failed
+kubectl fdb -n default remove process-group -c cluster --remove-all-failed
 `,
 	}
 
@@ -150,7 +150,7 @@ func getProcessGroupIDsFromPod(kubeClient client.Client, clusterName string, pod
 }
 
 // replaceProcessGroups adds process groups to the removal list of the cluster
-func replaceProcessGroups(kubeClient client.Client, clusterName string, processGroups []string, namespace string, withExclusion bool, withShrink bool, force bool, removeAllFailed bool) error {
+func replaceProcessGroups(kubeClient client.Client, clusterName string, processGroups []string, namespace string, withExclusion bool, withShrink bool, wait bool, removeAllFailed bool) error {
 	cluster, err := loadCluster(kubeClient, namespace, clusterName)
 
 	if err != nil {
@@ -207,7 +207,7 @@ func replaceProcessGroups(kubeClient client.Client, clusterName string, processG
 		cluster.Spec.ProcessCounts.DecreaseCount(class, amount)
 	}
 
-	if !force {
+	if wait {
 		confirmed := confirmAction(fmt.Sprintf("Remove %v from cluster %s/%s with exclude: %t and shrink: %t", processGroups, namespace, clusterName, withExclusion, withShrink))
 		if !confirmed {
 			return fmt.Errorf("user aborted the removal")
diff --git a/kubectl-fdb/cmd/restart.go b/kubectl-fdb/cmd/restart.go
index 3306cb5f..b5622f98 100644
--- a/kubectl-fdb/cmd/restart.go
+++ b/kubectl-fdb/cmd/restart.go
@@ -39,7 +39,7 @@ func newRestartCmd(streams genericclioptions.IOStreams) *cobra.Command {
 		Short: "Restarts process(es) in a given FDB cluster.",
 		Long:  "Restarts process(es) in a given FDB cluster.",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			force, err := cmd.Root().Flags().GetBool("force")
+			wait, err := cmd.Root().Flags().GetBool("wait")
 			if err != nil {
 				return err
 			}
@@ -108,7 +108,7 @@ func newRestartCmd(streams genericclioptions.IOStreams) *cobra.Command {
 				processes = args
 			}
 
-			return restartProcesses(cmd, config, clientSet, processes, namespace, clusterName, force)
+			return restartProcesses(cmd, config, clientSet, processes, namespace, clusterName, wait)
 		},
 		Example: `
 # Restart processes for a cluster in the current namespace
@@ -157,8 +157,8 @@ func convertConditions(inputConditions []string) ([]fdbv1beta2.ProcessGroupCondi
 }
 
 //nolint:interfacer // golint has a false-positive here -> `cmd` can be `github.com/hashicorp/go-retryablehttp.Logger`
-func restartProcesses(cmd *cobra.Command, restConfig *rest.Config, kubeClient *kubernetes.Clientset, processes []string, namespace string, clusterName string, force bool) error {
-	if !force {
+func restartProcesses(cmd *cobra.Command, restConfig *rest.Config, kubeClient *kubernetes.Clientset, processes []string, namespace string, clusterName string, wait bool) error {
+	if wait {
 		confirmed := confirmAction(fmt.Sprintf("Restart %v in cluster %s/%s", processes, namespace, clusterName))
 		if !confirmed {
 			return fmt.Errorf("user aborted the removal")
diff --git a/kubectl-fdb/cmd/root.go b/kubectl-fdb/cmd/root.go
index 636b6ace..fb044801 100644
--- a/kubectl-fdb/cmd/root.go
+++ b/kubectl-fdb/cmd/root.go
@@ -67,7 +67,7 @@ func NewRootCmd(streams genericclioptions.IOStreams) *cobra.Command {
 
 	viper.SetDefault("license", "apache 2")
 	cmd.PersistentFlags().StringP("operator-name", "o", "fdb-kubernetes-operator-controller-manager", "Name of the Deployment for the operator.")
-	cmd.PersistentFlags().BoolP("force", "f", false, "Suppress the confirmation dialog")
+	cmd.PersistentFlags().BoolP("wait", "w", true, "If the plugin should wait for confirmation before executing any action")
 	o.configFlags.AddFlags(cmd.Flags())
 
 	cmd.AddCommand(


Test patch:
diff --git a/api/v1beta2/foundationdb_database_configuration_test.go b/api/v1beta2/foundationdb_database_configuration_test.go
new file mode 100644
index 00000000..ad79d498
--- /dev/null
+++ b/api/v1beta2/foundationdb_database_configuration_test.go
@@ -0,0 +1,160 @@
+/*
+ * foundationdb_database_configuration_test.go
+ *
+ * This source file is part of the FoundationDB open source project
+ *
+ * Copyright 2022 Apple Inc. and the FoundationDB project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package v1beta2
+
+import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("DatabaseConfiguration", func() {
+	When("a single dc cluster is provided", func() {
+		var config *DatabaseConfiguration
+
+		BeforeEach(func() {
+			config = &DatabaseConfiguration{
+				StorageEngine:  StorageEngineSSD,
+				RedundancyMode: RedundancyModeTriple,
+				UsableRegions:  1,
+				RoleCounts: RoleCounts{
+					Logs:      3,
+					Storage:   3,
+					Proxies:   3,
+					Resolvers: 1,
+				},
+				Regions: []Region{
+					{
+						DataCenters: []DataCenter{
+							{
+								ID:        "primary",
+								Priority:  1,
+								Satellite: 0,
+							},
+						},
+						SatelliteLogs:           0,
+						SatelliteRedundancyMode: "",
+					},
+				},
+			}
+		})
+
+		When("the configuration string is calculated", func() {
+			It("should print the correct configuration string", func() {
+				Expect(config.GetConfigurationString(Versions.Default.String())).To(Equal("triple ssd usable_regions=1 logs=3 resolvers=1 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\",\\\"priority\\\":1}]}]"))
+			})
+		})
+
+		When("the configuration string is calculated with fail over", func() {
+			It("should not change the config and print the correct configuration string", func() {
+				newConfig := config.FailOver()
+				Expect(newConfig).To(Equal(*config))
+				Expect(newConfig.GetConfigurationString(Versions.Default.String())).To(Equal("triple ssd usable_regions=1 logs=3 resolvers=1 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\",\\\"priority\\\":1}]}]"))
+			})
+		})
+	})
+
+	When("a multi dc cluster is provided", func() {
+		var config *DatabaseConfiguration
+
+		BeforeEach(func() {
+			config = &DatabaseConfiguration{
+				StorageEngine:  StorageEngineSSD,
+				RedundancyMode: RedundancyModeTriple,
+				UsableRegions:  1,
+				RoleCounts: RoleCounts{
+					Logs:      3,
+					Storage:   3,
+					Proxies:   3,
+					Resolvers: 1,
+				},
+				Regions: []Region{
+					{
+						DataCenters: []DataCenter{
+							{
+								ID:        "primary",
+								Priority:  1,
+								Satellite: 0,
+							},
+							{
+								ID:        "primary-sat",
+								Priority:  1,
+								Satellite: 1,
+							},
+						},
+						SatelliteLogs:           3,
+						SatelliteRedundancyMode: RedundancyModeOneSatelliteSingle,
+					},
+					{
+						DataCenters: []DataCenter{
+							{
+								ID:        "remote",
+								Priority:  0,
+								Satellite: 0,
+							},
+							{
+								ID:        "remote-sat",
+								Priority:  1,
+								Satellite: 1,
+							},
+						},
+						SatelliteLogs:           3,
+						SatelliteRedundancyMode: RedundancyModeOneSatelliteDouble,
+					},
+				},
+			}
+		})
+
+		When("the configuration string is calculated", func() {
+			It("should print the correct configuration string", func() {
+				Expect(config.GetConfigurationString(Versions.Default.String())).To(Equal("triple ssd usable_regions=1 logs=3 resolvers=1 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_single\\\"},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\"},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_double\\\"}]"))
+			})
+		})
+
+		When("the configuration string is calculated with fail over", func() {
+			It("should change the priority of the primary and the remote DC and print the new configuration string", func() {
+				newConfig := config.FailOver()
+				Expect(newConfig).NotTo(Equal(*config))
+
+				Expect(len(newConfig.Regions)).To(BeNumerically("==", 2))
+				Expect(newConfig.Regions[0].SatelliteLogs).To(Equal(3))
+				Expect(newConfig.Regions[0].SatelliteRedundancyMode).To(Equal(RedundancyModeOneSatelliteSingle))
+				Expect(len(newConfig.Regions[0].DataCenters)).To(BeNumerically("==", 2))
+				Expect(newConfig.Regions[0].DataCenters[0].Priority).To(Equal(0))
+				Expect(newConfig.Regions[0].DataCenters[0].ID).To(Equal("primary"))
+				Expect(newConfig.Regions[0].DataCenters[0].Satellite).To(Equal(0))
+				Expect(newConfig.Regions[0].DataCenters[1].Priority).To(Equal(1))
+				Expect(newConfig.Regions[0].DataCenters[1].ID).To(Equal("primary-sat"))
+				Expect(newConfig.Regions[0].DataCenters[1].Satellite).To(Equal(1))
+
+				Expect(len(newConfig.Regions[1].DataCenters)).To(BeNumerically("==", 2))
+				Expect(newConfig.Regions[1].SatelliteLogs).To(Equal(3))
+				Expect(newConfig.Regions[1].SatelliteRedundancyMode).To(Equal(RedundancyModeOneSatelliteDouble))
+				Expect(newConfig.Regions[1].DataCenters[0].Priority).To(Equal(1))
+				Expect(newConfig.Regions[1].DataCenters[0].ID).To(Equal("remote"))
+				Expect(newConfig.Regions[1].DataCenters[1].Priority).To(Equal(1))
+				Expect(newConfig.Regions[1].DataCenters[1].ID).To(Equal("remote-sat"))
+				Expect(newConfig.Regions[1].DataCenters[1].Satellite).To(Equal(1))
+
+				Expect(newConfig.GetConfigurationString(Versions.Default.String())).To(Equal("triple ssd usable_regions=1 logs=3 resolvers=1 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\"},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_single\\\"},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_double\\\"}]"))
+			})
+		})
+	})
+})
diff --git a/kubectl-fdb/cmd/analyze_test.go b/kubectl-fdb/cmd/analyze_test.go
index 5024b0ca..54f4f175 100644
--- a/kubectl-fdb/cmd/analyze_test.go
+++ b/kubectl-fdb/cmd/analyze_test.go
@@ -97,7 +97,7 @@ var _ = Describe("[plugin] analyze cluster", func() {
 			ExpectedErrMsg    string
 			ExpectedStdouMsg  string
 			AutoFix           bool
-			Force             bool
+			NoWait            bool
 			HasErrors         bool
 			IgnoredConditions []string
 		}
@@ -115,7 +115,7 @@ var _ = Describe("[plugin] analyze cluster", func() {
 				inBuffer := bytes.Buffer{}
 
 				cmd := newAnalyzeCmd(genericclioptions.IOStreams{In: &inBuffer, Out: &outBuffer, ErrOut: &errBuffer})
-				err := analyzeCluster(cmd, kubeClient, clusterName, namespace, tc.AutoFix, tc.Force, tc.IgnoredConditions)
+				err := analyzeCluster(cmd, kubeClient, clusterName, namespace, tc.AutoFix, tc.NoWait, tc.IgnoredConditions)
 
 				if err != nil && !tc.HasErrors {
 					Expect(err).To(HaveOccurred())
diff --git a/kubectl-fdb/cmd/configuration_test.go b/kubectl-fdb/cmd/configuration_test.go
index 1b4fd1ad..e027c376 100644
--- a/kubectl-fdb/cmd/configuration_test.go
+++ b/kubectl-fdb/cmd/configuration_test.go
@@ -21,12 +21,15 @@
 package cmd
 
 import (
+	ctx "context"
+
 	fdbv1beta2 "github.com/FoundationDB/fdb-kubernetes-operator/api/v1beta2"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
@@ -70,7 +73,7 @@ var _ = Describe("[plugin] configuration command", func() {
 				Expect(configuration).To(Equal("  usable_regions=0 logs=0 resolvers=0 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"test\\\",\\\"priority\\\":1}]}]"))
 			})
 
-			It("should return the same configuration string with failover", func() {
+			It("should return the same configuration string with fail-over", func() {
 				scheme := runtime.NewScheme()
 				_ = clientgoscheme.AddToScheme(scheme)
 				_ = fdbv1beta2.AddToScheme(scheme)
@@ -111,6 +114,8 @@ var _ = Describe("[plugin] configuration command", func() {
 											Satellite: 1,
 										},
 									},
+									SatelliteLogs:           3,
+									SatelliteRedundancyMode: fdbv1beta2.RedundancyModeOneSatelliteSingle,
 								},
 								{
 									DataCenters: []fdbv1beta2.DataCenter{
@@ -129,6 +134,8 @@ var _ = Describe("[plugin] configuration command", func() {
 											Satellite: 1,
 										},
 									},
+									SatelliteLogs:           3,
+									SatelliteRedundancyMode: fdbv1beta2.RedundancyModeOneSatelliteDouble,
 								},
 							},
 						},
@@ -146,7 +153,7 @@ var _ = Describe("[plugin] configuration command", func() {
 
 				configuration, err := getConfigurationString(kubeClient, "test", "test", false)
 				Expect(err).NotTo(HaveOccurred())
-				Expect(configuration).To(Equal("  usable_regions=0 logs=0 resolvers=0 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"satellite\\\":1}]},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\"},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"satellite\\\":1}]}]"))
+				Expect(configuration).To(Equal("  usable_regions=0 logs=0 resolvers=0 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_single\\\"},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\"},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_double\\\"}]"))
 			})
 
 			It("should return the configuration string with the modified priority", func() {
@@ -157,7 +164,54 @@ var _ = Describe("[plugin] configuration command", func() {
 
 				configuration, err := getConfigurationString(kubeClient, "test", "test", true)
 				Expect(err).NotTo(HaveOccurred())
-				Expect(configuration).To(Equal("  usable_regions=0 logs=0 resolvers=0 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\"},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"satellite\\\":1}]},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"satellite\\\":1}]}]"))
+				Expect(configuration).To(Equal("  usable_regions=0 logs=0 resolvers=0 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\"},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_single\\\"},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_double\\\"}]"))
+			})
+
+			When("Updating the config for the cluster", func() {
+				It("should update the config with the modified priority", func() {
+					scheme := runtime.NewScheme()
+					_ = clientgoscheme.AddToScheme(scheme)
+					_ = fdbv1beta2.AddToScheme(scheme)
+					kubeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(cluster).Build()
+
+					err := updateConfig(kubeClient, "test", "test", true, false)
+					Expect(err).NotTo(HaveOccurred())
+
+					var resCluster fdbv1beta2.FoundationDBCluster
+					err = kubeClient.Get(ctx.Background(), client.ObjectKey{
+						Namespace: "test",
+						Name:      "test",
+					}, &resCluster)
+					Expect(err).NotTo(HaveOccurred())
+
+					config := resCluster.Spec.DatabaseConfiguration
+					Expect(len(config.Regions)).To(BeNumerically("==", 2))
+
+					Expect(config.Regions[0].SatelliteRedundancyMode).To(Equal(fdbv1beta2.RedundancyModeOneSatelliteSingle))
+					Expect(config.Regions[0].SatelliteLogs).To(Equal(3))
+
+					Expect(config.Regions[0].DataCenters[0].ID).To(Equal("primary"))
+					Expect(config.Regions[0].DataCenters[0].Satellite).To(Equal(0))
+					Expect(config.Regions[0].DataCenters[0].Priority).To(Equal(0))
+					Expect(config.Regions[0].DataCenters[1].ID).To(Equal("primary-sat"))
+					Expect(config.Regions[0].DataCenters[1].Satellite).To(Equal(1))
+					Expect(config.Regions[0].DataCenters[1].Priority).To(Equal(1))
+					Expect(config.Regions[0].DataCenters[2].ID).To(Equal("remote-sat"))
+					Expect(config.Regions[0].DataCenters[2].Satellite).To(Equal(1))
+					Expect(config.Regions[0].DataCenters[2].Priority).To(Equal(0))
+
+					Expect(config.Regions[1].DataCenters[0].ID).To(Equal("remote"))
+					Expect(config.Regions[1].DataCenters[0].Satellite).To(Equal(0))
+					Expect(config.Regions[1].DataCenters[0].Priority).To(Equal(1))
+					Expect(config.Regions[1].DataCenters[1].ID).To(Equal("remote-sat"))
+					Expect(config.Regions[1].DataCenters[1].Satellite).To(Equal(1))
+					Expect(config.Regions[1].DataCenters[1].Priority).To(Equal(1))
+					Expect(config.Regions[1].DataCenters[2].ID).To(Equal("primary-sat"))
+					Expect(config.Regions[1].DataCenters[2].Satellite).To(Equal(1))
+					Expect(config.Regions[1].DataCenters[2].Priority).To(Equal(0))
+
+					Expect(config.GetConfigurationString(fdbv1beta2.Versions.Default.String())).To(Equal("  usable_regions=0 logs=0 resolvers=0 log_routers=0 remote_logs=0 proxies=3 regions=[{\\\"datacenters\\\":[{\\\"id\\\":\\\"primary\\\"},{\\\"id\\\":\\\"primary-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_single\\\"},{\\\"datacenters\\\":[{\\\"id\\\":\\\"remote\\\",\\\"priority\\\":1},{\\\"id\\\":\\\"remote-sat\\\",\\\"priority\\\":1,\\\"satellite\\\":1},{\\\"id\\\":\\\"primary-sat\\\",\\\"satellite\\\":1}],\\\"satellite_logs\\\":3,\\\"satellite_redundancy_mode\\\":\\\"one_satellite_double\\\"}]"))
+				})
 			})
 		})
 	})
diff --git a/kubectl-fdb/cmd/cordon_test.go b/kubectl-fdb/cmd/cordon_test.go
index 670fa0ca..6e938663 100644
--- a/kubectl-fdb/cmd/cordon_test.go
+++ b/kubectl-fdb/cmd/cordon_test.go
@@ -112,7 +112,7 @@ var _ = Describe("[plugin] cordon command", func() {
 				_ = fdbv1beta2.AddToScheme(scheme)
 				kubeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(&cluster, &podList, &nodeList).Build()
 
-				err := cordonNode(kubeClient, &cluster, input.nodes, namespace, input.WithExclusion, true)
+				err := cordonNode(kubeClient, &cluster, input.nodes, namespace, input.WithExclusion, false)
 				Expect(err).NotTo(HaveOccurred())
 
 				var resCluster fdbv1beta2.FoundationDBCluster
diff --git a/kubectl-fdb/cmd/remove_process_group_test.go b/kubectl-fdb/cmd/remove_process_group_test.go
index df46e946..8e0c3074 100644
--- a/kubectl-fdb/cmd/remove_process_group_test.go
+++ b/kubectl-fdb/cmd/remove_process_group_test.go
@@ -171,7 +171,7 @@ var _ = Describe("[plugin] remove instances command", func() {
 					_ = fdbv1beta2.AddToScheme(scheme)
 					kubeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(cluster, &podList).Build()
 
-					err := replaceProcessGroups(kubeClient, clusterName, tc.Instances, namespace, tc.WithExclusion, tc.WithShrink, true, tc.RemoveAllFailed)
+					err := replaceProcessGroups(kubeClient, clusterName, tc.Instances, namespace, tc.WithExclusion, tc.WithShrink, false, tc.RemoveAllFailed)
 					Expect(err).NotTo(HaveOccurred())
 
 					var resCluster fdbv1beta2.FoundationDBCluster
@@ -262,7 +262,7 @@ var _ = Describe("[plugin] remove instances command", func() {
 				When("adding the same process group to the removal list without exclusion", func() {
 					It("should add the process group to the removal without exclusion list", func() {
 						removals := []string{"instance-1"}
-						err := replaceProcessGroups(kubeClient, clusterName, removals, namespace, false, false, true, false)
+						err := replaceProcessGroups(kubeClient, clusterName, removals, namespace, false, false, false, false)
 						Expect(err).NotTo(HaveOccurred())
 
 						var resCluster fdbv1beta2.FoundationDBCluster
@@ -282,7 +282,7 @@ var _ = Describe("[plugin] remove instances command", func() {
 				When("adding the same process group to the removal list", func() {
 					It("should add the process group to the removal without exclusion list", func() {
 						removals := []string{"instance-1"}
-						err := replaceProcessGroups(kubeClient, clusterName, removals, namespace, true, false, true, false)
+						err := replaceProcessGroups(kubeClient, clusterName, removals, namespace, true, false, false, false)
 						Expect(err).NotTo(HaveOccurred())
 
 						var resCluster fdbv1beta2.FoundationDBCluster