Repository: rook/rook
Pull request #10909 (2022-09-07 11:00:21)

external: fix import errors for python2
remove duplicate import urllib.parse which is handled below
with try and except no need to import separately. Also, change
the way to get the python version.

Signed-off-by: subhamkrai <srai@redhat.com>

<!-- Please take a look at our [Contributing](https://rook.io/docs/rook/latest/Contributing/development-flow/)
documentation before submitting a Pull Request!
Thank you for contributing to Rook! -->

**Description of your changes:**

**Which issue is resolved by this Pull Request:**
Resolves #

**Checklist:**

- [ ] **Commit Message Formatting**: Commit titles and messages follow guidelines in the [developer guide](https://rook.io/docs/rook/latest/Contributing/development-flow/#commit-structure)).
- [ ] **Skip Tests for Docs**: If this is only a documentation change, add the label `skip-ci` on the PR.
- [ ] Reviewed the developer guide on [Submitting a Pull Request](https://rook.io/docs/rook/latest/Contributing/development-flow/#submitting-a-pull-request)
- [ ] [Pending release notes](https://github.com/rook/rook/blob/master/PendingReleaseNotes.md) updated with breaking and/or notable changes for the next minor release.
- [ ] Documentation has been updated, if necessary.
- [ ] Unit tests have been added, if necessary.
- [ ] Integration tests have been added, if necessary.


subhamkrai: I tested the script in python2
```
python2 script.py --rbd-data-pool-name rbd
[{"kind": "ConfigMap", "data": {"maxMonId": "0", "data": "catalina=10.70.39.4:6789", "mapping": "{}"}, "name": "rook-ceph-mon-endpoints"}, {"kind": "Secret", "data": {"mon-secret": "mon-secret", "fsid": "a00131fa-5d07-45b9-b7d4-62ee5ad6beb6", "admin-secret": "admin-secret"}, "name": "rook-ceph-mon"}, {"kind": "Secret", "data": {"userKey": "AQBzxW1hi129ERAAc7EEzJmC1eupI79Bdn2J6A==", "userID": "client.healthchecker"}, "name": "rook-ceph-operator-creds"}, {"kind": "CephCluster", "data": {"MonitoringPort": "9283", "MonitoringEndpoint": "10.70.39.5,10.70.39.7,10.70.39.4"}, "name": "monitoring-endpoint"}, {"kind": "Secret", "data": {"userKey": "AQDHhBljrQvENBAAmwzY8dUPqqdTdyKKTVqHAg==", "userID": "csi-rbd-node"}, "name": "rook-csi-rbd-node"}, {"kind": "Secret", "data": {"userKey": "AQDHhBljc6x5NxAAzJza2dLnJtpydE9Qy8Pd3w==", "userID": "csi-rbd-provisioner"}, "name": "rook-csi-rbd-provisioner"}, {"kind": "Secret", "data": {"adminID": "csi-cephfs-provisioner", "adminKey": "AQDIhBljPlRPAhAAtyLb750poH60tBNEN3x4Tg=="}, "name": "rook-csi-cephfs-provisioner"}, {"kind": "Secret", "data": {"adminID": "csi-cephfs-node", "adminKey": "AQDHhBljF29sOhAA25aoviqItp9rQQ7gKGiU6Q=="}, "name": "rook-csi-cephfs-node"}, {"kind": "Secret", "data": {"userKey": "https://commando.lab.eng.blr.redhat.com:8443/", "userID": "ceph-dashboard-link"}, "name": "rook-ceph-dashboard-link"}, {"kind": "StorageClass", "data": {"csi.storage.k8s.io/node-stage-secret-name": "rook-csi-rbd-node", "csi.storage.k8s.io/provisioner-secret-name": "rook-csi-rbd-provisioner", "csi.storage.k8s.io/controller-expand-secret-name": "rook-csi-rbd-provisioner", "pool": "rbd"}, "name": "ceph-rbd"}, {"kind": "StorageClass", "data": {"csi.storage.k8s.io/node-stage-secret-name": "rook-csi-cephfs-node", "csi.storage.k8s.io/provisioner-secret-name": "rook-csi-cephfs-provisioner", "pool": "cephfs_data", "fsName": "cephfs", "csi.storage.k8s.io/controller-expand-secret-name": "rook-csi-cephfs-provisioner"}, "name": "cephfs"}]
```
parth-gr: > I tested the script in python2
> 
> ```
> python2 script.py --rbd-data-pool-name rbd
> [{"kind": "ConfigMap", "data": {"maxMonId": "0", "data": "catalina=10.70.39.4:6789", "mapping": "{}"}, "name": "rook-ceph-mon-endpoints"}, {"kind": "Secret", "data": {"mon-secret": "mon-secret", "fsid": "a00131fa-5d07-45b9-b7d4-62ee5ad6beb6", "admin-secret": "admin-secret"}, "name": "rook-ceph-mon"}, {"kind": "Secret", "data": {"userKey": "AQBzxW1hi129ERAAc7EEzJmC1eupI79Bdn2J6A==", "userID": "client.healthchecker"}, "name": "rook-ceph-operator-creds"}, {"kind": "CephCluster", "data": {"MonitoringPort": "9283", "MonitoringEndpoint": "10.70.39.5,10.70.39.7,10.70.39.4"}, "name": "monitoring-endpoint"}, {"kind": "Secret", "data": {"userKey": "AQDHhBljrQvENBAAmwzY8dUPqqdTdyKKTVqHAg==", "userID": "csi-rbd-node"}, "name": "rook-csi-rbd-node"}, {"kind": "Secret", "data": {"userKey": "AQDHhBljc6x5NxAAzJza2dLnJtpydE9Qy8Pd3w==", "userID": "csi-rbd-provisioner"}, "name": "rook-csi-rbd-provisioner"}, {"kind": "Secret", "data": {"adminID": "csi-cephfs-provisioner", "adminKey": "AQDIhBljPlRPAhAAtyLb750poH60tBNEN3x4Tg=="}, "name": "rook-csi-cephfs-provisioner"}, {"kind": "Secret", "data": {"adminID": "csi-cephfs-node", "adminKey": "AQDHhBljF29sOhAA25aoviqItp9rQQ7gKGiU6Q=="}, "name": "rook-csi-cephfs-node"}, {"kind": "Secret", "data": {"userKey": "https://commando.lab.eng.blr.redhat.com:8443/", "userID": "ceph-dashboard-link"}, "name": "rook-ceph-dashboard-link"}, {"kind": "StorageClass", "data": {"csi.storage.k8s.io/node-stage-secret-name": "rook-csi-rbd-node", "csi.storage.k8s.io/provisioner-secret-name": "rook-csi-rbd-provisioner", "csi.storage.k8s.io/controller-expand-secret-name": "rook-csi-rbd-provisioner", "pool": "rbd"}, "name": "ceph-rbd"}, {"kind": "StorageClass", "data": {"csi.storage.k8s.io/node-stage-secret-name": "rook-csi-cephfs-node", "csi.storage.k8s.io/provisioner-secret-name": "rook-csi-cephfs-provisioner", "pool": "cephfs_data", "fsName": "cephfs", "csi.storage.k8s.io/controller-expand-secret-name": "rook-csi-cephfs-provisioner"}, "name": "cephfs"}]
> ```

I see the CI still fails
subhamkrai: testing result, ```[root@catalina ~]# python2 script.py --rbd-data-pool-name rbd
[{"kind": "ConfigMap", "data": {"maxMonId": "0", "data": "catalina=10.70.39.4:6789", "mapping": "{}"}, "name": "rook-ceph-mon-endpoints"}, {"kind": "Secret", "data": {"mon-secret": "mon-secret", "fsid": "a00131fa-5d07-45b9-b7d4-62ee5ad6beb6", "admin-secret": "admin-secret"}, "name": "rook-ceph-mon"}, {"kind": "Secret", "data": {"userKey": "AQBzxW1hi129ERAAc7EEzJmC1eupI79Bdn2J6A==", "userID": "client.healthchecker"}, "name": "rook-ceph-operator-creds"}, {"kind": "CephCluster", "data": {"MonitoringPort": "9283", "MonitoringEndpoint": "10.70.39.5,10.70.39.7,10.70.39.4"}, "name": "monitoring-endpoint"}, {"kind": "Secret", "data": {"userKey": "AQDHhBljrQvENBAAmwzY8dUPqqdTdyKKTVqHAg==", "userID": "csi-rbd-node"}, "name": "rook-csi-rbd-node"}, {"kind": "Secret", "data": {"userKey": "AQDHhBljc6x5NxAAzJza2dLnJtpydE9Qy8Pd3w==", "userID": "csi-rbd-provisioner"}, "name": "rook-csi-rbd-provisioner"}, {"kind": "Secret", "data": {"adminID": "csi-cephfs-provisioner", "adminKey": "AQDIhBljPlRPAhAAtyLb750poH60tBNEN3x4Tg=="}, "name": "rook-csi-cephfs-provisioner"}, {"kind": "Secret", "data": {"adminID": "csi-cephfs-node", "adminKey": "AQDHhBljF29sOhAA25aoviqItp9rQQ7gKGiU6Q=="}, "name": "rook-csi-cephfs-node"}, {"kind": "Secret", "data": {"userKey": "https://commando.lab.eng.blr.redhat.com:8443/", "userID": "ceph-dashboard-link"}, "name": "rook-ceph-dashboard-link"}, {"kind": "StorageClass", "data": {"csi.storage.k8s.io/node-stage-secret-name": "rook-csi-rbd-node", "csi.storage.k8s.io/provisioner-secret-name": "rook-csi-rbd-provisioner", "csi.storage.k8s.io/controller-expand-secret-name": "rook-csi-rbd-provisioner", "pool": "rbd"}, "name": "ceph-rbd"}, {"kind": "StorageClass", "data": {"csi.storage.k8s.io/node-stage-secret-name": "rook-csi-cephfs-node", "csi.storage.k8s.io/provisioner-secret-name": "rook-csi-cephfs-provisioner", "pool": "cephfs_data", "fsName": "cephfs", "csi.storage.k8s.io/controller-expand-secret-name": "rook-csi-cephfs-provisioner"}, "name": "cephfs"}]```


Patch:
diff --git a/Documentation/CRDs/Object-Storage/ceph-object-multisite-crd.md b/Documentation/CRDs/Object-Storage/ceph-object-multisite-crd.md
index 8a22065c9..80a8fa5ea 100644
--- a/Documentation/CRDs/Object-Storage/ceph-object-multisite-crd.md
+++ b/Documentation/CRDs/Object-Storage/ceph-object-multisite-crd.md
@@ -86,7 +86,6 @@ spec:
       codingChunks: 1
   customEndpoints:
     - "http://rgw-a.fqdn"
-  preservePoolsOnDelete: true
 ```
 
 ### Object Zone Settings
@@ -107,14 +106,8 @@ The pools allow all of the settings defined in the Pool CRD spec. For more detai
 * `dataPool`: The settings to create the object store data pool. Can use replication or erasure coding.
 * `customEndpoints`:  Specify the endpoint(s) that will accept multisite replication traffic for this zone. You may include the port in the definition if necessary. For example: "https://my-object-store.my-domain.net:443". By default, Rook will set this to the DNS name of the ClusterIP Service created for the CephObjectStore that corresponds to this zone.
 
-  Most multisite configurations will not exist within the same Kubernetes cluster, meaning the default value will not be useful. In these cases, you will be required to create your own custom ingress resource for the CephObjectStore in order to make the zone available for replication. You must add the endpoint for your custom ingress resource to this list to allow the store to accept replication traffic.
+ Most multisite configurations will not exist within the same Kubernetes cluster, meaning the default value will not be useful. In these cases, you will be required to create your own custom ingress resource for the CephObjectStore in order to make the zone available for replication. You must add the endpoint for your custom ingress resource to this list to allow the store to accept replication traffic.
 
-  In the case of multiple stores (or multiple endpoints for a single store), you are not required to put all endpoints in this list. Only specify the endpoints that should be used for replication traffic.
+ In the case of multiple stores (or multiple endpoints for a single store), you are not required to put all endpoints in this list. Only specify the endpoints that should be used for replication traffic.
 
-  If you update `customEndpoints` to return to an empty list, you must the Rook operator to automatically add the CephObjectStore service endpoint to Ceph's internal configuration.
-
- * `preservePoolsOnDelete`: If it is set to 'true' the pools used to support the CephObjectZone will remain when it is deleted. This is a security measure to avoid accidental loss of data. It is set to 'true' by default.
-
-  It is better to check whether data synced with other peer zones before triggering the deletion to avoid accidental loss of data via steps mentioned [here](https://docs.ceph.com/en/latest/radosgw/multisite/#check-synchronization-status)
-
-  When deleting a CephObjectZone, deletion will be blocked until all `CephObjectStores` belonging to the zone are removed.
+ If you update `customEndpoints` to return to an empty list, you must the Rook operator to automatically add the CephObjectStore service endpoint to Ceph's internal configuration.
diff --git a/Documentation/CRDs/Object-Storage/ceph-object-store-crd.md b/Documentation/CRDs/Object-Storage/ceph-object-store-crd.md
index babc909be..f509af9ca 100644
--- a/Documentation/CRDs/Object-Storage/ceph-object-store-crd.md
+++ b/Documentation/CRDs/Object-Storage/ceph-object-store-crd.md
@@ -260,7 +260,3 @@ Rook will warn about which buckets are blocking deletion in three ways:
 1. An event will be registered on the CephObjectStore resource
 1. A status condition will be added to the CephObjectStore resource
 1. An error will be added to the Rook Ceph Operator log
-
-If the CephObjectStore is configured in a [multisite setup](ceph-object-multisite-crd.md) the above conditions are applicable only to stores that belong to a single master zone.
-Otherwise the conditions are ignored. Even if the store is removed the user can access the
-data from a peer object store.
diff --git a/Documentation/Getting-Started/Prerequisites/prerequisites.md b/Documentation/Getting-Started/Prerequisites/prerequisites.md
index 526110872..f79c2dff9 100644
--- a/Documentation/Getting-Started/Prerequisites/prerequisites.md
+++ b/Documentation/Getting-Started/Prerequisites/prerequisites.md
@@ -19,7 +19,7 @@ In order to configure the Ceph storage cluster, at least one of these local stor
 
 * Raw devices (no partitions or formatted filesystems)
 * Raw partitions (no formatted filesystem)
-* Persistent Volumes available from a storage class in `block` mode
+* PVs available from a storage class in `block` mode
 
 You can confirm whether your partitions or devices are formatted with filesystems with the following command.
 
diff --git a/Documentation/Getting-Started/quickstart.md b/Documentation/Getting-Started/quickstart.md
index aa3ff3ef3..5c0caa9e5 100644
--- a/Documentation/Getting-Started/quickstart.md
+++ b/Documentation/Getting-Started/quickstart.md
@@ -26,6 +26,8 @@ To make sure you have a Kubernetes cluster that is ready for `Rook`, you can [fo
 In order to configure the Ceph storage cluster, at least one of these local storage options are required:
 
 * Raw devices (no partitions or formatted filesystems)
+  * This requires `lvm2` to be installed on the host.
+    To avoid this dependency, you can create a single full-disk partition on the disk (see below)
 * Raw partitions (no formatted filesystem)
 * Persistent Volumes available from a storage class in `block` mode
 
diff --git a/Documentation/Helm-Charts/operator-chart.md b/Documentation/Helm-Charts/operator-chart.md
index 8ec872db7..7db6fadea 100644
--- a/Documentation/Helm-Charts/operator-chart.md
+++ b/Documentation/Helm-Charts/operator-chart.md
@@ -66,7 +66,6 @@ The following tables lists the configurable parameters of the rook-operator char
 | `csi.enableRbdDriver`               | Enable Ceph CSI RBD driver.                                                                                                                      | `true`                                                    |
 | `csi.enableCephfsDriver`            | Enable Ceph CSI CephFS driver.                                                                                                                   | `true`                                                    |
 | `csi.enableCephfsSnapshotter`       | Enable Snapshotter in CephFS provisioner pod.                                                                                                    | `true`                                                    |
-| `csi.enableNFSSnapshotter`          | Enable Snapshotter in NFS provisioner pod.                                                                                                       | `true`                                                    |
 | `csi.enableRBDSnapshotter`          | Enable Snapshotter in RBD provisioner pod.                                                                                                       | `true`                                                    |
 | `csi.pluginPriorityClassName`       | PriorityClassName to be set on csi driver plugin pods.                                                                                           | `<none>`                                                  |
 | `csi.provisionerPriorityClassName`  | PriorityClassName to be set on csi driver provisioner pods.                                                                                      | `<none>`                                                  |
@@ -125,10 +124,10 @@ The following tables lists the configurable parameters of the rook-operator char
 | `csi.attacher.image`                | Kubernetes CSI Attacher image.                                                                                                                   | `registry.k8s.io/sig-storage/csi-attacher:v3.4.0`              |
 | `csi.cephfsPodLabels`               | Labels to add to the CSI CephFS Pods.                                                                                                            | `<none>`                                                  |
 | `csi.rbdPodLabels`                  | Labels to add to the CSI RBD Pods.                                                                                                               | `<none>`                                                  |
+| `csi.volumeReplication.enabled`     | Enable Volume Replication.                                                                                                                       | `false`                                                   |
+| `csi.volumeReplication.image`       | Volume Replication Controller image.                                                                                                             | `quay.io/csiaddons/volumereplication-operator:v0.3.0`     |
 | `csi.csiAddons.enabled`             | Enable CSIAddons                                                                                                                                 | `false`                                                   |
-| `csi.csiAddons.image`               | CSIAddons Sidecar image.                                                                                                                         | `quay.io/csiaddons/k8s-sidecar:v0.5.0`                    |
-| `csi.topology.enabled`              | Enable topology based provisioning.                                                                                                              | `false`                                                   |
-| `csi.topology.domainLabels`         | domainLabels define which node labels to use as domains for CSI nodeplugins to advertise their domains.                                          | `<none>`                                                  |
+| `csi.csiAddons.image`               | CSIAddons Sidecar image.                                                                                                                         | `quay.io/csiaddons/k8s-sidecar:v0.4.0`                    |
 | `csi.nfs.enabled`                   | Enable nfs driver.                                                                                                                               | `false`                                                   |
 | `admissionController.tolerations`   | Array of tolerations in YAML format which will be added to admission controller deployment.                                                      | `<none>`                                                  |
 | `admissionController.nodeAffinity`  | The node labels for affinity of the admission controller deployment [^1]                                                                         | `<none>`                                                  |
diff --git a/Documentation/Storage-Configuration/Advanced/key-management-system.md b/Documentation/Storage-Configuration/Advanced/key-management-system.md
index bf1115a6e..ad0c5d4fe 100644
--- a/Documentation/Storage-Configuration/Advanced/key-management-system.md
+++ b/Documentation/Storage-Configuration/Advanced/key-management-system.md
@@ -15,16 +15,14 @@ The `security` section contains settings related to encryption of the cluster.
 
 Supported KMS providers:
 
-- [Vault](#vault)
-  - [Authentication methods](#authentication-methods)
-    - [Token-based authentication](#token-based-authentication)
-    - [Kubernetes-based authentication](#kubernetes-based-authentication)
-  - [General Vault configuration](#general-vault-configuration)
-  - [TLS configuration](#tls-configuration)
-- [IBM Key Protect](#ibm-key-protect)
-  - [Configuration](#configuration)
-- [Key Management Interoperability Protocol](#key-management-interoperability-protocol)
-  - [Configuration](#configuration-1)
+* [Vault](#vault)
+  * [Authentication methods](#authentication-methods)
+    * [Token-based authentication](#token-based-authentication)
+    * [Kubernetes-based authentication](#kubernetes-based-authentication)
+  * [General Vault configuration](#general-vault-configuration)
+  * [TLS configuration](#tls-configuration)
+* [IBM Key Protect](#ibm-key-protect)
+  * [Configuration](#configuration)
 
 ## Vault
 
@@ -283,47 +281,3 @@ More options are supported such as:
   [region](https://cloud.ibm.com/docs/key-protect?topic=key-protect-regions). Defaults to `https://us-south.kms.cloud.ibm.com`.
 * `IBM_TOKEN_URL`: the URL of the Key Protect instance to retrieve the token. Defaults to
   `https://iam.cloud.ibm.com/oidc/token`. Only needed for private instances.
-
-## Key Management Interoperability Protocol
-
-Rook supports storing OSD encryption keys in [Key Management Interoperability Protocol (KMIP)](https://www.ibm.com/cloud/key-protect) supported
-KMS.
-The current implementation stores OSD encryption
-keys using the [Register](https://docs.oasis-open.org/kmip/kmip-spec/v2.0/os/kmip-spec-v2.0-os.html#_Toc6497565) operation.
-Key is fetched and deleted using [Get](https://docs.oasis-open.org/kmip/kmip-spec/v2.0/os/kmip-spec-v2.0-os.html#_Toc6497545)
-and [Destroy](https://docs.oasis-open.org/kmip/kmip-spec/v2.0/os/kmip-spec-v2.0-os.html#_Toc6497541) operations respectively.
-
-### Configuration
-
-The Secret with credentials for the KMIP KMS is expected to contain the following.
-
-```yaml
-apiVersion: v1
-kind: Secret
-metadata:
-  name: kmip-credentials
-  namespace: rook-ceph
-stringData:
-  CA_CERT: <ca certificate>
-  CLIENT_CERT: <client certificate>
-  CLIENT_KEY: <client key>
-```
-
-In order for Rook to connect to KMIP, you must configure the following in your `CephCluster` template:
-
-```yaml
-security:
-  kms:
-    # name of the k8s config map containing all the kms connection details
-    connectionDetails:
-      KMS_PROVIDER: kmip
-      KMIP_ENDPOINT: <KMIP endpoint address>
-      # (optional) The endpoint server name. Useful when the KMIP endpoint does not have a DNS entry.
-      TLS_SERVER_NAME: <tls server name>
-      # (optional) Network read timeout, in seconds. The default value is 10.
-      READ_TIMEOUT: <read timeout>
-      # (optional) Network write timeout, in seconds. The default value is 10.
-      WRITE_TIMEOUT: <write timeout>
-    # name of the k8s secret containing the credentials.
-    tokenSecretName: kmip-credentials
-```
diff --git a/Documentation/Storage-Configuration/Block-Storage-RBD/rbd-mirroring.md b/Documentation/Storage-Configuration/Block-Storage-RBD/rbd-mirroring.md
index d22f1b925..bc6b3d2de 100644
--- a/Documentation/Storage-Configuration/Block-Storage-RBD/rbd-mirroring.md
+++ b/Documentation/Storage-Configuration/Block-Storage-RBD/rbd-mirroring.md
@@ -165,13 +165,13 @@ APIs for storage disaster recovery. The extended APIs are provided via Custom
 Resource Definition(CRD). Create the VolumeReplication CRDs on all the peer clusters.
 
 ```console
-kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.5.0/config/crd/bases/replication.storage.openshift.io_volumereplicationclasses.yaml
-kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.5.0/config/crd/bases/replication.storage.openshift.io_volumereplications.yaml
+kubectl create -f https://raw.githubusercontent.com/csi-addons/volume-replication-operator/v0.3.0/config/crd/bases/replication.storage.openshift.io_volumereplications.yaml
+kubectl create -f https://raw.githubusercontent.com/csi-addons/volume-replication-operator/v0.3.0/config/crd/bases/replication.storage.openshift.io_volumereplicationclasses.yaml
 ```
 
 ## Enable CSI Replication Sidecars
 
-To achieve RBD Mirroring, `csi-omap-generator` and `csi-addons`
+To achieve RBD Mirroring, `csi-omap-generator` and `volume-replication`
  containers need to be deployed in the RBD provisioner pods, which are not enabled by default.
 
 * **Omap Generator**: Omap generator is a sidecar container that when
@@ -182,13 +182,13 @@ To achieve RBD Mirroring, `csi-omap-generator` and `csi-addons`
 
 * **Volume Replication Operator**: Volume Replication Operator is a
  kubernetes operator that provides common and reusable APIs for
- storage disaster recovery. The volume replication operation is
- supported by the [CSIAddons](https://github.com/csi-addons/kubernetes-csi-addons#readme)
+ storage disaster recovery.
  It is based on [csi-addons/spec](https://github.com/csi-addons/spec)
  specification and can be used by any storage provider.
+ For more details, refer to [volume replication operator](https://github.com/csi-addons/volume-replication-operator).
 
 Execute the following steps on each peer cluster to enable the
- OMap generator and CSIADDONS sidecars:
+ OMap generator and Volume Replication sidecars:
 
 * Edit the `rook-ceph-operator-config` configmap and add the
  following configurations
@@ -202,7 +202,7 @@ Add the following properties if not present:
 ```yaml
 data:
   CSI_ENABLE_OMAP_GENERATOR: "true"
-  CSI_ENABLE_CSIADDONS: "true"
+  CSI_ENABLE_VOLUME_REPLICATION: "true"
 ```
 
 * After updating the configmap with those settings, two new sidecars
@@ -220,6 +220,10 @@ the storage admin information required for the volume replication operator.
 * **VolumeReplication**: *VolumeReplication* is a namespaced resource that contains references to storage object to be replicated and VolumeReplicationClass
 corresponding to the driver providing replication.
 
+!!! info
+    For more information, please refer to the
+    [volume-replication-operator](https://github.com/csi-addons/volume-replication-operator).
+
 ## Enable mirroring on a PVC
 
 Below guide assumes that we have a PVC (rbd-pvc) in BOUND state; created using
diff --git a/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-drivers.md b/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-drivers.md
index 3c3dc40d7..ea2f023e2 100644
--- a/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-drivers.md
+++ b/Documentation/Storage-Configuration/Ceph-CSI/ceph-csi-drivers.md
@@ -71,17 +71,26 @@ PVC will be updated to new size.
 
 ## RBD Mirroring
 
-To support RBD Mirroring, the [CSI-Addons sidecar](https://github.com/csi-addons/kubernetes-csi-addons#readme) will be started in the RBD provisioner pod.
-The CSI-Addons supports the VolumeReplication operation. The volume replication controller provides common and reusable APIs for storage disaster recovery. It is based on [csi-addons/spec](https://github.com/csi-addons/spec) specification and can be used by any storage provider.
+To support RBD Mirroring, the [Volume Replication Operator](https://github.com/csi-addons/volume-replication-operator/blob/main/README.md) will be started in the RBD provisioner pod.
+The Volume Replication Operator is a kubernetes operator that provides common and reusable APIs for storage disaster recovery. It is based on [csi-addons/spec](https://github.com/csi-addons/spec) specification and can be used by any storage provider.
 It follows the controller pattern and provides extended APIs for storage disaster recovery. The extended APIs are provided via Custom Resource Definitions (CRDs).
 
 ### Prerequisites
 
 Kubernetes version 1.21 or greater is required.
 
-### Enable CSIAddons Sidecar
+### Enable volume replication
 
-To enable the CSIAddons sidecar and deploy the controller, Please follow the steps [below](#csi-addons-controller)
+1. Install the volume replication CRDs:
+
+    ```console
+    kubectl create -f https://raw.githubusercontent.com/csi-addons/volume-replication-operator/v0.3.0/config/crd/bases/replication.storage.openshift.io_volumereplications.yaml
+    kubectl create -f https://raw.githubusercontent.com/csi-addons/volume-replication-operator/v0.3.0/config/crd/bases/replication.storage.openshift.io_volumereplicationclasses.yaml
+    ```
+
+2. Enable the volume replication controller:
+    * For Helm deployments see the [`csi.volumeReplication.enabled` setting](../../Helm-Charts/operator-chart.md#configuration).
+    * For non-Helm deployments set `CSI_ENABLE_VOLUME_REPLICATION: "true"` in operator.yaml
 
 ## Ephemeral volume support
 
@@ -123,9 +132,9 @@ The CSI-Addons Controller handles the requests from users to initiate an operati
 Users can deploy the controller by running the following commands:
 
 ```console
-kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.5.0/deploy/controller/crds.yaml
-kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.5.0/deploy/controller/rbac.yaml
-kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.5.0/deploy/controller/setup-controller.yaml
+kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.4.0/deploy/controller/crds.yaml
+kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.4.0/deploy/controller/rbac.yaml
+kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.4.0/deploy/controller/setup-controller.yaml
 ```
 
 This creates the required crds and configure permissions.
@@ -157,14 +166,11 @@ kubectl patch cm rook-ceph-operator-config -nrook-ceph -p $'data:\n "CSI_ENABLE_
 CSI-Addons supports the following operations:
 
 * Reclaim Space
-  * [Creating a ReclaimSpaceJob](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.5.0/docs/reclaimspace.md#reclaimspacejob)
-  * [Creating a ReclaimSpaceCronJob](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.5.0/docs/reclaimspace.md#reclaimspacecronjob)
-  * [Annotating PersistentVolumeClaims](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.5.0/docs/reclaimspace.md#annotating-perstentvolumeclaims)
+  * [Creating a ReclaimSpaceJob](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.3.0/docs/reclaimspace.md#reclaimspacejob)
+  * [Creating a ReclaimSpaceCronJob](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.3.0/docs/reclaimspace.md#reclaimspacecronjob)
+  * [Annotating PersistentVolumeClaims](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.3.0/docs/reclaimspace.md#annotating-perstentvolumeclaims)
 * Network Fencing
-  * [Creating a NetworkFence](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.5.0/docs/networkfence.md)
-* Volume Replication
-  * [Creating VolumeReplicationClass](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.5.0/docs/volumereplicationclass.md)
-  * [Creating VolumeReplication CR](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.5.0/docs/volumereplication.md)
+  * [Creating a NetworkFence](https://github.com/csi-addons/kubernetes-csi-addons/blob/v0.3.0/docs/networkfence.md)
 
 ## Enable RBD Encryption Support
 
diff --git a/Documentation/Storage-Configuration/Ceph-CSI/custom-images.md b/Documentation/Storage-Configuration/Ceph-CSI/custom-images.md
index 66e3c15a7..f997c3ec6 100644
--- a/Documentation/Storage-Configuration/Ceph-CSI/custom-images.md
+++ b/Documentation/Storage-Configuration/Ceph-CSI/custom-images.md
@@ -24,7 +24,8 @@ ROOK_CSI_PROVISIONER_IMAGE: "k8s.gcr.io/sig-storage/csi-provisioner:v3.2.1"
 ROOK_CSI_ATTACHER_IMAGE: "k8s.gcr.io/sig-storage/csi-attacher:v3.5.0"
 ROOK_CSI_RESIZER_IMAGE: "k8s.gcr.io/sig-storage/csi-resizer:v1.5.0"
 ROOK_CSI_SNAPSHOTTER_IMAGE: "k8s.gcr.io/sig-storage/csi-snapshotter:v6.0.1"
-ROOK_CSIADDONS_IMAGE: "quay.io/csiaddons/k8s-sidecar:v0.5.0"
+CSI_VOLUME_REPLICATION_IMAGE: "quay.io/csiaddons/volumereplication-operator:v0.3.0"
+ROOK_CSIADDONS_IMAGE: "quay.io/csiaddons/k8s-sidecar:v0.4.0"
 ```
 
 ### **Use default images**
diff --git a/Documentation/Storage-Configuration/NFS/nfs-csi-driver.md b/Documentation/Storage-Configuration/NFS/nfs-csi-driver.md
index 640d12f56..e03383f07 100644
--- a/Documentation/Storage-Configuration/NFS/nfs-csi-driver.md
+++ b/Documentation/Storage-Configuration/NFS/nfs-csi-driver.md
@@ -97,109 +97,3 @@ application pod.
 ### Connecting to an export directly
 After a PVC is created successfully, the `share` parameter set on the resulting PV contains the
 `share` path which can be used as the export path when [mounting the export manually](nfs.md#mounting-exports).
-
-## Taking snapshots of NFS exports
-
-NFS export PVCs can be snapshotted and later restored to new PVCs.
-
-### Creating snapshots
-
-First, create a VolumeSnapshotClass as in the example [here](https://github.com/rook/rook/tree/master/deploy/examples/csi/nfs/snapshotclass.yaml). The `csi.storage.k8s.io/snapshotter-secret-name` parameter should reference the name of the secret created for the cephfsplugin [here](https://github.com/rook/rook/tree/master/deploy/examples/csi/cephfs/snapshotclass.yaml).
-
-```console
-kubectl create -f deploy/examples/csi/nfs/snapshotclass.yaml
-```
-
-In [snapshot](https://github.com/rook/rook/tree/master/deploy/examples/csi/nfs/snapshot.yaml),
-`volumeSnapshotClassName` should be the name of the VolumeSnapshotClass
-previously created. The `persistentVolumeClaimName` should be the name of the
-PVC which is already created by the NFS CSI driver.
-
-```console
-kubectl create -f deploy/examples/csi/nfs/snapshot.yaml
-```
-
-### Verifying snapshots
-
-```console
-$ kubectl get volumesnapshotclass
-NAME                        DRIVER                          DELETIONPOLICY   AGE
-csi-nfslugin-snapclass      rook-ceph.nfs.csi.ceph.com      Delete           3h55m
-```
-
-```console
-$ kubectl get volumesnapshot
-NAME                  READYTOUSE   SOURCEPVC   SOURCESNAPSHOTCONTENT  RESTORESIZE   SNAPSHOTCLASS                SNAPSHOTCONTENT                                   CREATIONTIME   AGE
-nfs-pvc-snapshot      true         nfs-pvc                            1Gi           csi-nfsplugin-snapclass      snapcontent-34476204-a14a-4d59-bfbc-2bbba695652c  3h50m          3h51m
-```
-
-The snapshot will be ready to restore to a new PVC when `READYTOUSE` field of the
-volumesnapshot is set to true.
-
-### Restoring snapshot to a new PVC
-
-In
-[pvc-restore](https://github.com/rook/rook/tree/master/deploy/examples/csi/nfs/pvc-restore.yaml),
-`dataSource` name should be the name of the VolumeSnapshot previously
-created. The `dataSource` kind should be "VolumeSnapshot".
-
-Create a new PVC from the snapshot.
-
-```console
-kubectl create -f deploy/examples/csi/nfs/pvc-restore.yaml
-```
-
-### Verifying restored PVC Creation
-
-```console
-$ kubectl get pvc
-NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
-nfs-pvc              Bound    pvc-74734901-577a-11e9-b34f-525400581048   1Gi        RWX            rook-nfs          55m
-nfs-pvc-restore      Bound    pvc-95308c75-6c93-4928-a551-6b5137192209   1Gi        RWX            rook-nfs          34s
-```
-
-### Cleaning up snapshot resource
-
-To clean your cluster of the resources created by this example, run the following:
-
-```console
-kubectl delete -f deploy/examples/csi/nfs/pvc-restore.yaml
-kubectl delete -f deploy/examples/csi/nfs/snapshot.yaml
-kubectl delete -f deploy/examples/csi/nfs/snapshotclass.yaml
-```
-
-## Cloning NFS exports
-
-### Creating clones
-
-In
-[pvc-clone](https://github.com/rook/rook/tree/master/deploy/examples/csi/nfs/pvc-clone.yaml),
-`dataSource` should be the name of the PVC which is already created by NFS
-CSI driver. The `dataSource` kind should be "PersistentVolumeClaim" and also storageclass
-should be same as the source PVC.
-
-Create a new PVC Clone from the PVC as in the example [here](https://github.com/rook/rook/tree/master/deploy/examples/csi/nfs/pvc-clone.yaml).
-
-```console
-kubectl create -f deploy/examples/csi/nfs/pvc-clone.yaml
-```
-
-### Verifying a cloned PVC
-
-```console
-kubectl get pvc
-```
-
->```
->NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
->nfs-pvc           Bound    pvc-1ea51547-a88b-4ab0-8b4a-812caeaf025d   1Gi        RWX            rook-nfs       39m
->nfs-pvc-clone     Bound    pvc-b575bc35-d521-4c41-b4f9-1d733cd28fdf   1Gi        RWX            rook-nfs       8s
->```
-
-### Cleaning up clone resources
-
-To clean your cluster of the resources created by this example, run the following:
-
-```console
-kubectl delete -f deploy/examples/csi/nfs/pvc-clone.yaml
-```
diff --git a/Documentation/Upgrade/rook-upgrade.md b/Documentation/Upgrade/rook-upgrade.md
index f9a70e543..f7a3fd62c 100644
--- a/Documentation/Upgrade/rook-upgrade.md
+++ b/Documentation/Upgrade/rook-upgrade.md
@@ -52,11 +52,6 @@ those releases.
 * The minimum supported version of Ceph-CSI is v3.6.0. You must update to at least this version of
   Ceph-CSI before or at the same time you update the Rook operator image to v1.10
 
-* Before upgrading to K8s 1.25, ensure that you are running at least Rook v1.9.10, or v1.10.x.
-  If you upgrade to K8s 1.25 before upgrading to v1.9.10 or newer, the Helm chart may be
-  blocked from upgrading to newer versions of Rook. See [#10826](https://github.com/rook/rook/issues/10826)
-  for a possible workaround.
-
 ## Considerations
 
 With this upgrade guide, there are a few notes to consider:
diff --git a/build/crds/build-crds.sh b/build/crds/build-crds.sh
index ffa9b8ecf..6eb31b1dc 100755
--- a/build/crds/build-crds.sh
+++ b/build/crds/build-crds.sh
@@ -51,12 +51,26 @@ copy_ob_obc_crds() {
   cp -f "${SCRIPT_ROOT}/deploy/olm/assemble/objectbucket.io_objectbuckets.yaml" "$OLM_CATALOG_DIR"
 }
 
+copy_volume_replication_crds() {
+  volume_replication_dir=${SCRIPT_ROOT}/.cache/crds/volumereplication
+  volume_replication_crd=replication.storage.openshift.io_volumereplications.yaml
+  volume_replication_class_crd=replication.storage.openshift.io_volumereplicationclasses.yaml
+  if [[ ! -d "${volume_replication_dir}" ]]; then
+    mkdir -p "${volume_replication_dir}"
+    VOLUME_REPLICATION_URL=${VOLUME_REPLICATION_URL:-https://raw.githubusercontent.com/csi-addons/volume-replication-operator/v0.3.0/config/crd/bases}
+    curl -L ${VOLUME_REPLICATION_URL}/${volume_replication_crd} -o ${volume_replication_dir}/${volume_replication_crd}
+    curl -L ${VOLUME_REPLICATION_URL}/${volume_replication_class_crd} -o ${volume_replication_dir}/${volume_replication_class_crd}
+  fi
+
+  cp -f "${volume_replication_dir}/${volume_replication_crd}" "$OLM_CATALOG_DIR"
+  cp -f "${volume_replication_dir}/${volume_replication_class_crd}" "$OLM_CATALOG_DIR"
+}
+
 generating_crds_v1() {
   echo "Generating ceph crds"
   "$CONTROLLER_GEN_BIN_PATH" "$CRD_OPTIONS" paths="./pkg/apis/ceph.rook.io/v1" output:crd:artifacts:config="$OLM_CATALOG_DIR"
   # the csv upgrade is failing on the volumeClaimTemplate.metadata.annotations.crushDeviceClass unless we preserve the annotations as an unknown field
   $YQ_BIN_PATH eval --inplace '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.storage.properties.storageClassDeviceSets.items.properties.volumeClaimTemplates.items.properties.metadata.properties.annotations.x-kubernetes-preserve-unknown-fields = true' "${OLM_CATALOG_DIR}"/ceph.rook.io_cephclusters.yaml
-  $YQ_BIN_PATH eval --inplace '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.security.properties.sssd.properties.sidecar.properties.sssdConfigFile.properties.volumeSource.properties.hostPath |= with(select(.description != null);.description |= sub("--- ", ""))' "${OLM_CATALOG_DIR}"/ceph.rook.io_cephnfses.yaml
 }
 
 generating_main_crd() {
@@ -112,3 +126,7 @@ echo "---" >> "$CEPH_CRDS_FILE_PATH" # yq doesn't output the first doc separator
 $YQ_BIN_PATH eval-all '.' "${CRD_FILES[@]}" >> "$CEPH_CRDS_FILE_PATH"
 
 build_helm_resources
+
+# copy the volume replication crds last so they won't be included in the helm chart or crds.yaml,
+# we just want them to end up owned by the csv
+copy_volume_replication_crds
diff --git a/build/rbac/get-helm-rbac.sh b/build/rbac/get-helm-rbac.sh
index 8fbce04d4..c5ec28285 100755
--- a/build/rbac/get-helm-rbac.sh
+++ b/build/rbac/get-helm-rbac.sh
@@ -27,6 +27,6 @@ done
 
 echo "generating Helm template with options: ${options[*]}" &>/dev/stderr
 
-${HELM} template ../../deploy/charts/rook-ceph "${options[@]}" --debug | ./keep-rbac-yaml.sh
+${HELM} template ../../deploy/charts/rook-ceph "${options[@]}" | ./keep-rbac-yaml.sh
 
 popd &>/dev/stderr
diff --git a/deploy/charts/rook-ceph-cluster/templates/cephobjectstore.yaml b/deploy/charts/rook-ceph-cluster/templates/cephobjectstore.yaml
index 90f5b152a..ee3b58d53 100644
--- a/deploy/charts/rook-ceph-cluster/templates/cephobjectstore.yaml
+++ b/deploy/charts/rook-ceph-cluster/templates/cephobjectstore.yaml
@@ -13,7 +13,7 @@ apiVersion: storage.k8s.io/v1
 kind: StorageClass
 metadata:
   name: {{ $objectstore.storageClass.name }}
-provisioner: {{ $root.Release.Namespace }}.ceph.rook.io/bucket
+provisioner: {{ $root.Values.operatorNamespace }}.ceph.rook.io/bucket
 reclaimPolicy: {{ default "Delete" $objectstore.storageClass.reclaimPolicy }}
 parameters:
   objectStoreName: {{ $objectstore.name }}
diff --git a/deploy/charts/rook-ceph/templates/clusterrole.yaml b/deploy/charts/rook-ceph/templates/clusterrole.yaml
index 4d40a4896..396b620e2 100644
--- a/deploy/charts/rook-ceph/templates/clusterrole.yaml
+++ b/deploy/charts/rook-ceph/templates/clusterrole.yaml
@@ -395,7 +395,7 @@ metadata:
 rules:
   - apiGroups: [""]
     resources: ["persistentvolumes"]
-    verbs: ["get", "list", "watch", "create", "delete", "patch"]
+    verbs: ["get", "list", "watch", "create", "delete"]
   - apiGroups: [""]
     resources: ["persistentvolumeclaims"]
     verbs: ["get", "list", "watch", "patch"]
@@ -417,21 +417,6 @@ rules:
   - apiGroups: [""]
     resources: ["secrets"]
     verbs: ["get"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshotclasses"]
-    verbs: ["get", "list", "watch"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshotcontents"]
-    verbs: ["get", "list", "watch", "update", "patch"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshotcontents/status"]
-    verbs: ["update", "patch"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshots"]
-    verbs: ["get", "list"]
-  - apiGroups: [""]
-    resources: ["persistentvolumeclaims/status"]
-    verbs: ["patch"]
 ---
 # TODO: remove this, once https://github.com/rook/rook/issues/10141
 # is resolved.
@@ -518,9 +503,6 @@ rules:
   - apiGroups: [""]
     resources: ["serviceaccounts/token"]
     verbs: ["create"]
-  - apiGroups: [""]
-    resources: ["nodes"]
-    verbs: ["get"]
 ---
 kind: ClusterRole
 apiVersion: rbac.authorization.k8s.io/v1
@@ -572,16 +554,22 @@ rules:
   - apiGroups: [""]
     resources: ["configmaps"]
     verbs: ["get"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplications", "volumereplicationclasses"]
+    verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplications/finalizers"]
+    verbs: ["update"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplications/status"]
+    verbs: ["get", "patch", "update"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplicationclasses/status"]
+    verbs: ["get"]
   - apiGroups: [""]
     resources: ["serviceaccounts"]
     verbs: ["get"]
   - apiGroups: [""]
     resources: ["serviceaccounts/token"]
     verbs: ["create"]
-  - apiGroups: [""]
-    resources: ["nodes"]
-    verbs: ["get", "list", watch"]
-  - apiGroups: ["storage.k8s.io"]
-    resources: ["csinodes"]
-    verbs: ["get", "list", "watch"]
 {{- end }}
diff --git a/deploy/charts/rook-ceph/templates/configmap.yaml b/deploy/charts/rook-ceph/templates/configmap.yaml
index 27b09e723..56f093aa7 100644
--- a/deploy/charts/rook-ceph/templates/configmap.yaml
+++ b/deploy/charts/rook-ceph/templates/configmap.yaml
@@ -12,7 +12,6 @@ data:
   ROOK_CSI_ENABLE_RBD: {{ .Values.csi.enableRbdDriver | quote }}
   ROOK_CSI_ENABLE_CEPHFS: {{ .Values.csi.enableCephfsDriver | quote }}
   CSI_ENABLE_CEPHFS_SNAPSHOTTER: {{ .Values.csi.enableCephfsSnapshotter | quote }}
-  CSI_ENABLE_NFS_SNAPSHOTTER: {{ .Values.csi.enableNFSSnapshotter | quote }}
   CSI_ENABLE_RBD_SNAPSHOTTER: {{ .Values.csi.enableRBDSnapshotter | quote }}
   CSI_PLUGIN_ENABLE_SELINUX_HOST_MOUNT: {{ .Values.csi.enablePluginSelinuxHostMount | quote }}
   CSI_ENABLE_ENCRYPTION: {{ .Values.csi.enableCSIEncryption | quote }}
@@ -77,18 +76,18 @@ data:
   ROOK_CSI_RESIZER_IMAGE: {{ .Values.csi.resizer.image | quote }}
 {{- end }}
 {{- end }}
+{{- if .Values.csi.volumeReplication }}
+  CSI_ENABLE_VOLUME_REPLICATION: {{ .Values.csi.volumeReplication.enabled | quote }}
+{{- if .Values.csi.volumeReplication.image }}
+  CSI_VOLUME_REPLICATION_IMAGE: {{ .Values.csi.volumeReplication.image | quote }}
+{{- end }}
+{{- end }}
 {{- if .Values.csi.csiAddons }}
   CSI_ENABLE_CSIADDONS: {{ .Values.csi.csiAddons.enabled | quote }}
 {{- if .Values.csi.csiAddons.image }}
   ROOK_CSIADDONS_IMAGE: {{ .Values.csi.csiAddons.image | quote }}
 {{- end }}
 {{- end }}
-{{- if .Values.csi.topology }}
-  CSI_ENABLE_TOPOLOGY: {{ .Values.csi.topology.enabled | quote }}
-{{- if .Values.csi.topology.domainLabels }}
-  CSI_TOPOLOGY_DOMAIN_LABELS: {{ .Values.csi.topology.domainLabels | join "," }}
-{{- end }}
-{{- end }}
 {{- if .Values.csi.nfs }}
   ROOK_CSI_ENABLE_NFS: {{ .Values.csi.nfs.enabled | quote }}
 {{- end }}
diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml
index 4f9b4ad31..68927087e 100644
--- a/deploy/charts/rook-ceph/templates/resources.yaml
+++ b/deploy/charts/rook-ceph/templates/resources.yaml
@@ -572,28 +572,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -5130,28 +5108,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -7285,7 +7241,7 @@ spec:
                                         - path
                                       type: object
                                     hostPath:
-                                      description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not mount host directories as read/write.'
+                                      description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath --- TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not mount host directories as read/write.'
                                       properties:
                                         path:
                                           description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
@@ -8327,28 +8283,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -8417,28 +8351,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -10146,28 +10058,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -10560,10 +10450,6 @@ spec:
                       type: object
                       x-kubernetes-preserve-unknown-fields: true
                   type: object
-                preservePoolsOnDelete:
-                  default: true
-                  description: Preserve pools on object zone deletion
-                  type: boolean
                 zoneGroup:
                   description: The display name for the ceph users
                   type: string
@@ -10575,28 +10461,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -11259,28 +11123,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
diff --git a/deploy/charts/rook-ceph/values.yaml b/deploy/charts/rook-ceph/values.yaml
index 5863bae28..5dcfda821 100644
--- a/deploy/charts/rook-ceph/values.yaml
+++ b/deploy/charts/rook-ceph/values.yaml
@@ -66,8 +66,6 @@ csi:
   enableCSIHostNetwork: true
   # set to false to disable deployment of snapshotter container in CephFS provisioner pod.
   enableCephfsSnapshotter: true
-  # set to false to disable deployment of snapshotter container in NFS provisioner pod.
-  enableNFSSnapshotter: true
   # set to false to disable deployment of snapshotter container in RBD provisioner pod.
   enableRBDSnapshotter: true
   # set to false if the selinux is not enabled or unavailable in cluster nodes.
@@ -379,24 +377,19 @@ csi:
   #nfsPodLabels: "key1=value1,key2=value2"
   # Labels to add to the CSI RBD Deployments and DaemonSets Pods.
   #rbdPodLabels: "key1=value1,key2=value2"
+  # Enable the volume replication controller.
+  # Before enabling, ensure the Volume Replication CRDs are created.
+  # See https://rook.io/docs/rook/latest/ceph-csi-drivers.html#rbd-mirroring
+  volumeReplication:
+    enabled: false
+    #image: "quay.io/csiaddons/volumereplication-operator:v0.3.0"
   # Enable the CSIAddons sidecar.
   csiAddons:
     enabled: false
-    #image: "quay.io/csiaddons/k8s-sidecar:v0.5.0"
+    #image: "quay.io/csiaddons/k8s-sidecar:v0.4.0"
   # Enable the nfs csi driver.
   nfs:
     enabled: false
-  # Enable topology based provisioning.
-  topology:
-    enabled: false
-    # domainLabels define which node labels to use as domains
-    # for CSI nodeplugins to advertise their domains
-    # NOTE: the value here serves as an example and needs to be
-    # updated with node labels that define domains of interest
-    # domainLabels:
-    # - kubernetes.io/hostname
-    # - topology.kubernetes.io/zone
-    # - topology.rook.io/rack
 enableDiscoveryDaemon: false
 cephCommandsTimeoutSeconds: "15"
 
diff --git a/deploy/examples/common.yaml b/deploy/examples/common.yaml
index c3245dcb5..dfdebfbed 100644
--- a/deploy/examples/common.yaml
+++ b/deploy/examples/common.yaml
@@ -91,9 +91,6 @@ rules:
   - apiGroups: [""]
     resources: ["serviceaccounts/token"]
     verbs: ["create"]
-  - apiGroups: [""]
-    resources: ["nodes"]
-    verbs: ["get"]
 ---
 kind: ClusterRole
 apiVersion: rbac.authorization.k8s.io/v1
@@ -145,18 +142,24 @@ rules:
   - apiGroups: [""]
     resources: ["configmaps"]
     verbs: ["get"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplications", "volumereplicationclasses"]
+    verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplications/finalizers"]
+    verbs: ["update"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplications/status"]
+    verbs: ["get", "patch", "update"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumereplicationclasses/status"]
+    verbs: ["get"]
   - apiGroups: [""]
     resources: ["serviceaccounts"]
     verbs: ["get"]
   - apiGroups: [""]
     resources: ["serviceaccounts/token"]
     verbs: ["create"]
-  - apiGroups: [""]
-    resources: ["nodes"]
-    verbs: ["get", "list", watch"]
-  - apiGroups: ["storage.k8s.io"]
-    resources: ["csinodes"]
-    verbs: ["get", "list", "watch"]
 ---
 # The cluster role for managing all the cluster-specific resources in a namespace
 apiVersion: rbac.authorization.k8s.io/v1
diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml
index d3f526389..60dc94cc5 100644
--- a/deploy/examples/crds.yaml
+++ b/deploy/examples/crds.yaml
@@ -573,28 +573,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -5127,28 +5105,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -7279,7 +7235,7 @@ spec:
                                         - path
                                       type: object
                                     hostPath:
-                                      description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not mount host directories as read/write.'
+                                      description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath --- TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not mount host directories as read/write.'
                                       properties:
                                         path:
                                           description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
@@ -8321,28 +8277,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -8410,28 +8344,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -10136,28 +10048,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -10549,10 +10439,6 @@ spec:
                       type: object
                       x-kubernetes-preserve-unknown-fields: true
                   type: object
-                preservePoolsOnDelete:
-                  default: true
-                  description: Preserve pools on object zone deletion
-                  type: boolean
                 zoneGroup:
                   description: The display name for the ceph users
                   type: string
@@ -10564,28 +10450,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
@@ -11247,28 +11111,6 @@ spec:
             status:
               description: Status represents the status of an object
               properties:
-                conditions:
-                  items:
-                    description: Condition represents a status condition on any Rook-Ceph Custom Resource.
-                    properties:
-                      lastHeartbeatTime:
-                        format: date-time
-                        type: string
-                      lastTransitionTime:
-                        format: date-time
-                        type: string
-                      message:
-                        type: string
-                      reason:
-                        description: ConditionReason is a reason for a condition
-                        type: string
-                      status:
-                        type: string
-                      type:
-                        description: ConditionType represent a resource's status
-                        type: string
-                    type: object
-                  type: array
                 observedGeneration:
                   description: ObservedGeneration is the latest generation observed by the controller.
                   format: int64
diff --git a/deploy/examples/create-external-cluster-resources.py b/deploy/examples/create-external-cluster-resources.py
index fa84051d1..64de25458 100644
--- a/deploy/examples/create-external-cluster-resources.py
+++ b/deploy/examples/create-external-cluster-resources.py
@@ -25,11 +25,14 @@ from hashlib import sha1 as sha
 from os import linesep as LINESEP
 from os import path
 from email.utils import formatdate
-import urllib.parse
-
 import requests
 from requests.auth import AuthBase
 
+py3k = False
+if sys.version_info.major >= 3:
+    py3k = True
+    import urllib.parse
+
 ModuleNotFoundError = ImportError
 
 try:
@@ -58,13 +61,9 @@ except ModuleNotFoundError:
     # for 3.x
     from urllib.parse import urlparse
 
-py3k = False
 try:
-    from urlparse import urlparse
     from base64 import encodestring
 except:
-    py3k = True
-    from urllib.parse import urlparse
     from base64 import encodebytes as encodestring
 
 
@@ -1097,7 +1096,7 @@ class RadosJSON:
             "--display-name",
             "Rook RGW Admin Ops user",
             "--caps",
-            "buckets=*;users=*;usage=read;metadata=read;zone=read",
+            "info=read;buckets=*;users=*;usage=read;metadata=read;zone=read",
         ]
         if self._arg_parser.dry_run:
             return self.dry_run("ceph " + " ".join(cmd))
@@ -1128,7 +1127,7 @@ class RadosJSON:
                 )
                 raise Exception(err_msg)
 
-        # separately add info=read caps for rgw-endpoint ip validation
+        # separately add info=read caps, because sometimes users already exited and the cap doesn't update
         info_cap_supported = True
         cmd = [
             "radosgw-admin",
diff --git a/deploy/examples/csi/nfs/pvc-clone.yaml b/deploy/examples/csi/nfs/pvc-clone.yaml
deleted file mode 100644
index a4830353a..000000000
--- a/deploy/examples/csi/nfs/pvc-clone.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
-  name: nfs-pvc-clone
-spec:
-  storageClassName: rook-nfs
-  dataSource:
-    name: nfs-pvc
-    kind: PersistentVolumeClaim
-  accessModes:
-    - ReadWriteMany
-  resources:
-    requests:
-      storage: 1Gi
diff --git a/deploy/examples/csi/nfs/pvc-restore.yaml b/deploy/examples/csi/nfs/pvc-restore.yaml
deleted file mode 100644
index 8a9d68c1f..000000000
--- a/deploy/examples/csi/nfs/pvc-restore.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
-  name: nfs-pvc-restore
-spec:
-  storageClassName: rook-nfs
-  dataSource:
-    name: nfs-pvc-snapshot
-    kind: VolumeSnapshot
-    apiGroup: snapshot.storage.k8s.io
-  accessModes:
-    - ReadWriteMany
-  resources:
-    requests:
-      storage: 1Gi
diff --git a/deploy/examples/csi/nfs/rbac.yaml b/deploy/examples/csi/nfs/rbac.yaml
index b8dbef640..7dc981f60 100644
--- a/deploy/examples/csi/nfs/rbac.yaml
+++ b/deploy/examples/csi/nfs/rbac.yaml
@@ -24,7 +24,7 @@ metadata:
 rules:
   - apiGroups: [""]
     resources: ["persistentvolumes"]
-    verbs: ["get", "list", "watch", "create", "delete", "patch"]
+    verbs: ["get", "list", "watch", "create", "delete"]
   - apiGroups: [""]
     resources: ["persistentvolumeclaims"]
     verbs: ["get", "list", "watch", "patch"]
@@ -46,21 +46,6 @@ rules:
   - apiGroups: [""]
     resources: ["secrets"]
     verbs: ["get"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshotclasses"]
-    verbs: ["get", "list", "watch"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshotcontents"]
-    verbs: ["get", "list", "watch", "update", "patch"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshotcontents/status"]
-    verbs: ["update", "patch"]
-  - apiGroups: ["snapshot.storage.k8s.io"]
-    resources: ["volumesnapshots"]
-    verbs: ["get", "list"]
-  - apiGroups: [""]
-    resources: ["persistentvolumeclaims/status"]
-    verbs: ["patch"]
 ---
 # TODO: remove this, once https://github.com/rook/rook/issues/10141
 # is resolved.
diff --git a/deploy/examples/csi/nfs/snapshot.yaml b/deploy/examples/csi/nfs/snapshot.yaml
deleted file mode 100644
index bf1bd973a..000000000
--- a/deploy/examples/csi/nfs/snapshot.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-apiVersion: snapshot.storage.k8s.io/v1
-kind: VolumeSnapshot
-metadata:
-  name: nfs-pvc-snapshot
-spec:
-  volumeSnapshotClassName: csi-nfsplugin-snapclass
-  source:
-    persistentVolumeClaimName: nfs-pvc
diff --git a/deploy/examples/csi/nfs/snapshotclass.yaml b/deploy/examples/csi/nfs/snapshotclass.yaml
deleted file mode 100644
index b11cefd35..000000000
--- a/deploy/examples/csi/nfs/snapshotclass.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
----
-apiVersion: snapshot.storage.k8s.io/v1
-kind: VolumeSnapshotClass
-metadata:
-  name: csi-nfsplugin-snapclass
-driver: rook-ceph.nfs.csi.ceph.com # driver:namespace:operator
-parameters:
-  # Specify a string that identifies your cluster. Ceph CSI supports any
-  # unique string. When Ceph CSI is deployed by Rook use the Rook namespace,
-  # for example "rook-ceph".
-  clusterID: rook-ceph # namespace:cluster
-  csi.storage.k8s.io/snapshotter-secret-name: rook-csi-cephfs-provisioner
-  csi.storage.k8s.io/snapshotter-secret-namespace: rook-ceph # namespace:cluster
-deletionPolicy: Delete
diff --git a/deploy/examples/csi/nfs/storageclass.yaml b/deploy/examples/csi/nfs/storageclass.yaml
index 85e60f754..57818282c 100644
--- a/deploy/examples/csi/nfs/storageclass.yaml
+++ b/deploy/examples/csi/nfs/storageclass.yaml
@@ -42,7 +42,7 @@ parameters:
   csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph # namespace:cluster
 
 reclaimPolicy: Delete
-allowVolumeExpansion: true
+allowVolumeExpansion: false
 mountOptions:
   # uncomment the following line for debugging
   #- debug
diff --git a/deploy/examples/images.txt b/deploy/examples/images.txt
index 9ed4e531f..82b281797 100644
--- a/deploy/examples/images.txt
+++ b/deploy/examples/images.txt
@@ -1,6 +1,7 @@
  quay.io/ceph/ceph:v17.2.3
  quay.io/cephcsi/cephcsi:v3.7.0
- quay.io/csiaddons/k8s-sidecar:v0.5.0
+ quay.io/csiaddons/k8s-sidecar:v0.4.0
+ quay.io/csiaddons/volumereplication-operator:v0.3.0
  registry.k8s.io/sig-storage/csi-attacher:v3.5.0
  registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.5.1
  registry.k8s.io/sig-storage/csi-provisioner:v3.2.1
diff --git a/deploy/examples/object-multisite.yaml b/deploy/examples/object-multisite.yaml
index a835983f6..c391a7627 100644
--- a/deploy/examples/object-multisite.yaml
+++ b/deploy/examples/object-multisite.yaml
@@ -40,8 +40,6 @@ spec:
   # customEndpoints:
   #   - "http://rgw-a.fqdn"
   #   - "http://rgw-b.fqdn"
-  # if the pools need to be removed from backend enable following setting
-  # preservePoolsOnDelete: false
 ---
 apiVersion: ceph.rook.io/v1
 kind: CephObjectStore
diff --git a/deploy/examples/operator-openshift.yaml b/deploy/examples/operator-openshift.yaml
index fb01447cf..7453099ab 100644
--- a/deploy/examples/operator-openshift.yaml
+++ b/deploy/examples/operator-openshift.yaml
@@ -155,9 +155,6 @@ data:
   # set to false to disable deployment of snapshotter container in CephFS provisioner pod.
   CSI_ENABLE_CEPHFS_SNAPSHOTTER: "true"
 
-  # set to false to disable deployment of snapshotter container in NFS provisioner pod.
-  CSI_ENABLE_NFS_SNAPSHOTTER: "true"
-
   # set to false to disable deployment of snapshotter container in RBD provisioner pod.
   CSI_ENABLE_RBD_SNAPSHOTTER: "true"
 
@@ -517,21 +514,18 @@ data:
   # Whether to start the discovery daemon to watch for raw storage devices on nodes in the cluster.
   # This daemon does not need to run if you are only going to create your OSDs based on StorageClassDeviceSets with PVCs.
   ROOK_ENABLE_DISCOVERY_DAEMON: "false"
+  # Enable the volume replication controller
+  # Before enabling, ensure the Volume Replication CRDs are created.
+  # See https://rook.io/docs/rook/latest/ceph-csi-drivers.html#rbd-mirroring
+  CSI_ENABLE_VOLUME_REPLICATION: "false"
   # The timeout value (in seconds) of Ceph commands. It should be >= 1. If this variable is not set or is an invalid value, it's default to 15.
   ROOK_CEPH_COMMANDS_TIMEOUT_SECONDS: "15"
+  # CSI_VOLUME_REPLICATION_IMAGE: "quay.io/csiaddons/volumereplication-operator:v0.3.0"
   # Enable the csi addons sidecar.
   CSI_ENABLE_CSIADDONS: "false"
-  # ROOK_CSIADDONS_IMAGE: "quay.io/csiaddons/k8s-sidecar:v0.5.0"
+  # ROOK_CSIADDONS_IMAGE: "quay.io/csiaddons/k8s-sidecar:v0.4.0"
   # The GCSI RPC timeout value (in seconds). It should be >= 120. If this variable is not set or is an invalid value, it's default to 150.
   CSI_GRPC_TIMEOUT_SECONDS: "150"
-
-  # Enable topology based provisioning.
-  CSI_ENABLE_TOPOLOGY: "false"
-  # Domain labels define which node labels to use as domains
-  # for CSI nodeplugins to advertise their domains
-  # NOTE: the value here serves as an example and needs to be
-  # updated with node labels that define domains of interest
-  # CSI_TOPOLOGY_DOMAIN_LABELS: "kubernetes.io/hostname,topology.kubernetes.io/zone,topology.rook.io/rack"
 ---
 # The deployment for the rook operator
 # OLM: BEGIN OPERATOR DEPLOYMENT
diff --git a/deploy/examples/operator.yaml b/deploy/examples/operator.yaml
index cb69e7f03..e928f1284 100644
--- a/deploy/examples/operator.yaml
+++ b/deploy/examples/operator.yaml
@@ -71,9 +71,6 @@ data:
   # set to false to disable deployment of snapshotter container in CephFS provisioner pod.
   CSI_ENABLE_CEPHFS_SNAPSHOTTER: "true"
 
-  # set to false to disable deployment of snapshotter container in NFS provisioner pod.
-  CSI_ENABLE_NFS_SNAPSHOTTER: "true"
-
   # set to false to disable deployment of snapshotter container in RBD provisioner pod.
   CSI_ENABLE_RBD_SNAPSHOTTER: "true"
 
@@ -444,19 +441,16 @@ data:
   ROOK_ENABLE_DISCOVERY_DAEMON: "false"
   # The timeout value (in seconds) of Ceph commands. It should be >= 1. If this variable is not set or is an invalid value, it's default to 15.
   ROOK_CEPH_COMMANDS_TIMEOUT_SECONDS: "15"
+  # Enable the volume replication controller.
+  # Before enabling, ensure the Volume Replication CRDs are created.
+  # See https://rook.io/docs/rook/latest/ceph-csi-drivers.html#rbd-mirroring
+  CSI_ENABLE_VOLUME_REPLICATION: "false"
+  # CSI_VOLUME_REPLICATION_IMAGE: "quay.io/csiaddons/volumereplication-operator:v0.3.0"
   # Enable the csi addons sidecar.
   CSI_ENABLE_CSIADDONS: "false"
-  # ROOK_CSIADDONS_IMAGE: "quay.io/csiaddons/k8s-sidecar:v0.5.0"
+  # ROOK_CSIADDONS_IMAGE: "quay.io/csiaddons/k8s-sidecar:v0.4.0"
   # The CSI GRPC timeout value (in seconds). It should be >= 120. If this variable is not set or is an invalid value, it's default to 150.
   CSI_GRPC_TIMEOUT_SECONDS: "150"
-
-  # Enable topology based provisioning.
-  CSI_ENABLE_TOPOLOGY: "false"
-  # Domain labels define which node labels to use as domains
-  # for CSI nodeplugins to advertise their domains
-  # NOTE: the value here serves as an example and needs to be
-  # updated with node labels that define domains of interest
-  # CSI_TOPOLOGY_DOMAIN_LABELS: "kubernetes.io/hostname,topology.kubernetes.io/zone,topology.rook.io/rack"
 ---
 # OLM: BEGIN OPERATOR DEPLOYMENT
 apiVersion: apps/v1
diff --git a/design/ceph/object/ceph-multisite-overview.md b/design/ceph/object/ceph-multisite-overview.md
index 214e1ed9e..4ac040b82 100644
--- a/design/ceph/object/ceph-multisite-overview.md
+++ b/design/ceph/object/ceph-multisite-overview.md
@@ -48,9 +48,6 @@ To enable Ceph's multisite, the following steps need to happen.
 3. A master zone in the master zone group needs to be created
 4. An object store needs to be added to the master zone
 
-### Master Zone/Zonegroup
-The master zone of the master zonegroup is designated as the 'metadata master zone', and all changes to user and bucket metadata are written through that zone first before replicating to other zones via metadata sync. This is different from data sync, where objects can be written to any zone and replicated to its peers in the zonegroup.
-
 ## Rook Ceph Multisite Steps
 
 1. If an admin is creating a new realm on a Rook Ceph cluster, the admin should create:
diff --git a/design/ceph/object/zone.md b/design/ceph/object/zone.md
index 1073811c4..cb84004ad 100644
--- a/design/ceph/object/zone.md
+++ b/design/ceph/object/zone.md
@@ -40,7 +40,6 @@ spec:
       codingChunks: 2
   customEndpoints:
     - "http://zone-a.fqdn"
-  preservePoolsOnDelete: true
 ```
 
 Now create the ceph-object-zone.
@@ -71,7 +70,7 @@ The order in which these resources are created is not important.
 
 When the storage admin is ready to sync data from another Ceph cluster with multisite set up (primary cluster) to a Rook Ceph cluster (pulling cluster), the pulling cluster will have a newly created in the zone group from the primary cluster.
 
-A [ceph-object-pull-realm](/design/ceph/object/ceph-object-pull-realm.md) resource must be created to pull the realm information from the primary cluster to the pulling cluster.
+A [ceph-object-pull-realm](/design/object/ceph-object-pull-realm.md) resource must be created to pull the realm information from the primary cluster to the pulling cluster.
 
 Once the ceph-object-pull-realm is configured a ceph-object-zone must be created.
 
@@ -79,21 +78,11 @@ After an ceph-object-store is configured to be in this ceph-object-zone, the all
 
 ## Deleting and Reconfiguring the Ceph Object Zone
 
-At the moment creating a CephObjectZone resource does not handle configuration updates for the zone.
+At the moment creating an ceph-object-zone resource only handles Day 1 initial configuration for the zone.
 
-By default when a CephObjectZone is deleted, the pools supporting the zone are not deleted from the Ceph cluster. But if `preservePoolsOnDelete` is set to false, then pools are deleted from the Ceph cluster.
+Changes made to the resource's configuration or deletion of the resource are not reflected on the Ceph cluster.
 
-A CephObjectZone will be removed only if all CephObjectStores that reference the zone are deleted first.
-
-### Deleting CephObjectStores in a multisite configuration
-
-One of the following scenarios is possible when deleting a CephObjectStore in a multisite configuration. Rook's behavior is noted after each scenario.
-1. The store belongs to a [master zone](/design/ceph/object/ceph-multisite-overview.md/#master-zonezonegroup) that has no other peers.
-  - This case is essentially the same as deleting a CephObjectStore outside of a multisite configuration; Rook should check for dependents before deleting the store
-2. The store belongs to a master zone that has other peers
-  - Rook will error on this condition with a message instructing the user to manually set another zone as the master zone once that zone has all data backed up to it
-3. The store is a non-master peer
-  - Rook will not check for dependents in this case, as the data in the master zone is assumed to have a copy of all user data
+To be clear, when the ceph-object-zone resource is deleted or modified, the zone is not deleted from the Ceph cluster. Zone deletion must be done through the toolbox.
 
 ### Deleting Zone through Toolboxes
 
@@ -145,8 +134,6 @@ The following variables can be configured in the ceph-object-zone resource.
 
 - `customEndpoints`:  Specify the endpoint(s) that will accept multisite replication traffic for this zone. You may include the port in the definition if necessary. For example: "https://my-object-store.my-domain.net:443".
 
-- `preservePoolsOnDelete`: If it is set to 'true' the pools used to support the zone will remain when the CephObjectZone is deleted. This is a security measure to avoid accidental loss of data. It is set to 'true' by default. If not specified it is also deemed as 'true'.
-
 ```yaml
 apiVersion: ceph.rook.io/v1alpha1
 kind: CephObjectZone
@@ -166,7 +153,6 @@ spec:
       codingChunks: 2
   customEndpoints:
     - "http://rgw-a.fqdn"
-  preservePoolsOnDelete: true
 ```
 
 ### Pools
diff --git a/go.mod b/go.mod
index 8cb5081a1..717b27bcc 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,6 @@ require (
 	github.com/banzaicloud/k8s-objectmatcher v1.8.0
 	github.com/ceph/go-ceph v0.16.0
 	github.com/coreos/pkg v0.0.0-20220709002704-04386ae12ed0
-	github.com/gemalto/kmip-go v0.0.8-0.20220721195433-3fe83e2d3f26
 	github.com/go-ini/ini v1.67.0
 	github.com/google/go-cmp v0.5.8
 	github.com/google/uuid v1.3.0
@@ -64,8 +63,6 @@ require (
 	github.com/NYTimes/gziphandler v1.1.1 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f // indirect
-	github.com/ansel1/merry v1.6.2 // indirect
-	github.com/ansel1/merry/v2 v2.0.1 // indirect
 	github.com/armon/go-metrics v0.4.0 // indirect
 	github.com/armon/go-radix v1.0.0 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
@@ -89,7 +86,6 @@ require (
 	github.com/evanphx/json-patch/v5 v5.6.0 // indirect
 	github.com/fatih/color v1.13.0 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
-	github.com/gemalto/flume v0.13.0 // indirect
 	github.com/go-logr/logr v1.2.3 // indirect
 	github.com/go-ole/go-ole v1.2.5 // indirect
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
@@ -168,7 +164,6 @@ require (
 	github.com/mattn/go-colorable v0.1.12 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
-	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 	github.com/miekg/dns v1.1.41 // indirect
 	github.com/mitchellh/cli v1.1.2 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
@@ -213,7 +208,6 @@ require (
 	go.opencensus.io v0.23.0 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
-	go.uber.org/zap v1.21.0 // indirect
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
 	golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect
 	golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 // indirect
diff --git a/go.sum b/go.sum
index 27a6f3f92..87c26edb4 100644
--- a/go.sum
+++ b/go.sum
@@ -178,15 +178,6 @@ github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f h1:oRD
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
 github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/ansel1/merry v1.5.0/go.mod h1:wUy/yW0JX0ix9GYvUbciq+bi3jW/vlKPlbpI7qdZpOw=
-github.com/ansel1/merry v1.5.1/go.mod h1:wUy/yW0JX0ix9GYvUbciq+bi3jW/vlKPlbpI7qdZpOw=
-github.com/ansel1/merry v1.6.1/go.mod h1:ioJjPJ/IsjxH+cC0lpf5TmbKnbcGa9qTk0fDbeRfnGQ=
-github.com/ansel1/merry v1.6.2 h1:0xr40haRrfVzmOH/JVOu7KOKGEI1c/7q5EmgTEbn+Ng=
-github.com/ansel1/merry v1.6.2/go.mod h1:pAcMW+2uxIgpzEON021vMtFsrymREY6faJWiiz1QGVQ=
-github.com/ansel1/merry/v2 v2.0.0-beta.10/go.mod h1:OUvUYh4KLVhf3+sR9Hk8QxCukijznkpheEd837b7vLg=
-github.com/ansel1/merry/v2 v2.0.1 h1:WeiKZdslHPAPFYxTtgX7clC2Vh75NCoWs5OjCZbIA0A=
-github.com/ansel1/merry/v2 v2.0.1/go.mod h1:dD5OhpiPrVkvgseRYd+xgYlx7s6ytU3v9BTTJlDA7FM=
-github.com/ansel1/vespucci/v4 v4.1.1/go.mod h1:zzdrO4IgBfgcGMbGTk/qNGL8JPslmW3nPpcBHKReFYY=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64 h1:ZsPrlYPY/v1PR7pGrmYD/rq5BFiSPalH8i9eEkSfnnI=
@@ -231,7 +222,6 @@ github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod
 github.com/banzaicloud/k8s-objectmatcher v1.8.0 h1:Nugn25elKtPMTA2br+JgHNeSQ04sc05MDPmpJnd1N2A=
 github.com/banzaicloud/k8s-objectmatcher v1.8.0/go.mod h1:p2LSNAjlECf07fbhDyebTkPUIYnU05G+WfGgkTmgeMg=
 github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
-github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -446,10 +436,6 @@ github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7 h1:D2LrfOPgGHQprIx
 github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7/go.mod h1:GeIq9qoE43YdGnDXURnmKTnGg15pQz4mYkXSTChbneI=
 github.com/gammazero/workerpool v0.0.0-20190406235159-88d534f22b56 h1:VzbudKn/nvxYKOdzgkEBS6SSreRjAgoJ+ZeS4wPFkgc=
 github.com/gammazero/workerpool v0.0.0-20190406235159-88d534f22b56/go.mod h1:w9RqFVO2BM3xwWEcAB8Fwp0OviTBBEiRmSBDfbXnd3w=
-github.com/gemalto/flume v0.13.0 h1:EEeQvAxyFys3BH8IxEU7ZpM6Kr1sYn20HuZq6dgyMR8=
-github.com/gemalto/flume v0.13.0/go.mod h1:3iOEZiK/HD8SnFTqHCQoOHQKaHlBY0b6z55P8SLaOzk=
-github.com/gemalto/kmip-go v0.0.8-0.20220721195433-3fe83e2d3f26 h1:AGbIx+qTKLkYrrxL6QuwjAR5MvbuX06uMHJFb8mG+ro=
-github.com/gemalto/kmip-go v0.0.8-0.20220721195433-3fe83e2d3f26/go.mod h1:7bAnjuzri8yGoJMwngnAd0HdXMRDQU+l1Zaiz12Tr68=
 github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
 github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -460,7 +446,6 @@ github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0
 github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
 github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
 github.com/go-errors/errors v1.4.1 h1:IvVlgbzSsaUNudsw5dcXSzF3EWyXTi5XrAdngnuhRyg=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -1088,8 +1073,6 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
-github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
 github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.3.0 h1:MjRRgZyTGo90G+UrwlDQjU+uG4Z7By65qvQxGoILT/8=
 github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.3.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0=
 github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
@@ -1155,7 +1138,6 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
 github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
@@ -1168,7 +1150,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@@ -1177,8 +1158,6 @@ github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
-github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
 github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
 github.com/michaelklishin/rabbit-hole v0.0.0-20191008194146-93d9988f0cd5 h1:uA3b4GgZMZxAJsTkd+CVQ85b7KBlD7HLpd/FfTNlGN0=
 github.com/michaelklishin/rabbit-hole v0.0.0-20191008194146-93d9988f0cd5/go.mod h1:+pmbihVqjC3GPdfWv1V2TnRSuVvwrWLKfEP/MZVB/Wc=
@@ -1621,14 +1600,12 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
-go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
 go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
 go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
@@ -1637,10 +1614,8 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
 go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
-go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
-go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
+go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
 golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -2130,7 +2105,6 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210224155714-063164c882e6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -2146,7 +2120,6 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr
 google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
 google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
 google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220208230804-65c12eb4c068/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/genproto v0.0.0-20220808145710-bf34ca4dd83a h1:FX/Y0fehmt5BT/GcKqm2u8l/Y1d0EQwAkI0vbXytJ60=
 google.golang.org/genproto v0.0.0-20220808145710-bf34ca4dd83a/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -2183,7 +2156,6 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
 google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
-google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
 google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
 google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
diff --git a/pkg/apis/ceph.rook.io/v1/object.go b/pkg/apis/ceph.rook.io/v1/object.go
index 903bacf54..c8ce342cc 100644
--- a/pkg/apis/ceph.rook.io/v1/object.go
+++ b/pkg/apis/ceph.rook.io/v1/object.go
@@ -109,7 +109,3 @@ func (s *ObjectStoreSpec) GetServiceServingCert() string {
 func (c *CephObjectStore) GetStatusConditions() *[]Condition {
 	return &c.Status.Conditions
 }
-
-func (z *CephObjectZone) GetStatusConditions() *[]Condition {
-	return &z.Status.Conditions
-}
diff --git a/pkg/apis/ceph.rook.io/v1/security.go b/pkg/apis/ceph.rook.io/v1/security.go
index 45d0186c9..135c97e0b 100644
--- a/pkg/apis/ceph.rook.io/v1/security.go
+++ b/pkg/apis/ceph.rook.io/v1/security.go
@@ -53,11 +53,6 @@ func (kms *KeyManagementServiceSpec) IsIBMKeyProtectKMS() bool {
 	return getParam(kms.ConnectionDetails, "KMS_PROVIDER") == "ibmkeyprotect"
 }
 
-// IsKMIPKMS return whether KMIP KMS is configured
-func (kms *KeyManagementServiceSpec) IsKMIPKMS() bool {
-	return getParam(kms.ConnectionDetails, "KMS_PROVIDER") == "kmip"
-}
-
 // IsTLSEnabled return KMS TLS details are configured
 func (kms *KeyManagementServiceSpec) IsTLSEnabled() bool {
 	for _, tlsOption := range VaultTLSConnectionDetails {
diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go
index 3f3472175..1ccdac3d1 100755
--- a/pkg/apis/ceph.rook.io/v1/types.go
+++ b/pkg/apis/ceph.rook.io/v1/types.go
@@ -864,8 +864,7 @@ type Status struct {
 	Phase string `json:"phase,omitempty"`
 	// ObservedGeneration is the latest generation observed by the controller.
 	// +optional
-	ObservedGeneration int64       `json:"observedGeneration,omitempty"`
-	Conditions         []Condition `json:"conditions,omitempty"`
+	ObservedGeneration int64 `json:"observedGeneration,omitempty"`
 }
 
 // ReplicatedSpec represents the spec for replication in a pool
@@ -1674,11 +1673,6 @@ type ObjectZoneSpec struct {
 	// +nullable
 	// +optional
 	CustomEndpoints []string `json:"customEndpoints,omitempty"`
-
-	// Preserve pools on object zone deletion
-	// +optional
-	// +kubebuilder:default=true
-	PreservePoolsOnDelete bool `json:"preservePoolsOnDelete"`
 }
 
 // CephBucketTopic represents a Ceph Object Topic for Bucket Notifications
diff --git a/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go b/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go
index 721906dac..e384ccd96 100644
--- a/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go
@@ -448,7 +448,7 @@ func (in *CephBucketNotification) DeepCopyInto(out *CephBucketNotification) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -911,7 +911,7 @@ func (in *CephFilesystemMirror) DeepCopyInto(out *CephFilesystemMirror) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -1136,7 +1136,7 @@ func (in *CephNFS) DeepCopyInto(out *CephNFS) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -1201,7 +1201,7 @@ func (in *CephObjectRealm) DeepCopyInto(out *CephObjectRealm) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -1396,7 +1396,7 @@ func (in *CephObjectZone) DeepCopyInto(out *CephObjectZone) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -1428,7 +1428,7 @@ func (in *CephObjectZoneGroup) DeepCopyInto(out *CephObjectZoneGroup) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -1526,7 +1526,7 @@ func (in *CephRBDMirror) DeepCopyInto(out *CephRBDMirror) {
 	if in.Status != nil {
 		in, out := &in.Status, &out.Status
 		*out = new(Status)
-		(*in).DeepCopyInto(*out)
+		**out = **in
 	}
 	return
 }
@@ -3871,13 +3871,6 @@ func (in *StatesSpec) DeepCopy() *StatesSpec {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Status) DeepCopyInto(out *Status) {
 	*out = *in
-	if in.Conditions != nil {
-		in, out := &in.Conditions, &out.Conditions
-		*out = make([]Condition, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
 	return
 }
 
diff --git a/pkg/daemon/ceph/osd/encryption.go b/pkg/daemon/ceph/osd/encryption.go
index 50a9e57f8..283aa46c7 100644
--- a/pkg/daemon/ceph/osd/encryption.go
+++ b/pkg/daemon/ceph/osd/encryption.go
@@ -19,7 +19,6 @@ package osd
 import (
 	"fmt"
 	"os"
-	"path"
 	"regexp"
 	"strings"
 
@@ -86,27 +85,6 @@ func setKEKinEnv(context *clusterd.Context, clusterInfo *cephclient.ClusterInfo)
 		clusterSpec.Security.KeyManagementService.ConnectionDetails[kms.IbmKeyProtectServiceApiKey] = ibmServiceApiKey
 	}
 
-	if clusterSpec.Security.KeyManagementService.IsKMIPKMS() {
-		// the following files will be mounted to the osd pod.
-		byteValue, err := os.ReadFile(path.Join(kms.EtcKmipDir, kms.KmipCACertFileName))
-		if err != nil {
-			return errors.Wrapf(err, "failed to read file %q", kms.KmipCACertFileName)
-		}
-		clusterSpec.Security.KeyManagementService.ConnectionDetails[kms.KmipCACert] = string(byteValue)
-
-		byteValue, err = os.ReadFile(path.Join(kms.EtcKmipDir, kms.KmipClientCertFileName))
-		if err != nil {
-			return errors.Wrapf(err, "failed to read file %q", kms.KmipClientCertFileName)
-		}
-		clusterSpec.Security.KeyManagementService.ConnectionDetails[kms.KmipClientCert] = string(byteValue)
-
-		byteValue, err = os.ReadFile(path.Join(kms.EtcKmipDir, kms.KmipClientKeyFileName))
-		if err != nil {
-			return errors.Wrapf(err, "failed to read file %q", kms.KmipClientKeyFileName)
-		}
-		clusterSpec.Security.KeyManagementService.ConnectionDetails[kms.KmipClientKey] = string(byteValue)
-	}
-
 	kmsConfig := kms.NewConfig(context, clusterSpec, clusterInfo)
 
 	// Fetch the KEK
diff --git a/pkg/daemon/ceph/osd/kms/envs.go b/pkg/daemon/ceph/osd/kms/envs.go
index ed83ed473..92c4ded06 100644
--- a/pkg/daemon/ceph/osd/kms/envs.go
+++ b/pkg/daemon/ceph/osd/kms/envs.go
@@ -30,8 +30,7 @@ import (
 )
 
 var (
-	kmipKMSPrefix  = "KMIP_"
-	knownKMSPrefix = []string{"VAULT_", "IBM_", kmipKMSPrefix}
+	knownKMSPrefix = []string{"VAULT_", "IBM_"}
 )
 
 // VaultTokenEnvVarFromSecret returns the kms token secret value as an env var
@@ -100,16 +99,6 @@ func ConfigToEnvVar(spec cephv1.ClusterSpec) []v1.EnvVar {
 		envs = append(envs, ibmKeyProtectServiceAPIKeyEnvVarFromSecret(spec.Security.KeyManagementService.TokenSecretName))
 	}
 
-	if spec.Security.KeyManagementService.IsKMIPKMS() {
-		for key, val := range spec.Security.KeyManagementService.ConnectionDetails {
-			// these token details will be mounted into osd pod instead of being inserted as env vars.
-			if sets.NewString(kmsKMIPMandatoryTokenDetails...).Has(key) {
-				continue
-			}
-			envs = append(envs, v1.EnvVar{Name: kmipKMSPrefix + key, Value: val})
-		}
-	}
-
 	for k, v := range spec.Security.KeyManagementService.ConnectionDetails {
 		if spec.Security.KeyManagementService.IsVaultKMS() {
 			// Skip TLS and token env var to avoid env being set multiple times
@@ -118,10 +107,6 @@ func ConfigToEnvVar(spec cephv1.ClusterSpec) []v1.EnvVar {
 				continue
 			}
 		}
-		if spec.Security.KeyManagementService.IsKMIPKMS() {
-			// required KMIP env vars are already set above.
-			continue
-		}
 
 		envs = append(envs, v1.EnvVar{Name: k, Value: v})
 	}
@@ -150,11 +135,7 @@ func ConfigEnvsToMapString() map[string]string {
 		for _, knownKMS := range knownKMSPrefix {
 			if strings.HasPrefix(pair[0], knownKMS) || pair[0] == Provider {
 				logger.Debugf("adding env %q", pair[0])
-				if knownKMS == kmipKMSPrefix {
-					envs[strings.TrimPrefix(pair[0], knownKMS)] = os.Getenv(pair[0])
-				} else {
-					envs[pair[0]] = os.Getenv(pair[0])
-				}
+				envs[pair[0]] = os.Getenv(pair[0])
 			}
 		}
 	}
diff --git a/pkg/daemon/ceph/osd/kms/k8s.go b/pkg/daemon/ceph/osd/kms/k8s.go
index f44f29995..e240711c5 100644
--- a/pkg/daemon/ceph/osd/kms/k8s.go
+++ b/pkg/daemon/ceph/osd/kms/k8s.go
@@ -54,17 +54,6 @@ func (c *Config) storeSecretInKubernetes(pvcName, key string) error {
 	return nil
 }
 
-// getKubernetesSecret returns key value from secret.
-func (c *Config) getKubernetesSecret(pvcName string) (string, error) {
-	secretName := GenerateOSDEncryptionSecretName(pvcName)
-	secret, err := c.context.Clientset.CoreV1().Secrets(c.ClusterInfo.Namespace).Get(c.ClusterInfo.Context, secretName, metav1.GetOptions{})
-	if err != nil {
-		return "", errors.Wrapf(err, "failed to get secret %q", secretName)
-	}
-
-	return string(secret.Data[OsdEncryptionSecretNameKeyName]), nil
-}
-
 func generateOSDEncryptedKeySecret(pvcName, key string, clusterInfo *cephclient.ClusterInfo) (*v1.Secret, error) {
 	s := &v1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
diff --git a/pkg/daemon/ceph/osd/kms/kmip.go b/pkg/daemon/ceph/osd/kms/kmip.go
deleted file mode 100644
index bd2bddfee..000000000
--- a/pkg/daemon/ceph/osd/kms/kmip.go
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
-Copyright 2022 The Rook Authors. All rights reserved.
-
-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 kms
-
-import (
-	"bufio"
-	"bytes"
-	"crypto/tls"
-	"crypto/x509"
-	"encoding/base64"
-	"fmt"
-	"io"
-	"strconv"
-	"time"
-
-	kmip "github.com/gemalto/kmip-go"
-	"github.com/gemalto/kmip-go/kmip14"
-	"github.com/gemalto/kmip-go/ttlv"
-	"github.com/google/uuid"
-	"github.com/pkg/errors"
-)
-
-const (
-	TypeKMIP = "kmip"
-
-	// KMIP version.
-	protocolMajor = 1
-	protocolMinor = 4
-
-	// kmipDefaultReadTimeout is the default read network timeout.
-	kmipDefaultReadTimeout = uint8(10)
-
-	// kmipDefaultWriteTimeout is the default write network timeout.
-	kmipDefaultWriteTimeout = uint8(10)
-
-	// cryptographicLength of the key.
-	cryptographicLength = 128
-
-	//nolint:gosec, value not credential, just configuration keys.
-	kmipEndpoint         = "KMIP_ENDPOINT"
-	kmipTLSServerName    = "TLS_SERVER_NAME"
-	kmipReadTimeOut      = "READ_TIMEOUT"
-	kmipWriteTimeOut     = "WRITE_TIMEOUT"
-	KmipCACert           = "CA_CERT"
-	KmipClientCert       = "CLIENT_CERT"
-	KmipClientKey        = "CLIENT_KEY"
-	KmipUniqueIdentifier = "UNIQUE_IDENTIFIER"
-
-	// EtcKmipDir is kmip config dir.
-	EtcKmipDir = "/etc/kmip"
-)
-
-var (
-	kmsKMIPMandatoryTokenDetails      = []string{KmipCACert, KmipClientCert, KmipClientKey}
-	kmsKMIPMandatoryConnectionDetails = []string{kmipEndpoint}
-	ErrKMIPEndpointNotSet             = errors.Errorf("%s not set.", kmipEndpoint)
-	ErrKMIPCACertNotSet               = errors.Errorf("%s not set.", KmipCACert)
-	ErrKMIPClientCertNotSet           = errors.Errorf("%s not set.", KmipClientCert)
-	ErrKMIPClientKeyNotSet            = errors.Errorf("%s not set.", KmipClientKey)
-)
-
-type kmipKMS struct {
-	// standard KMIP configuration options
-	endpoint         string
-	tlsConfig        *tls.Config
-	uniqueIdentifier string
-	readTimeout      uint8
-	writeTimeout     uint8
-}
-
-// InitKKMIP initializes the KMIP KMS.
-func InitKMIP(config map[string]string) (*kmipKMS, error) {
-	kms := &kmipKMS{}
-
-	kms.endpoint = GetParam(config, kmipEndpoint)
-	if kms.endpoint == "" {
-		return nil, ErrKMIPEndpointNotSet
-	}
-
-	// optional
-	serverName := GetParam(config, kmipTLSServerName)
-
-	// optional
-	kms.readTimeout = kmipDefaultReadTimeout
-	timeout, err := strconv.Atoi(GetParam(config, kmipReadTimeOut))
-	if err == nil {
-		kms.readTimeout = uint8(timeout)
-	}
-
-	// optional
-	kms.writeTimeout = kmipDefaultWriteTimeout
-	timeout, err = strconv.Atoi(GetParam(config, kmipWriteTimeOut))
-	if err == nil {
-		kms.writeTimeout = uint8(timeout)
-	}
-
-	caCert := GetParam(config, KmipCACert)
-	if caCert == "" {
-		return nil, ErrKMIPCACertNotSet
-	}
-
-	clientCert := GetParam(config, KmipClientCert)
-	if clientCert == "" {
-		return nil, ErrKMIPClientCertNotSet
-	}
-
-	clientKey := GetParam(config, KmipClientKey)
-	if clientKey == "" {
-		return nil, ErrKMIPClientKeyNotSet
-	}
-
-	caCertPool := x509.NewCertPool()
-	caCertPool.AppendCertsFromPEM([]byte(caCert))
-	cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
-	if err != nil {
-		return nil, fmt.Errorf("invalid X509 key pair: %w", err)
-	}
-
-	kms.tlsConfig = &tls.Config{
-		MinVersion:   tls.VersionTLS12,
-		ServerName:   serverName,
-		RootCAs:      caCertPool,
-		Certificates: []tls.Certificate{cert},
-	}
-
-	return kms, nil
-}
-
-// IsKMIP determines whether the configured KMS is KMIP.
-func (c *Config) IsKMIP() bool { return c.Provider == TypeKMIP }
-
-// registerKey will create a register key and return its unique identifier.
-func (kms *kmipKMS) registerKey(keyName, keyValue string) (string, error) {
-	valueBytes, err := base64.StdEncoding.DecodeString(keyValue)
-	if err != nil {
-		return "", errors.Wrap(err, "failed to convert string to bytes")
-	}
-	conn, err := kms.connect()
-	if err != nil {
-		return "", errors.Wrap(err, "failed to connect to kmip kms")
-	}
-	defer conn.Close()
-	registerPayload := kmip.RegisterRequestPayload{
-		ObjectType: kmip14.ObjectTypeSymmetricKey,
-		SymmetricKey: &kmip.SymmetricKey{
-			KeyBlock: kmip.KeyBlock{
-				KeyFormatType: kmip14.KeyFormatTypeOpaque,
-				KeyValue: &kmip.KeyValue{
-					KeyMaterial: valueBytes,
-				},
-				CryptographicLength:    cryptographicLength,
-				CryptographicAlgorithm: kmip14.CryptographicAlgorithmAES,
-			},
-		},
-	}
-	registerPayload.TemplateAttribute.Append(kmip14.TagCryptographicUsageMask, kmip14.CryptographicUsageMaskExport)
-	respMsg, decoder, uniqueBatchItemID, err := kms.send(conn, kmip14.OperationRegister, registerPayload)
-	if err != nil {
-		return "", errors.Wrap(err, "failed to send register request to kmip")
-	}
-	bi, err := kms.verifyResponse(respMsg, kmip14.OperationRegister, uniqueBatchItemID)
-	if err != nil {
-		return "", errors.Wrap(err, "failed to verify kmip register response")
-	}
-
-	var registerRespPayload kmip.RegisterResponsePayload
-	err = decoder.DecodeValue(&registerRespPayload, bi.ResponsePayload.(ttlv.TTLV))
-	if err != nil {
-		return "", errors.Wrap(err, "failed to decode kmip response value")
-	}
-
-	return registerRespPayload.UniqueIdentifier, nil
-}
-
-func (kms *kmipKMS) getKey(uniqueIdentifier string) (string, error) {
-	conn, err := kms.connect()
-	if err != nil {
-		return "", errors.Wrap(err, "failed to connect to kmip kms")
-	}
-	defer conn.Close()
-
-	respMsg, decoder, uniqueBatchItemID, err := kms.send(conn, kmip14.OperationGet, kmip.GetRequestPayload{
-		UniqueIdentifier: uniqueIdentifier,
-	})
-	if err != nil {
-		return "", errors.Wrap(err, "failed to send get request to kmip")
-	}
-	bi, err := kms.verifyResponse(respMsg, kmip14.OperationGet, uniqueBatchItemID)
-	if err != nil {
-		return "", errors.Wrap(err, "failed to verify kmip response")
-	}
-	var getRespPayload kmip.GetResponsePayload
-	err = decoder.DecodeValue(&getRespPayload, bi.ResponsePayload.(ttlv.TTLV))
-	if err != nil {
-		return "", errors.Wrap(err, "failed to decode kmip response value")
-	}
-
-	secretBytes := getRespPayload.SymmetricKey.KeyBlock.KeyValue.KeyMaterial.([]byte)
-	secretBase64 := base64.StdEncoding.EncodeToString(secretBytes)
-
-	return secretBase64, nil
-}
-
-func (kms *kmipKMS) deleteKey(uniqueIdentifier string) error {
-	conn, err := kms.connect()
-	if err != nil {
-		return errors.Wrap(err, "failed to connect to kmip kms")
-	}
-	defer conn.Close()
-
-	respMsg, decoder, uniqueBatchItemID, err := kms.send(conn, kmip14.OperationDestroy, kmip.DestroyRequestPayload{
-		UniqueIdentifier: uniqueIdentifier,
-	})
-	if err != nil {
-		return errors.Wrap(err, "failed to send delete request to kmip")
-	}
-	bi, err := kms.verifyResponse(respMsg, kmip14.OperationDestroy, uniqueBatchItemID)
-	if err != nil {
-		return errors.Wrap(err, "failed to verify kmip response")
-	}
-	var destroyRespPayload kmip.DestroyResponsePayload
-	err = decoder.DecodeValue(&destroyRespPayload, bi.ResponsePayload.(ttlv.TTLV))
-	if err != nil {
-		return errors.Wrap(err, "failed to decode kmip response value")
-	}
-
-	return nil
-}
-
-// connect to the kmip endpoint, perform TLS and KMIP handshakes.
-func (kms *kmipKMS) connect() (*tls.Conn, error) {
-	conn, err := tls.Dial("tcp", kms.endpoint, kms.tlsConfig)
-	if err != nil {
-		return nil, fmt.Errorf("failed to dial kmip connection endpoint: %w", err)
-	}
-	defer func() {
-		if err != nil {
-			conn.Close()
-		}
-	}()
-	if kms.readTimeout != 0 {
-		err = conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(kms.readTimeout)))
-		if err != nil {
-			return nil, fmt.Errorf("failed to set read deadline: %w", err)
-		}
-	}
-	if kms.writeTimeout != 0 {
-		err = conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(kms.writeTimeout)))
-		if err != nil {
-			return nil, fmt.Errorf("failed to set write deadline: %w", err)
-		}
-	}
-
-	err = conn.Handshake()
-	if err != nil {
-		return nil, fmt.Errorf("failed to perform connection handshake: %w", err)
-	}
-
-	err = kms.discover(conn)
-	if err != nil {
-		return nil, err
-	}
-
-	return conn, nil
-}
-
-// discover performs KMIP discover operation.
-// https://docs.oasis-open.org/kmip/spec/v1.4/kmip-spec-v1.4.html
-// chapter 4.26.
-func (kms *kmipKMS) discover(conn io.ReadWriter) error {
-	respMsg, decoder, uniqueBatchItemID, err := kms.send(conn,
-		kmip14.OperationDiscoverVersions,
-		kmip.DiscoverVersionsRequestPayload{
-			ProtocolVersion: []kmip.ProtocolVersion{
-				{
-					ProtocolVersionMajor: protocolMajor,
-					ProtocolVersionMinor: protocolMinor,
-				},
-			},
-		})
-	if err != nil {
-		return err
-	}
-
-	batchItem, err := kms.verifyResponse(
-		respMsg,
-		kmip14.OperationDiscoverVersions,
-		uniqueBatchItemID)
-	if err != nil {
-		return err
-	}
-
-	ttlvPayload, ok := batchItem.ResponsePayload.(ttlv.TTLV)
-	if !ok {
-		return errors.New("failed to parse responsePayload")
-	}
-
-	var respDiscoverVersionsPayload kmip.DiscoverVersionsResponsePayload
-	err = decoder.DecodeValue(&respDiscoverVersionsPayload, ttlvPayload)
-	if err != nil {
-		return err
-	}
-
-	if len(respDiscoverVersionsPayload.ProtocolVersion) != 1 {
-		return fmt.Errorf("invalid len of discovered protocol versions %v expected 1",
-			len(respDiscoverVersionsPayload.ProtocolVersion))
-	}
-	pv := respDiscoverVersionsPayload.ProtocolVersion[0]
-	if pv.ProtocolVersionMajor != protocolMajor || pv.ProtocolVersionMinor != protocolMinor {
-		return fmt.Errorf("invalid discovered protocol version %v.%v expected %v.%v",
-			pv.ProtocolVersionMajor, pv.ProtocolVersionMinor, protocolMajor, protocolMinor)
-	}
-
-	return nil
-}
-
-// send sends KMIP operation over tls connection, returns
-// kmip response message,
-// ttlv Decoder to decode message into desired format,
-// batchItem ID,
-// and error.
-func (kms *kmipKMS) send(
-	conn io.ReadWriter,
-	operation kmip14.Operation,
-	payload interface{},
-) (*kmip.ResponseMessage, *ttlv.Decoder, []byte, error) {
-	biID := uuid.New()
-
-	msg := kmip.RequestMessage{
-		RequestHeader: kmip.RequestHeader{
-			ProtocolVersion: kmip.ProtocolVersion{
-				ProtocolVersionMajor: protocolMajor,
-				ProtocolVersionMinor: protocolMinor,
-			},
-			BatchCount: 1,
-		},
-		BatchItem: []kmip.RequestBatchItem{
-			{
-				UniqueBatchItemID: biID[:],
-				Operation:         operation,
-				RequestPayload:    payload,
-			},
-		},
-	}
-
-	req, err := ttlv.Marshal(msg)
-	if err != nil {
-		return nil, nil, nil,
-			fmt.Errorf("failed to ttlv marshal message: %w", err)
-	}
-
-	_, err = conn.Write(req)
-	if err != nil {
-		return nil, nil, nil,
-			fmt.Errorf("failed to write request onto connection: %w", err)
-	}
-
-	decoder := ttlv.NewDecoder(bufio.NewReader(conn))
-	resp, err := decoder.NextTTLV()
-	if err != nil {
-		return nil, nil, nil,
-			fmt.Errorf("failed to read ttlv KMIP value: %w", err)
-	}
-
-	var respMsg kmip.ResponseMessage
-	err = decoder.DecodeValue(&respMsg, resp)
-	if err != nil {
-		return nil, nil, nil,
-			fmt.Errorf("failed to decode response value: %w", err)
-	}
-
-	return &respMsg, decoder, biID[:], nil
-}
-
-// verifyResponse verifies the response success and return the batch item.
-func (kms *kmipKMS) verifyResponse(
-	respMsg *kmip.ResponseMessage,
-	operation kmip14.Operation,
-	uniqueBatchItemID []byte,
-) (*kmip.ResponseBatchItem, error) {
-	if respMsg.ResponseHeader.BatchCount != 1 {
-		return nil, fmt.Errorf("batch count %q should be \"1\"",
-			respMsg.ResponseHeader.BatchCount)
-	}
-	if len(respMsg.BatchItem) != 1 {
-		return nil, fmt.Errorf("batch Intems list len %q should be \"1\"",
-			len(respMsg.BatchItem))
-	}
-	batchItem := respMsg.BatchItem[0]
-	if operation != batchItem.Operation {
-		return nil, fmt.Errorf("unexpected operation, real %q expected %q",
-			batchItem.Operation, operation)
-	}
-	if !bytes.Equal(uniqueBatchItemID, batchItem.UniqueBatchItemID) {
-		return nil, fmt.Errorf("unexpected uniqueBatchItemID, real %q expected %q",
-			batchItem.UniqueBatchItemID, uniqueBatchItemID)
-	}
-	if kmip14.ResultStatusSuccess != batchItem.ResultStatus {
-		return nil, fmt.Errorf("unexpected result status %q expected success %q,"+
-			"result reason %q, result message %q",
-			batchItem.ResultStatus, kmip14.ResultStatusSuccess,
-			batchItem.ResultReason, batchItem.ResultMessage)
-	}
-
-	return &batchItem, nil
-}
diff --git a/pkg/daemon/ceph/osd/kms/kms.go b/pkg/daemon/ceph/osd/kms/kms.go
index 75e01c7d7..372ae4d81 100644
--- a/pkg/daemon/ceph/osd/kms/kms.go
+++ b/pkg/daemon/ceph/osd/kms/kms.go
@@ -30,7 +30,6 @@ import (
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 	"github.com/rook/rook/pkg/clusterd"
 	cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
-	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
@@ -68,8 +67,6 @@ func NewConfig(context *clusterd.Context, clusterSpec *cephv1.ClusterSpec, clust
 		config.Provider = secrets.TypeVault
 	case TypeIBM:
 		config.Provider = TypeIBM
-	case TypeKMIP:
-		config.Provider = TypeKMIP
 	default:
 		logger.Errorf("unsupported kms type %q", Provider)
 	}
@@ -117,33 +114,6 @@ func (c *Config) PutSecret(secretName, secretValue string) error {
 			return errors.Wrap(err, "failed to put secret in ibm key protect")
 		}
 	}
-	if c.IsKMIP() {
-		_, err := c.getKubernetesSecret(secretName)
-		if err == nil {
-			// if error is nil, secret exists, just return nil.
-			return nil
-		}
-		// if error is not found, continue with creation.
-		if !kerrors.IsNotFound(err) {
-			return errors.Wrapf(err, "failed to check secret exists for %q", secretName)
-		}
-
-		kmip, err := InitKMIP(c.clusterSpec.Security.KeyManagementService.ConnectionDetails)
-		if err != nil {
-			return errors.Wrap(err, "failed to init kmip")
-		}
-
-		// register the key with kmip server.
-		uniqueIdentifier, err := kmip.registerKey(secretName, secretValue)
-		if err != nil {
-			return errors.Wrap(err, "failed to register secret in kmip")
-		}
-		// store the uniqueIdentifier in Kubernetes Secret.
-		err = c.storeSecretInKubernetes(secretName, uniqueIdentifier)
-		if err != nil {
-			return errors.Wrap(err, "failed to store unique identifier in kubernetes secret")
-		}
-	}
 
 	return nil
 }
@@ -175,22 +145,6 @@ func (c *Config) GetSecret(secretName string) (string, error) {
 		}
 		value = string(keyObject.Payload)
 	}
-	if c.IsKMIP() {
-		uniqueIdentifier, err := c.getKubernetesSecret(secretName)
-		if err != nil {
-			return "", errors.Wrap(err, "failed to get unique id")
-		}
-
-		kmip, err := InitKMIP(c.clusterSpec.Security.KeyManagementService.ConnectionDetails)
-		if err != nil {
-			return "", errors.Wrap(err, "failed to init kmip")
-		}
-
-		value, err = kmip.getKey(uniqueIdentifier)
-		if err != nil {
-			return "", errors.Wrap(err, "failed to get key from kmip")
-		}
-	}
 
 	return value, nil
 }
@@ -242,21 +196,6 @@ func (c *Config) DeleteSecret(secretName string) error {
 			return errors.Wrap(err, "failed to delete secret in ibm key protect")
 		}
 	}
-	if c.IsKMIP() {
-		uniqueIdentifier, err := c.getKubernetesSecret(secretName)
-		if err != nil {
-			return errors.Wrap(err, "failed to get unique id")
-		}
-		kmip, err := InitKMIP(c.clusterSpec.Security.KeyManagementService.ConnectionDetails)
-		if err != nil {
-			return errors.Wrap(err, "failed to init kmip")
-		}
-
-		err = kmip.deleteKey(uniqueIdentifier)
-		if err != nil {
-			return errors.Wrap(err, "failed to delete key with kmip")
-		}
-	}
 
 	return nil
 }
@@ -318,16 +257,6 @@ func ValidateConnectionDetails(ctx context.Context, clusterdContext *clusterd.Co
 				// Append the token secret details to the connection details
 				kms.ConnectionDetails[config] = strings.TrimSuffix(strings.TrimSpace(string(v)), "\n")
 			}
-
-		case TypeKMIP:
-			for _, config := range kmsKMIPMandatoryTokenDetails {
-				v, ok := kmsToken.Data[config]
-				if !ok || len(v) == 0 {
-					return errors.Errorf("failed to read k8s kms secret %q key %q (not found or empty)", config, kms.TokenSecretName)
-				}
-				// Append the token secret details to the connection details
-				kms.ConnectionDetails[config] = strings.TrimSuffix(strings.TrimSpace(string(v)), "\n")
-			}
 		}
 	}
 
@@ -359,13 +288,6 @@ func ValidateConnectionDetails(ctx context.Context, clusterdContext *clusterd.Co
 			}
 		}
 
-	case TypeKMIP:
-		for _, config := range kmsKMIPMandatoryConnectionDetails {
-			if GetParam(kms.ConnectionDetails, config) == "" {
-				return errors.Errorf("failed to validate kms config %q. cannot be empty", config)
-			}
-		}
-
 	default:
 		return errors.Errorf("failed to validate kms provider connection details (provider %q not supported)", provider)
 	}
diff --git a/pkg/daemon/ceph/osd/kms/volumes.go b/pkg/daemon/ceph/osd/kms/volumes.go
index 2c19033d5..4aaf70368 100644
--- a/pkg/daemon/ceph/osd/kms/volumes.go
+++ b/pkg/daemon/ceph/osd/kms/volumes.go
@@ -31,12 +31,9 @@ const (
 	vaultKeySecretKeyName    = "key"
 
 	// File names of the Secret value when mapping on the filesystem
-	VaultCAFileName        = "vault.ca"
-	VaultCertFileName      = "vault.crt"
-	VaultKeyFileName       = "vault.key"
-	KmipCACertFileName     = "ca.crt"
-	KmipClientCertFileName = "client.crt"
-	KmipClientKeyFileName  = "client.key"
+	VaultCAFileName   = "vault.ca"
+	VaultCertFileName = "vault.crt"
+	VaultKeyFileName  = "vault.key"
 
 	// File name for token file
 	VaultFileName = "vault.token"
@@ -114,48 +111,3 @@ func tlsSecretPath(tlsOption string) string {
 
 	return ""
 }
-
-func KMIPVolumeAndMount(tokenSecretName string) (v1.Volume, v1.VolumeMount) {
-	mode := int32(0444)
-	v := v1.Volume{
-		Name: TypeKMIP,
-		VolumeSource: v1.VolumeSource{
-			Projected: &v1.ProjectedVolumeSource{
-				Sources: []v1.VolumeProjection{
-					{
-						Secret: &v1.SecretProjection{
-							LocalObjectReference: v1.LocalObjectReference{
-								Name: tokenSecretName,
-							},
-							Items: []v1.KeyToPath{
-								{
-									Key:  KmipCACert,
-									Path: KmipCACertFileName,
-									Mode: &mode,
-								},
-								{
-									Key:  KmipClientCert,
-									Path: KmipClientCertFileName,
-									Mode: &mode,
-								},
-								{
-									Key:  KmipClientKey,
-									Path: KmipClientKeyFileName,
-									Mode: &mode,
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-	}
-
-	m := v1.VolumeMount{
-		Name:      TypeKMIP,
-		ReadOnly:  true,
-		MountPath: EtcKmipDir,
-	}
-
-	return v, m
-}
diff --git a/pkg/operator/ceph/cluster/controller.go b/pkg/operator/ceph/cluster/controller.go
index 5de52d8ef..08c45814d 100644
--- a/pkg/operator/ceph/cluster/controller.go
+++ b/pkg/operator/ceph/cluster/controller.go
@@ -543,7 +543,6 @@ func (c *ClusterController) deleteOSDEncryptionKeyFromKMS(currentCluster *cephv1
 
 	// Initialize the KMS code
 	kmsConfig := kms.NewConfig(c.context, &currentCluster.Spec, c.clusterMap[currentCluster.Namespace].ClusterInfo)
-	kmsConfig.ClusterInfo.Context = ctx
 
 	// If token auth is used by the KMS we set it as an env variable
 	if currentCluster.Spec.Security.KeyManagementService.IsTokenAuthEnabled() && currentCluster.Spec.Security.KeyManagementService.IsVaultKMS() {
@@ -553,10 +552,9 @@ func (c *ClusterController) deleteOSDEncryptionKeyFromKMS(currentCluster *cephv1
 		}
 	}
 
-	// We need to fetch the IBM_KP_SERVICE_API_KEY value and KMIP kms related values too.
-	if currentCluster.Spec.Security.KeyManagementService.IsIBMKeyProtectKMS() || currentCluster.Spec.Security.KeyManagementService.IsKMIPKMS() {
-		// This will validate the connection details again and will add the IBM_KP_SERVICE_API_KEY to the spec and
-		// token details required for KMIP kms is added too.
+	// We need to fetch the IBM_KP_SERVICE_API_KEY value
+	if currentCluster.Spec.Security.KeyManagementService.IsIBMKeyProtectKMS() {
+		// This will validate the connection details again and will add the IBM_KP_SERVICE_API_KEY to the spec
 		err = kms.ValidateConnectionDetails(ctx, c.context, &currentCluster.Spec.Security.KeyManagementService, currentCluster.Namespace)
 		if err != nil {
 			return errors.Wrap(err, "failed to validate kms connection details to delete the secret")
diff --git a/pkg/operator/ceph/cluster/osd/provision_spec.go b/pkg/operator/ceph/cluster/osd/provision_spec.go
index 254fb70ec..05eea2a78 100644
--- a/pkg/operator/ceph/cluster/osd/provision_spec.go
+++ b/pkg/operator/ceph/cluster/osd/provision_spec.go
@@ -118,10 +118,6 @@ func (c *Cluster) provisionPodTemplateSpec(osdProps osdProperties, restart v1.Re
 					volumeTLS, _ := kms.VaultVolumeAndMount(c.spec.Security.KeyManagementService.ConnectionDetails, "")
 					volumes = append(volumes, volumeTLS)
 				}
-				if c.spec.Security.KeyManagementService.IsKMIPKMS() {
-					volumeKMIP, _ := kms.KMIPVolumeAndMount(c.spec.Security.KeyManagementService.TokenSecretName)
-					volumes = append(volumes, volumeKMIP)
-				}
 			}
 		}
 	} else {
@@ -280,11 +276,6 @@ func (c *Cluster) provisionOSDContainer(osdProps osdProperties, copyBinariesMoun
 					volumeMounts = append(volumeMounts, volumeMountsTLS)
 				}
 				envVars = append(envVars, kms.ConfigToEnvVar(c.spec)...)
-				if c.spec.Security.KeyManagementService.IsKMIPKMS() {
-					envVars = append(envVars, cephVolumeRawEncryptedEnvVarFromSecret(osdProps))
-					_, volmeMountsKMIP := kms.KMIPVolumeAndMount(c.spec.Security.KeyManagementService.TokenSecretName)
-					volumeMounts = append(volumeMounts, volmeMountsKMIP)
-				}
 			} else {
 				envVars = append(envVars, cephVolumeRawEncryptedEnvVarFromSecret(osdProps))
 			}
diff --git a/pkg/operator/ceph/cluster/osd/spec.go b/pkg/operator/ceph/cluster/osd/spec.go
index 6c9024182..8bc2df10c 100644
--- a/pkg/operator/ceph/cluster/osd/spec.go
+++ b/pkg/operator/ceph/cluster/osd/spec.go
@@ -323,10 +323,6 @@ func (c *Cluster) makeDeployment(osdProps osdProperties, osd OSDInfo, provisionC
 				encryptedVol, _ := kms.VaultVolumeAndMount(c.spec.Security.KeyManagementService.ConnectionDetails, "")
 				volumes = append(volumes, encryptedVol)
 			}
-			if c.spec.Security.KeyManagementService.IsEnabled() && c.spec.Security.KeyManagementService.IsKMIPKMS() {
-				encryptedVol, _ := kms.KMIPVolumeAndMount(c.spec.Security.KeyManagementService.TokenSecretName)
-				volumes = append(volumes, encryptedVol)
-			}
 		}
 	}
 
diff --git a/pkg/operator/ceph/controller/spec.go b/pkg/operator/ceph/controller/spec.go
index bad9e59e7..6cea7c79d 100644
--- a/pkg/operator/ceph/controller/spec.go
+++ b/pkg/operator/ceph/controller/spec.go
@@ -570,23 +570,12 @@ func GenerateLivenessProbeExecDaemon(daemonType, daemonID string) *v1.Probe {
 				//
 				// Example:
 				// env -i sh -c "ceph --admin-daemon /run/ceph/ceph-osd.0.asok status"
-				//
-				// Ceph gives pretty un-diagnostic error message when `ceph status` or `ceph mon_status` command fails.
-				// Add a clear message after Ceph's to help.
-				// ref: https://github.com/rook/rook/issues/9846
 				Command: []string{
 					"env",
 					"-i",
 					"sh",
 					"-c",
-					fmt.Sprintf(`outp="$(ceph --admin-daemon %s %s 2>&1)"
-rc=$?
-if [ $rc -ne 0 ]; then
-  echo "ceph daemon health check failed with the following output:"
-  echo "$outp" | sed -e 's/^/> /g'
-  exit $rc
-fi`,
-						confDaemon.buildSocketPath(), confDaemon.buildAdminSocketCommand()),
+					fmt.Sprintf("ceph --admin-daemon %s %s", confDaemon.buildSocketPath(), confDaemon.buildAdminSocketCommand()),
 				},
 			},
 		},
diff --git a/pkg/operator/ceph/csi/csi.go b/pkg/operator/ceph/csi/csi.go
index 46b6872a1..bb12c4592 100644
--- a/pkg/operator/ceph/csi/csi.go
+++ b/pkg/operator/ceph/csi/csi.go
@@ -152,10 +152,9 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error {
 		CSIParam.EnableOIDCTokenProjection = true
 	}
 
-	// enable RBD, CephFS and NFS snapshotter by default
+	// enable RBD and CephFS snapshotter by default
 	CSIParam.EnableRBDSnapshotter = true
 	CSIParam.EnableCephFSSnapshotter = true
-	CSIParam.EnableNFSSnapshotter = true
 
 	if strings.EqualFold(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_RBD_SNAPSHOTTER", "true"), "false") {
 		CSIParam.EnableRBDSnapshotter = false
@@ -165,8 +164,9 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error {
 		CSIParam.EnableCephFSSnapshotter = false
 	}
 
-	if strings.EqualFold(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_NFS_SNAPSHOTTER", "true"), "false") {
-		CSIParam.EnableNFSSnapshotter = false
+	CSIParam.EnableVolumeReplicationSideCar = false
+	if strings.EqualFold(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_VOLUME_REPLICATION", "false"), "true") {
+		CSIParam.EnableVolumeReplicationSideCar = true
 	}
 
 	CSIParam.EnableCSIAddonsSideCar = false
@@ -174,11 +174,6 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error {
 		CSIParam.EnableCSIAddonsSideCar = true
 	}
 
-	CSIParam.EnableCSITopology = false
-	if strings.EqualFold(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_TOPOLOGY", "false"), "true") {
-		CSIParam.EnableCSITopology = true
-	}
-
 	if strings.EqualFold(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_ENCRYPTION", "false"), "true") {
 		CSIParam.EnableCSIEncryption = true
 	}
@@ -259,8 +254,8 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error {
 	CSIParam.AttacherImage = k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_ATTACHER_IMAGE", DefaultAttacherImage)
 	CSIParam.SnapshotterImage = k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_SNAPSHOTTER_IMAGE", DefaultSnapshotterImage)
 	CSIParam.KubeletDirPath = k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_KUBELET_DIR_PATH", DefaultKubeletDirPath)
+	CSIParam.VolumeReplicationImage = k8sutil.GetValue(r.opConfig.Parameters, "CSI_VOLUME_REPLICATION_IMAGE", DefaultVolumeReplicationImage)
 	CSIParam.CSIAddonsImage = k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSIADDONS_IMAGE", DefaultCSIAddonsImage)
-	CSIParam.CSIDomainLabels = k8sutil.GetValue(r.opConfig.Parameters, "CSI_TOPOLOGY_DOMAIN_LABELS", "")
 	csiCephFSPodLabels := k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_CEPHFS_POD_LABELS", "")
 	CSIParam.CSICephFSPodLabels = k8sutil.ParseStringToLabels(csiCephFSPodLabels)
 	csiNFSPodLabels := k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_NFS_POD_LABELS", "")
diff --git a/pkg/operator/ceph/csi/predicate.go b/pkg/operator/ceph/csi/predicate.go
index d04a8ac5f..8962a96e6 100644
--- a/pkg/operator/ceph/csi/predicate.go
+++ b/pkg/operator/ceph/csi/predicate.go
@@ -18,6 +18,7 @@ package csi
 
 import (
 	"context"
+	"regexp"
 
 	"github.com/google/go-cmp/cmp"
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
@@ -79,9 +80,7 @@ func predicateController(ctx context.Context, c client.Client, opNamespace strin
 					if old.Name == opcontroller.OperatorSettingConfigMapName && new.Name == opcontroller.OperatorSettingConfigMapName {
 						diff := cmp.Diff(old.Data, new.Data, resourceQtyComparer)
 						logger.Debugf("operator configmap diff:\n %s", diff)
-						if diff != "" {
-							return true
-						}
+						return findCSIChange(diff)
 					}
 				}
 			}
@@ -110,3 +109,17 @@ func predicateController(ctx context.Context, c client.Client, opNamespace strin
 		},
 	}
 }
+
+func findCSIChange(str string) bool {
+	var re = regexp.MustCompile(`(?m)^(\+|-).*(\"ROOK_CSI_|\"CSI_).*,$`)
+	found := re.FindAllString(str, -1)
+	if len(found) > 0 {
+		for _, match := range found {
+			// logger.Debugf("ceph csi config changed with: %q", match)
+			logger.Infof("ceph csi config changed with: %q", match)
+		}
+		return true
+	}
+
+	return false
+}
diff --git a/pkg/operator/ceph/csi/spec.go b/pkg/operator/ceph/csi/spec.go
index 9416ff4d1..3b9a478ef 100644
--- a/pkg/operator/ceph/csi/spec.go
+++ b/pkg/operator/ceph/csi/spec.go
@@ -39,50 +39,48 @@ import (
 )
 
 type Param struct {
-	CSIPluginImage               string
-	RegistrarImage               string
-	ProvisionerImage             string
-	AttacherImage                string
-	SnapshotterImage             string
-	ResizerImage                 string
-	DriverNamePrefix             string
-	EnableCSIGRPCMetrics         string
-	KubeletDirPath               string
-	ForceCephFSKernelClient      string
-	CephFSPluginUpdateStrategy   string
-	NFSPluginUpdateStrategy      string
-	RBDPluginUpdateStrategy      string
-	PluginPriorityClassName      string
-	ProvisionerPriorityClassName string
-	VolumeReplicationImage       string
-	CSIAddonsImage               string
-	CSIClusterName               string
-	CSIDomainLabels              string
-	GRPCTimeout                  time.Duration
-	CSIEnableMetadata            bool
-	EnablePluginSelinuxHostMount bool
-	EnableCSIHostNetwork         bool
-	EnableOMAPGenerator          bool
-	EnableRBDSnapshotter         bool
-	EnableCephFSSnapshotter      bool
-	EnableNFSSnapshotter         bool
-	EnableCSIAddonsSideCar       bool
-	MountCustomCephConf          bool
-	EnableOIDCTokenProjection    bool
-	EnableCSIEncryption          bool
-	EnableCSITopology            bool
-	EnableLiveness               bool
-	LogLevel                     uint8
-	SidecarLogLevel              uint8
-	CephFSGRPCMetricsPort        uint16
-	CephFSLivenessMetricsPort    uint16
-	RBDGRPCMetricsPort           uint16
-	CSIAddonsPort                uint16
-	RBDLivenessMetricsPort       uint16
-	ProvisionerReplicas          int32
-	CSICephFSPodLabels           map[string]string
-	CSINFSPodLabels              map[string]string
-	CSIRBDPodLabels              map[string]string
+	CSIPluginImage                 string
+	RegistrarImage                 string
+	ProvisionerImage               string
+	AttacherImage                  string
+	SnapshotterImage               string
+	ResizerImage                   string
+	DriverNamePrefix               string
+	EnableCSIGRPCMetrics           string
+	KubeletDirPath                 string
+	ForceCephFSKernelClient        string
+	CephFSPluginUpdateStrategy     string
+	NFSPluginUpdateStrategy        string
+	RBDPluginUpdateStrategy        string
+	PluginPriorityClassName        string
+	ProvisionerPriorityClassName   string
+	VolumeReplicationImage         string
+	CSIAddonsImage                 string
+	CSIClusterName                 string
+	GRPCTimeout                    time.Duration
+	CSIEnableMetadata              bool
+	EnablePluginSelinuxHostMount   bool
+	EnableCSIHostNetwork           bool
+	EnableOMAPGenerator            bool
+	EnableRBDSnapshotter           bool
+	EnableCephFSSnapshotter        bool
+	EnableVolumeReplicationSideCar bool
+	EnableCSIAddonsSideCar         bool
+	MountCustomCephConf            bool
+	EnableOIDCTokenProjection      bool
+	EnableCSIEncryption            bool
+	EnableLiveness                 bool
+	LogLevel                       uint8
+	SidecarLogLevel                uint8
+	CephFSGRPCMetricsPort          uint16
+	CephFSLivenessMetricsPort      uint16
+	RBDGRPCMetricsPort             uint16
+	CSIAddonsPort                  uint16
+	RBDLivenessMetricsPort         uint16
+	ProvisionerReplicas            int32
+	CSICephFSPodLabels             map[string]string
+	CSINFSPodLabels                map[string]string
+	CSIRBDPodLabels                map[string]string
 }
 
 type templateParam struct {
@@ -128,13 +126,14 @@ var (
 // manually challenging.
 var (
 	// image names
-	DefaultCSIPluginImage   = "quay.io/cephcsi/cephcsi:v3.7.0"
-	DefaultRegistrarImage   = "registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.5.1"
-	DefaultProvisionerImage = "registry.k8s.io/sig-storage/csi-provisioner:v3.2.1"
-	DefaultAttacherImage    = "registry.k8s.io/sig-storage/csi-attacher:v3.5.0"
-	DefaultSnapshotterImage = "registry.k8s.io/sig-storage/csi-snapshotter:v6.0.1"
-	DefaultResizerImage     = "registry.k8s.io/sig-storage/csi-resizer:v1.5.0"
-	DefaultCSIAddonsImage   = "quay.io/csiaddons/k8s-sidecar:v0.5.0"
+	DefaultCSIPluginImage         = "quay.io/cephcsi/cephcsi:v3.7.0"
+	DefaultRegistrarImage         = "registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.5.1"
+	DefaultProvisionerImage       = "registry.k8s.io/sig-storage/csi-provisioner:v3.2.1"
+	DefaultAttacherImage          = "registry.k8s.io/sig-storage/csi-attacher:v3.5.0"
+	DefaultSnapshotterImage       = "registry.k8s.io/sig-storage/csi-snapshotter:v6.0.1"
+	DefaultResizerImage           = "registry.k8s.io/sig-storage/csi-resizer:v1.5.0"
+	DefaultVolumeReplicationImage = "quay.io/csiaddons/volumereplication-operator:v0.3.0"
+	DefaultCSIAddonsImage         = "quay.io/csiaddons/k8s-sidecar:v0.4.0"
 
 	// Local package template path for RBD
 	//go:embed template/rbd/csi-rbdplugin.yaml
diff --git a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml
index 7f4ac6d2d..ad106b38b 100644
--- a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml
+++ b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml
@@ -21,46 +21,6 @@ spec:
       priorityClassName: {{ .ProvisionerPriorityClassName }}
       {{ end }}
       containers:
-        {{ if .EnableNFSSnapshotter }}
-        - name: csi-snapshotter
-          image:  {{ .SnapshotterImage }}
-          args:
-            - "--csi-address=$(ADDRESS)"
-            - "--v={{ .SidecarLogLevel }}"
-            - "--timeout={{ .GRPCTimeout }}"
-            - "--leader-election=true"
-            - "--leader-election-namespace={{ .Namespace }}"
-            - "--leader-election-lease-duration=137s"
-            - "--leader-election-renew-deadline=107s"
-            - "--leader-election-retry-period=26s"
-            - "--extra-create-metadata=true"
-          env:
-            - name: ADDRESS
-              value: unix:///csi/csi-provisioner.sock
-          imagePullPolicy: "IfNotPresent"
-          volumeMounts:
-            - name: socket-dir
-              mountPath: /csi
-        {{ end }}
-        - name: csi-resizer
-          image: {{ .ResizerImage }}
-          args:
-            - "--csi-address=$(ADDRESS)"
-            - "--v={{ .SidecarLogLevel }}"
-            - "--timeout={{ .GRPCTimeout }}"
-            - "--leader-election=true"
-            - "--leader-election-namespace={{ .Namespace }}"
-            - "--leader-election-lease-duration=137s"
-            - "--leader-election-renew-deadline=107s"
-            - "--leader-election-retry-period=26s"
-            - "--handle-volume-inuse-error=false"
-          env:
-            - name: ADDRESS
-              value: unix:///csi/csi-provisioner.sock
-          imagePullPolicy: "IfNotPresent"
-          volumeMounts:
-            - name: socket-dir
-              mountPath: /csi
         - name: csi-provisioner
           image: {{ .ProvisionerImage }}
           args:
diff --git a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml
index 691d59b65..243f5a7cb 100644
--- a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml
+++ b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml
@@ -36,9 +36,6 @@ spec:
             - "--leader-election-retry-period=26s"
             - "--default-fstype=ext4"
             - "--extra-create-metadata=true"
-            {{- if .EnableCSITopology }}
-            - "--feature-gates=Topology=true"
-            {{- end }}
           env:
             - name: ADDRESS
               value: unix:///csi/csi-provisioner.sock
@@ -124,6 +121,25 @@ spec:
             - name: keys-tmp-dir
               mountPath: /tmp/csi/keys
         {{ end }}
+        {{ if .EnableVolumeReplicationSideCar }}
+        - name: volume-replication
+          image: {{ .VolumeReplicationImage }}
+          args :
+            - "--metrics-bind-address=0"
+            - "--leader-election-namespace={{ .Namespace }}"
+            - "--driver-name={{ .DriverNamePrefix }}rbd.csi.ceph.com"
+            - "--csi-address=$(ADDRESS)"
+            - "--rpc-timeout={{ .GRPCTimeout }}"
+            - "--health-probe-bind-address=:9998"
+            - "--leader-elect=true"
+          env:
+            - name: ADDRESS
+              value: unix:///csi/csi-provisioner.sock
+          imagePullPolicy: "IfNotPresent"
+          volumeMounts:
+            - name: socket-dir
+              mountPath: /csi
+        {{ end }}
         {{ if .EnableCSIAddonsSideCar }}
         - name: csi-addons
           image: {{ .CSIAddonsImage }}
@@ -131,6 +147,7 @@ spec:
             - "--node-id=$(NODE_ID)"
             - "--v={{ .LogLevel }}"
             - "--csi-addons-address=$(CSIADDONS_ENDPOINT)"
+            - "--controller-ip=$(POD_IP)"
             - "--controller-port={{ .CSIAddonsPort }}"
             - "--pod=$(POD_NAME)"
             - "--namespace=$(POD_NAMESPACE)"
@@ -139,6 +156,10 @@ spec:
           ports:
             - containerPort: {{ .CSIAddonsPort }}
           env:
+            - name: POD_IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.podIP
             - name: NODE_ID
               valueFrom:
                 fieldRef:
diff --git a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml
index 2d25b7cbb..c387abba2 100644
--- a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml
+++ b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml
@@ -71,9 +71,6 @@ spec:
             {{ if .EnableCSIAddonsSideCar }}
             - "--csi-addons-endpoint=$(CSIADDONS_ENDPOINT)"
             {{ end }}
-            {{- if .EnableCSITopology }}
-            - "--domainlabels={{ .CSIDomainLabels }}"
-            {{- end }}
           env:
             - name: POD_IP
               valueFrom:
@@ -144,6 +141,7 @@ spec:
             - "--node-id=$(NODE_ID)"
             - "--v={{ .LogLevel }}"
             - "--csi-addons-address=$(CSIADDONS_ENDPOINT)"
+            - "--controller-ip=$(POD_IP)"
             - "--controller-port={{ .CSIAddonsPort }}"
             - "--pod=$(POD_NAME)"
             - "--namespace=$(POD_NAMESPACE)"
@@ -152,6 +150,10 @@ spec:
           ports:
             - containerPort: {{ .CSIAddonsPort }}
           env:
+            - name: POD_IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.podIP
             - name: NODE_ID
               valueFrom:
                 fieldRef:
diff --git a/pkg/operator/ceph/object/admin.go b/pkg/operator/ceph/object/admin.go
index b6db1e743..fa777a082 100644
--- a/pkg/operator/ceph/object/admin.go
+++ b/pkg/operator/ceph/object/admin.go
@@ -250,6 +250,7 @@ func runAdminCommand(c *Context, expectJSON bool, args ...string) (string, error
 			fmt.Sprintf("--rgw-zonegroup=%s", c.ZoneGroup),
 			fmt.Sprintf("--rgw-zone=%s", c.Zone),
 		}
+
 		args = append(args, options...)
 	}
 
diff --git a/pkg/operator/ceph/object/dependents.go b/pkg/operator/ceph/object/dependents.go
index bba074993..cf7d6cb4b 100644
--- a/pkg/operator/ceph/object/dependents.go
+++ b/pkg/operator/ceph/object/dependents.go
@@ -27,10 +27,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-const (
-	bucketDependentType                = "buckets in the object store (could be from ObjectBucketClaims or COSI Buckets)"
-	zoneIsMasterWithPeersDependentType = "zone is master and has peers"
-)
+const bucketDependentType = "buckets in the object store (could be from ObjectBucketClaims or COSI Buckets)"
 
 // CephObjectStoreDependents returns the buckets which exist in the object store that should block
 // deletion.
@@ -47,34 +44,6 @@ func CephObjectStoreDependents(
 
 	deps := dependents.NewDependentList()
 
-	if store.Spec.IsMultisite() {
-		// stores in multisite configs have different conditions that change what dependents should be checked
-		zoneIsMaster, err := CheckZoneIsMaster(objCtx)
-		if err != nil {
-			return deps, errors.Wrapf(err, baseErrMsg)
-		}
-		if !zoneIsMaster {
-			// zone is a peer, and the master is the source of truth
-			// we assume master is up-to-date and this peer can be deleted safely
-			// without checking for bucket dependents
-			return deps, nil
-		}
-
-		// check whether any peer zone exists
-		err = getMasterZoneDependents(deps, clusterdCtx, clusterInfo, store, objCtx)
-		if err != nil {
-			return deps, errors.Wrapf(err, "%s. failed to check multisite dependents", baseErrMsg)
-		}
-		if !deps.Empty() {
-			// zone is master with peers; require user intervention
-			logger.Errorf("%s. Either change the master or remove its peers before the deletion", zoneIsMasterWithPeersDependentType)
-			return deps, errors.Errorf("%s: %q\nall peer zones must be deleted, or a peer zone must be manually set as the master zone after that peer has all necessary data synched to it", zoneIsMasterWithPeersDependentType, deps.OfKind(zoneIsMasterWithPeersDependentType))
-		}
-
-		// this is a master zone with NO peers. it is the last store  that has this data,
-		// so we should prevent users from accidentally deleting it by continuing to check for buckets
-	}
-
 	// NOTE: we should still check for buckets when the RGW connection is external since we have no
 	// way of knowing if the bucket was created due to an ObjectBucketClaim or COSI Bucket.
 	err := getBucketDependents(deps, clusterdCtx, clusterInfo, store, objCtx, opsCtx)
@@ -137,31 +106,3 @@ func getBucketDependents(
 
 	return nil
 }
-
-func getMasterZoneDependents(
-	deps *dependents.DependentList,
-	clusterdCtx *clusterd.Context,
-	clusterInfo *client.ClusterInfo,
-	store *v1.CephObjectStore,
-	objContext *Context,
-) error {
-	realmArg := fmt.Sprintf("--rgw-realm=%s", objContext.Realm)
-	zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", objContext.ZoneGroup)
-	zoneGroupOutput, err := RunAdminCommandNoMultisite(objContext, true, "zonegroup", "get", realmArg, zoneGroupArg)
-	if err != nil {
-		return errors.Wrapf(err, "failed to fetch zonegroup %q", objContext.ZoneGroup)
-	}
-	zoneGroupJson, err := DecodeZoneGroupConfig(zoneGroupOutput)
-	if err != nil {
-		return errors.Wrapf(err, "failed to decode zonegroup %q", objContext.ZoneGroup)
-	}
-	// if only master zone remains then it is okay delete
-	if len(zoneGroupJson.Zones) > 1 {
-		for _, zone := range zoneGroupJson.Zones {
-			if zone.Name != store.Spec.Zone.Name {
-				deps.Add(zoneIsMasterWithPeersDependentType, zone.Name)
-			}
-		}
-	}
-	return nil
-}
diff --git a/pkg/operator/ceph/object/objectstore.go b/pkg/operator/ceph/object/objectstore.go
index 9b8798a54..31a1e40d6 100644
--- a/pkg/operator/ceph/object/objectstore.go
+++ b/pkg/operator/ceph/object/objectstore.go
@@ -61,7 +61,6 @@ var (
 		"rgw.log",
 		"rgw.buckets.index",
 		"rgw.buckets.non-ec",
-		"rgw.otp",
 	}
 	dataPoolName = "rgw.buckets.data"
 
@@ -120,7 +119,7 @@ func removeObjectStoreFromMultisite(objContext *Context, spec cephv1.ObjectStore
 		zoneEndpoints := strings.Join(zoneEndpointsList, ",")
 		endpointArg := fmt.Sprintf("--endpoints=%s", zoneEndpoints)
 
-		zoneIsMaster, err := CheckZoneIsMaster(objContext)
+		zoneIsMaster, err := checkZoneIsMaster(objContext)
 		if err != nil {
 			return errors.Wrapf(err, "failed to determine if zone %q is master", objContext.Zone)
 		}
@@ -184,11 +183,7 @@ func deleteSingleSiteRealmAndPools(objContext *Context, spec cephv1.ObjectStoreS
 	}
 
 	if !spec.PreservePoolsOnDelete {
-		if EmptyPool(spec.DataPool) && EmptyPool(spec.MetadataPool) {
-			logger.Info("skipping removal of pools since not specified in the object store")
-			return nil
-		}
-		err = DeletePools(objContext, lastStore, objContext.Name)
+		err = deletePools(objContext, spec, lastStore)
 		if err != nil {
 			return errors.Wrap(err, "failed to delete object store pools")
 		}
@@ -232,7 +227,7 @@ func getMultisiteForObjectStore(ctx context.Context, clusterdContext *clusterd.C
 	return name, name, name, nil
 }
 
-func CheckZoneIsMaster(objContext *Context) (bool, error) {
+func checkZoneIsMaster(objContext *Context) (bool, error) {
 	logger.Debugf("checking if zone %v is the master zone", objContext.Zone)
 	realmArg := fmt.Sprintf("--rgw-realm=%s", objContext.Realm)
 	zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", objContext.ZoneGroup)
@@ -457,7 +452,7 @@ func JoinMultisite(objContext *Context, endpointArg, zoneEndpoints, namespace st
 	zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", objContext.ZoneGroup)
 	zoneArg := fmt.Sprintf("--rgw-zone=%s", objContext.Zone)
 
-	zoneIsMaster, err := CheckZoneIsMaster(objContext)
+	zoneIsMaster, err := checkZoneIsMaster(objContext)
 	if err != nil {
 		return err
 	}
@@ -637,7 +632,12 @@ func getObjectStores(context *Context) ([]string, error) {
 	return r.Realms, nil
 }
 
-func DeletePools(ctx *Context, lastStore bool, poolPrefix string) error {
+func deletePools(ctx *Context, spec cephv1.ObjectStoreSpec, lastStore bool) error {
+	if emptyPool(spec.DataPool) && emptyPool(spec.MetadataPool) {
+		logger.Info("skipping removal of pools since not specified in the object store")
+		return nil
+	}
+
 	pools := append(metadataPools, dataPoolName)
 	if lastStore {
 		pools = append(pools, rootPool)
@@ -646,7 +646,7 @@ func DeletePools(ctx *Context, lastStore bool, poolPrefix string) error {
 	if configurePoolsConcurrently() {
 		waitGroup, _ := errgroup.WithContext(ctx.clusterInfo.Context)
 		for _, pool := range pools {
-			name := poolName(poolPrefix, pool)
+			name := poolName(ctx.Name, pool)
 			waitGroup.Go(func() error {
 				if err := cephclient.DeletePool(ctx.Context, ctx.clusterInfo, name); err != nil {
 					return errors.Wrapf(err, "failed to delete pool %q. ", name)
@@ -663,7 +663,7 @@ func DeletePools(ctx *Context, lastStore bool, poolPrefix string) error {
 
 	} else {
 		for _, pool := range pools {
-			name := poolName(poolPrefix, pool)
+			name := poolName(ctx.Name, pool)
 			if err := cephclient.DeletePool(ctx.Context, ctx.clusterInfo, name); err != nil {
 				logger.Warningf("failed to delete pool %q. %v", name, err)
 			}
@@ -714,7 +714,7 @@ func missingPools(context *Context) ([]string, error) {
 	}
 
 	missingPools := []string{}
-	for _, objPool := range allObjectPools(context.Zone) {
+	for _, objPool := range allObjectPools(context.Name) {
 		if !existingPools.Has(objPool) {
 			missingPools = append(missingPools, objPool)
 		}
@@ -724,7 +724,7 @@ func missingPools(context *Context) ([]string, error) {
 }
 
 func CreatePools(context *Context, clusterSpec *cephv1.ClusterSpec, metadataPool, dataPool cephv1.PoolSpec) error {
-	if EmptyPool(dataPool) && EmptyPool(metadataPool) {
+	if emptyPool(dataPool) && emptyPool(metadataPool) {
 		logger.Info("no pools specified for the CR, checking for their existence...")
 		missingPools, err := missingPools(context)
 		if err != nil {
@@ -806,12 +806,12 @@ func createRGWPool(ctx *Context, clusterSpec *cephv1.ClusterSpec, poolSpec cephv
 	return nil
 }
 
-func poolName(poolPrefix, poolName string) string {
+func poolName(storeName, poolName string) string {
 	if strings.HasPrefix(poolName, ".") {
 		return poolName
 	}
 	// the name of the pool is <instance>.<name>, except for the pool ".rgw.root" that spans object stores
-	return fmt.Sprintf("%s.%s", poolPrefix, poolName)
+	return fmt.Sprintf("%s.%s", storeName, poolName)
 }
 
 // GetObjectBucketProvisioner returns the bucket provisioner name appended with operator namespace if OBC is watching on it
@@ -1048,19 +1048,3 @@ func listsAreEqual(a, b []string) bool {
 	}
 	return true
 }
-
-func CheckIfZonePresentInZoneGroup(objContext *Context) (bool, error) {
-	output, err := runAdminCommand(objContext, true, "zonegroup", "get")
-	if err != nil {
-		return false, err
-	}
-	zoneGroupJson, err := DecodeZoneGroupConfig(output)
-	if err != nil {
-		return false, errors.Wrap(err, "failed to parse `radosgw-admin zonegroup get` output")
-	}
-	zoneExists, _ := findZoneEndpoints(objContext.Zone, zoneGroupJson.Zones)
-	if zoneExists {
-		return true, nil
-	}
-	return false, nil
-}
diff --git a/pkg/operator/ceph/object/rgw.go b/pkg/operator/ceph/object/rgw.go
index 66c8c6782..87628ff88 100644
--- a/pkg/operator/ceph/object/rgw.go
+++ b/pkg/operator/ceph/object/rgw.go
@@ -291,12 +291,12 @@ func (r *ReconcileCephObjectStore) validateStore(s *cephv1.CephObjectStore) erro
 
 	// Validate the pool settings, but allow for empty pools specs in case they have already been created
 	// such as by the ceph mgr
-	if !EmptyPool(s.Spec.MetadataPool) {
+	if !emptyPool(s.Spec.MetadataPool) {
 		if err := pool.ValidatePoolSpec(r.context, r.clusterInfo, r.clusterSpec, &s.Spec.MetadataPool); err != nil {
 			return errors.Wrap(err, "invalid metadata pool spec")
 		}
 	}
-	if !EmptyPool(s.Spec.DataPool) {
+	if !emptyPool(s.Spec.DataPool) {
 		if err := pool.ValidatePoolSpec(r.context, r.clusterInfo, r.clusterSpec, &s.Spec.DataPool); err != nil {
 			return errors.Wrap(err, "invalid data pool spec")
 		}
@@ -309,7 +309,7 @@ func (c *clusterConfig) generateSecretName(id string) string {
 	return fmt.Sprintf("%s-%s-%s-keyring", AppName, c.store.Name, id)
 }
 
-func EmptyPool(pool cephv1.PoolSpec) bool {
+func emptyPool(pool cephv1.PoolSpec) bool {
 	return reflect.DeepEqual(pool, cephv1.PoolSpec{})
 }
 
diff --git a/pkg/operator/ceph/object/zone/controller.go b/pkg/operator/ceph/object/zone/controller.go
index 2663784fa..992494ed6 100644
--- a/pkg/operator/ceph/object/zone/controller.go
+++ b/pkg/operator/ceph/object/zone/controller.go
@@ -19,7 +19,6 @@ package zone
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"reflect"
 	"strings"
@@ -28,6 +27,7 @@ import (
 
 	opcontroller "github.com/rook/rook/pkg/operator/ceph/controller"
 	"github.com/rook/rook/pkg/operator/ceph/reporting"
+	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/tools/record"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -55,10 +55,6 @@ const (
 	controllerName = "ceph-object-zone-controller"
 )
 
-type domainRootType struct {
-	DomainRoot string `json:"domain_root"`
-}
-
 var waitForRequeueIfObjectZoneGroupNotReady = reconcile.Result{Requeue: true, RequeueAfter: 10 * time.Second}
 
 var logger = capnslog.NewPackageLogger("github.com/rook/rook", controllerName)
@@ -139,16 +135,11 @@ func (r *ReconcileObjectZone) reconcile(request reconcile.Request) (reconcile.Re
 		// Error reading the object - requeue the request.
 		return reconcile.Result{}, *cephObjectZone, errors.Wrap(err, "failed to get CephObjectZone")
 	}
-
 	// update observedGeneration local variable with current generation value,
 	// because generation can be changed before reconcile got completed
 	// CR status will be updated at end of reconcile, so to reflect the reconcile has finished
 	observedGeneration := cephObjectZone.ObjectMeta.Generation
-	// Set a finalizer so we can do cleanup before the object goes away
-	err = opcontroller.AddFinalizerIfNotPresent(r.opManagerContext, r.client, cephObjectZone)
-	if err != nil {
-		return reconcile.Result{}, *cephObjectZone, errors.Wrap(err, "failed to add finalizer")
-	}
+
 	// The CR was just created, initializing status fields
 	if cephObjectZone.Status == nil {
 		r.updateStatus(k8sutil.ObservedGenerationNotAvailable, request.NamespacedName, k8sutil.EmptyStatus)
@@ -160,11 +151,6 @@ func (r *ReconcileObjectZone) reconcile(request reconcile.Request) (reconcile.Re
 		// This handles the case where the Ceph Cluster is gone and we want to delete that CR
 		//
 		if !cephObjectZone.GetDeletionTimestamp().IsZero() && !cephClusterExists {
-			// Remove finalizer
-			err := opcontroller.RemoveFinalizer(r.opManagerContext, r.client, cephObjectZone)
-			if err != nil {
-				return reconcile.Result{}, *cephObjectZone, errors.Wrap(err, "failed to remove finalizer")
-			}
 			// Return and do not requeue. Successful deletion.
 			return reconcile.Result{}, *cephObjectZone, nil
 		}
@@ -172,6 +158,15 @@ func (r *ReconcileObjectZone) reconcile(request reconcile.Request) (reconcile.Re
 	}
 	r.clusterSpec = &cephCluster.Spec
 
+	// DELETE: the CR was deleted
+	if !cephObjectZone.GetDeletionTimestamp().IsZero() {
+		logger.Debugf("deleting zone CR %q", cephObjectZone.Name)
+		r.recorder.Eventf(cephObjectZone, v1.EventTypeNormal, string(cephv1.ReconcileStarted), "deleting CephObjectZOne %q", cephObjectZone.Name)
+
+		// Return and do not requeue. Successful deletion.
+		return reconcile.Result{}, *cephObjectZone, nil
+	}
+
 	// Populate clusterInfo during each reconcile
 	r.clusterInfo, _, _, err = opcontroller.LoadClusterInfo(r.context, r.opManagerContext, request.NamespacedName.Namespace)
 	if err != nil {
@@ -185,21 +180,15 @@ func (r *ReconcileObjectZone) reconcile(request reconcile.Request) (reconcile.Re
 		return reconcile.Result{}, *cephObjectZone, errors.Wrapf(err, "invalid CephObjectZone CR %q", cephObjectZone.Name)
 	}
 
+	// Start object reconciliation, updating status for this
+	r.updateStatus(k8sutil.ObservedGenerationNotAvailable, request.NamespacedName, k8sutil.ReconcilingStatus)
+
 	// Make sure an ObjectZoneGroup is present
-	realmName, reconcileResponse, err := r.getCephObjectZoneGroup(cephObjectZone)
+	realmName, reconcileResponse, err := r.reconcileObjectZoneGroup(cephObjectZone)
 	if err != nil {
 		return reconcileResponse, *cephObjectZone, err
 	}
 
-	// DELETE: the CR was deleted
-	if !cephObjectZone.GetDeletionTimestamp().IsZero() {
-		res, err := r.deleteCephObjectZone(cephObjectZone, realmName)
-		return res, *cephObjectZone, err
-	}
-
-	// Start object reconciliation, updating status for this
-	r.updateStatus(k8sutil.ObservedGenerationNotAvailable, request.NamespacedName, k8sutil.ReconcilingStatus)
-
 	// Make sure zone group has been created in Ceph Cluster
 	reconcileResponse, err = r.reconcileCephZoneGroup(cephObjectZone, realmName)
 	if err != nil {
@@ -324,7 +313,7 @@ func (r *ReconcileObjectZone) createPoolsAndZone(objContext *object.Context, zon
 	return nil
 }
 
-func (r *ReconcileObjectZone) getCephObjectZoneGroup(zone *cephv1.CephObjectZone) (string, reconcile.Result, error) {
+func (r *ReconcileObjectZone) reconcileObjectZoneGroup(zone *cephv1.CephObjectZone) (string, reconcile.Result, error) {
 	// empty zoneGroup gets filled by r.client.Get()
 	zoneGroup := &cephv1.CephObjectZoneGroup{}
 	err := r.client.Get(r.opManagerContext, types.NamespacedName{Name: zone.Spec.ZoneGroup, Namespace: zone.Namespace}, zoneGroup)
@@ -407,131 +396,3 @@ func (r *ReconcileObjectZone) updateStatus(observedGeneration int64, name types.
 	}
 	logger.Debugf("object zone %q status updated to %q", name, status)
 }
-func (r *ReconcileObjectZone) deleteZone(objContext *object.Context) error {
-	realmArg := fmt.Sprintf("--rgw-realm=%s", objContext.Realm)
-	//	zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", objContext.ZoneGroup)
-	zoneArg := fmt.Sprintf("--rgw-zone=%s", objContext.Zone)
-
-	args := []string{"zone", "delete", realmArg, zoneArg}
-	output, err := object.RunAdminCommandNoMultisite(objContext, false, args...)
-	if err != nil {
-		return errors.Wrapf(err, "failed to delete ceph zone %q for reason %q", objContext.Zone, output)
-	}
-	return nil
-}
-
-func (r *ReconcileObjectZone) removeZoneFromZonegroup(objContext *object.Context) error {
-	realmArg := fmt.Sprintf("--rgw-realm=%s", objContext.Realm)
-	zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", objContext.ZoneGroup)
-	zoneArg := fmt.Sprintf("--rgw-zone=%s", objContext.Zone)
-
-	args := []string{"zonegroup", "remove", realmArg, zoneGroupArg, zoneArg}
-	output, err := object.RunAdminCommandNoMultisite(objContext, false, args...)
-	if err != nil {
-		return errors.Wrapf(err, "failed to delete ceph zone %q for reason %q", objContext.Zone, output)
-	}
-
-	args = []string{"period", "update", "--commit", realmArg, zoneGroupArg}
-	output, err = object.RunAdminCommandNoMultisite(objContext, false, args...)
-	if err != nil {
-		return errors.Wrapf(err, "failed to commit updates in ceph zonegroup %q for reason %q", objContext.ZoneGroup, output)
-	}
-	return nil
-}
-
-func (r *ReconcileObjectZone) deleteZonePools(objContext *object.Context, zone *cephv1.CephObjectZone, realmName string) error {
-	realmArg := fmt.Sprintf("--rgw-realm=%s", realmName)
-	zoneGroupArg := fmt.Sprintf("--rgw-zonegroup=%s", zone.Spec.ZoneGroup)
-	zoneArg := fmt.Sprintf("--rgw-zone=%s", zone.Name)
-
-	zoneOutput, err := object.RunAdminCommandNoMultisite(objContext, true, "zone", "get", realmArg, zoneGroupArg, zoneArg)
-	if err != nil {
-		return errors.Wrapf(err, "failed to get zone %q", zone.Name)
-	}
-	poolPrefix, err := decodePoolPrefixfromZone(zoneOutput)
-	if err != nil {
-		return errors.Wrapf(err, "failed to parse pool prefix for zone json %v", zoneOutput)
-	}
-
-	logger.Debugf("deleting pools for ceph zone %q with prefix %q", zone.Name, poolPrefix)
-
-	if object.EmptyPool(zone.Spec.DataPool) && object.EmptyPool(zone.Spec.MetadataPool) {
-		logger.Info("skipping removal of pools since not specified in the object zone")
-		return nil
-	}
-	err = object.DeletePools(objContext, false, poolPrefix)
-	if err != nil {
-		return errors.Wrap(err, "failed to delete rgw pools")
-	}
-
-	return nil
-}
-
-func decodePoolPrefixfromZone(data string) (string, error) {
-	var domain domainRootType
-	err := json.Unmarshal([]byte(data), &domain)
-	if err != nil {
-		return "", errors.Wrap(err, "failed to unmarshal json")
-	}
-	s := strings.Split(domain.DomainRoot, ".rgw.")
-	return s[0], err
-}
-func (r *ReconcileObjectZone) deleteCephObjectZone(zone *cephv1.CephObjectZone, realmName string) (reconcile.Result, error) {
-	logger.Debugf("deleting zone CR %q", zone.Name)
-	objContext := object.NewContext(r.context, r.clusterInfo, zone.Name)
-	objContext.Realm = realmName
-	objContext.ZoneGroup = zone.Spec.ZoneGroup
-	objContext.Zone = zone.Name
-	zonePresent, err := object.CheckIfZonePresentInZoneGroup(objContext)
-	if err != nil {
-		return reconcile.Result{}, err
-	}
-	zoneIsMaster, err := object.CheckZoneIsMaster(objContext)
-	if err != nil {
-		return reconcile.Result{}, err
-	}
-	if zonePresent {
-		deps, err := CephObjectZoneDependentStores(r.context, r.clusterInfo, zone, objContext)
-		if err != nil {
-			return reconcile.Result{}, err
-		}
-		if !deps.Empty() {
-			err := reporting.ReportDeletionBlockedDueToDependents(r.opManagerContext, logger, r.client, zone, deps)
-			return opcontroller.WaitForRequeueIfFinalizerBlocked, err
-		}
-		reporting.ReportDeletionNotBlockedDueToDependents(r.opManagerContext, logger, r.client, r.recorder, zone)
-		if !zoneIsMaster {
-			err = r.removeZoneFromZonegroup(objContext)
-			if err != nil {
-				return reconcile.Result{}, err
-			}
-			zonePresent = false
-		}
-	}
-
-	// zone successfully removed from zonegroup proceed with delete
-	// master zone cannot be removed from zonegroup, it will be always present
-	if !zonePresent || zoneIsMaster {
-		if !zone.Spec.PreservePoolsOnDelete {
-			// This case zone is removed only after the successful pool deletion
-			err = r.deleteZonePools(objContext, zone, realmName)
-			if err != nil {
-				res, _, err := r.setFailedStatus(k8sutil.ObservedGenerationNotAvailable, zone, types.NamespacedName{Namespace: zone.Namespace, Name: zone.Name}, "failed to delete ceph zone", err)
-				return res, err
-			}
-		} else {
-			logger.Infof("PreservePoolsOnDelete is set in object zone %s. Pools is not deleted, but Zone is not removed", objContext.Name)
-		}
-		err = r.deleteZone(objContext)
-		if err != nil {
-			return reconcile.Result{}, errors.Wrapf(err, "failed to delete zone %s", objContext.Name)
-		}
-		// Remove finalizer
-		err = opcontroller.RemoveFinalizer(r.opManagerContext, r.client, zone)
-		if err != nil {
-			return reconcile.Result{}, errors.Wrap(err, "failed to remove finalizer")
-		}
-	}
-	// Return and do not requeue. Successful deletion.
-	return reconcile.Result{}, nil
-}
diff --git a/pkg/operator/ceph/object/zone/dependents.go b/pkg/operator/ceph/object/zone/dependents.go
deleted file mode 100644
index 7b7ec61c8..000000000
--- a/pkg/operator/ceph/object/zone/dependents.go
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-Copyright 2022 The Rook Authors. All rights reserved.
-
-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 zone
-
-import (
-	"fmt"
-
-	"github.com/pkg/errors"
-	v1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
-	"github.com/rook/rook/pkg/clusterd"
-	"github.com/rook/rook/pkg/daemon/ceph/client"
-	"github.com/rook/rook/pkg/operator/ceph/object"
-	"github.com/rook/rook/pkg/util/dependents"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func CephObjectZoneDependentStores(
-	clusterdCtx *clusterd.Context,
-	clusterInfo *client.ClusterInfo,
-	zone *v1.CephObjectZone,
-	objContext *object.Context,
-) (*dependents.DependentList, error) {
-	nsName := fmt.Sprintf("%s/%s", zone.Namespace, zone.Name)
-	baseErrMsg := fmt.Sprintf("failed to get dependents of CephObjectZone %q", nsName)
-
-	deps := dependents.NewDependentList()
-	// CephObjectStores
-	stores, err := clusterdCtx.RookClientset.CephV1().CephObjectStores(zone.Namespace).List(clusterInfo.Context, metav1.ListOptions{})
-	if err != nil {
-		return deps, errors.Wrapf(err, "%s. failed to list CephObjectStores for CephObjectZone %q", baseErrMsg, nsName)
-	}
-	for _, store := range stores.Items {
-		if store.Spec.Zone.Name == zone.Name {
-			deps.Add("CephObjectStore", store.Name)
-			logger.Debugf("found CephObjectStore %q that depends on CephObjectZone %q", store.Name, nsName)
-
-		} else {
-			logger.Debugf("found CephObjectStore %q that does not depend on CephObjectZone %q", store.Name, nsName)
-		}
-	}
-
-	return deps, nil
-}


Test patch:
diff --git a/deploy/examples/object-multisite-test.yaml b/deploy/examples/object-multisite-test.yaml
index 74575be6c..8e7fe4a7f 100644
--- a/deploy/examples/object-multisite-test.yaml
+++ b/deploy/examples/object-multisite-test.yaml
@@ -38,8 +38,6 @@ spec:
   # recommended to set this value if ingress used for exposing rgw endpoints
   # customEndpoints:
   #   - "http://rgw-a.fqdn"
-  # if the pools need to be removed from backend enable following setting
-  # preservePoolsOnDelete: false
 ---
 apiVersion: ceph.rook.io/v1
 kind: CephObjectStore
diff --git a/pkg/daemon/ceph/osd/kms/envs_test.go b/pkg/daemon/ceph/osd/kms/envs_test.go
index 20bb44786..c65369d4b 100644
--- a/pkg/daemon/ceph/osd/kms/envs_test.go
+++ b/pkg/daemon/ceph/osd/kms/envs_test.go
@@ -141,14 +141,6 @@ func TestVaultConfigToEnvVar(t *testing.T) {
 				{Name: "KMS_PROVIDER", Value: TypeIBM},
 			},
 		},
-		{
-			"kmip - token details is removed from the details",
-			args{spec: cephv1.ClusterSpec{Security: cephv1.SecuritySpec{KeyManagementService: cephv1.KeyManagementServiceSpec{ConnectionDetails: map[string]string{"KMS_PROVIDER": TypeKMIP, "CLIENT_KEY": "foo", "CLIENT_CERT": "foo", "CA_CERT": "foo", "TLS_SERVER_NAME": "pykmip"}, TokenSecretName: "kmip-token"}}}},
-			[]v1.EnvVar{
-				{Name: "KMIP_KMS_PROVIDER", Value: TypeKMIP},
-				{Name: "KMIP_TLS_SERVER_NAME", Value: "pykmip"},
-			},
-		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/pkg/daemon/ceph/osd/kms/kmip_test.go b/pkg/daemon/ceph/osd/kms/kmip_test.go
deleted file mode 100644
index 6d3a828f8..000000000
--- a/pkg/daemon/ceph/osd/kms/kmip_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-Copyright 2022 The Rook Authors. All rights reserved.
-
-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 kms
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestInitKMIP(t *testing.T) {
-	type args struct {
-		config map[string]string
-	}
-	tests := []struct {
-		name string
-		args args
-		want *kmipKMS
-		err  error
-	}{
-		{
-			name: "endpoint not set",
-			args: args{
-				config: map[string]string{},
-			},
-			want: nil,
-			err:  ErrKMIPEndpointNotSet,
-		},
-		{
-			name: "ca cert not set",
-			args: args{
-				config: map[string]string{
-					kmipEndpoint: "pykimp.local",
-				},
-			},
-			want: nil,
-			err:  ErrKMIPCACertNotSet,
-		},
-		{
-			name: "client cert not set",
-			args: args{
-				config: map[string]string{
-					kmipEndpoint: "pykimp.local",
-					KmipCACert:   "abcd",
-				},
-			},
-			want: nil,
-			err:  ErrKMIPClientCertNotSet,
-		},
-		{
-			name: "client key not set",
-			args: args{
-				config: map[string]string{
-					kmipEndpoint:   "pykimp.local",
-					KmipCACert:     "abcd",
-					KmipClientCert: "abcd",
-				},
-			},
-			want: nil,
-			err:  ErrKMIPClientKeyNotSet,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			_, err := InitKMIP(tt.args.config)
-			assert.Equal(t, tt.err, err)
-		})
-	}
-}
diff --git a/pkg/daemon/ceph/osd/kms/kms_test.go b/pkg/daemon/ceph/osd/kms/kms_test.go
index 49e53fe7f..014e640ad 100644
--- a/pkg/daemon/ceph/osd/kms/kms_test.go
+++ b/pkg/daemon/ceph/osd/kms/kms_test.go
@@ -50,15 +50,6 @@ func TestValidateConnectionDetails(t *testing.T) {
 		},
 		Data: map[string][]byte{"foo": []byte("bar")},
 	}
-	kmipSecret := &v1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "kmip-token",
-			Namespace: ns,
-		},
-		Data: map[string][]byte{"CLIENT_CERT": []byte("bar"),
-			"CLIENT_KEY": []byte("bar"),
-		},
-	}
 	tlsSecret := &v1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "vault-ca-secret",
@@ -70,12 +61,6 @@ func TestValidateConnectionDetails(t *testing.T) {
 			"KMS_PROVIDER": TypeIBM,
 		},
 	}
-	kmipKMSSpec := &cephv1.KeyManagementServiceSpec{
-		ConnectionDetails: map[string]string{
-			"KMS_PROVIDER": TypeKMIP,
-		},
-		TokenSecretName: "kmip-token",
-	}
 
 	t.Run("no kms provider given", func(t *testing.T) {
 		err := ValidateConnectionDetails(ctx, clusterdContext, kms, ns)
@@ -84,30 +69,6 @@ func TestValidateConnectionDetails(t *testing.T) {
 		kms.ConnectionDetails["KMS_PROVIDER"] = "vault"
 	})
 
-	t.Run("kmip - missing ca cert", func(t *testing.T) {
-		_, err := clusterdContext.Clientset.CoreV1().Secrets(ns).Create(ctx, kmipSecret, metav1.CreateOptions{})
-		assert.NoError(t, err)
-		err = ValidateConnectionDetails(ctx, clusterdContext, kmipKMSSpec, ns)
-		assert.Error(t, err, ErrKMIPEndpointNotSet)
-	})
-
-	t.Run("kmip - missing endpoint", func(t *testing.T) {
-		kmipSecret.Data[KmipCACert] = []byte("foo")
-		_, err := clusterdContext.Clientset.CoreV1().Secrets(ns).Update(ctx, kmipSecret, metav1.UpdateOptions{})
-		assert.NoError(t, err)
-		err = ValidateConnectionDetails(ctx, clusterdContext, kmipKMSSpec, ns)
-		assert.Error(t, err, ErrKMIPEndpointNotSet)
-	})
-
-	t.Run("kmip - success", func(t *testing.T) {
-		kmipKMSSpec.ConnectionDetails[kmipEndpoint] = "pykmip.local"
-		err := ValidateConnectionDetails(ctx, clusterdContext, kmipKMSSpec, ns)
-		assert.NoError(t, err)
-		assert.Equal(t, "foo", kmipKMSSpec.ConnectionDetails[KmipCACert])
-		assert.Equal(t, "bar", kmipKMSSpec.ConnectionDetails[KmipClientCert])
-		assert.Equal(t, "bar", kmipKMSSpec.ConnectionDetails[KmipClientKey])
-	})
-
 	t.Run("vault - no token object", func(t *testing.T) {
 		kms.TokenSecretName = "vault-token"
 		err := ValidateConnectionDetails(ctx, clusterdContext, kms, ns)
diff --git a/pkg/daemon/ceph/osd/kms/volumes_test.go b/pkg/daemon/ceph/osd/kms/volumes_test.go
index 8b75eb79f..712cd809b 100644
--- a/pkg/daemon/ceph/osd/kms/volumes_test.go
+++ b/pkg/daemon/ceph/osd/kms/volumes_test.go
@@ -150,74 +150,3 @@ func TestVaultVolumeAndMountWithCustomName(t *testing.T) {
 		})
 	}
 }
-
-func TestKMIPVolumeAndMount(t *testing.T) {
-	mode := int32(0444)
-	tokenSecretName := "kmip-credentials"
-	type args struct {
-		tokenSecretName string
-	}
-	tests := []struct {
-		name  string
-		args  args
-		want  v1.Volume
-		want1 v1.VolumeMount
-	}{
-		{
-			name: "",
-			args: args{
-				tokenSecretName: tokenSecretName,
-			},
-			want: v1.Volume{
-				Name: TypeKMIP,
-				VolumeSource: v1.VolumeSource{
-					Projected: &v1.ProjectedVolumeSource{
-						Sources: []v1.VolumeProjection{
-							{
-
-								Secret: &v1.SecretProjection{
-									LocalObjectReference: v1.LocalObjectReference{
-										Name: tokenSecretName,
-									},
-									Items: []v1.KeyToPath{
-										{
-											Key:  KmipCACert,
-											Path: KmipCACertFileName,
-											Mode: &mode,
-										},
-										{
-											Key:  KmipClientCert,
-											Path: KmipClientCertFileName,
-											Mode: &mode,
-										},
-										{
-											Key:  KmipClientKey,
-											Path: KmipClientKeyFileName,
-											Mode: &mode,
-										},
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			want1: v1.VolumeMount{
-				Name:      TypeKMIP,
-				ReadOnly:  true,
-				MountPath: EtcKmipDir,
-			},
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got, got1 := KMIPVolumeAndMount(tt.args.tokenSecretName)
-			if !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("KMIPVolumeAndMount() got = %v, want %v", got, tt.want)
-			}
-			if !reflect.DeepEqual(got1, tt.want1) {
-				t.Errorf("KMIPVolumeAndMount() got1 = %v, want %v", got1, tt.want1)
-			}
-		})
-	}
-}
diff --git a/pkg/operator/ceph/cluster/osd/spec_test.go b/pkg/operator/ceph/cluster/osd/spec_test.go
index 5cc2c752f..63bccf3ac 100644
--- a/pkg/operator/ceph/cluster/osd/spec_test.go
+++ b/pkg/operator/ceph/cluster/osd/spec_test.go
@@ -382,30 +382,6 @@ func testPodDevices(t *testing.T, dataDir, deviceName string, allDevices bool) {
 	assert.Equal(t, 7, len(cont.VolumeMounts), cont.VolumeMounts)
 	assert.Equal(t, 9, len(deployment.Spec.Template.Spec.Volumes), deployment.Spec.Template.Spec.Volumes) // One more than the encryption with k8s for the kek get init container
 
-	// Test with encrypted OSD on PVC with RAW with KMS
-	osdProp.encrypted = true
-	osdProp.metadataPVC = corev1.PersistentVolumeClaimVolumeSource{}
-	osdProp.walPVC = corev1.PersistentVolumeClaimVolumeSource{}
-	c.spec.Security.KeyManagementService.ConnectionDetails = map[string]string{"KMS_PROVIDER": "kmip"}
-	c.spec.Security.KeyManagementService.TokenSecretName = "kmip-credentials"
-	deployment, err = c.makeDeployment(osdProp, osd, dataPathMap)
-	assert.Nil(t, err)
-	assert.NotNil(t, deployment)
-	assert.Equal(t, 9, len(deployment.Spec.Template.Spec.InitContainers), deployment.Spec.Template.Spec.InitContainers)
-	assert.Equal(t, "blkdevmapper", deployment.Spec.Template.Spec.InitContainers[0].Name)
-	assert.Equal(t, "encryption-kms-get-kek", deployment.Spec.Template.Spec.InitContainers[1].Name)
-	assert.Equal(t, "encryption-open", deployment.Spec.Template.Spec.InitContainers[2].Name)
-	assert.Equal(t, "blkdevmapper-encryption", deployment.Spec.Template.Spec.InitContainers[3].Name)
-	assert.Equal(t, "encrypted-block-status", deployment.Spec.Template.Spec.InitContainers[4].Name)
-	assert.Equal(t, "expand-encrypted-bluefs", deployment.Spec.Template.Spec.InitContainers[5].Name)
-	assert.Equal(t, "activate", deployment.Spec.Template.Spec.InitContainers[6].Name)
-	assert.Equal(t, "expand-bluefs", deployment.Spec.Template.Spec.InitContainers[7].Name)
-	assert.Equal(t, "chown-container-data-dir", deployment.Spec.Template.Spec.InitContainers[8].Name)
-	assert.Equal(t, 1, len(deployment.Spec.Template.Spec.Containers))
-	cont = deployment.Spec.Template.Spec.Containers[0]
-	assert.Equal(t, 7, len(cont.VolumeMounts), cont.VolumeMounts)
-	assert.Equal(t, 10, len(deployment.Spec.Template.Spec.Volumes), deployment.Spec.Template.Spec.Volumes)
-
 	// Test with encrypted OSD on PVC with RAW with KMS with TLS
 	osdProp.encrypted = true
 	osdProp.metadataPVC = corev1.PersistentVolumeClaimVolumeSource{}
diff --git a/pkg/operator/ceph/controller/spec_test.go b/pkg/operator/ceph/controller/spec_test.go
index f75ce631f..e1203032f 100644
--- a/pkg/operator/ceph/controller/spec_test.go
+++ b/pkg/operator/ceph/controller/spec_test.go
@@ -153,13 +153,8 @@ func TestGenerateLivenessProbeExecDaemon(t *testing.T) {
 		"-i",
 		"sh",
 		"-c",
-		`outp="$(ceph --admin-daemon /run/ceph/ceph-osd.0.asok status 2>&1)"
-rc=$?
-if [ $rc -ne 0 ]; then
-  echo "ceph daemon health check failed with the following output:"
-  echo "$outp" | sed -e 's/^/> /g'
-  exit $rc
-fi`}
+		"ceph --admin-daemon /run/ceph/ceph-osd.0.asok status",
+	}
 
 	assert.Equal(t, expectedCommand, probe.ProbeHandler.Exec.Command)
 	assert.Equal(t, livenessProbeInitialDelaySeconds, probe.InitialDelaySeconds)
diff --git a/pkg/operator/ceph/csi/predicate_test.go b/pkg/operator/ceph/csi/predicate_test.go
index ae3ff720b..95f86820d 100644
--- a/pkg/operator/ceph/csi/predicate_test.go
+++ b/pkg/operator/ceph/csi/predicate_test.go
@@ -31,6 +31,108 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/predicate"
 )
 
+func Test_findCSIChange(t *testing.T) {
+	t.Run("no match", func(t *testing.T) {
+		var str = `  map[string]string{
+        "CSI_FORCE_CEPHFS_KERNEL_CLIENT":     "true",
+        "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION": "false",
+        "ROOK_CSI_ENABLE_GRPC_METRICS":       "true",
+        "ROOK_CSI_ENABLE_RBD":                "true",
+        "ROOK_ENABLE_DISCOVERY_DAEMON":       "false",
+-       "ROOK_LOG_LEVEL":                     "INFO",
++       "ROOK_LOG_LEVEL":                     "DEBUG",
+        "ROOK_OBC_WATCH_OPERATOR_NAMESPACE":  "true",
+  }`
+		b := findCSIChange(str)
+		assert.False(t, b)
+	})
+
+	t.Run("match on addition", func(t *testing.T) {
+		var str = `  map[string]string{
+        "CSI_FORCE_CEPHFS_KERNEL_CLIENT":     "true",
+        "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION": "false",
++       "ROOK_CSI_ENABLE_CEPHFS":             "false",
+        "ROOK_CSI_ENABLE_GRPC_METRICS":       "true",
+        "ROOK_CSI_ENABLE_RBD":                "true",
+        "ROOK_ENABLE_DISCOVERY_DAEMON":       "false",
+-       "ROOK_LOG_LEVEL":                     "INFO",
++       "ROOK_LOG_LEVEL":                     "DEBUG",
+        "ROOK_OBC_WATCH_OPERATOR_NAMESPACE":  "true",
+  }`
+		b := findCSIChange(str)
+		assert.True(t, b)
+	})
+
+	t.Run("match on deletion", func(t *testing.T) {
+		var str = `  map[string]string{
+        "CSI_FORCE_CEPHFS_KERNEL_CLIENT":     "true",
+        "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION": "false",
+-       "ROOK_CSI_ENABLE_CEPHFS":             "true",
+        "ROOK_CSI_ENABLE_GRPC_METRICS":       "true",
+        "ROOK_CSI_ENABLE_RBD":                "true",
+        "ROOK_ENABLE_DISCOVERY_DAEMON":       "false",
+-       "ROOK_LOG_LEVEL":                     "INFO",
++       "ROOK_LOG_LEVEL":                     "DEBUG",
+        "ROOK_OBC_WATCH_OPERATOR_NAMESPACE":  "true",
+  }`
+		b := findCSIChange(str)
+		assert.True(t, b)
+	})
+
+	t.Run("match on addition and deletion", func(t *testing.T) {
+		var str = `  map[string]string{
+        "CSI_FORCE_CEPHFS_KERNEL_CLIENT":     "true",
+        "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION": "false",
+-       "ROOK_CSI_ENABLE_CEPHFS":             "true",
++       "ROOK_CSI_ENABLE_CEPHFS":             "false",
+        "ROOK_CSI_ENABLE_GRPC_METRICS":       "true",
+        "ROOK_CSI_ENABLE_RBD":                "true",
+        "ROOK_ENABLE_DISCOVERY_DAEMON":       "false",
+-       "ROOK_LOG_LEVEL":                     "INFO",
++       "ROOK_LOG_LEVEL":                     "DEBUG",
+        "ROOK_OBC_WATCH_OPERATOR_NAMESPACE":  "true",
+  }`
+		b := findCSIChange(str)
+		assert.True(t, b)
+	})
+
+	t.Run("match with CSI_ name", func(t *testing.T) {
+		var str = `  map[string]string{
+        "CSI_FORCE_CEPHFS_KERNEL_CLIENT":     "true",
+        "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION": "false",
+-       "CSI_PROVISIONER_TOLERATIONS":             "true",
++       "CSI_PROVISIONER_TOLERATIONS":             "false",
+        "ROOK_CSI_ENABLE_GRPC_METRICS":       "true",
+        "ROOK_CSI_ENABLE_RBD":                "true",
+        "ROOK_ENABLE_DISCOVERY_DAEMON":       "false",
+-       "ROOK_LOG_LEVEL":                     "INFO",
++       "ROOK_LOG_LEVEL":                     "DEBUG",
+        "ROOK_OBC_WATCH_OPERATOR_NAMESPACE":  "true",
+  }`
+		b := findCSIChange(str)
+		assert.True(t, b)
+	})
+
+	t.Run("match with CSI_ and ROOK_CSI_ name", func(t *testing.T) {
+		var str = `  map[string]string{
+        "CSI_FORCE_CEPHFS_KERNEL_CLIENT":     "true",
+        "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION": "false",
+-       "CSI_PROVISIONER_TOLERATIONS":             "true",
++       "CSI_PROVISIONER_TOLERATIONS":             "false",
+-       "ROOK_CSI_ENABLE_CEPHFS":             "true",
++       "ROOK_CSI_ENABLE_CEPHFS":             "false",
+        "ROOK_CSI_ENABLE_GRPC_METRICS":       "true",
+        "ROOK_CSI_ENABLE_RBD":                "true",
+        "ROOK_ENABLE_DISCOVERY_DAEMON":       "false",
+-       "ROOK_LOG_LEVEL":                     "INFO",
++       "ROOK_LOG_LEVEL":                     "DEBUG",
+        "ROOK_OBC_WATCH_OPERATOR_NAMESPACE":  "true",
+  }`
+		b := findCSIChange(str)
+		assert.True(t, b)
+	})
+}
+
 func Test_predicateController(t *testing.T) {
 	capnslog.SetGlobalLogLevel(capnslog.DEBUG)
 	var (
@@ -87,6 +189,15 @@ func Test_predicateController(t *testing.T) {
 		assert.False(t, p.Update(u))
 	})
 
+	t.Run("update event is a CM and the content changed but with incorrect setting", func(t *testing.T) {
+		cm.Data = map[string]string{"foo": "bar"}
+		cm2.Name = "rook-ceph-operator-config"
+		cm2.Data = map[string]string{"foo": "ooo"}
+		u = event.UpdateEvent{ObjectOld: &cm, ObjectNew: &cm2}
+		p = predicateController(context.TODO(), client, "rook-ceph")
+		assert.False(t, p.Update(u))
+	})
+
 	t.Run("update event is a CM and the content changed with correct setting", func(t *testing.T) {
 		cm.Data = map[string]string{"foo": "bar"}
 		cm2.Name = "rook-ceph-operator-config"
diff --git a/pkg/operator/ceph/object/dependents_test.go b/pkg/operator/ceph/object/dependents_test.go
index 6c1574c0e..58fde43b2 100644
--- a/pkg/operator/ceph/object/dependents_test.go
+++ b/pkg/operator/ceph/object/dependents_test.go
@@ -32,7 +32,6 @@ import (
 	rookclient "github.com/rook/rook/pkg/client/clientset/versioned/fake"
 	"github.com/rook/rook/pkg/clusterd"
 	"github.com/rook/rook/pkg/daemon/ceph/client"
-	cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
 	"github.com/rook/rook/pkg/util/exec"
 	exectest "github.com/rook/rook/pkg/util/exec/test"
 	"github.com/stretchr/testify/assert"
@@ -40,182 +39,6 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
-const (
-	zoneA                      = "zone-a"
-	zoneB                      = "zone-b"
-	zoneGroupGetSingleZoneJSON = `{
-		"id": "fd8ff110-d3fd-49b4-b24f-f6cd3dddfedf",
-		"name": "zonegroup-a",
-		"api_name": "zonegroup-a",
-		"is_master": "true",
-		"endpoints": [
-			"http://rook-ceph-rgw-store-a.rook-ceph.svc:80"
-        ],
-		"hostnames": [],
-		"hostnames_s3website": [],
-		"master_zone": "6cb39d2c-3005-49da-9be3-c1a92a97d28a",
-		"zones": [
-			{
-				"id": "6cb39d2c-3005-49da-9be3-c1a92a97d28a",
-				"name": "zone-a",
-				"endpoints": [
-					"http://rook-ceph-rgw-store-a.rook-ceph.svc:80"
-				],
-				"log_meta": "false",
-				"log_data": "false",
-				"bucket_index_max_shards": 0,
-				"read_only": "false",
-				"tier_type": "",
-				"sync_from_all": "true",
-				"sync_from": [],
-				"redirect_zone": ""
-			}
-		],
-		"placement_targets": [
-			{
-				"name": "default-placement",
-				"tags": [],
-				"storage_classes": [
-					"STANDARD"
-				]
-			}
-		],
-		"default_placement": "default-placement",
-		"realm_id": "237e6250-5f7d-4b85-9359-8cb2b1848507"
-	}`
-	zoneGroupGetMultipleZoneJSON = `{
-		"id": "fd8ff110-d3fd-49b4-b24f-f6cd3dddfedf",
-		"name": "zonegroup-a",
-		"api_name": "zonegroup-a",
-		"is_master": "true",
-		"endpoints": [
-			"http://rook-ceph-rgw-store-a.rook-ceph.svc:80"
-        ],
-		"hostnames": [],
-		"hostnames_s3website": [],
-		"master_zone": "6cb39d2c-3005-49da-9be3-c1a92a97d28a",
-		"zones": [
-			{
-				"id": "6cb39d2c-3005-49da-9be3-c1a92a97d28a",
-				"name": "zone-a",
-				"endpoints": [
-					"http://rook-ceph-rgw-store-a.rook-ceph.svc:80"
-				],
-				"log_meta": "false",
-				"log_data": "false",
-				"bucket_index_max_shards": 0,
-				"read_only": "false",
-				"tier_type": "",
-				"sync_from_all": "true",
-				"sync_from": [],
-				"redirect_zone": ""
-			},
-			{
-				"id": "6cb39d2c-3005-49da-9be3-c1a92a97d28b",
-				"name": "zone-b",
-				"endpoints": [
-					"http://rook-ceph-rgw-store-b.rook-ceph.svc:80"
-				],
-				"log_meta": "false",
-				"log_data": "false",
-				"bucket_index_max_shards": 0,
-				"read_only": "false",
-				"tier_type": "",
-				"sync_from_all": "true",
-				"sync_from": [],
-				"redirect_zone": ""
-			}
-		],
-		"placement_targets": [
-			{
-				"name": "default-placement",
-				"tags": [],
-				"storage_classes": [
-					"STANDARD"
-				]
-			}
-		],
-		"default_placement": "default-placement",
-		"realm_id": "237e6250-5f7d-4b85-9359-8cb2b1848507"
-	}`
-	zoneGetZoneAJSON = `{
-               "id": "6cb39d2c-3005-49da-9be3-c1a92a97d28a",
-               "name": "zone-a",
-               "domain_root": "zone-a.rgw.meta:root",
-               "control_pool": "zone-a.rgw.control",
-               "gc_pool": "zone-a.rgw.log:gc",
-               "lc_pool": "zone-a.rgw.log:lc",
-               "log_pool": "zone-a.rgw.log",
-               "intent_log_pool": "zone-a.rgw.log:intent",
-               "usage_log_pool": "zone-a.rgw.log:usage",
-               "reshard_pool": "zone-a.rgw.log:reshard",
-               "user_keys_pool": "zone-a.rgw.meta:users.keys",
-               "user_email_pool": "zone-a.rgw.meta:users.email",
-               "user_swift_pool": "zone-a.rgw.meta:users.swift",
-               "user_uid_pool": "zone-a.rgw.meta:users.uid",
-               "otp_pool": "zone-a.rgw.otp",
-               "system_key": {
-                       "access_key": "",
-                       "secret_key": ""
-               },
-               "placement_pools": [
-                       {
-                               "key": "default-placement",
-                               "val": {
-                                       "index_pool": "zone-a.rgw.buckets.index",
-                                       "storage_classes": {
-                                               "STANDARD": {
-                                                       "data_pool": "zone-a.rgw.buckets.data"
-                                               }
-                                       },
-                                       "data_extra_pool": "zone-a.rgw.buckets.non-ec",
-                                       "index_type": 0
-                               }
-                       }
-               ],
-               "metadata_heap": "",
-               "realm_id": ""
-       }`
-	zoneGetZoneBJSON = `{
-               "id": "6cb39d2c-3005-49da-9be3-c1a92a97d28b",
-               "name": "zone-b",
-               "domain_root": "zone-b.rgw.meta:root",
-               "control_pool": "zone-b.rgw.control",
-               "gc_pool": "zone-b.rgw.log:gc",
-               "lc_pool": "zone-b.rgw.log:lc",
-               "log_pool": "zone-b.rgw.log",
-               "intent_log_pool": "zone-b.rgw.log:intent",
-               "usage_log_pool": "zone-b.rgw.log:usage",
-               "reshard_pool": "zone-b.rgw.log:reshard",
-               "user_keys_pool": "zone-b.rgw.meta:users.keys",
-               "user_email_pool": "zone-b.rgw.meta:users.email",
-               "user_swift_pool": "zone-b.rgw.meta:users.swift",
-               "user_uid_pool": "zone-b.rgw.meta:users.uid",
-               "otp_pool": "zone-b.rgw.otp",
-               "system_key": {
-                       "access_key": "",
-                       "secret_key": ""
-               },
-               "placement_pools": [
-                       {
-                               "key": "default-placement",
-                               "val": {
-                                       "index_pool": "zone-b.rgw.buckets.index",
-                                       "storage_classes": {
-                                               "STANDARD": {
-                                                       "data_pool": "zone-b.rgw.buckets.data"
-                                               }
-                                       },
-                                       "data_extra_pool": "zone-b.rgw.buckets.non-ec",
-                                       "index_type": 0
-                               }
-                       }
-               ],
-               "metadata_heap": "",
-               "realm_id": ""
-       }`
-)
-
 func TestCephObjectStoreDependents(t *testing.T) {
 	scheme := runtime.NewScheme()
 	assert.NoError(t, cephv1.AddToScheme(scheme))
@@ -251,28 +74,8 @@ func TestCephObjectStoreDependents(t *testing.T) {
 		{Name: "my-store.rgw.buckets.data"},
 		{Name: ".rgw.root"},
 		{Name: "my-store.rgw.buckets.index"},
-		{Name: "my-store.rgw.otp"},
-	}
-	zoneBPools := []*client.CephStoragePoolSummary{
-		{Name: "zone-b.rgw.control"},
-		{Name: "zone-b.rgw.meta"},
-		{Name: "zone-b.rgw.log"},
-		{Name: "zone-b.rgw.buckets.non-ec"},
-		{Name: "zone-b.rgw.buckets.data"},
-		{Name: ".rgw.root"},
-		{Name: "zone-b.rgw.buckets.index"},
-		{Name: "zone-b.rgw.otp"},
-	}
-	zoneAPools := []*client.CephStoragePoolSummary{
-		{Name: "zone-a.rgw.control"},
-		{Name: "zone-a.rgw.meta"},
-		{Name: "zone-a.rgw.log"},
-		{Name: "zone-a.rgw.buckets.non-ec"},
-		{Name: "zone-a.rgw.buckets.data"},
-		{Name: ".rgw.root"},
-		{Name: "zone-a.rgw.buckets.index"},
-		{Name: "zone-a.rgw.otp"},
 	}
+
 	// Mock HTTP call
 	mockClient := func(bucket string) *MockClient {
 		return &MockClient{
@@ -288,9 +91,6 @@ func TestCephObjectStoreDependents(t *testing.T) {
 		}
 	}
 
-	setMultisiteContext := func(context *clusterd.Context, clusterInfo *cephclient.ClusterInfo, store *cephv1.CephObjectStore) *Context {
-		return &Context{Context: context, Name: store.Name, clusterInfo: clusterInfo, Realm: "realm-a", ZoneGroup: "zonegroup-a", Zone: store.Spec.Zone.Name}
-	}
 	clusterInfo := client.AdminTestClusterInfo(ns)
 	// Create objectmeta with the given name in our test namespace
 	meta := func(name string) v1.ObjectMeta {
@@ -312,32 +112,6 @@ func TestCephObjectStoreDependents(t *testing.T) {
 			Gateway: cephv1.GatewaySpec{Port: 80},
 		},
 	}
-	storeZoneB := &cephv1.CephObjectStore{
-		ObjectMeta: v1.ObjectMeta{
-			Name:      "zone-b-store",
-			Namespace: ns,
-		},
-		TypeMeta: v1.TypeMeta{
-			Kind: "CephObjectStore",
-		},
-		Spec: cephv1.ObjectStoreSpec{
-			Gateway: cephv1.GatewaySpec{Port: 80},
-			Zone:    cephv1.ZoneSpec{Name: zoneB},
-		},
-	}
-	storeZoneA := &cephv1.CephObjectStore{
-		ObjectMeta: v1.ObjectMeta{
-			Name:      "zone-a-store",
-			Namespace: ns,
-		},
-		TypeMeta: v1.TypeMeta{
-			Kind: "CephObjectStore",
-		},
-		Spec: cephv1.ObjectStoreSpec{
-			Gateway: cephv1.GatewaySpec{Port: 80},
-			Zone:    cephv1.ZoneSpec{Name: zoneA},
-		},
-	}
 
 	t.Run("missing pools so skipping", func(t *testing.T) {
 		c = newClusterdCtx(executor)
@@ -435,261 +209,13 @@ func TestCephObjectStoreDependents(t *testing.T) {
 		assert.ElementsMatch(t, []string{"u1"}, deps.OfKind("CephObjectStoreUsers"))
 	})
 
-	t.Run("store belong to secondary zone with no objectstore users and no buckets", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneBPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneBJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		store.Spec.Zone.Name = zoneB
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneB, setMultisiteContext(c, clusterInfo, storeZoneB), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-
-	t.Run("store belong to secondary zone with one objectstore users but wrong store and no buckets", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneBPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneBJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor, &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")})
-		_, err := c.RookClientset.CephV1().CephObjectStoreUsers(clusterInfo.Namespace).Create(context.TODO(), &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")}, v1.CreateOptions{})
-		assert.NoError(t, err)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneB, setMultisiteContext(c, clusterInfo, storeZoneB), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-
-	t.Run("store belong to secondary zone with one objectstore users and no buckets", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneBPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneBJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor, &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")})
-		_, err := c.RookClientset.CephV1().CephObjectStoreUsers(clusterInfo.Namespace).Create(context.TODO(), &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1"), Spec: cephv1.ObjectStoreUserSpec{Store: storeZoneB.Name}}, v1.CreateOptions{})
-		assert.NoError(t, err)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneB, setMultisiteContext(c, clusterInfo, storeZoneB), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-
-	t.Run("store belong to secondary zone with no objectstore users and one bucket", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneBPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneBJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`["my-bucket"]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneB, setMultisiteContext(c, clusterInfo, storeZoneB), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-
-	t.Run("store belong to master zone with no objectstore users, no buckets and no peers", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetSingleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-
-	t.Run("store belong to master zone with one objectstore users but wrong store and no buckets and no peers", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetSingleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor, &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")})
-		_, err := c.RookClientset.CephV1().CephObjectStoreUsers(clusterInfo.Namespace).Create(context.TODO(), &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")}, v1.CreateOptions{})
-		assert.NoError(t, err)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-
-	t.Run("store belong to master zone with one objectstore users and no buckets and no peers", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetSingleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor, &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")})
-		_, err := c.RookClientset.CephV1().CephObjectStoreUsers(clusterInfo.Namespace).Create(context.TODO(), &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1"), Spec: cephv1.ObjectStoreUserSpec{Store: storeZoneA.Name}}, v1.CreateOptions{})
-		assert.NoError(t, err)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.NoError(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"u1"}, deps.OfKind("CephObjectStoreUsers"))
-	})
-
-	t.Run("store belong to master zone with no objectstore users and one bucket and no peer", func(t *testing.T) {
+	t.Run("no objectstore users and buckets", func(t *testing.T) {
 		executor = &exectest.MockExecutor{
 			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
 				logger.Infof("Command: %s %v", command, args)
 				if args[0] == "osd" {
 					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
+						output, err := json.Marshal(pools)
 						assert.Nil(t, err)
 						return string(output), nil
 					}
@@ -700,165 +226,15 @@ func TestCephObjectStoreDependents(t *testing.T) {
 				if command == "radosgw-admin" && args[0] == "user" {
 					return userCreateJSON, nil
 				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetSingleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
 				return "", errors.Errorf("no such command %v %v", command, args)
 			},
 		}
 		c = newClusterdCtx(executor)
 		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`["my-bucket"]`))
 		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
+		deps, err := CephObjectStoreDependents(c, clusterInfo, store, NewContext(c, clusterInfo, store.Name), &AdminOpsContext{AdminOpsClient: client})
 		assert.NoError(t, err)
 		assert.False(t, deps.Empty())
 		assert.ElementsMatch(t, []string{"my-bucket"}, deps.OfKind("buckets in the object store (could be from ObjectBucketClaims or COSI Buckets)"), deps)
 	})
-
-	t.Run("store belong to master zone with no objectstore users, no buckets and one peer", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.Error(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"zone-b"}, deps.OfKind(zoneIsMasterWithPeersDependentType))
-	})
-
-	t.Run("store belong to master zone with one objectstore users but wrong store and no buckets and one peer", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor, &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")})
-		_, err := c.RookClientset.CephV1().CephObjectStoreUsers(clusterInfo.Namespace).Create(context.TODO(), &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")}, v1.CreateOptions{})
-		assert.NoError(t, err)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.Error(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"zone-b"}, deps.OfKind(zoneIsMasterWithPeersDependentType))
-	})
-
-	t.Run("store belong to master zone with one objectstore users and no buckets and one peer", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor, &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1")})
-		_, err := c.RookClientset.CephV1().CephObjectStoreUsers(clusterInfo.Namespace).Create(context.TODO(), &cephv1.CephObjectStoreUser{ObjectMeta: meta("u1"), Spec: cephv1.ObjectStoreUserSpec{Store: storeZoneA.Name}}, v1.CreateOptions{})
-		assert.NoError(t, err)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`[]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.Error(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"zone-b"}, deps.OfKind(zoneIsMasterWithPeersDependentType))
-	})
-
-	t.Run("store belong to master zone with no objectstore users and one bucket and one peer", func(t *testing.T) {
-		executor = &exectest.MockExecutor{
-			MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) {
-				logger.Infof("Command: %s %v", command, args)
-				if args[0] == "osd" {
-					if args[1] == "lspools" {
-						output, err := json.Marshal(zoneAPools)
-						assert.Nil(t, err)
-						return string(output), nil
-					}
-				}
-				return "", errors.Errorf("unexpected ceph command %q", args)
-			},
-			MockExecuteCommandWithTimeout: func(timeout time.Duration, command string, args ...string) (string, error) {
-				if command == "radosgw-admin" && args[0] == "user" {
-					return userCreateJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zonegroup" && args[1] == "get" {
-					return zoneGroupGetMultipleZoneJSON, nil
-				}
-				if command == "radosgw-admin" && args[0] == "zone" && args[1] == "get" {
-					return zoneGetZoneAJSON, nil
-				}
-				return "", errors.Errorf("no such command %v %v", command, args)
-			},
-		}
-		c = newClusterdCtx(executor)
-		client, err := admin.New("rook-ceph-rgw-my-store.mycluster.svc", "53S6B9S809NUP19IJ2K3", "1bXPegzsGClvoGAiJdHQD1uOW2sQBLAZM9j9VtXR", mockClient(`["my-bucket"]`))
-		assert.NoError(t, err)
-		deps, err := CephObjectStoreDependents(c, clusterInfo, storeZoneA, setMultisiteContext(c, clusterInfo, storeZoneA), &AdminOpsContext{AdminOpsClient: client})
-		assert.Error(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"zone-b"}, deps.OfKind(zoneIsMasterWithPeersDependentType))
-	})
 }
diff --git a/pkg/operator/ceph/object/objectstore_test.go b/pkg/operator/ceph/object/objectstore_test.go
index 4216f8729..95538d7a2 100644
--- a/pkg/operator/ceph/object/objectstore_test.go
+++ b/pkg/operator/ceph/object/objectstore_test.go
@@ -211,7 +211,7 @@ func deleteStore(t *testing.T, name string, existingStores string, expectedDelet
 	}
 	err = deleteRealmAndPools(context, spec)
 	assert.Nil(t, err)
-	expectedPoolsDeleted = 7
+	expectedPoolsDeleted = 6
 	if expectedDeleteRootPool {
 		expectedPoolsDeleted++
 	}
diff --git a/pkg/operator/ceph/object/rgw_test.go b/pkg/operator/ceph/object/rgw_test.go
index cace7ba3f..e04703716 100644
--- a/pkg/operator/ceph/object/rgw_test.go
+++ b/pkg/operator/ceph/object/rgw_test.go
@@ -143,16 +143,16 @@ func TestGenerateSecretName(t *testing.T) {
 }
 
 func TestEmptyPoolSpec(t *testing.T) {
-	assert.True(t, EmptyPool(cephv1.PoolSpec{}))
+	assert.True(t, emptyPool(cephv1.PoolSpec{}))
 
 	p := cephv1.PoolSpec{FailureDomain: "foo"}
-	assert.False(t, EmptyPool(p))
+	assert.False(t, emptyPool(p))
 
 	p = cephv1.PoolSpec{Replicated: cephv1.ReplicatedSpec{Size: 1}}
-	assert.False(t, EmptyPool(p))
+	assert.False(t, emptyPool(p))
 
 	p = cephv1.PoolSpec{ErasureCoded: cephv1.ErasureCodedSpec{CodingChunks: 1}}
-	assert.False(t, EmptyPool(p))
+	assert.False(t, emptyPool(p))
 }
 
 func TestBuildDomainNameAndEndpoint(t *testing.T) {
diff --git a/pkg/operator/ceph/object/zone/dependents_test.go b/pkg/operator/ceph/object/zone/dependents_test.go
deleted file mode 100644
index c911979a7..000000000
--- a/pkg/operator/ceph/object/zone/dependents_test.go
+++ /dev/null
@@ -1,112 +0,0 @@
-package zone
-
-import (
-	"context"
-	"testing"
-
-	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
-	rookclient "github.com/rook/rook/pkg/client/clientset/versioned/fake"
-	"github.com/rook/rook/pkg/clusterd"
-	"github.com/rook/rook/pkg/daemon/ceph/client"
-	"github.com/rook/rook/pkg/operator/ceph/object"
-	"github.com/rook/rook/pkg/util/exec"
-	exectest "github.com/rook/rook/pkg/util/exec/test"
-	"github.com/stretchr/testify/assert"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-)
-
-func TestCephObjectZoneDependentStores(t *testing.T) {
-	scheme := runtime.NewScheme()
-	assert.NoError(t, cephv1.AddToScheme(scheme))
-	namespace := "test-ceph-object-store-dependents"
-	zoneGroupName := "zonegroup-a"
-	metadataPool := cephv1.PoolSpec{}
-	dataPool := cephv1.PoolSpec{}
-	clusterInfo := client.AdminTestClusterInfo(namespace)
-
-	objectZoneA := &cephv1.CephObjectZone{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "zone-a",
-			Namespace: namespace,
-		},
-		TypeMeta: metav1.TypeMeta{
-			Kind: "CephObjectZone",
-		},
-		Spec: cephv1.ObjectZoneSpec{
-			ZoneGroup:    zoneGroupName,
-			MetadataPool: metadataPool,
-			DataPool:     dataPool,
-		},
-	}
-
-	objectStoreA := &cephv1.CephObjectStore{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "store-a",
-			Namespace: namespace,
-		},
-		TypeMeta: metav1.TypeMeta{
-			Kind: "CephObjectStore",
-		},
-		Spec: cephv1.ObjectStoreSpec{},
-	}
-	objectStoreA.Spec.Zone.Name = "zone-a"
-	objectStoreA.Spec.Gateway.Port = 80
-	objectStoreB := &cephv1.CephObjectStore{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "store-b",
-			Namespace: namespace,
-		},
-		TypeMeta: metav1.TypeMeta{
-			Kind: "CephObjectStore",
-		},
-		Spec: cephv1.ObjectStoreSpec{},
-	}
-	objectStoreB.Spec.Zone.Name = "zone-b"
-	objectStoreB.Spec.Gateway.Port = 80
-
-	var c *clusterd.Context
-	executor := &exectest.MockExecutor{}
-	newClusterdCtx := func(executor exec.Executor) *clusterd.Context {
-		return &clusterd.Context{
-			RookClientset: rookclient.NewSimpleClientset(),
-			Executor:      executor,
-		}
-	}
-	t.Run("no objectstores exists", func(t *testing.T) {
-		c = newClusterdCtx(executor)
-		deps, err := CephObjectZoneDependentStores(c, clusterInfo, objectZoneA, object.NewContext(c, clusterInfo, objectZoneA.Name))
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-	t.Run("one objectstores exists", func(t *testing.T) {
-		c = newClusterdCtx(executor)
-		_, err := c.RookClientset.CephV1().CephObjectStores(clusterInfo.Namespace).Create(context.TODO(), objectStoreA, v1.CreateOptions{})
-		assert.NoError(t, err)
-		deps, err := CephObjectZoneDependentStores(c, clusterInfo, objectZoneA, object.NewContext(c, clusterInfo, objectZoneA.Name))
-		assert.NoError(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"store-a"}, deps.OfKind("CephObjectStore"))
-	})
-	t.Run("objectstore exists for different zone", func(t *testing.T) {
-		c = newClusterdCtx(executor)
-		_, err := c.RookClientset.CephV1().CephObjectStores(clusterInfo.Namespace).Create(context.TODO(), objectStoreB, v1.CreateOptions{})
-		assert.NoError(t, err)
-		deps, err := CephObjectZoneDependentStores(c, clusterInfo, objectZoneA, object.NewContext(c, clusterInfo, objectZoneA.Name))
-		assert.NoError(t, err)
-		assert.True(t, deps.Empty())
-	})
-	t.Run("multipleobjectstore exists for zone", func(t *testing.T) {
-		c = newClusterdCtx(executor)
-		_, err := c.RookClientset.CephV1().CephObjectStores(clusterInfo.Namespace).Create(context.TODO(), objectStoreA, v1.CreateOptions{})
-		assert.NoError(t, err)
-		objectStoreB.Spec.Zone.Name = "zone-a"
-		_, err = c.RookClientset.CephV1().CephObjectStores(clusterInfo.Namespace).Create(context.TODO(), objectStoreB, v1.CreateOptions{})
-		assert.NoError(t, err)
-		deps, err := CephObjectZoneDependentStores(c, clusterInfo, objectZoneA, object.NewContext(c, clusterInfo, objectZoneA.Name))
-		assert.NoError(t, err)
-		assert.False(t, deps.Empty())
-		assert.ElementsMatch(t, []string{"store-a", "store-b"}, deps.OfKind("CephObjectStore"))
-	})
-}
diff --git a/tests/framework/installer/ceph_installer.go b/tests/framework/installer/ceph_installer.go
index ca37d7d0c..11c4441d8 100644
--- a/tests/framework/installer/ceph_installer.go
+++ b/tests/framework/installer/ceph_installer.go
@@ -60,7 +60,7 @@ const (
 osd_pool_default_size = 1
 bdev_flock_retry = 20
 `
-	volumeReplicationVersion = "v0.5.0"
+	volumeReplicationVersion = "v0.3.0"
 )
 
 var (
@@ -69,7 +69,7 @@ var (
 	QuincyVersion                = cephv1.CephVersionSpec{Image: quincyTestImage}
 	QuincyDevelVersion           = cephv1.CephVersionSpec{Image: quincyDevelTestImage}
 	MasterVersion                = cephv1.CephVersionSpec{Image: masterTestImage, AllowUnsupported: true}
-	volumeReplicationBaseURL     = fmt.Sprintf("https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/%s/config/crd/bases/", volumeReplicationVersion)
+	volumeReplicationBaseURL     = fmt.Sprintf("https://raw.githubusercontent.com/csi-addons/volume-replication-operator/%s/config/crd/bases/", volumeReplicationVersion)
 	volumeReplicationCRDURL      = volumeReplicationBaseURL + "replication.storage.openshift.io_volumereplications.yaml"
 	volumeReplicationClassCRDURL = volumeReplicationBaseURL + "replication.storage.openshift.io_volumereplicationclasses.yaml"
 )
diff --git a/tests/scripts/github-action-helper.sh b/tests/scripts/github-action-helper.sh
index a8c8c3605..5369b3ff1 100755
--- a/tests/scripts/github-action-helper.sh
+++ b/tests/scripts/github-action-helper.sh
@@ -143,8 +143,6 @@ function build_rook() {
         ;;
       *)
         # valid failure
-        echo "failed with the following log:"
-        echo "$o"
         exit 1
         ;;
       esac