Repository: rook/rook
Pull request #15027 (2024-11-19 13:33:44)

external: fix detect job in radosnamespace controller
in external mode deployments, ceph image is not provided and the job keeps on failing to get the cup version
fix by checking  if Ceph image is available

Issue:
```
2024-11-19 11:48:29.363305 E | blockpool-rados-namespace-controller: failed to reconcile "openshift-storage/namespace1" failed to detect ceph version: failed to set up ceph version job: Rook image [registry.redhat.io/odf4/rook-ceph-rhel9-operator@sha256:4477808782076370cc98ce59eaafb239e80d6c14f6eb6efdaae67cc397741305] and run image [] must be specified
```

<!-- Thank you for contributing to Rook! -->

<!-- STEPS TO FOLLOW:
  1. Add a description of the changes (frequently the same as the commit description)
  2. Enter the issue number next to "Resolves #" below (if there is no tracking issue resolved, **remove that section**)
  3. Review our Contributing documentation at https://rook.io/docs/rook/latest/Contributing/development-flow/
  4. Follow the steps in the checklist below, starting with the **Commit Message Formatting**.
-->

<!-- Uncomment this section with the issue number if an issue is being resolved
**Issue 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).
- [ ] 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.


parth-gr: Testing
```
[rider@localhost rook]$ oc get cephBlockPoolRadosnamespace
NAME         PHASE   BLOCKPOOL   AGE
namespace1   Ready   rbd         14s
[rider@localhost rook]$ 
[rider@localhost rook]$ 
[rider@localhost rook]$ oc get cephBlockPoolRadosnamespace -o yaml 
apiVersion: v1
items:
- apiVersion: ceph.rook.io/v1
  kind: CephBlockPoolRadosNamespace
  metadata:
    creationTimestamp: "2024-11-19T13:49:01Z"
    finalizers:
    - cephblockpoolradosnamespace.ceph.rook.io
    generation: 1
    managedFields:
    - apiVersion: ceph.rook.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:ownerReferences:
            .: {}
            k:{"uid":"fb9b85f0-653b-4f71-9bf3-b94e977775e5"}: {}
        f:spec:
          .: {}
          f:blockPoolName: {}
      manager: ocs-operator
      operation: Update
      time: "2024-11-19T13:49:01Z"
    - apiVersion: ceph.rook.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:finalizers:
            .: {}
            v:"cephblockpoolradosnamespace.ceph.rook.io": {}
      manager: rook
      operation: Update
      time: "2024-11-19T13:49:01Z"
    - apiVersion: ceph.rook.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        f:status:
          .: {}
          f:info:
            .: {}
            f:clusterID: {}
          f:phase: {}
      manager: rook
      operation: Update
      subresource: status
      time: "2024-11-19T13:49:01Z"
    name: namespace1
    namespace: openshift-storage
    ownerReferences:
    - apiVersion: ocs.openshift.io/v1
      kind: StorageCluster
      name: ocs-external-storagecluster
      uid: fb9b85f0-653b-4f71-9bf3-b94e977775e5
    resourceVersion: "237611"
    uid: 2cec67c9-0922-4ef9-8c98-4e794768f332
  spec:
    blockPoolName: rbd
  status:
    info:
      clusterID: a5d111a3e1d0317f2badf81d3760a16d
    phase: Ready
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""
[rider@localhost rook]$ 


```

Patch:
diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml
index c8a62ce72..41b25dfd4 100644
--- a/.github/workflows/docs-check.yml
+++ b/.github/workflows/docs-check.yml
@@ -36,7 +36,7 @@ jobs:
         with:
           python-version: 3.9
 
-      - uses: DavidAnson/markdownlint-cli2-action@eb5ca3ab411449c66620fe7f1b3c9e10547144b0 # v18.0.0
+      - uses: DavidAnson/markdownlint-cli2-action@db43aef879112c3119a410d69f66701e0d530809 # v17.0.0
         with:
           globs: |
             Documentation/**/*.md
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index f14f93226..0674e4318 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -64,6 +64,6 @@ jobs:
       # Upload the results to GitHub's code scanning dashboard (optional).
       # Commenting out will disable upload of results to your repo's Code Scanning dashboard
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
+        uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
         with:
           sarif_file: results.sarif
diff --git a/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md b/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md
index 104e2045f..1354048de 100644
--- a/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md
+++ b/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md
@@ -57,9 +57,6 @@ If any setting is unspecified, a suitable default will be used automatically.
         - `interval`: frequency of the snapshots. The interval can be specified in days, hours, or minutes using d, h, m suffix respectively.
         - `startTime`: optional, determines at what time the snapshot process starts, specified using the ISO 8601 time format.
 
-!!! note
-    If mirroring is enabled, whether to monitor the status and the interval of status updates is based on the `statusCheck` spec values of the parent CephBlockPool CR.
-
 ## Creating a Storage Class
 
 Once the RADOS namespace is created, an RBD-based StorageClass can be created to
diff --git a/Documentation/CRDs/Cluster/external-cluster/provider-export.md b/Documentation/CRDs/Cluster/external-cluster/provider-export.md
index 765552ac5..c8e2195a8 100644
--- a/Documentation/CRDs/Cluster/external-cluster/provider-export.md
+++ b/Documentation/CRDs/Cluster/external-cluster/provider-export.md
@@ -4,7 +4,7 @@ In order to configure an external Ceph cluster with Rook, we need to extract som
 
 ## 1. Create all users and keys
 
-Run the python script [create-external-cluster-resources.py](https://github.com/rook/rook/blob/master/deploy/examples/external/create-external-cluster-resources.py) in the provider Ceph cluster cephadm shell, to have access to create the necessary users and keys.
+Run the python script [create-external-cluster-resources.py](https://github.com/rook/rook/blob/master/deploy/examples/external/create-external-cluster-resources.py) for creating all users and keys.
 
 ```console
 python3 create-external-cluster-resources.py --rbd-data-pool-name <pool_name> --cephfs-filesystem-name <filesystem-name> --rgw-endpoint  <rgw-endpoint> --namespace <namespace> --format bash
diff --git a/Documentation/CRDs/specification.md b/Documentation/CRDs/specification.md
index 4bbadf471..89f570a27 100644
--- a/Documentation/CRDs/specification.md
+++ b/Documentation/CRDs/specification.md
@@ -3297,45 +3297,6 @@ map[string]string
 <em>(Optional)</em>
 </td>
 </tr>
-<tr>
-<td>
-<code>mirroringStatus</code><br/>
-<em>
-<a href="#ceph.rook.io/v1.MirroringStatusSpec">
-MirroringStatusSpec
-</a>
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-</td>
-</tr>
-<tr>
-<td>
-<code>mirroringInfo</code><br/>
-<em>
-<a href="#ceph.rook.io/v1.MirroringInfoSpec">
-MirroringInfoSpec
-</a>
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-</td>
-</tr>
-<tr>
-<td>
-<code>snapshotScheduleStatus</code><br/>
-<em>
-<a href="#ceph.rook.io/v1.SnapshotScheduleStatusSpec">
-SnapshotScheduleStatusSpec
-</a>
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-</td>
-</tr>
 </tbody>
 </table>
 <h3 id="ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus
@@ -3395,17 +3356,6 @@ MirroringInfoSpec
 </tr>
 <tr>
 <td>
-<code>poolID</code><br/>
-<em>
-int
-</em>
-</td>
-<td>
-<p>optional</p>
-</td>
-</tr>
-<tr>
-<td>
 <code>snapshotScheduleStatus</code><br/>
 <em>
 <a href="#ceph.rook.io/v1.SnapshotScheduleStatusSpec">
@@ -8080,69 +8030,13 @@ HealthCheckSpec
 </tr>
 </tbody>
 </table>
-<h3 id="ceph.rook.io/v1.MirroringInfo">MirroringInfo
-</h3>
-<p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringInfoSpec">MirroringInfoSpec</a>)
-</p>
-<div>
-<p>MirroringInfo is the mirroring info of a given pool/radosnamespace</p>
-</div>
-<table>
-<thead>
-<tr>
-<th>Field</th>
-<th>Description</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>
-<code>mode</code><br/>
-<em>
-string
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>Mode is the mirroring mode</p>
-</td>
-</tr>
-<tr>
-<td>
-<code>site_name</code><br/>
-<em>
-string
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>SiteName is the current site name</p>
-</td>
-</tr>
-<tr>
-<td>
-<code>peers</code><br/>
-<em>
-<a href="#ceph.rook.io/v1.PeersSpec">
-[]PeersSpec
-</a>
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>Peers are the list of peer sites connected to that cluster</p>
-</td>
-</tr>
-</tbody>
-</table>
 <h3 id="ceph.rook.io/v1.MirroringInfoSpec">MirroringInfoSpec
 </h3>
 <p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephBlockPoolRadosNamespaceStatus">CephBlockPoolRadosNamespaceStatus</a>, <a href="#ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus</a>)
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus</a>)
 </p>
 <div>
-<p>MirroringInfoSpec is the status of the pool/radosnamespace mirroring</p>
+<p>MirroringInfoSpec is the status of the pool mirroring</p>
 </div>
 <table>
 <thead>
@@ -8154,16 +8048,16 @@ string
 <tbody>
 <tr>
 <td>
-<code>MirroringInfo</code><br/>
+<code>PoolMirroringInfo</code><br/>
 <em>
-<a href="#ceph.rook.io/v1.MirroringInfo">
-MirroringInfo
+<a href="#ceph.rook.io/v1.PoolMirroringInfo">
+PoolMirroringInfo
 </a>
 </em>
 </td>
 <td>
 <p>
-(Members of <code>MirroringInfo</code> are embedded into this type.)
+(Members of <code>PoolMirroringInfo</code> are embedded into this type.)
 </p>
 <em>(Optional)</em>
 </td>
@@ -8303,45 +8197,13 @@ MirroringPeerSpec
 </tr>
 </tbody>
 </table>
-<h3 id="ceph.rook.io/v1.MirroringStatus">MirroringStatus
-</h3>
-<p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringStatusSpec">MirroringStatusSpec</a>)
-</p>
-<div>
-<p>MirroringStatus is the pool/radosNamespace mirror status</p>
-</div>
-<table>
-<thead>
-<tr>
-<th>Field</th>
-<th>Description</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>
-<code>summary</code><br/>
-<em>
-<a href="#ceph.rook.io/v1.MirroringStatusSummarySpec">
-MirroringStatusSummarySpec
-</a>
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>Summary is the mirroring status summary</p>
-</td>
-</tr>
-</tbody>
-</table>
 <h3 id="ceph.rook.io/v1.MirroringStatusSpec">MirroringStatusSpec
 </h3>
 <p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephBlockPoolRadosNamespaceStatus">CephBlockPoolRadosNamespaceStatus</a>, <a href="#ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus</a>)
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus</a>)
 </p>
 <div>
-<p>MirroringStatusSpec is the status of the pool/radosNamespace mirroring</p>
+<p>MirroringStatusSpec is the status of the pool mirroring</p>
 </div>
 <table>
 <thead>
@@ -8353,19 +8215,19 @@ MirroringStatusSummarySpec
 <tbody>
 <tr>
 <td>
-<code>MirroringStatus</code><br/>
+<code>PoolMirroringStatus</code><br/>
 <em>
-<a href="#ceph.rook.io/v1.MirroringStatus">
-MirroringStatus
+<a href="#ceph.rook.io/v1.PoolMirroringStatus">
+PoolMirroringStatus
 </a>
 </em>
 </td>
 <td>
 <p>
-(Members of <code>MirroringStatus</code> are embedded into this type.)
+(Members of <code>PoolMirroringStatus</code> are embedded into this type.)
 </p>
 <em>(Optional)</em>
-<p>MirroringStatus is the mirroring status of a pool/radosNamespace</p>
+<p>PoolMirroringStatus is the mirroring status of a pool</p>
 </td>
 </tr>
 <tr>
@@ -8406,74 +8268,6 @@ string
 </tr>
 </tbody>
 </table>
-<h3 id="ceph.rook.io/v1.MirroringStatusSummarySpec">MirroringStatusSummarySpec
-</h3>
-<p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringStatus">MirroringStatus</a>)
-</p>
-<div>
-<p>MirroringStatusSummarySpec is the summary output of the command</p>
-</div>
-<table>
-<thead>
-<tr>
-<th>Field</th>
-<th>Description</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>
-<code>health</code><br/>
-<em>
-string
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>Health is the mirroring health</p>
-</td>
-</tr>
-<tr>
-<td>
-<code>daemon_health</code><br/>
-<em>
-string
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>DaemonHealth is the health of the mirroring daemon</p>
-</td>
-</tr>
-<tr>
-<td>
-<code>image_health</code><br/>
-<em>
-string
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>ImageHealth is the health of the mirrored image</p>
-</td>
-</tr>
-<tr>
-<td>
-<code>states</code><br/>
-<em>
-<a href="#ceph.rook.io/v1.StatesSpec">
-StatesSpec
-</a>
-</em>
-</td>
-<td>
-<em>(Optional)</em>
-<p>States is the various state for all mirrored images</p>
-</td>
-</tr>
-</tbody>
-</table>
 <h3 id="ceph.rook.io/v1.Module">Module
 </h3>
 <p>
@@ -10766,7 +10560,7 @@ int
 <h3 id="ceph.rook.io/v1.PeersSpec">PeersSpec
 </h3>
 <p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringInfo">MirroringInfo</a>)
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.PoolMirroringInfo">PoolMirroringInfo</a>)
 </p>
 <div>
 <p>PeersSpec contains peer details</p>
@@ -10981,6 +10775,162 @@ string
 </tr>
 </tbody>
 </table>
+<h3 id="ceph.rook.io/v1.PoolMirroringInfo">PoolMirroringInfo
+</h3>
+<p>
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringInfoSpec">MirroringInfoSpec</a>)
+</p>
+<div>
+<p>PoolMirroringInfo is the mirroring info of a given pool</p>
+</div>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>mode</code><br/>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Mode is the mirroring mode</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>site_name</code><br/>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>SiteName is the current site name</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>peers</code><br/>
+<em>
+<a href="#ceph.rook.io/v1.PeersSpec">
+[]PeersSpec
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Peers are the list of peer sites connected to that cluster</p>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="ceph.rook.io/v1.PoolMirroringStatus">PoolMirroringStatus
+</h3>
+<p>
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringStatusSpec">MirroringStatusSpec</a>)
+</p>
+<div>
+<p>PoolMirroringStatus is the pool mirror status</p>
+</div>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>summary</code><br/>
+<em>
+<a href="#ceph.rook.io/v1.PoolMirroringStatusSummarySpec">
+PoolMirroringStatusSummarySpec
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Summary is the mirroring status summary</p>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="ceph.rook.io/v1.PoolMirroringStatusSummarySpec">PoolMirroringStatusSummarySpec
+</h3>
+<p>
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.PoolMirroringStatus">PoolMirroringStatus</a>)
+</p>
+<div>
+<p>PoolMirroringStatusSummarySpec is the summary output of the command</p>
+</div>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>health</code><br/>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Health is the mirroring health</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>daemon_health</code><br/>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>DaemonHealth is the health of the mirroring daemon</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>image_health</code><br/>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>ImageHealth is the health of the mirrored image</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>states</code><br/>
+<em>
+<a href="#ceph.rook.io/v1.StatesSpec">
+StatesSpec
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>States is the various state for all mirrored images</p>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="ceph.rook.io/v1.PoolPlacementSpec">PoolPlacementSpec
 </h3>
 <p>
@@ -11015,9 +10965,7 @@ bool
 </em>
 </td>
 <td>
-<em>(Optional)</em>
-<p>Sets given placement as default. Only one placement in the list can be marked as default.
-Default is false.</p>
+<p>Sets given placement as default. Only one placement in the list can be marked as default.</p>
 </td>
 </tr>
 <tr>
@@ -12380,7 +12328,7 @@ string
 <h3 id="ceph.rook.io/v1.SnapshotScheduleStatusSpec">SnapshotScheduleStatusSpec
 </h3>
 <p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephBlockPoolRadosNamespaceStatus">CephBlockPoolRadosNamespaceStatus</a>, <a href="#ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus</a>)
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephBlockPoolStatus">CephBlockPoolStatus</a>)
 </p>
 <div>
 <p>SnapshotScheduleStatusSpec is the status of the snapshot schedule</p>
@@ -12516,7 +12464,7 @@ string
 <h3 id="ceph.rook.io/v1.StatesSpec">StatesSpec
 </h3>
 <p>
-(<em>Appears on:</em><a href="#ceph.rook.io/v1.MirroringStatusSummarySpec">MirroringStatusSummarySpec</a>)
+(<em>Appears on:</em><a href="#ceph.rook.io/v1.PoolMirroringStatusSummarySpec">PoolMirroringStatusSummarySpec</a>)
 </p>
 <div>
 <p>StatesSpec are rbd images mirroring state</p>
diff --git a/PendingReleaseNotes.md b/PendingReleaseNotes.md
index c4e63de81..116f32932 100644
--- a/PendingReleaseNotes.md
+++ b/PendingReleaseNotes.md
@@ -7,4 +7,3 @@
 ## Features
 
 - Enable mirroring for CephBlockPoolRadosNamespaces (see [#14701](https://github.com/rook/rook/pull/14701)).
-- Enable periodic monitoring for CephBlockPoolRadosNamespaces mirroring (see [#14896](https://github.com/rook/rook/pull/14896)).
diff --git a/deploy/charts/rook-ceph-cluster/templates/deployment.yaml b/deploy/charts/rook-ceph-cluster/templates/deployment.yaml
index 63adf22d3..b785da650 100644
--- a/deploy/charts/rook-ceph-cluster/templates/deployment.yaml
+++ b/deploy/charts/rook-ceph-cluster/templates/deployment.yaml
@@ -9,9 +9,6 @@ metadata:
     app: rook-ceph-tools
 spec:
   replicas: 1
-{{- if .Values.revisionHistoryLimit }}
-  revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
-{{- end }}
   selector:
     matchLabels:
       app: rook-ceph-tools
@@ -117,7 +114,6 @@ spec:
               mountPath: /etc/rook
             - name: ceph-admin-secret
               mountPath: /var/lib/rook-ceph-mon
-      serviceAccountName: rook-ceph-default
       volumes:
         - name: ceph-admin-secret
           secret:
diff --git a/deploy/charts/rook-ceph/templates/deployment.yaml b/deploy/charts/rook-ceph/templates/deployment.yaml
index 3df7bf610..b9f38d233 100644
--- a/deploy/charts/rook-ceph/templates/deployment.yaml
+++ b/deploy/charts/rook-ceph/templates/deployment.yaml
@@ -9,9 +9,6 @@ metadata:
     {{- include "library.rook-ceph.labels" . | nindent 4 }}
 spec:
   replicas: {{ .Values.scaleDownOperator | ternary 0 1 }}
-{{- if .Values.revisionHistoryLimit }}
-  revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
-{{- end }}
   selector:
     matchLabels:
       app: rook-ceph-operator
diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml
index aaa889361..9f0e70332 100644
--- a/deploy/charts/rook-ceph/templates/resources.yaml
+++ b/deploy/charts/rook-ceph/templates/resources.yaml
@@ -109,142 +109,9 @@ spec:
                     type: string
                   nullable: true
                   type: object
-                mirroringInfo:
-                  description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring
-                  properties:
-                    details:
-                      type: string
-                    lastChanged:
-                      type: string
-                    lastChecked:
-                      type: string
-                    mode:
-                      description: Mode is the mirroring mode
-                      type: string
-                    peers:
-                      description: Peers are the list of peer sites connected to that cluster
-                      items:
-                        description: PeersSpec contains peer details
-                        properties:
-                          client_name:
-                            description: ClientName is the CephX user used to connect to the peer
-                            type: string
-                          direction:
-                            description: Direction is the peer mirroring direction
-                            type: string
-                          mirror_uuid:
-                            description: MirrorUUID is the mirror UUID
-                            type: string
-                          site_name:
-                            description: SiteName is the current site name
-                            type: string
-                          uuid:
-                            description: UUID is the peer UUID
-                            type: string
-                        type: object
-                      type: array
-                    site_name:
-                      description: SiteName is the current site name
-                      type: string
-                  type: object
-                mirroringStatus:
-                  description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring
-                  properties:
-                    details:
-                      description: Details contains potential status errors
-                      type: string
-                    lastChanged:
-                      description: LastChanged is the last time time the status last changed
-                      type: string
-                    lastChecked:
-                      description: LastChecked is the last time time the status was checked
-                      type: string
-                    summary:
-                      description: Summary is the mirroring status summary
-                      properties:
-                        daemon_health:
-                          description: DaemonHealth is the health of the mirroring daemon
-                          type: string
-                        health:
-                          description: Health is the mirroring health
-                          type: string
-                        image_health:
-                          description: ImageHealth is the health of the mirrored image
-                          type: string
-                        states:
-                          description: States is the various state for all mirrored images
-                          nullable: true
-                          properties:
-                            error:
-                              description: Error is when the mirroring state is errored
-                              type: integer
-                            replaying:
-                              description: Replaying is when the replay of the mirroring journal is on-going
-                              type: integer
-                            starting_replay:
-                              description: StartingReplay is when the replay of the mirroring journal starts
-                              type: integer
-                            stopped:
-                              description: Stopped is when the mirroring state is stopped
-                              type: integer
-                            stopping_replay:
-                              description: StopReplaying is when the replay of the mirroring journal stops
-                              type: integer
-                            syncing:
-                              description: Syncing is when the image is syncing
-                              type: integer
-                            unknown:
-                              description: Unknown is when the mirroring state is unknown
-                              type: integer
-                          type: object
-                      type: object
-                  type: object
                 phase:
                   description: ConditionType represent a resource's status
                   type: string
-                snapshotScheduleStatus:
-                  description: SnapshotScheduleStatusSpec is the status of the snapshot schedule
-                  properties:
-                    details:
-                      description: Details contains potential status errors
-                      type: string
-                    lastChanged:
-                      description: LastChanged is the last time time the status last changed
-                      type: string
-                    lastChecked:
-                      description: LastChecked is the last time time the status was checked
-                      type: string
-                    snapshotSchedules:
-                      description: SnapshotSchedules is the list of snapshots scheduled
-                      items:
-                        description: SnapshotSchedulesSpec is the list of snapshot scheduled for images in a pool
-                        properties:
-                          image:
-                            description: Image is the mirrored image
-                            type: string
-                          items:
-                            description: Items is the list schedules times for a given snapshot
-                            items:
-                              description: SnapshotSchedule is a schedule
-                              properties:
-                                interval:
-                                  description: Interval is the interval in which snapshots will be taken
-                                  type: string
-                                start_time:
-                                  description: StartTime is the snapshot starting time
-                                  type: string
-                              type: object
-                            type: array
-                          namespace:
-                            description: Namespace is the RADOS namespace the image is part of
-                            type: string
-                          pool:
-                            description: Pool is the pool name
-                            type: string
-                        type: object
-                      nullable: true
-                      type: array
-                  type: object
               type: object
               x-kubernetes-preserve-unknown-fields: true
           required:
@@ -538,7 +405,7 @@ spec:
                   nullable: true
                   type: object
                 mirroringInfo:
-                  description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring
+                  description: MirroringInfoSpec is the status of the pool mirroring
                   properties:
                     details:
                       type: string
@@ -576,7 +443,7 @@ spec:
                       type: string
                   type: object
                 mirroringStatus:
-                  description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring
+                  description: MirroringStatusSpec is the status of the pool mirroring
                   properties:
                     details:
                       description: Details contains potential status errors
@@ -634,9 +501,6 @@ spec:
                 phase:
                   description: ConditionType represent a resource's status
                   type: string
-                poolID:
-                  description: optional
-                  type: integer
                 snapshotScheduleStatus:
                   description: SnapshotScheduleStatusSpec is the status of the snapshot schedule
                   properties:
@@ -12523,9 +12387,7 @@ spec:
                             minLength: 1
                             type: string
                           default:
-                            description: |-
-                              Sets given placement as default. Only one placement in the list can be marked as default.
-                              Default is false.
+                            description: Sets given placement as default. Only one placement in the list can be marked as default.
                             type: boolean
                           metadataPoolName:
                             description: The metadata pool used to store ObjectStore bucket index.
@@ -12564,6 +12426,7 @@ spec:
                             type: array
                         required:
                           - dataPoolName
+                          - default
                           - metadataPoolName
                           - name
                         type: object
@@ -13450,9 +13313,7 @@ spec:
                             minLength: 1
                             type: string
                           default:
-                            description: |-
-                              Sets given placement as default. Only one placement in the list can be marked as default.
-                              Default is false.
+                            description: Sets given placement as default. Only one placement in the list can be marked as default.
                             type: boolean
                           metadataPoolName:
                             description: The metadata pool used to store ObjectStore bucket index.
@@ -13491,6 +13352,7 @@ spec:
                             type: array
                         required:
                           - dataPoolName
+                          - default
                           - metadataPoolName
                           - name
                         type: object
diff --git a/deploy/charts/rook-ceph/templates/role.yaml b/deploy/charts/rook-ceph/templates/role.yaml
index ee6a3e4d7..343c2527b 100644
--- a/deploy/charts/rook-ceph/templates/role.yaml
+++ b/deploy/charts/rook-ceph/templates/role.yaml
@@ -74,16 +74,7 @@ rules:
 {{- if and .Values.csi.csiAddons .Values.csi.csiAddons.enabled }}
   - apiGroups: ["csiaddons.openshift.io"]
     resources: ["csiaddonsnodes"]
-    verbs: ["get", "create", "update"]
-  - apiGroups: [""]
-    resources: ["pods"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["replicasets"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["deployments/finalizers", "daemonsets/finalizers"]
-    verbs: ["update"]
+    verbs: ["create"]
 {{- end }}
 ---
 {{- if and .Values.csi.csiAddons .Values.csi.csiAddons.enabled }}
@@ -95,16 +86,7 @@ metadata:
 rules:
   - apiGroups: ["csiaddons.openshift.io"]
     resources: ["csiaddonsnodes"]
-    verbs: ["get", "create", "update"]
-  - apiGroups: [""]
-    resources: ["pods"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["replicasets"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["deployments/finalizers", "daemonsets/finalizers"]
-    verbs: ["update"]
+    verbs: ["create"]
 ---
 {{- end }}
 kind: Role
@@ -119,15 +101,6 @@ rules:
   {{- if and .Values.csi.csiAddons .Values.csi.csiAddons.enabled }}
   - apiGroups: ["csiaddons.openshift.io"]
     resources: ["csiaddonsnodes"]
-    verbs: ["get", "create", "update"]
-  - apiGroups: [""]
-    resources: ["pods"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["replicasets"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["deployments/finalizers", "daemonsets/finalizers"]
-    verbs: ["update"]
+    verbs: ["create"]
   {{- end }}
 {{- end }}
diff --git a/deploy/examples/common.yaml b/deploy/examples/common.yaml
index 713b39fa6..fae242f78 100644
--- a/deploy/examples/common.yaml
+++ b/deploy/examples/common.yaml
@@ -779,16 +779,7 @@ rules:
     verbs: ["get", "watch", "list", "delete", "update", "create"]
   - apiGroups: ["csiaddons.openshift.io"]
     resources: ["csiaddonsnodes"]
-    verbs: ["get", "create", "update"]
-  - apiGroups: [""]
-    resources: ["pods"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["replicasets"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["deployments/finalizers", "daemonsets/finalizers"]
-    verbs: ["update"]
+    verbs: ["create"]
 ---
 kind: Role
 apiVersion: rbac.authorization.k8s.io/v1
@@ -798,16 +789,7 @@ metadata:
 rules:
   - apiGroups: ["csiaddons.openshift.io"]
     resources: ["csiaddonsnodes"]
-    verbs: ["get", "create", "update"]
-  - apiGroups: [""]
-    resources: ["pods"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["replicasets"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["deployments/finalizers", "daemonsets/finalizers"]
-    verbs: ["update"]
+    verbs: ["create"]
 ---
 kind: Role
 apiVersion: rbac.authorization.k8s.io/v1
@@ -820,16 +802,7 @@ rules:
     verbs: ["get", "watch", "list", "delete", "update", "create"]
   - apiGroups: ["csiaddons.openshift.io"]
     resources: ["csiaddonsnodes"]
-    verbs: ["get", "create", "update"]
-  - apiGroups: [""]
-    resources: ["pods"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["replicasets"]
-    verbs: ["get"]
-  - apiGroups: ["apps"]
-    resources: ["deployments/finalizers", "daemonsets/finalizers"]
-    verbs: ["update"]
+    verbs: ["create"]
 ---
 kind: Role
 apiVersion: rbac.authorization.k8s.io/v1
diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml
index 721ce8af1..6cbfc7321 100644
--- a/deploy/examples/crds.yaml
+++ b/deploy/examples/crds.yaml
@@ -112,142 +112,9 @@ spec:
                     type: string
                   nullable: true
                   type: object
-                mirroringInfo:
-                  description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring
-                  properties:
-                    details:
-                      type: string
-                    lastChanged:
-                      type: string
-                    lastChecked:
-                      type: string
-                    mode:
-                      description: Mode is the mirroring mode
-                      type: string
-                    peers:
-                      description: Peers are the list of peer sites connected to that cluster
-                      items:
-                        description: PeersSpec contains peer details
-                        properties:
-                          client_name:
-                            description: ClientName is the CephX user used to connect to the peer
-                            type: string
-                          direction:
-                            description: Direction is the peer mirroring direction
-                            type: string
-                          mirror_uuid:
-                            description: MirrorUUID is the mirror UUID
-                            type: string
-                          site_name:
-                            description: SiteName is the current site name
-                            type: string
-                          uuid:
-                            description: UUID is the peer UUID
-                            type: string
-                        type: object
-                      type: array
-                    site_name:
-                      description: SiteName is the current site name
-                      type: string
-                  type: object
-                mirroringStatus:
-                  description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring
-                  properties:
-                    details:
-                      description: Details contains potential status errors
-                      type: string
-                    lastChanged:
-                      description: LastChanged is the last time time the status last changed
-                      type: string
-                    lastChecked:
-                      description: LastChecked is the last time time the status was checked
-                      type: string
-                    summary:
-                      description: Summary is the mirroring status summary
-                      properties:
-                        daemon_health:
-                          description: DaemonHealth is the health of the mirroring daemon
-                          type: string
-                        health:
-                          description: Health is the mirroring health
-                          type: string
-                        image_health:
-                          description: ImageHealth is the health of the mirrored image
-                          type: string
-                        states:
-                          description: States is the various state for all mirrored images
-                          nullable: true
-                          properties:
-                            error:
-                              description: Error is when the mirroring state is errored
-                              type: integer
-                            replaying:
-                              description: Replaying is when the replay of the mirroring journal is on-going
-                              type: integer
-                            starting_replay:
-                              description: StartingReplay is when the replay of the mirroring journal starts
-                              type: integer
-                            stopped:
-                              description: Stopped is when the mirroring state is stopped
-                              type: integer
-                            stopping_replay:
-                              description: StopReplaying is when the replay of the mirroring journal stops
-                              type: integer
-                            syncing:
-                              description: Syncing is when the image is syncing
-                              type: integer
-                            unknown:
-                              description: Unknown is when the mirroring state is unknown
-                              type: integer
-                          type: object
-                      type: object
-                  type: object
                 phase:
                   description: ConditionType represent a resource's status
                   type: string
-                snapshotScheduleStatus:
-                  description: SnapshotScheduleStatusSpec is the status of the snapshot schedule
-                  properties:
-                    details:
-                      description: Details contains potential status errors
-                      type: string
-                    lastChanged:
-                      description: LastChanged is the last time time the status last changed
-                      type: string
-                    lastChecked:
-                      description: LastChecked is the last time time the status was checked
-                      type: string
-                    snapshotSchedules:
-                      description: SnapshotSchedules is the list of snapshots scheduled
-                      items:
-                        description: SnapshotSchedulesSpec is the list of snapshot scheduled for images in a pool
-                        properties:
-                          image:
-                            description: Image is the mirrored image
-                            type: string
-                          items:
-                            description: Items is the list schedules times for a given snapshot
-                            items:
-                              description: SnapshotSchedule is a schedule
-                              properties:
-                                interval:
-                                  description: Interval is the interval in which snapshots will be taken
-                                  type: string
-                                start_time:
-                                  description: StartTime is the snapshot starting time
-                                  type: string
-                              type: object
-                            type: array
-                          namespace:
-                            description: Namespace is the RADOS namespace the image is part of
-                            type: string
-                          pool:
-                            description: Pool is the pool name
-                            type: string
-                        type: object
-                      nullable: true
-                      type: array
-                  type: object
               type: object
               x-kubernetes-preserve-unknown-fields: true
           required:
@@ -540,7 +407,7 @@ spec:
                   nullable: true
                   type: object
                 mirroringInfo:
-                  description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring
+                  description: MirroringInfoSpec is the status of the pool mirroring
                   properties:
                     details:
                       type: string
@@ -578,7 +445,7 @@ spec:
                       type: string
                   type: object
                 mirroringStatus:
-                  description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring
+                  description: MirroringStatusSpec is the status of the pool mirroring
                   properties:
                     details:
                       description: Details contains potential status errors
@@ -636,9 +503,6 @@ spec:
                 phase:
                   description: ConditionType represent a resource's status
                   type: string
-                poolID:
-                  description: optional
-                  type: integer
                 snapshotScheduleStatus:
                   description: SnapshotScheduleStatusSpec is the status of the snapshot schedule
                   properties:
@@ -12514,9 +12378,7 @@ spec:
                             minLength: 1
                             type: string
                           default:
-                            description: |-
-                              Sets given placement as default. Only one placement in the list can be marked as default.
-                              Default is false.
+                            description: Sets given placement as default. Only one placement in the list can be marked as default.
                             type: boolean
                           metadataPoolName:
                             description: The metadata pool used to store ObjectStore bucket index.
@@ -12555,6 +12417,7 @@ spec:
                             type: array
                         required:
                           - dataPoolName
+                          - default
                           - metadataPoolName
                           - name
                         type: object
@@ -13438,9 +13301,7 @@ spec:
                             minLength: 1
                             type: string
                           default:
-                            description: |-
-                              Sets given placement as default. Only one placement in the list can be marked as default.
-                              Default is false.
+                            description: Sets given placement as default. Only one placement in the list can be marked as default.
                             type: boolean
                           metadataPoolName:
                             description: The metadata pool used to store ObjectStore bucket index.
@@ -13479,6 +13340,7 @@ spec:
                             type: array
                         required:
                           - dataPoolName
+                          - default
                           - metadataPoolName
                           - name
                         type: object
diff --git a/deploy/examples/radosnamespace-mirrored.yaml b/deploy/examples/radosnamesapce-mirrored.yaml
similarity index 100%
rename from deploy/examples/radosnamespace-mirrored.yaml
rename to deploy/examples/radosnamesapce-mirrored.yaml
diff --git a/go.mod b/go.mod
index 399c08ba1..2eeb5de12 100644
--- a/go.mod
+++ b/go.mod
@@ -42,7 +42,7 @@ require (
 	go.uber.org/automaxprocs v1.6.0
 	go.uber.org/zap v1.27.0
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
-	golang.org/x/sync v0.9.0
+	golang.org/x/sync v0.8.0
 	gopkg.in/ini.v1 v1.67.0
 	gopkg.in/yaml.v2 v2.4.0
 	k8s.io/api v0.31.2
diff --git a/go.sum b/go.sum
index 26776756e..5a29b130a 100644
--- a/go.sum
+++ b/go.sum
@@ -1131,8 +1131,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
-golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go
index 81035abb8..da0ef9b58 100755
--- a/pkg/apis/ceph.rook.io/v1/types.go
+++ b/pkg/apis/ceph.rook.io/v1/types.go
@@ -850,8 +850,6 @@ type CephBlockPoolStatus struct {
 	MirroringStatus *MirroringStatusSpec `json:"mirroringStatus,omitempty"`
 	// +optional
 	MirroringInfo *MirroringInfoSpec `json:"mirroringInfo,omitempty"`
-	// optional
-	PoolID int `json:"poolID,omitempty"`
 	// +optional
 	SnapshotScheduleStatus *SnapshotScheduleStatusSpec `json:"snapshotScheduleStatus,omitempty"`
 	// +optional
@@ -863,11 +861,11 @@ type CephBlockPoolStatus struct {
 	Conditions         []Condition `json:"conditions,omitempty"`
 }
 
-// MirroringStatusSpec is the status of the pool/radosNamespace mirroring
+// MirroringStatusSpec is the status of the pool mirroring
 type MirroringStatusSpec struct {
-	// MirroringStatus is the mirroring status of a pool/radosNamespace
+	// PoolMirroringStatus is the mirroring status of a pool
 	// +optional
-	MirroringStatus `json:",inline"`
+	PoolMirroringStatus `json:",inline"`
 	// LastChecked is the last time time the status was checked
 	// +optional
 	LastChecked string `json:"lastChecked,omitempty"`
@@ -879,15 +877,15 @@ type MirroringStatusSpec struct {
 	Details string `json:"details,omitempty"`
 }
 
-// MirroringStatus is the pool/radosNamespace mirror status
-type MirroringStatus struct {
+// PoolMirroringStatus is the pool mirror status
+type PoolMirroringStatus struct {
 	// Summary is the mirroring status summary
 	// +optional
-	Summary *MirroringStatusSummarySpec `json:"summary,omitempty"`
+	Summary *PoolMirroringStatusSummarySpec `json:"summary,omitempty"`
 }
 
-// MirroringStatusSummarySpec is the summary output of the command
-type MirroringStatusSummarySpec struct {
+// PoolMirroringStatusSummarySpec is the summary output of the command
+type PoolMirroringStatusSummarySpec struct {
 	// Health is the mirroring health
 	// +optional
 	Health string `json:"health,omitempty"`
@@ -928,10 +926,10 @@ type StatesSpec struct {
 	Error int `json:"error,omitempty"`
 }
 
-// MirroringInfoSpec is the status of the pool/radosnamespace mirroring
+// MirroringInfoSpec is the status of the pool mirroring
 type MirroringInfoSpec struct {
 	// +optional
-	*MirroringInfo `json:",inline"`
+	*PoolMirroringInfo `json:",inline"`
 	// +optional
 	LastChecked string `json:"lastChecked,omitempty"`
 	// +optional
@@ -940,8 +938,8 @@ type MirroringInfoSpec struct {
 	Details string `json:"details,omitempty"`
 }
 
-// MirroringInfo is the mirroring info of a given pool/radosnamespace
-type MirroringInfo struct {
+// PoolMirroringInfo is the mirroring info of a given pool
+type PoolMirroringInfo struct {
 	// Mode is the mirroring mode
 	// +optional
 	Mode string `json:"mode,omitempty"`
@@ -1566,8 +1564,6 @@ type PoolPlacementSpec struct {
 	Name string `json:"name"`
 
 	// Sets given placement as default. Only one placement in the list can be marked as default.
-	// Default is false.
-	// +optional
 	Default bool `json:"default"`
 
 	// The metadata pool used to store ObjectStore bucket index.
@@ -3396,12 +3392,6 @@ type CephBlockPoolRadosNamespaceStatus struct {
 	// +optional
 	// +nullable
 	Info map[string]string `json:"info,omitempty"`
-	// +optional
-	MirroringStatus *MirroringStatusSpec `json:"mirroringStatus,omitempty"`
-	// +optional
-	MirroringInfo *MirroringInfoSpec `json:"mirroringInfo,omitempty"`
-	// +optional
-	SnapshotScheduleStatus *SnapshotScheduleStatusSpec `json:"snapshotScheduleStatus,omitempty"`
 }
 
 // Represents the source of a volume to mount.
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 92e443c3e..e653d3869 100644
--- a/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go
@@ -482,21 +482,6 @@ func (in *CephBlockPoolRadosNamespaceStatus) DeepCopyInto(out *CephBlockPoolRado
 			(*out)[key] = val
 		}
 	}
-	if in.MirroringStatus != nil {
-		in, out := &in.MirroringStatus, &out.MirroringStatus
-		*out = new(MirroringStatusSpec)
-		(*in).DeepCopyInto(*out)
-	}
-	if in.MirroringInfo != nil {
-		in, out := &in.MirroringInfo, &out.MirroringInfo
-		*out = new(MirroringInfoSpec)
-		(*in).DeepCopyInto(*out)
-	}
-	if in.SnapshotScheduleStatus != nil {
-		in, out := &in.SnapshotScheduleStatus, &out.SnapshotScheduleStatus
-		*out = new(SnapshotScheduleStatusSpec)
-		(*in).DeepCopyInto(*out)
-	}
 	return
 }
 
@@ -3098,33 +3083,12 @@ func (in *MirrorHealthCheckSpec) DeepCopy() *MirrorHealthCheckSpec {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MirroringInfo) DeepCopyInto(out *MirroringInfo) {
-	*out = *in
-	if in.Peers != nil {
-		in, out := &in.Peers, &out.Peers
-		*out = make([]PeersSpec, len(*in))
-		copy(*out, *in)
-	}
-	return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirroringInfo.
-func (in *MirroringInfo) DeepCopy() *MirroringInfo {
-	if in == nil {
-		return nil
-	}
-	out := new(MirroringInfo)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MirroringInfoSpec) DeepCopyInto(out *MirroringInfoSpec) {
 	*out = *in
-	if in.MirroringInfo != nil {
-		in, out := &in.MirroringInfo, &out.MirroringInfo
-		*out = new(MirroringInfo)
+	if in.PoolMirroringInfo != nil {
+		in, out := &in.PoolMirroringInfo, &out.PoolMirroringInfo
+		*out = new(PoolMirroringInfo)
 		(*in).DeepCopyInto(*out)
 	}
 	return
@@ -3187,31 +3151,10 @@ func (in *MirroringSpec) DeepCopy() *MirroringSpec {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MirroringStatus) DeepCopyInto(out *MirroringStatus) {
-	*out = *in
-	if in.Summary != nil {
-		in, out := &in.Summary, &out.Summary
-		*out = new(MirroringStatusSummarySpec)
-		**out = **in
-	}
-	return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirroringStatus.
-func (in *MirroringStatus) DeepCopy() *MirroringStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(MirroringStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MirroringStatusSpec) DeepCopyInto(out *MirroringStatusSpec) {
 	*out = *in
-	in.MirroringStatus.DeepCopyInto(&out.MirroringStatus)
+	in.PoolMirroringStatus.DeepCopyInto(&out.PoolMirroringStatus)
 	return
 }
 
@@ -3225,23 +3168,6 @@ func (in *MirroringStatusSpec) DeepCopy() *MirroringStatusSpec {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MirroringStatusSummarySpec) DeepCopyInto(out *MirroringStatusSummarySpec) {
-	*out = *in
-	out.States = in.States
-	return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirroringStatusSummarySpec.
-func (in *MirroringStatusSummarySpec) DeepCopy() *MirroringStatusSummarySpec {
-	if in == nil {
-		return nil
-	}
-	out := new(MirroringStatusSummarySpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Module) DeepCopyInto(out *Module) {
 	*out = *in
@@ -4133,6 +4059,65 @@ func (in *PlacementStorageClassSpec) DeepCopy() *PlacementStorageClassSpec {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PoolMirroringInfo) DeepCopyInto(out *PoolMirroringInfo) {
+	*out = *in
+	if in.Peers != nil {
+		in, out := &in.Peers, &out.Peers
+		*out = make([]PeersSpec, len(*in))
+		copy(*out, *in)
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolMirroringInfo.
+func (in *PoolMirroringInfo) DeepCopy() *PoolMirroringInfo {
+	if in == nil {
+		return nil
+	}
+	out := new(PoolMirroringInfo)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PoolMirroringStatus) DeepCopyInto(out *PoolMirroringStatus) {
+	*out = *in
+	if in.Summary != nil {
+		in, out := &in.Summary, &out.Summary
+		*out = new(PoolMirroringStatusSummarySpec)
+		**out = **in
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolMirroringStatus.
+func (in *PoolMirroringStatus) DeepCopy() *PoolMirroringStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(PoolMirroringStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PoolMirroringStatusSummarySpec) DeepCopyInto(out *PoolMirroringStatusSummarySpec) {
+	*out = *in
+	out.States = in.States
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolMirroringStatusSummarySpec.
+func (in *PoolMirroringStatusSummarySpec) DeepCopy() *PoolMirroringStatusSummarySpec {
+	if in == nil {
+		return nil
+	}
+	out := new(PoolMirroringStatusSummarySpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PoolPlacementSpec) DeepCopyInto(out *PoolPlacementSpec) {
 	*out = *in
diff --git a/pkg/daemon/ceph/client/mirror.go b/pkg/daemon/ceph/client/mirror.go
index a37a95d87..30b4f3c24 100644
--- a/pkg/daemon/ceph/client/mirror.go
+++ b/pkg/daemon/ceph/client/mirror.go
@@ -165,7 +165,7 @@ func RemoveClusterPeer(context *clusterd.Context, clusterInfo *ClusterInfo, pool
 }
 
 // GetPoolMirroringStatus prints the pool mirroring status
-func GetPoolMirroringStatus(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.MirroringStatus, error) {
+func GetPoolMirroringStatus(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.PoolMirroringStatus, error) {
 	logger.Debugf("retrieving mirroring pool %q status", poolName)
 
 	// Build command
@@ -179,7 +179,7 @@ func GetPoolMirroringStatus(context *clusterd.Context, clusterInfo *ClusterInfo,
 		return nil, errors.Wrapf(err, "failed to retrieve mirroring pool %q status", poolName)
 	}
 
-	var poolMirroringStatus cephv1.MirroringStatus
+	var poolMirroringStatus cephv1.PoolMirroringStatus
 	if err := json.Unmarshal([]byte(buf), &poolMirroringStatus); err != nil {
 		return nil, errors.Wrap(err, "failed to unmarshal mirror pool status response")
 	}
@@ -211,8 +211,7 @@ func GetMirroredPoolImages(context *clusterd.Context, clusterInfo *ClusterInfo,
 }
 
 // GetPoolMirroringInfo  prints the pool mirroring information
-// `poolName` is the name of the pool or the pool/radosNamespace
-func GetPoolMirroringInfo(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.MirroringInfo, error) {
+func GetPoolMirroringInfo(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.PoolMirroringInfo, error) {
 	logger.Debugf("retrieving mirroring pool %q info", poolName)
 
 	// Build command
@@ -227,7 +226,7 @@ func GetPoolMirroringInfo(context *clusterd.Context, clusterInfo *ClusterInfo, p
 	}
 
 	// Unmarshal JSON into Go struct
-	var poolMirroringInfo cephv1.MirroringInfo
+	var poolMirroringInfo cephv1.PoolMirroringInfo
 	if err := json.Unmarshal(buf, &poolMirroringInfo); err != nil {
 		return nil, errors.Wrap(err, "failed to unmarshal mirror pool info response")
 	}
@@ -281,18 +280,17 @@ func removeSnapshotSchedule(context *clusterd.Context, clusterInfo *ClusterInfo,
 	return nil
 }
 
-// `poolName` is the name of the pool or the pool/radosNamespace
-func EnableSnapshotSchedules(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string, snapshotSchedules []cephv1.SnapshotScheduleSpec) error {
+func EnableSnapshotSchedules(context *clusterd.Context, clusterInfo *ClusterInfo, pool string, snapshotSchedules []cephv1.SnapshotScheduleSpec) error {
 	logger.Info("resetting current snapshot schedules in cluster namespace %q", clusterInfo.Namespace)
 	// Reset any existing schedules
-	err := removeSnapshotSchedules(context, clusterInfo, poolName)
+	err := removeSnapshotSchedules(context, clusterInfo, pool)
 	if err != nil {
 		logger.Errorf("failed to remove snapshot schedules. %v", err)
 	}
 
 	// Enable all the snap schedules
 	for _, snapSchedule := range snapshotSchedules {
-		err := enableSnapshotSchedule(context, clusterInfo, snapSchedule, poolName)
+		err := enableSnapshotSchedule(context, clusterInfo, snapSchedule, pool)
 		if err != nil {
 			return errors.Wrap(err, "failed to enable snapshot schedule")
 		}
diff --git a/pkg/daemon/ceph/client/mirror_health.go b/pkg/daemon/ceph/client/mirror_health.go
deleted file mode 100644
index 7880921e7..000000000
--- a/pkg/daemon/ceph/client/mirror_health.go
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
-Copyright 2020 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 client
-
-import (
-	"context"
-	"time"
-
-	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
-	"github.com/rook/rook/pkg/clusterd"
-	"github.com/rook/rook/pkg/operator/ceph/reporting"
-	kerrors "k8s.io/apimachinery/pkg/api/errors"
-	"k8s.io/apimachinery/pkg/types"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-var (
-	defaultHealthCheckInterval = 1 * time.Minute
-)
-
-type mirrorChecker struct {
-	context        *clusterd.Context
-	interval       *time.Duration
-	client         client.Client
-	clusterInfo    *ClusterInfo
-	namespacedName types.NamespacedName
-	monitoringSpec *cephv1.NamedPoolSpec
-	objectType     client.Object
-}
-
-// newMirrorChecker creates a new HealthChecker object
-func NewMirrorChecker(context *clusterd.Context, client client.Client, clusterInfo *ClusterInfo, namespacedName types.NamespacedName, monitoringSpec *cephv1.NamedPoolSpec, object client.Object) *mirrorChecker {
-	c := &mirrorChecker{
-		context:        context,
-		interval:       &defaultHealthCheckInterval,
-		clusterInfo:    clusterInfo,
-		namespacedName: namespacedName,
-		client:         client,
-		monitoringSpec: monitoringSpec,
-		objectType:     object,
-	}
-
-	// allow overriding the check interval
-	checkInterval := monitoringSpec.StatusCheck.Mirror.Interval
-	if checkInterval != nil {
-		logger.Infof("mirroring status check interval for %q is %q", namespacedName.Name, checkInterval.Duration.String())
-		c.interval = &checkInterval.Duration
-	}
-
-	return c
-}
-
-// checkMirroring periodically checks the health of the cluster
-func (c *mirrorChecker) CheckMirroring(context context.Context) {
-	// check the mirroring health immediately before starting the loop
-	err := c.CheckMirroringHealth()
-	if err != nil {
-		c.UpdateStatusMirroring(nil, nil, nil, err.Error())
-		logger.Debugf("failed to check mirroring status for %q. %v", c.namespacedName.Name, err)
-	}
-
-	for {
-		select {
-		case <-context.Done():
-			logger.Infof("stopping monitoring mirroring status for %q", c.namespacedName.Name)
-			return
-
-		case <-time.After(*c.interval):
-			logger.Debugf("checking mirroring status for %q", c.namespacedName.Name)
-			err := c.CheckMirroringHealth()
-			if err != nil {
-				c.UpdateStatusMirroring(nil, nil, nil, err.Error())
-				logger.Debugf("failed to check mirroring status for %q. %v", c.namespacedName.Name, err)
-			}
-		}
-	}
-}
-
-func (c *mirrorChecker) CheckMirroringHealth() error {
-	// Check mirroring status
-	mirrorStatus, err := GetPoolMirroringStatus(c.context, c.clusterInfo, c.monitoringSpec.Name)
-	if err != nil {
-		c.UpdateStatusMirroring(nil, nil, nil, err.Error())
-	}
-
-	// Check mirroring info
-	mirrorInfo, err := GetPoolMirroringInfo(c.context, c.clusterInfo, c.monitoringSpec.Name)
-	if err != nil {
-		c.UpdateStatusMirroring(nil, nil, nil, err.Error())
-	}
-
-	// If snapshot scheduling is enabled let's add it to the status
-	// snapSchedStatus := cephclient.SnapshotScheduleStatus{}
-	snapSchedStatus := []cephv1.SnapshotSchedulesSpec{}
-	if c.monitoringSpec.Mirroring.SnapshotSchedulesEnabled() {
-		snapSchedStatus, err = ListSnapshotSchedulesRecursively(c.context, c.clusterInfo, c.monitoringSpec.Name)
-		if err != nil {
-			c.UpdateStatusMirroring(nil, nil, nil, err.Error())
-		}
-	}
-
-	// On success
-	c.UpdateStatusMirroring(mirrorStatus.Summary, mirrorInfo, snapSchedStatus, "")
-
-	return nil
-}
-
-// updateStatusBucket updates an object with a given status
-func (c *mirrorChecker) UpdateStatusMirroring(mirrorStatus *cephv1.MirroringStatusSummarySpec, mirrorInfo *cephv1.MirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) {
-	switch c.objectType.(type) {
-	case *cephv1.CephBlockPool:
-		updatePoolStatusMirroring(c, mirrorStatus, mirrorInfo, snapSchedStatus, details)
-
-	case *cephv1.CephBlockPoolRadosNamespace:
-		updateRadosNamespaceStatusMirroring(c, mirrorStatus, mirrorInfo, snapSchedStatus, details)
-	}
-}
-
-func updatePoolStatusMirroring(c *mirrorChecker, mirrorStatus *cephv1.MirroringStatusSummarySpec, mirrorInfo *cephv1.MirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) {
-	blockPool := &cephv1.CephBlockPool{}
-	if err := c.client.Get(c.clusterInfo.Context, c.namespacedName, blockPool); err != nil {
-		if kerrors.IsNotFound(err) {
-			logger.Debug("CephBlockPool %q resource not found for updating the mirroring status, ignoring.", c.namespacedName)
-			return
-		}
-		logger.Warningf("failed to retrieve ceph block pool %q to update mirroring status. %v", c.namespacedName.Name, err)
-		return
-	}
-	if blockPool.Status == nil {
-		blockPool.Status = &cephv1.CephBlockPoolStatus{}
-	}
-
-	// Update the CephBlockPool CR status field
-	blockPool.Status.MirroringStatus, blockPool.Status.MirroringInfo, blockPool.Status.SnapshotScheduleStatus = toCustomResourceStatus(blockPool.Status.MirroringStatus, mirrorStatus, blockPool.Status.MirroringInfo, mirrorInfo, blockPool.Status.SnapshotScheduleStatus, snapSchedStatus, details)
-	if err := reporting.UpdateStatus(c.client, blockPool); err != nil {
-		logger.Errorf("failed to set ceph block pool %q mirroring status. %v", c.namespacedName.Name, err)
-		return
-	}
-
-	logger.Debugf("ceph block pool %q mirroring status updated", c.namespacedName.Name)
-}
-
-func updateRadosNamespaceStatusMirroring(c *mirrorChecker, mirrorStatus *cephv1.MirroringStatusSummarySpec, mirrorInfo *cephv1.MirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) {
-	radosNamespace := &cephv1.CephBlockPoolRadosNamespace{}
-	if err := c.client.Get(c.clusterInfo.Context, c.namespacedName, radosNamespace); err != nil {
-		if kerrors.IsNotFound(err) {
-			logger.Debug("CephBlockPoolRadosNamespace %q resource not found for updating the mirroring status, ignoring.", c.namespacedName)
-			return
-		}
-		logger.Warningf("failed to retrieve ceph block pool rados namespace %q to update mirroring status. %v", c.namespacedName.Name, err)
-		return
-	}
-	if radosNamespace.Status == nil {
-		radosNamespace.Status = &cephv1.CephBlockPoolRadosNamespaceStatus{}
-	}
-
-	blockPool := &cephv1.CephBlockPool{}
-	namespaceName := types.NamespacedName{Name: radosNamespace.Spec.BlockPoolName, Namespace: radosNamespace.Namespace}
-	if err := c.client.Get(c.clusterInfo.Context, namespaceName, blockPool); err != nil {
-		if kerrors.IsNotFound(err) {
-			logger.Debug("CephBlockPool %q resource not found for updating the mirroring status, ignoring.", namespaceName)
-			return
-		}
-		logger.Warningf("failed to retrieve ceph block pool %q to update mirroring status. %v", namespaceName, err)
-		return
-	}
-
-	if blockPool.Spec.StatusCheck.Mirror.Disabled {
-		logger.Debugf("mirroring status check is disabled for %q", c.namespacedName.Name)
-		return
-	}
-
-	// Update the CephBlockPoolRadosNamespace CR status field
-	radosNamespace.Status.MirroringStatus, radosNamespace.Status.MirroringInfo, radosNamespace.Status.SnapshotScheduleStatus = toCustomResourceStatus(radosNamespace.Status.MirroringStatus, mirrorStatus, radosNamespace.Status.MirroringInfo, mirrorInfo, radosNamespace.Status.SnapshotScheduleStatus, snapSchedStatus, details)
-	if err := reporting.UpdateStatus(c.client, radosNamespace); err != nil {
-		logger.Errorf("failed to set ceph block pool rados namespace %q mirroring status. %v", c.namespacedName.Name, err)
-		return
-	}
-}
-
-func toCustomResourceStatus(currentStatus *cephv1.MirroringStatusSpec, mirroringStatus *cephv1.MirroringStatusSummarySpec,
-	currentInfo *cephv1.MirroringInfoSpec, mirroringInfo *cephv1.MirroringInfo,
-	currentSnapSchedStatus *cephv1.SnapshotScheduleStatusSpec, snapSchedStatus []cephv1.SnapshotSchedulesSpec,
-	details string) (*cephv1.MirroringStatusSpec, *cephv1.MirroringInfoSpec, *cephv1.SnapshotScheduleStatusSpec) {
-	mirroringStatusSpec := &cephv1.MirroringStatusSpec{}
-	mirroringInfoSpec := &cephv1.MirroringInfoSpec{}
-	snapshotScheduleStatusSpec := &cephv1.SnapshotScheduleStatusSpec{}
-
-	// mirroringStatus will be nil in case of an error to fetch it
-	if mirroringStatus != nil {
-		mirroringStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339)
-		mirroringStatusSpec.MirroringStatus.Summary = mirroringStatus
-	}
-
-	// Always display the details, typically an error
-	mirroringStatusSpec.Details = details
-
-	if currentStatus != nil {
-		mirroringStatusSpec.LastChanged = currentStatus.LastChanged
-	}
-
-	// mirroringInfo will be nil in case of an error to fetch it
-	if mirroringInfo != nil {
-		mirroringInfoSpec.LastChecked = time.Now().UTC().Format(time.RFC3339)
-		mirroringInfoSpec.MirroringInfo = mirroringInfo
-	}
-	// Always display the details, typically an error
-	mirroringInfoSpec.Details = details
-
-	if currentInfo != nil {
-		mirroringInfoSpec.LastChanged = currentInfo.LastChecked
-	}
-
-	// snapSchedStatus will be nil in case of an error to fetch it
-	if len(snapSchedStatus) != 0 {
-		snapshotScheduleStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339)
-		snapshotScheduleStatusSpec.SnapshotSchedules = snapSchedStatus
-	}
-	// Always display the details, typically an error
-	snapshotScheduleStatusSpec.Details = details
-
-	if currentSnapSchedStatus != nil {
-		snapshotScheduleStatusSpec.LastChanged = currentSnapSchedStatus.LastChecked
-	}
-
-	return mirroringStatusSpec, mirroringInfoSpec, snapshotScheduleStatusSpec
-}
diff --git a/pkg/operator/ceph/cluster/mon/health.go b/pkg/operator/ceph/cluster/mon/health.go
index 050d88f43..a8fe149fe 100644
--- a/pkg/operator/ceph/cluster/mon/health.go
+++ b/pkg/operator/ceph/cluster/mon/health.go
@@ -518,6 +518,11 @@ func (c *Cluster) failMon(monCount, desiredMonCount int, name string) bool {
 		return true
 	}
 
+	if err := c.allowFailover(name); err != nil {
+		logger.Warningf("aborting mon %q failover. %v", name, err)
+		return false
+	}
+
 	// prevent any voluntary mon drain while failing over
 	if err := c.blockMonDrain(types.NamespacedName{Name: monPDBName, Namespace: c.Namespace}); err != nil {
 		logger.Errorf("failed to block mon drain. %v", err)
@@ -535,6 +540,20 @@ func (c *Cluster) failMon(monCount, desiredMonCount int, name string) bool {
 	return true
 }
 
+func (c *Cluster) allowFailover(name string) error {
+	if !c.spec.IsStretchCluster() {
+		// always failover if not a stretch cluster
+		return nil
+	}
+	if name != c.arbiterMon {
+		// failover if it's a non-arbiter
+		return nil
+	}
+
+	// Ceph does not support updating the arbiter mon in older versions
+	return errors.Errorf("refusing to failover arbiter mon %q on a stretched cluster", name)
+}
+
 func (c *Cluster) removeOrphanMonResources() {
 	if c.spec.Mon.VolumeClaimTemplate == nil {
 		logger.Debug("skipping check for orphaned mon pvcs since using the host path")
diff --git a/pkg/operator/ceph/cluster/nodedaemon/crash.go b/pkg/operator/ceph/cluster/nodedaemon/crash.go
index a95bc0462..9f3eb43bc 100644
--- a/pkg/operator/ceph/cluster/nodedaemon/crash.go
+++ b/pkg/operator/ceph/cluster/nodedaemon/crash.go
@@ -126,7 +126,7 @@ func (r *ReconcileNode) createOrUpdateCephCrash(node corev1.Node, tolerations []
 			},
 		}
 		cephv1.GetCrashCollectorAnnotations(cephCluster.Spec.Annotations).ApplyToObjectMeta(&deploy.Spec.Template.ObjectMeta)
-		deploy.Spec.RevisionHistoryLimit = controller.RevisionHistoryLimit()
+
 		return nil
 	}
 
diff --git a/pkg/operator/ceph/cluster/osd/key_rotation.go b/pkg/operator/ceph/cluster/osd/key_rotation.go
index e69973310..ae10ca7b6 100644
--- a/pkg/operator/ceph/cluster/osd/key_rotation.go
+++ b/pkg/operator/ceph/cluster/osd/key_rotation.go
@@ -94,12 +94,6 @@ func (c *Cluster) getKeyRotationContainer(osdProps osdProperties, volumeMounts [
 			RunAsUser:              &runAsUser,
 			RunAsNonRoot:           &runAsNonRoot,
 			ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
-			Capabilities: &v1.Capabilities{
-				Add: []v1.Capability{},
-				Drop: []v1.Capability{
-					"NET_RAW",
-				},
-			},
 		},
 		Resources: osdProps.resources,
 	}
diff --git a/pkg/operator/ceph/cluster/osd/provision_spec.go b/pkg/operator/ceph/cluster/osd/provision_spec.go
index 25521c88a..48147c486 100644
--- a/pkg/operator/ceph/cluster/osd/provision_spec.go
+++ b/pkg/operator/ceph/cluster/osd/provision_spec.go
@@ -342,12 +342,6 @@ func (c *Cluster) provisionOSDContainer(osdProps osdProperties, copyBinariesMoun
 			RunAsUser:              &runAsUser,
 			RunAsNonRoot:           &runAsNonRoot,
 			ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
-			Capabilities: &v1.Capabilities{
-				Add: []v1.Capability{},
-				Drop: []v1.Capability{
-					"NET_RAW",
-				},
-			},
 		},
 		Resources: cephv1.GetPrepareOSDResources(c.spec.Resources),
 	}
diff --git a/pkg/operator/ceph/cluster/osd/spec.go b/pkg/operator/ceph/cluster/osd/spec.go
index 79c066bf2..4506d5249 100644
--- a/pkg/operator/ceph/cluster/osd/spec.go
+++ b/pkg/operator/ceph/cluster/osd/spec.go
@@ -107,42 +107,11 @@ OSD_ID="$ROOK_OSD_ID"
 OSD_UUID=%s
 OSD_STORE_FLAG="%s"
 OSD_DATA_DIR=/var/lib/ceph/osd/ceph-"$OSD_ID"
-KEYRING_FILE="$OSD_DATA_DIR"/keyring
 CV_MODE=%s
 DEVICE="$%s"
 
-# In rare cases keyring file created with prepare-osd but did not
-# being stored in ceph auth system therefore we need to import it
-# from keyring file instead of creating new one
-if ! ceph -n client.admin auth get osd."$OSD_ID" -k /etc/ceph/admin-keyring-store/keyring; then
-    if [ -f "$KEYRING_FILE" ]; then
-        # import keyring from existing file
-        TMP_DIR=$(mktemp -d)
-
-        python3 -c "
-import configparser
-
-config = configparser.ConfigParser()
-config.read('$KEYRING_FILE')
-
-if not config.has_section('osd.$OSD_ID'):
-    exit()
-
-config['osd.$OSD_ID'] = {'key': config['osd.$OSD_ID']['key'], 'caps mon': '\"allow profile osd\"', 'caps mgr': '\"allow profile osd\"', 'caps osd': '\"allow *\"'}
-
-with open('$TMP_DIR/keyring', 'w') as configfile:
-    config.write(configfile)
-"
-
-        cat "$TMP_DIR"/keyring
-        ceph -n client.admin auth import -i "$TMP_DIR"/keyring -k /etc/ceph/admin-keyring-store/keyring
-
-        rm --recursive --force "$TMP_DIR"
-    else
-        # create new keyring if no keyring file found
-        ceph -n client.admin auth get-or-create osd."$OSD_ID" mon 'allow profile osd' mgr 'allow profile osd' osd 'allow *' -k /etc/ceph/admin-keyring-store/keyring
-    fi
-fi
+# create new keyring
+ceph -n client.admin auth get-or-create osd."$OSD_ID" mon 'allow profile osd' mgr 'allow profile osd' osd 'allow *' -k /etc/ceph/admin-keyring-store/keyring
 
 # active the osd with ceph-volume
 if [[ "$CV_MODE" == "lvm" ]]; then
@@ -513,12 +482,6 @@ func (c *Cluster) makeDeployment(osdProps osdProperties, osd *OSDInfo, provision
 		Privileged:             &privileged,
 		RunAsUser:              &runAsUser,
 		ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
-		Capabilities: &v1.Capabilities{
-			Add: []v1.Capability{},
-			Drop: []v1.Capability{
-				"NET_RAW",
-			},
-		},
 	}
 
 	// needed for luksOpen synchronization when devices are encrypted and the osd is prepared with LVM
@@ -950,9 +913,6 @@ func getBlockDevMapperContext() *v1.SecurityContext {
 			Add: []v1.Capability{
 				"MKNOD",
 			},
-			Drop: []v1.Capability{
-				"NET_RAW",
-			},
 		},
 		Privileged: &privileged,
 	}
diff --git a/pkg/operator/ceph/cluster/osd/topology/topology.go b/pkg/operator/ceph/cluster/osd/topology/topology.go
index ce4022e16..a69552b14 100644
--- a/pkg/operator/ceph/cluster/osd/topology/topology.go
+++ b/pkg/operator/ceph/cluster/osd/topology/topology.go
@@ -23,7 +23,6 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/coreos/pkg/capnslog"
 	"github.com/rook/rook/pkg/daemon/ceph/client"
 	corev1 "k8s.io/api/core/v1"
 )
@@ -40,8 +39,6 @@ var (
 
 	// The list of supported failure domains in the CRUSH map, ordered from lowest to highest
 	CRUSHMapLevelsOrdered = append([]string{"host"}, append(CRUSHTopologyLabels, KubernetesTopologyLabels...)...)
-
-	logger = capnslog.NewPackageLogger("github.com/rook/rook", "osd-topology")
 )
 
 const (
@@ -110,27 +107,18 @@ func extractTopologyFromLabels(labels map[string]string) (map[string]string, str
 	}
 	// iterate in lowest to highest order as the lowest level should be sustained and higher level duplicate
 	// should be removed
-	duplicateTopology := make(map[string][]string)
+	duplicateTopology := make(map[string]int)
 	for i := len(allKubernetesTopologyLabels) - 1; i >= 0; i-- {
 		topologyLabel := allKubernetesTopologyLabels[i]
 		if value, ok := labels[topologyLabel]; ok {
 			if _, ok := duplicateTopology[value]; ok {
 				delete(topology, kubernetesTopologyLabelToCRUSHLabel(topologyLabel))
+			} else {
+				duplicateTopology[value] = 1
 			}
-			duplicateTopology[value] = append(duplicateTopology[value], topologyLabel)
 		}
 	}
 
-	// remove non-duplicate entries, and report if any duplicate entries were found
-	for value, duplicateKeys := range duplicateTopology {
-		if len(duplicateKeys) <= 1 {
-			delete(duplicateTopology, value)
-		}
-	}
-	if len(duplicateTopology) != 0 {
-		logger.Warningf("Found duplicate location values with labels: %v", duplicateTopology)
-	}
-
 	return topology, topologyAffinity
 }
 
diff --git a/pkg/operator/ceph/cluster/rbd/controller.go b/pkg/operator/ceph/cluster/rbd/controller.go
index 09dc827bb..9a8c6b594 100644
--- a/pkg/operator/ceph/cluster/rbd/controller.go
+++ b/pkg/operator/ceph/cluster/rbd/controller.go
@@ -83,7 +83,7 @@ type ReconcileCephRBDMirror struct {
 
 // peerSpec represents peer details
 type peerSpec struct {
-	info      *cephv1.MirroringInfo
+	info      *cephv1.PoolMirroringInfo
 	poolName  string
 	direction string
 }
diff --git a/pkg/operator/ceph/controller/controller_utils.go b/pkg/operator/ceph/controller/controller_utils.go
index acdf7920b..9d5e20752 100644
--- a/pkg/operator/ceph/controller/controller_utils.go
+++ b/pkg/operator/ceph/controller/controller_utils.go
@@ -54,7 +54,8 @@ const (
 	enforceHostNetworkSettingName  string = "ROOK_ENFORCE_HOST_NETWORK"
 	enforceHostNetworkDefaultValue string = "false"
 
-	revisionHistoryLimitSettingName string = "ROOK_REVISION_HISTORY_LIMIT"
+	revisionHistoryLimitSettingName  string = "ROOK_REVISION_HISTORY_LIMIT"
+	revisionHistoryLimitDefaultValue string = ""
 
 	// UninitializedCephConfigError refers to the error message printed by the Ceph CLI when there is no ceph configuration file
 	// This typically is raised when the operator has not finished initializing
@@ -137,21 +138,18 @@ func EnforceHostNetwork() bool {
 }
 
 func SetRevisionHistoryLimit(data map[string]string) {
-	strval := k8sutil.GetValue(data, revisionHistoryLimitSettingName, "")
-	var limit int32
-	if strval == "" {
-		logger.Debugf("not parsing empty string to int for %q. assuming default value.", revisionHistoryLimitSettingName)
-		revisionHistoryLimit = nil
-		return
-	}
-	numval, err := strconv.ParseInt(strval, 10, 32)
-	if err != nil {
-		logger.Warningf("failed to parse value %q for %q. assuming default value. %v", strval, revisionHistoryLimitSettingName, err)
-		revisionHistoryLimit = nil
-		return
+	strval := k8sutil.GetValue(data, revisionHistoryLimitSettingName, revisionHistoryLimitDefaultValue)
+	if strval != "" {
+		numval, err := strconv.ParseInt(strval, 10, 32)
+		if err != nil {
+			logger.Warningf("failed to parse value %q for %q. assuming default value.", strval, revisionHistoryLimitSettingName)
+			revisionHistoryLimit = nil
+			return
+
+		}
+		limit := int32(numval)
+		revisionHistoryLimit = &limit
 	}
-	limit = int32(numval)
-	revisionHistoryLimit = &limit
 
 }
 
diff --git a/pkg/operator/ceph/controller/spec.go b/pkg/operator/ceph/controller/spec.go
index b37d5e49f..73c5a424e 100644
--- a/pkg/operator/ceph/controller/spec.go
+++ b/pkg/operator/ceph/controller/spec.go
@@ -729,12 +729,6 @@ func PodSecurityContext() *v1.SecurityContext {
 
 	return &v1.SecurityContext{
 		Privileged: &privileged,
-		Capabilities: &v1.Capabilities{
-			Add: []v1.Capability{},
-			Drop: []v1.Capability{
-				"NET_RAW",
-			},
-		},
 	}
 }
 
@@ -760,12 +754,6 @@ func PrivilegedContext(runAsRoot bool) *v1.SecurityContext {
 		sec.RunAsUser = &rootUser
 	}
 
-	sec.Capabilities = &v1.Capabilities{
-		Add: []v1.Capability{},
-		Drop: []v1.Capability{
-			"NET_RAW",
-		},
-	}
 	return sec
 }
 
diff --git a/pkg/operator/ceph/csi/ceph_connection.go b/pkg/operator/ceph/csi/ceph_connection.go
index 518b09d2f..bedb6664b 100644
--- a/pkg/operator/ceph/csi/ceph_connection.go
+++ b/pkg/operator/ceph/csi/ceph_connection.go
@@ -17,13 +17,10 @@ limitations under the License.
 package csi
 
 import (
-	"os"
-
 	"github.com/pkg/errors"
 
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 	cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
-	"github.com/rook/rook/pkg/operator/k8sutil"
 
 	csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1"
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -37,13 +34,18 @@ func CreateUpdateCephConnection(c client.Client, clusterInfo *cephclient.Cluster
 	csiCephConnection := &csiopv1a1.CephConnection{}
 
 	csiCephConnection.Name = clusterInfo.NamespacedName().Name
-	csiCephConnection.Namespace = os.Getenv(k8sutil.PodNamespaceEnvVar)
+	csiCephConnection.Namespace = clusterInfo.NamespacedName().Namespace
 
 	spec, err := generateCephConnSpec(c, clusterInfo, csiCephConnection.Spec, clusterSpec)
 	if err != nil {
 		return errors.Wrapf(err, "failed to set ceph connection CR %q in namespace %q", csiCephConnection.Name, clusterInfo.Namespace)
 	}
 
+	err = clusterInfo.OwnerInfo.SetOwnerReference(csiCephConnection)
+	if err != nil {
+		return errors.Wrapf(err, "failed to set owner reference for ceph connection CR %q", csiCephConnection.Name)
+	}
+
 	err = c.Get(clusterInfo.Context, types.NamespacedName{Name: csiCephConnection.Name, Namespace: csiCephConnection.Namespace}, csiCephConnection)
 	if err != nil {
 		if kerrors.IsNotFound(err) {
diff --git a/pkg/operator/ceph/csi/config.go b/pkg/operator/ceph/csi/config.go
index 1d733aa69..482c71545 100644
--- a/pkg/operator/ceph/csi/config.go
+++ b/pkg/operator/ceph/csi/config.go
@@ -18,14 +18,9 @@ package csi
 
 import (
 	"context"
-	"os"
-	"reflect"
-	"runtime/debug"
 	"strings"
 
-	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 	cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
-	"github.com/rook/rook/pkg/operator/k8sutil"
 
 	csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1"
 	"github.com/pkg/errors"
@@ -41,7 +36,7 @@ func CreateUpdateClientProfileRadosNamespace(ctx context.Context, c client.Clien
 
 	csiOpClientProfile := &csiopv1a1.ClientProfile{}
 	csiOpClientProfile.Name = clusterID
-	csiOpClientProfile.Namespace = os.Getenv(k8sutil.PodNamespaceEnvVar)
+	csiOpClientProfile.Namespace = cephBlockPoolRadosNamespacedName.Namespace
 	csiOpClientProfile.Spec = csiopv1a1.ClientProfileSpec{
 		CephConnectionRef: v1.LocalObjectReference{
 			Name: clusterName,
@@ -51,7 +46,12 @@ func CreateUpdateClientProfileRadosNamespace(ctx context.Context, c client.Clien
 		},
 	}
 
-	err := c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile)
+	err := clusterInfo.OwnerInfo.SetOwnerReference(csiOpClientProfile)
+	if err != nil {
+		return errors.Wrapf(err, "failed to set owner reference for clientProfile CR %q for radosNamespace", csiOpClientProfile.Name)
+	}
+
+	err = c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile)
 	if err != nil {
 		if apierrors.IsNotFound(err) {
 			err = c.Create(ctx, csiOpClientProfile)
@@ -79,7 +79,12 @@ func CreateUpdateClientProfileSubVolumeGroup(ctx context.Context, c client.Clien
 
 	csiOpClientProfile := generateProfileSubVolumeGroupSpec(clusterInfo, cephFilesystemNamespacedName, clusterID, clusterName)
 
-	err := c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile)
+	err := clusterInfo.OwnerInfo.SetOwnerReference(csiOpClientProfile)
+	if err != nil {
+		return errors.Wrapf(err, "failed to set owner reference for clientProfile CR %q for subVolGrp", csiOpClientProfile.Name)
+	}
+
+	err = c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile)
 	if err != nil {
 		if apierrors.IsNotFound(err) {
 			err = c.Create(ctx, csiOpClientProfile)
@@ -104,7 +109,7 @@ func CreateUpdateClientProfileSubVolumeGroup(ctx context.Context, c client.Clien
 func generateProfileSubVolumeGroupSpec(clusterInfo *cephclient.ClusterInfo, cephFilesystemNamespacedName types.NamespacedName, clusterID, clusterName string) *csiopv1a1.ClientProfile {
 	csiOpClientProfile := &csiopv1a1.ClientProfile{}
 	csiOpClientProfile.Name = clusterID
-	csiOpClientProfile.Namespace = os.Getenv(k8sutil.PodNamespaceEnvVar)
+	csiOpClientProfile.Namespace = cephFilesystemNamespacedName.Namespace
 	csiOpClientProfile.Spec = csiopv1a1.ClientProfileSpec{
 		CephConnectionRef: v1.LocalObjectReference{
 			Name: clusterName,
@@ -114,14 +119,15 @@ func generateProfileSubVolumeGroupSpec(clusterInfo *cephclient.ClusterInfo, ceph
 		},
 	}
 
-	if !reflect.DeepEqual(clusterInfo.CSIDriverSpec.CephFS, cephv1.CSICephFSSpec{}) {
-		if clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions != "" {
-			kernelMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions, "=")
-			csiOpClientProfile.Spec.CephFs.KernelMountOptions = map[string]string{kernelMountKeyVal[0]: kernelMountKeyVal[1]}
-		} else if clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions != "" {
-			fuseMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions, "=")
-			csiOpClientProfile.Spec.CephFs.FuseMountOptions = map[string]string{fuseMountKeyVal[0]: fuseMountKeyVal[1]}
-		}
+	kernelMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions, "=")
+	fuseMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions, "=")
+
+	if len(kernelMountKeyVal) == 2 {
+		csiOpClientProfile.Spec.CephFs.KernelMountOptions = map[string]string{kernelMountKeyVal[0]: kernelMountKeyVal[1]}
+	}
+
+	if len(fuseMountKeyVal) == 2 {
+		csiOpClientProfile.Spec.CephFs.FuseMountOptions = map[string]string{fuseMountKeyVal[0]: fuseMountKeyVal[1]}
 	}
 
 	return csiOpClientProfile
@@ -130,42 +136,22 @@ func generateProfileSubVolumeGroupSpec(clusterInfo *cephclient.ClusterInfo, ceph
 // CreateDefaultClientProfile creates a default client profile for csi-operator to connect driver
 func CreateDefaultClientProfile(c client.Client, clusterInfo *cephclient.ClusterInfo, namespaced types.NamespacedName) error {
 	logger.Info("Creating ceph-csi clientProfile default CR")
-	defer func() {
-		if r := recover(); r != nil {
-			logger.Errorf("Panic when creating the default client profile: %+v", r)
-			logger.Errorf("Stack trace:")
-			logger.Errorf(string(debug.Stack()))
-		}
-	}()
 
 	csiOpClientProfile := &csiopv1a1.ClientProfile{}
 	csiOpClientProfile.Name = clusterInfo.Namespace
-	csiOpClientProfile.Namespace = os.Getenv(k8sutil.PodNamespaceEnvVar)
+	csiOpClientProfile.Namespace = clusterInfo.Namespace
 	csiOpClientProfile.Spec = csiopv1a1.ClientProfileSpec{
 		CephConnectionRef: v1.LocalObjectReference{
 			Name: namespaced.Name,
 		},
 	}
 
-	if !reflect.DeepEqual(clusterInfo.CSIDriverSpec.CephFS, cephv1.CSICephFSSpec{}) {
-		if clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions != "" {
-			kernelMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions, "=")
-			if len(kernelMountKeyVal) >= 2 {
-				csiOpClientProfile.Spec.CephFs = &csiopv1a1.CephFsConfigSpec{
-					KernelMountOptions: map[string]string{kernelMountKeyVal[0]: kernelMountKeyVal[1]},
-				}
-			}
-		} else if clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions != "" {
-			fuseMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions, "=")
-			if len(fuseMountKeyVal) >= 2 {
-				csiOpClientProfile.Spec.CephFs = &csiopv1a1.CephFsConfigSpec{
-					FuseMountOptions: map[string]string{fuseMountKeyVal[0]: fuseMountKeyVal[1]},
-				}
-			}
-		}
+	err := clusterInfo.OwnerInfo.SetOwnerReference(csiOpClientProfile)
+	if err != nil {
+		return errors.Wrapf(err, "failed to set owner reference for default clientProfile CR %q", csiOpClientProfile.Name)
 	}
 
-	err := c.Get(clusterInfo.Context, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile)
+	err = c.Get(clusterInfo.Context, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile)
 	if err != nil {
 		if apierrors.IsNotFound(err) {
 			err = c.Create(clusterInfo.Context, csiOpClientProfile)
diff --git a/pkg/operator/ceph/csi/operator_config.go b/pkg/operator/ceph/csi/operator_config.go
index 638e512b2..d1aceecfb 100644
--- a/pkg/operator/ceph/csi/operator_config.go
+++ b/pkg/operator/ceph/csi/operator_config.go
@@ -17,6 +17,8 @@ limitations under the License.
 package csi
 
 import (
+	"reflect"
+
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 
 	csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1"
@@ -117,11 +119,14 @@ func (r *ReconcileCSI) generateCSIOpConfigSpec(cluster cephv1.CephCluster, opCon
 			CephFsClientType: cephfsClientType,
 		},
 	}
-	if CSIParam.EnableCSIEncryption {
-		opConfig.Spec.DriverSpecDefaults.Encryption = &csiopv1a1.EncryptionSpec{
-			ConfigMapRef: v1.LocalObjectReference{
-				Name: "rook-ceph-csi-kms-config",
-			},
+	if !reflect.DeepEqual(cluster.Spec.Network, cephv1.NetworkSpec{}) {
+
+		if cluster.Spec.Network.Connections.Encryption.Enabled {
+			opConfig.Spec.DriverSpecDefaults.Encryption = &csiopv1a1.EncryptionSpec{
+				ConfigMapRef: v1.LocalObjectReference{
+					Name: "rook-ceph-csi-kms-config",
+				},
+			}
 		}
 	}
 
diff --git a/pkg/operator/ceph/csi/operator_driver.go b/pkg/operator/ceph/csi/operator_driver.go
index 165107da3..e13f5afee 100644
--- a/pkg/operator/ceph/csi/operator_driver.go
+++ b/pkg/operator/ceph/csi/operator_driver.go
@@ -41,35 +41,35 @@ func (r *ReconcileCSI) createOrUpdateDriverResources(cluster cephv1.CephCluster,
 
 	if EnableRBD {
 		logger.Info("Creating RBD driver resources")
-		err := r.transferCSIDriverOwner(r.opManagerContext, RBDDriverName)
+		err := r.transferCSIDriverOwner(r.opManagerContext, clusterInfo, RBDDriverName)
 		if err != nil {
 			return errors.Wrap(err, "failed to create update RBD driver for csi-operator driver CR ")
 		}
 		err = r.createOrUpdateRBDDriverResource(cluster, clusterInfo)
 		if err != nil {
-			return errors.Wrapf(err, "failed to create or update RBD driver resource in the namespace %q", r.opConfig.OperatorNamespace)
+			return errors.Wrapf(err, "failed to create or update RBD driver resource in the namespace %q", clusterInfo.Namespace)
 		}
 	}
 	if EnableCephFS {
 		logger.Info("Creating CephFS driver resources")
-		err := r.transferCSIDriverOwner(r.opManagerContext, CephFSDriverName)
+		err := r.transferCSIDriverOwner(r.opManagerContext, clusterInfo, CephFSDriverName)
 		if err != nil {
 			return errors.Wrap(err, "failed to create update CephFS driver for csi-operator driver CR ")
 		}
 		err = r.createOrUpdateCephFSDriverResource(cluster, clusterInfo)
 		if err != nil {
-			return errors.Wrapf(err, "failed to create or update cephFS driver resource in the namespace %q", r.opConfig.OperatorNamespace)
+			return errors.Wrapf(err, "failed to create or update cephFS driver resource in the namespace %q", clusterInfo.Namespace)
 		}
 	}
 	if EnableNFS {
 		logger.Info("Creating NFS driver resources")
-		err := r.transferCSIDriverOwner(r.opManagerContext, NFSDriverName)
+		err := r.transferCSIDriverOwner(r.opManagerContext, clusterInfo, NFSDriverName)
 		if err != nil {
 			return errors.Wrap(err, "failed to create update NFS driver for csi-operator driver CR ")
 		}
 		err = r.createOrUpdateNFSDriverResource(cluster, clusterInfo)
 		if err != nil {
-			return errors.Wrapf(err, "failed to create or update NFS driver resource in the namespace %q", r.opConfig.OperatorNamespace)
+			return errors.Wrapf(err, "failed to create or update NFS driver resource in the namespace %q", clusterInfo.Namespace)
 		}
 	}
 
@@ -77,7 +77,7 @@ func (r *ReconcileCSI) createOrUpdateDriverResources(cluster cephv1.CephCluster,
 }
 
 func (r *ReconcileCSI) createOrUpdateRBDDriverResource(cluster cephv1.CephCluster, clusterInfo *cephclient.ClusterInfo) error {
-	resourceName := fmt.Sprintf("%s.rbd.csi.ceph.com", r.opConfig.OperatorNamespace)
+	resourceName := fmt.Sprintf("%s.rbd.csi.ceph.com", clusterInfo.Namespace)
 	spec, err := r.generateDriverSpec(cluster.Name)
 	if err != nil {
 		return err
@@ -87,7 +87,7 @@ func (r *ReconcileCSI) createOrUpdateRBDDriverResource(cluster cephv1.CephCluste
 		TypeMeta: metav1.TypeMeta{},
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      resourceName,
-			Namespace: r.opConfig.OperatorNamespace,
+			Namespace: clusterInfo.Namespace,
 		},
 		Spec: spec,
 	}
@@ -123,7 +123,7 @@ func (r *ReconcileCSI) createOrUpdateRBDDriverResource(cluster cephv1.CephCluste
 }
 
 func (r *ReconcileCSI) createOrUpdateCephFSDriverResource(cluster cephv1.CephCluster, clusterInfo *cephclient.ClusterInfo) error {
-	resourceName := fmt.Sprintf("%s.cephfs.csi.ceph.com", r.opConfig.OperatorNamespace)
+	resourceName := fmt.Sprintf("%s.cephfs.csi.ceph.com", clusterInfo.Namespace)
 	spec, err := r.generateDriverSpec(cluster.Name)
 	if err != nil {
 		return err
@@ -133,7 +133,7 @@ func (r *ReconcileCSI) createOrUpdateCephFSDriverResource(cluster cephv1.CephClu
 		TypeMeta: metav1.TypeMeta{},
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      resourceName,
-			Namespace: r.opConfig.OperatorNamespace,
+			Namespace: clusterInfo.Namespace,
 		},
 		Spec: spec,
 	}
@@ -175,7 +175,7 @@ func (r *ReconcileCSI) createOrUpdateCephFSDriverResource(cluster cephv1.CephClu
 }
 
 func (r *ReconcileCSI) createOrUpdateNFSDriverResource(cluster cephv1.CephCluster, clusterInfo *cephclient.ClusterInfo) error {
-	resourceName := fmt.Sprintf("%s.nfs.csi.ceph.com", r.opConfig.OperatorNamespace)
+	resourceName := fmt.Sprintf("%s.nfs.csi.ceph.com", clusterInfo.Namespace)
 	spec, err := r.generateDriverSpec(cluster.Name)
 	if err != nil {
 		return err
@@ -185,7 +185,7 @@ func (r *ReconcileCSI) createOrUpdateNFSDriverResource(cluster cephv1.CephCluste
 		TypeMeta: metav1.TypeMeta{},
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      resourceName,
-			Namespace: r.opConfig.OperatorNamespace,
+			Namespace: clusterInfo.Namespace,
 		},
 		Spec: spec,
 	}
@@ -221,7 +221,7 @@ func (r *ReconcileCSI) createOrUpdateNFSDriverResource(cluster cephv1.CephCluste
 func (r ReconcileCSI) createOrUpdateDriverResource(clusterInfo *cephclient.ClusterInfo, driverResource *csiopv1a1.Driver) error {
 	spec := driverResource.Spec
 
-	err := r.client.Get(r.opManagerContext, types.NamespacedName{Name: driverResource.Name, Namespace: r.opConfig.OperatorNamespace}, driverResource)
+	err := r.client.Get(r.opManagerContext, types.NamespacedName{Name: driverResource.Name, Namespace: clusterInfo.Namespace}, driverResource)
 	if err != nil {
 		if kerrors.IsNotFound(err) {
 			err = r.client.Create(r.opManagerContext, driverResource)
@@ -380,7 +380,7 @@ func createDriverNodePluginResouces(opConfig map[string]string, key string) csio
 }
 
 // transferCSIDriverOwner update CSIDriver and returns the error if any
-func (r *ReconcileCSI) transferCSIDriverOwner(ctx context.Context, name string) error {
+func (r *ReconcileCSI) transferCSIDriverOwner(ctx context.Context, clusterInfo *cephclient.ClusterInfo, name string) error {
 
 	logger.Info("adding annotation to CSIDriver resource for csi-operator to own it")
 	csiDriver, err := r.context.Clientset.StorageV1().CSIDrivers().Get(ctx, name, metav1.GetOptions{})
@@ -393,7 +393,6 @@ func (r *ReconcileCSI) transferCSIDriverOwner(ctx context.Context, name string)
 
 	key := "csi.ceph.io/ownerref"
 	ownerObjKey := client.ObjectKeyFromObject(csiDriver)
-	ownerObjKey.Namespace = r.opConfig.OperatorNamespace
 	val, err := json.Marshal(ownerObjKey)
 	if err != nil {
 		return errors.Wrapf(err, "failed to marshal owner object key %q", ownerObjKey.Name)
diff --git a/pkg/operator/ceph/csi/spec.go b/pkg/operator/ceph/csi/spec.go
index 0f587270f..f3e14a681 100644
--- a/pkg/operator/ceph/csi/spec.go
+++ b/pkg/operator/ceph/csi/spec.go
@@ -338,7 +338,6 @@ func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error {
 		if err != nil {
 			return errors.Wrap(err, "failed to load rbdplugin template")
 		}
-		rbdPlugin.Spec.RevisionHistoryLimit = opcontroller.RevisionHistoryLimit()
 		if tp.CSILogRotation {
 			applyLogrotateSidecar(&rbdPlugin.Spec.Template, "csi-rbd-daemonset-log-collector", LogrotateTemplatePath, tp)
 		}
@@ -352,7 +351,6 @@ func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error {
 			applyLogrotateSidecar(&rbdProvisionerDeployment.Spec.Template, "csi-rbd-deployment-log-collector", LogrotateTemplatePath, tp)
 		}
 		rbdProvisionerDeployment.Spec.Template.Spec.HostNetwork = opcontroller.EnforceHostNetwork()
-		rbdProvisionerDeployment.Spec.RevisionHistoryLimit = opcontroller.RevisionHistoryLimit()
 
 		// Create service if either liveness or GRPC metrics are enabled.
 		if CSIParam.EnableLiveness {
@@ -370,8 +368,6 @@ func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error {
 		if err != nil {
 			return errors.Wrap(err, "failed to load CephFS plugin template")
 		}
-		cephfsPlugin.Spec.RevisionHistoryLimit = opcontroller.RevisionHistoryLimit()
-
 		if tp.CSILogRotation {
 			applyLogrotateSidecar(&cephfsPlugin.Spec.Template, "csi-cephfs-daemonset-log-collector", LogrotateTemplatePath, tp)
 		}
@@ -385,7 +381,6 @@ func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error {
 			applyLogrotateSidecar(&cephfsProvisionerDeployment.Spec.Template, "csi-cephfs-deployment-log-collector", LogrotateTemplatePath, tp)
 		}
 		cephfsProvisionerDeployment.Spec.Template.Spec.HostNetwork = opcontroller.EnforceHostNetwork()
-		cephfsProvisionerDeployment.Spec.RevisionHistoryLimit = opcontroller.RevisionHistoryLimit()
 
 		// Create service if either liveness or GRPC metrics are enabled.
 		if CSIParam.EnableLiveness {
@@ -404,7 +399,6 @@ func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error {
 		if err != nil {
 			return errors.Wrap(err, "failed to load nfs plugin template")
 		}
-		nfsPlugin.Spec.RevisionHistoryLimit = opcontroller.RevisionHistoryLimit()
 		if tp.CSILogRotation {
 			applyLogrotateSidecar(&nfsPlugin.Spec.Template, "csi-nfs-daemonset-log-collector", LogrotateTemplatePath, tp)
 		}
@@ -418,7 +412,6 @@ func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error {
 			applyLogrotateSidecar(&nfsProvisionerDeployment.Spec.Template, "csi-nfs-deployment-log-collector", LogrotateTemplatePath, tp)
 		}
 		nfsProvisionerDeployment.Spec.Template.Spec.HostNetwork = opcontroller.EnforceHostNetwork()
-		nfsProvisionerDeployment.Spec.RevisionHistoryLimit = opcontroller.RevisionHistoryLimit()
 	}
 
 	// get common provisioner tolerations and node affinity
diff --git a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml
index 35fa8d0c1..d78fc1cbe 100644
--- a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml
+++ b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml
@@ -256,7 +256,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           {{ end }}
           volumeMounts:
diff --git a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml
index 6d92de1ab..bd4bac53c 100644
--- a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml
+++ b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml
@@ -39,7 +39,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           image: {{ .RegistrarImage }}
           imagePullPolicy: {{ .ImagePullPolicy }}
@@ -145,7 +144,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           image: {{ .CSIPluginImage }}
           args:
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 a62473bb1..9411546f2 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
@@ -44,10 +44,6 @@ spec:
             - name: ADDRESS
               value: /csi/csi-provisioner.sock
           imagePullPolicy: {{ .ImagePullPolicy }}
-          securityContext:
-            capabilities:
-              add: []
-              drop: ["ALL"]
           volumeMounts:
             - name: socket-dir
               mountPath: /csi
@@ -75,10 +71,6 @@ spec:
             - name: ADDRESS
               value: unix:///csi/csi-provisioner.sock
           imagePullPolicy: {{ .ImagePullPolicy }}
-          securityContext:
-            capabilities:
-              add: []
-              drop: ["ALL"]
           volumeMounts:
             - name: socket-dir
               mountPath: /csi
@@ -106,10 +98,6 @@ spec:
             - name: ADDRESS
               value: unix:///csi/csi-provisioner.sock
           imagePullPolicy: {{ .ImagePullPolicy }}
-          securityContext:
-            capabilities:
-              add: []
-              drop: ["ALL"]
           volumeMounts:
             - name: socket-dir
               mountPath: /csi
@@ -137,10 +125,6 @@ spec:
             - name: ADDRESS
               value: unix:///csi/csi-provisioner.sock
           imagePullPolicy: {{ .ImagePullPolicy }}
-          securityContext:
-            capabilities:
-              add: []
-              drop: ["ALL"]
           volumeMounts:
             - name: socket-dir
               mountPath: /csi
diff --git a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml
index d6b7e8d18..a0d16acf6 100644
--- a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml
+++ b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml
@@ -33,7 +33,6 @@ spec:
           # created by privileged CSI driver container.
           securityContext:
             capabilities:
-              add: []
               drop: ["ALL"]
             privileged: true
           image: {{ .RegistrarImage }}
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 23a019bc0..741b362b9 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
@@ -209,7 +209,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           {{ end }}
           volumeMounts:
@@ -268,7 +267,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           {{ end }}
           volumeMounts:
diff --git a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml
index 99adaa2c6..fb0a3fca5 100644
--- a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml
+++ b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml
@@ -40,7 +40,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           image: {{ .RegistrarImage }}
           imagePullPolicy: {{ .ImagePullPolicy }}
@@ -154,7 +153,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           image: {{ .CSIAddonsImage }}
           args :
@@ -206,7 +204,6 @@ spec:
           securityContext:
             privileged: true
             capabilities:
-              add: []
               drop: ["ALL"]
           image: {{ .CSIPluginImage }}
           args:
diff --git a/pkg/operator/ceph/object/shared_pools.go b/pkg/operator/ceph/object/shared_pools.go
index 95bafb14c..b447cdf46 100644
--- a/pkg/operator/ceph/object/shared_pools.go
+++ b/pkg/operator/ceph/object/shared_pools.go
@@ -89,6 +89,7 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha
 
 	fromSpec := toZonePlacementPools(spec, name)
 
+	defaultPlacementName := getDefaultPlacementName(spec)
 	inConfig := map[string]struct{}{}
 	idxToRemove := map[int]struct{}{}
 	for i, p := range placements {
@@ -101,19 +102,10 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha
 			return nil, fmt.Errorf("unable to get pool placement name for zone %s: %w", name, err)
 		}
 		// check if placement should be removed
-		if _, inSpec := fromSpec[placementID]; !inSpec {
-			if placementID == defaultPlacementCephConfigName {
-				// 'default-placement' should always be kept as a workaround for https://tracker.ceph.com/issues/68775.
-				// if user specified other placement as default, then copy pool names to 'default-placement' from it:
-				if userDefault, inSpec := fromSpec[getDefaultPlacementName(spec)]; inSpec {
-					// duplicate user defined default placement under 'default-placement' name in spec to update pools on the next step
-					fromSpec[defaultPlacementCephConfigName] = userDefault
-				}
-			} else {
-				// remove placement if it is not in spec
-				idxToRemove[i] = struct{}{}
-				continue
-			}
+		if _, inSpec := fromSpec[placementID]; !inSpec && placementID != defaultPlacementName {
+			// remove placement if it is not in spec, but don't remove default placement
+			idxToRemove[i] = struct{}{}
+			continue
 		}
 		// update placement with values from spec:
 		if pSpec, inSpec := fromSpec[placementID]; inSpec {
@@ -163,29 +155,6 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha
 		placements = append(placements, pObj)
 	}
 
-	// sort placements array.
-	// Reason: 'radosgw-admin zone set --infile' sorts placement_pools by key before storing it in ceph
-	// and returns JSON with sorted placement_pools array. So we sort input array for easy comparison with applied JSON.
-	sort.Slice(placements, func(i, j int) bool {
-		pI, ok := placements[i].(map[string]interface{})
-		if !ok {
-			return false
-		}
-		nameI, err := getObjProperty[string](pI, "key")
-		if err != nil {
-			return false
-		}
-		pJ, ok := placements[j].(map[string]interface{})
-		if !ok {
-			return false
-		}
-		nameJ, err := getObjProperty[string](pJ, "key")
-		if err != nil {
-			return false
-		}
-		return nameI < nameJ
-	})
-
 	_, err = updateObjProperty(zone, placements, "placement_pools")
 	if err != nil {
 		return nil, fmt.Errorf("unable to set pool placements for zone %q: %w", name, err)
@@ -213,9 +182,16 @@ func getDefaultMetadataPool(spec cephv1.ObjectSharedPoolsSpec) string {
 
 // toZonePlacementPools converts pool placement CRD definition to zone config json format structures
 func toZonePlacementPools(spec cephv1.ObjectSharedPoolsSpec, ns string) map[string]ZonePlacementPool {
+	hasDefault := false
 	res := make(map[string]ZonePlacementPool, len(spec.PoolPlacements)+1)
-	// map sharedPools if presented:
-	if spec.DataPoolName != "" && spec.MetadataPoolName != "" {
+	for _, pp := range spec.PoolPlacements {
+		if pp.Default {
+			hasDefault = true
+		}
+		res[pp.Name] = toZonePlacementPool(pp, ns)
+	}
+	if !hasDefault && spec.DataPoolName != "" && spec.MetadataPoolName != "" {
+		// set shared pools as default if no default placement was provided
 		res[defaultPlacementCephConfigName] = ZonePlacementPool{
 			Key: defaultPlacementCephConfigName,
 			Val: ZonePlacementPoolVal{
@@ -235,10 +211,6 @@ func toZonePlacementPools(spec cephv1.ObjectSharedPoolsSpec, ns string) map[stri
 			},
 		}
 	}
-	// map pool placements:
-	for _, pp := range spec.PoolPlacements {
-		res[pp.Name] = toZonePlacementPool(pp, ns)
-	}
 	return res
 }
 
@@ -521,7 +493,7 @@ func updateZoneGroupJSON(objContext *Context, group map[string]interface{}) (map
 	args := []string{"zonegroup", "set", zoneArg, "--infile=" + configFilename, realmArg, zoneGroupArg}
 	updatedBytes, err := RunAdminCommandNoMultisite(objContext, false, args...)
 	if err != nil {
-		return nil, errors.Wrap(err, fmt.Sprintf("failed to set zonegroup config %s", updatedBytes))
+		return nil, errors.Wrap(err, "failed to set zone config")
 	}
 	updated := map[string]interface{}{}
 	err = json.Unmarshal([]byte(updatedBytes), &updated)
diff --git a/pkg/operator/ceph/pool/controller.go b/pkg/operator/ceph/pool/controller.go
index c3c0d7732..33ac9b428 100644
--- a/pkg/operator/ceph/pool/controller.go
+++ b/pkg/operator/ceph/pool/controller.go
@@ -21,7 +21,6 @@ import (
 	"context"
 	"fmt"
 	"reflect"
-	"sort"
 	"strings"
 
 	"github.com/coreos/pkg/capnslog"
@@ -180,7 +179,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile
 
 	// The CR was just created, initializing status fields
 	if cephBlockPool.Status == nil {
-		r.updateStatus(request.NamespacedName, cephv1.ConditionProgressing, k8sutil.ObservedGenerationNotAvailable)
+		updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionProgressing, k8sutil.ObservedGenerationNotAvailable)
 	}
 
 	// Make sure a CephCluster is present otherwise do nothing
@@ -298,7 +297,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile
 			logger.Info(opcontroller.OperatorNotInitializedMessage)
 			return opcontroller.WaitForRequeueIfOperatorNotInitialized, *cephBlockPool, nil
 		}
-		r.updateStatus(request.NamespacedName, cephv1.ConditionFailure, k8sutil.ObservedGenerationNotAvailable)
+		updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionFailure, k8sutil.ObservedGenerationNotAvailable)
 		return reconcileResponse, *cephBlockPool, errors.Wrapf(err, "failed to create pool %q.", cephBlockPool.GetName())
 	}
 
@@ -306,19 +305,29 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile
 	if err := configureRBDStats(r.context, clusterInfo, ""); err != nil {
 		return reconcile.Result{}, *cephBlockPool, errors.Wrap(err, "failed to enable/disable stats collection for pool(s)")
 	}
-	checker := cephclient.NewMirrorChecker(r.context, r.client, r.clusterInfo, request.NamespacedName, &poolSpec, cephBlockPool)
+	checker := newMirrorChecker(r.context, r.client, r.clusterInfo, request.NamespacedName, &poolSpec)
 	// ADD PEERS
 	logger.Debug("reconciling create rbd mirror peer configuration")
 	if cephBlockPool.Spec.Mirroring.Enabled {
 		// Always create a bootstrap peer token in case another cluster wants to add us as a peer
 		reconcileResponse, err = opcontroller.CreateBootstrapPeerSecret(r.context, clusterInfo, cephBlockPool, k8sutil.NewOwnerInfo(cephBlockPool, r.scheme))
 		if err != nil {
-			r.updateStatus(request.NamespacedName, cephv1.ConditionFailure, k8sutil.ObservedGenerationNotAvailable)
+			updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionFailure, k8sutil.ObservedGenerationNotAvailable)
 			return reconcileResponse, *cephBlockPool, errors.Wrapf(err, "failed to create rbd-mirror bootstrap peer for pool %q.", cephBlockPool.GetName())
 		}
 
 		// Check if rbd-mirror CR and daemons are running
 		logger.Debug("listing rbd-mirror CR")
+		// Run the goroutine to update the mirroring status
+		if !cephBlockPool.Spec.StatusCheck.Mirror.Disabled {
+			// Start monitoring of the pool
+			if r.blockPoolContexts[blockPoolChannelKey].started {
+				logger.Debug("pool monitoring go routine already running!")
+			} else {
+				go checker.checkMirroring(r.blockPoolContexts[blockPoolChannelKey].internalCtx)
+				r.blockPoolContexts[blockPoolChannelKey].started = true
+			}
+		}
 
 		// Add bootstrap peer if any
 		logger.Debug("reconciling ceph bootstrap peers import")
@@ -335,26 +344,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile
 
 		// update ObservedGeneration in status at the end of reconcile
 		// Set Ready status, we are done reconciling
-		r.updateStatus(request.NamespacedName, cephv1.ConditionReady, observedGeneration)
-
-		if cephBlockPool.Spec.StatusCheck.Mirror.Disabled {
-			// Stop monitoring the mirroring status of this pool
-			if blockPoolContextsExists && r.blockPoolContexts[blockPoolChannelKey].started {
-				logger.Info("stop monitoring the mirroring status of the pool %q", cephBlockPool.Name)
-				r.cancelMirrorMonitoring(cephBlockPool)
-				// Reset the MirrorHealthCheckSpec
-				checker.UpdateStatusMirroring(nil, nil, nil, "")
-			}
-		} else {
-			// Start monitoring of the pool
-			if r.blockPoolContexts[blockPoolChannelKey].started {
-				logger.Debug("pool monitoring go routine already running!")
-			} else {
-				r.blockPoolContexts[blockPoolChannelKey].started = true
-				// Run the goroutine to update the mirroring status
-				go checker.CheckMirroring(r.blockPoolContexts[blockPoolChannelKey].internalCtx)
-			}
-		}
+		updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionReady, observedGeneration)
 
 		// If not mirrored there is no Status Info field to fulfil
 	} else {
@@ -365,13 +355,13 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile
 		}
 		// update ObservedGeneration in status at the end of reconcile
 		// Set Ready status, we are done reconciling
-		r.updateStatus(request.NamespacedName, cephv1.ConditionReady, observedGeneration)
+		updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionReady, observedGeneration)
 
 		// Stop monitoring the mirroring status of this pool
 		if blockPoolContextsExists && r.blockPoolContexts[blockPoolChannelKey].started {
 			r.cancelMirrorMonitoring(cephBlockPool)
 			// Reset the MirrorHealthCheckSpec
-			checker.UpdateStatusMirroring(nil, nil, nil, "")
+			checker.updateStatusMirroring(nil, nil, nil, "")
 		}
 	}
 
@@ -451,50 +441,35 @@ func deletePool(context *clusterd.Context, clusterInfo *cephclient.ClusterInfo,
 	return nil
 }
 
-// generateStatsPoolList combines existingStatsPools and rookStatsPools, removes items in removePools,
-// removes duplicates, ensures no empty strings, and returns a comma-separated string in a deterministic order.
-func generateStatsPoolList(existingStatsPools []string, rookStatsPools []string, removePools []string) string {
-	poolList := []string{}
-
-	// Helper function to add a poolList if it's not in the removePools list and not already in poolList
-	addUniquePool := func(pool string) {
-		if pool == "" {
-			return
-		}
-		// Check if the pool should be removed or already exists in poolList
-		if contains(removePools, pool) || contains(poolList, pool) {
-			return
+// remove removes any element from a list
+func remove(list []string, s string) []string {
+	for i, v := range list {
+		if v == s {
+			list = append(list[:i], list[i+1:]...)
 		}
-		poolList = append(poolList, pool)
-	}
-	for _, pool := range existingStatsPools {
-		addUniquePool(pool)
 	}
-	for _, pool := range rookStatsPools {
-		addUniquePool(pool)
-	}
-
-	sort.Strings(poolList) // Sort the list to ensure deterministic output
 
-	return strings.Join(poolList, ",")
+	return list
 }
 
-// Helper function to check if a slice contains a string
-func contains(slice []string, item string) bool {
-	for _, s := range slice {
-		if s == item {
-			return true
+// Remove duplicate entries from slice
+func removeDuplicates(slice []string) []string {
+	inResult := make(map[string]bool)
+	var result []string
+	for _, str := range slice {
+		if _, ok := inResult[str]; !ok {
+			inResult[str] = true
+			result = append(result, str)
 		}
 	}
-	return false
+	return result
 }
 
 func configureRBDStats(clusterContext *clusterd.Context, clusterInfo *cephclient.ClusterInfo, deletedPool string) error {
 	logger.Debug("configuring RBD per-image IO statistics collection")
 	namespaceListOpt := client.InNamespace(clusterInfo.Namespace)
 	cephBlockPoolList := &cephv1.CephBlockPoolList{}
-	var rookStatsPools []string
-	var removePools []string
+	var enableStatsForCephBlockPools []string
 	err := clusterContext.Client.List(clusterInfo.Context, cephBlockPoolList, namespaceListOpt)
 	if err != nil {
 		return errors.Wrap(err, "failed to retrieve list of CephBlockPool")
@@ -502,29 +477,28 @@ func configureRBDStats(clusterContext *clusterd.Context, clusterInfo *cephclient
 	for _, cephBlockPool := range cephBlockPoolList.Items {
 		if cephBlockPool.GetDeletionTimestamp() == nil && cephBlockPool.Spec.EnableRBDStats {
 			// add to list of CephBlockPool with enableRBDStats set to true and not marked for deletion
-			rookStatsPools = append(rookStatsPools, cephBlockPool.ToNamedPoolSpec().Name)
-		} else {
-			removePools = append(removePools, cephBlockPool.ToNamedPoolSpec().Name)
+			enableStatsForCephBlockPools = append(enableStatsForCephBlockPools, cephBlockPool.ToNamedPoolSpec().Name)
 		}
 	}
-	if deletedPool != "" {
-		removePools = append(removePools, deletedPool)
-	}
+	enableStatsForCephBlockPools = remove(enableStatsForCephBlockPools, deletedPool)
 	monStore := config.GetMonStore(clusterContext, clusterInfo)
 	// Check for existing rbd stats pools
-	existingStatsPools, e := monStore.Get("mgr", "mgr/prometheus/rbd_stats_pools")
+	existingRBDStatsPools, e := monStore.Get("mgr", "mgr/prometheus/rbd_stats_pools")
 	if e != nil {
 		return errors.Wrapf(e, "failed to get rbd_stats_pools")
 	}
-	existingStatsPoolsList := strings.Split(existingStatsPools, ",")
-	enableStatsForPools := generateStatsPoolList(existingStatsPoolsList, rookStatsPools, removePools)
-	logger.Infof("enableStatsForPools=%q ", enableStatsForPools)
+
+	existingRBDStatsPoolsList := strings.Split(existingRBDStatsPools, ",")
+	enableStatsForPools := append(enableStatsForCephBlockPools, existingRBDStatsPoolsList...)
+	enableStatsForPools = removeDuplicates(enableStatsForPools)
+
 	logger.Debugf("RBD per-image IO statistics will be collected for pools: %v", enableStatsForPools)
+
 	if len(enableStatsForPools) == 0 {
 		err = monStore.Delete("mgr", "mgr/prometheus/rbd_stats_pools")
 	} else {
 		// appending existing rbd stats pools if any
-		err = monStore.Set("mgr", "mgr/prometheus/rbd_stats_pools", enableStatsForPools)
+		err = monStore.Set("mgr", "mgr/prometheus/rbd_stats_pools", strings.Trim(strings.Join(enableStatsForPools, ","), ","))
 	}
 	if err != nil {
 		return errors.Wrapf(err, "failed to enable rbd_stats_pools")
diff --git a/pkg/operator/ceph/pool/health.go b/pkg/operator/ceph/pool/health.go
new file mode 100644
index 000000000..90731bf91
--- /dev/null
+++ b/pkg/operator/ceph/pool/health.go
@@ -0,0 +1,117 @@
+/*
+Copyright 2020 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 pool
+
+import (
+	"context"
+	"time"
+
+	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"
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var (
+	defaultHealthCheckInterval = 1 * time.Minute
+)
+
+type mirrorChecker struct {
+	context        *clusterd.Context
+	interval       *time.Duration
+	client         client.Client
+	clusterInfo    *cephclient.ClusterInfo
+	namespacedName types.NamespacedName
+	poolSpec       *cephv1.NamedPoolSpec
+}
+
+// newMirrorChecker creates a new HealthChecker object
+func newMirrorChecker(context *clusterd.Context, client client.Client, clusterInfo *cephclient.ClusterInfo, namespacedName types.NamespacedName, poolSpec *cephv1.NamedPoolSpec) *mirrorChecker {
+	c := &mirrorChecker{
+		context:        context,
+		interval:       &defaultHealthCheckInterval,
+		clusterInfo:    clusterInfo,
+		namespacedName: namespacedName,
+		client:         client,
+		poolSpec:       poolSpec,
+	}
+
+	// allow overriding the check interval
+	checkInterval := poolSpec.StatusCheck.Mirror.Interval
+	if checkInterval != nil {
+		logger.Infof("pool mirroring status check interval for block pool %q is %q", namespacedName.Name, checkInterval.Duration.String())
+		c.interval = &checkInterval.Duration
+	}
+
+	return c
+}
+
+// checkMirroring periodically checks the health of the cluster
+func (c *mirrorChecker) checkMirroring(context context.Context) {
+	// check the mirroring health immediately before starting the loop
+	err := c.checkMirroringHealth()
+	if err != nil {
+		c.updateStatusMirroring(nil, nil, nil, err.Error())
+		logger.Debugf("failed to check pool mirroring status for ceph block pool %q. %v", c.namespacedName.Name, err)
+	}
+
+	for {
+		select {
+		case <-context.Done():
+			logger.Infof("stopping monitoring pool mirroring status %q", c.namespacedName.Name)
+			return
+
+		case <-time.After(*c.interval):
+			logger.Debugf("checking pool mirroring status %q", c.namespacedName.Name)
+			err := c.checkMirroringHealth()
+			if err != nil {
+				c.updateStatusMirroring(nil, nil, nil, err.Error())
+				logger.Debugf("failed to check pool mirroring status for ceph block pool %q. %v", c.namespacedName.Name, err)
+			}
+		}
+	}
+}
+
+func (c *mirrorChecker) checkMirroringHealth() error {
+	// Check mirroring status
+	mirrorStatus, err := cephclient.GetPoolMirroringStatus(c.context, c.clusterInfo, c.poolSpec.Name)
+	if err != nil {
+		c.updateStatusMirroring(nil, nil, nil, err.Error())
+	}
+
+	// Check mirroring info
+	mirrorInfo, err := cephclient.GetPoolMirroringInfo(c.context, c.clusterInfo, c.poolSpec.Name)
+	if err != nil {
+		c.updateStatusMirroring(nil, nil, nil, err.Error())
+	}
+
+	// If snapshot scheduling is enabled let's add it to the status
+	// snapSchedStatus := cephclient.SnapshotScheduleStatus{}
+	snapSchedStatus := []cephv1.SnapshotSchedulesSpec{}
+	if c.poolSpec.Mirroring.SnapshotSchedulesEnabled() {
+		snapSchedStatus, err = cephclient.ListSnapshotSchedulesRecursively(c.context, c.clusterInfo, c.poolSpec.Name)
+		if err != nil {
+			c.updateStatusMirroring(nil, nil, nil, err.Error())
+		}
+	}
+
+	// On success
+	c.updateStatusMirroring(mirrorStatus.Summary, mirrorInfo, snapSchedStatus, "")
+
+	return nil
+}
diff --git a/pkg/operator/ceph/pool/radosnamespace/controller.go b/pkg/operator/ceph/pool/radosnamespace/controller.go
index f013db310..57dfbbf93 100644
--- a/pkg/operator/ceph/pool/radosnamespace/controller.go
+++ b/pkg/operator/ceph/pool/radosnamespace/controller.go
@@ -57,8 +57,6 @@ var logger = capnslog.NewPackageLogger("github.com/rook/rook", controllerName)
 
 var poolNamespace = reflect.TypeOf(cephv1.CephBlockPoolRadosNamespace{}).Name()
 
-var detectCephVersion = opcontroller.DetectCephVersion
-
 // Sets the type meta for the controller main object
 var controllerTypeMeta = metav1.TypeMeta{
 	Kind:       poolNamespace,
@@ -67,19 +65,12 @@ var controllerTypeMeta = metav1.TypeMeta{
 
 // ReconcileCephBlockPoolRadosNamespace reconciles a CephBlockPoolRadosNamespace object
 type ReconcileCephBlockPoolRadosNamespace struct {
-	client                 client.Client
-	scheme                 *runtime.Scheme
-	context                *clusterd.Context
-	clusterInfo            *cephclient.ClusterInfo
-	radosNamespaceContexts map[string]*mirrorHealth
-	opManagerContext       context.Context
-	opConfig               opcontroller.OperatorConfig
-}
-
-type mirrorHealth struct {
-	internalCtx    context.Context
-	internalCancel context.CancelFunc
-	started        bool
+	client           client.Client
+	scheme           *runtime.Scheme
+	context          *clusterd.Context
+	clusterInfo      *cephclient.ClusterInfo
+	opManagerContext context.Context
+	opConfig         opcontroller.OperatorConfig
 }
 
 // Add creates a new CephBlockPoolRadosNamespace Controller and adds it to the
@@ -92,12 +83,11 @@ func Add(mgr manager.Manager, context *clusterd.Context, opManagerContext contex
 // newReconciler returns a new reconcile.Reconciler
 func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) reconcile.Reconciler {
 	return &ReconcileCephBlockPoolRadosNamespace{
-		client:                 mgr.GetClient(),
-		scheme:                 mgr.GetScheme(),
-		context:                context,
-		radosNamespaceContexts: make(map[string]*mirrorHealth),
-		opManagerContext:       opManagerContext,
-		opConfig:               opConfig,
+		client:           mgr.GetClient(),
+		scheme:           mgr.GetScheme(),
+		context:          context,
+		opManagerContext: opManagerContext,
+		opConfig:         opConfig,
 	}
 }
 
@@ -163,8 +153,6 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque
 		r.updateStatus(r.client, request.NamespacedName, cephv1.ConditionProgressing)
 	}
 
-	poolAndRadosNamespaceName := fmt.Sprintf("%s/%s", cephBlockPoolRadosNamespace.Spec.BlockPoolName, getRadosNamespaceName(cephBlockPoolRadosNamespace))
-
 	// Make sure a CephCluster is present otherwise do nothing
 	cephCluster, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.opManagerContext, r.client, request.NamespacedName, controllerName)
 	if !isReadyToReconcile {
@@ -175,8 +163,6 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque
 		// If not, we should wait for it to be ready
 		// This handles the case where the operator is not ready to accept Ceph command but the cluster exists
 		if !cephBlockPoolRadosNamespace.GetDeletionTimestamp().IsZero() && !cephClusterExists {
-			// don't leak the health checker routine if we are force-deleting
-			r.cancelMirrorMonitoring(radosNamespaceChannelKeyName(cephBlockPoolRadosNamespace.Namespace, poolAndRadosNamespaceName))
 			// Remove finalizer
 			err = opcontroller.RemoveFinalizer(r.opManagerContext, r.client, cephBlockPoolRadosNamespace)
 			if err != nil {
@@ -195,21 +181,7 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque
 		return reconcile.Result{}, errors.Wrap(err, "failed to populate cluster info")
 	}
 	r.clusterInfo.Context = r.opManagerContext
-	cephversion, err := detectCephVersion(
-		r.opManagerContext,
-		r.opConfig.Image,
-		cephBlockPoolRadosNamespace.Namespace,
-		controllerName,
-		k8sutil.NewOwnerInfo(cephBlockPoolRadosNamespace, r.scheme),
-		r.context.Clientset,
-		&cephCluster.Spec,
-	)
-	if err != nil {
-		return reconcile.Result{}, errors.Wrap(err, "failed to detect ceph version")
-	}
-	if cephversion != nil {
-		r.clusterInfo.CephVersion = *cephversion
-	}
+
 	// DELETE: the CR was deleted
 	if !cephBlockPoolRadosNamespace.GetDeletionTimestamp().IsZero() {
 		logger.Debugf("delete cephBlockPoolRadosNamespace %q", namespacedName)
@@ -231,9 +203,6 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque
 				}
 				return reconcile.Result{}, errors.Wrapf(err, "failed to delete ceph blockpool rados namespace %q", cephBlockPoolRadosNamespace.Name)
 			}
-			// If the ceph block pool is still in the map, we must remove it during CR deletion
-			// We must remove it first otherwise the checker will panic since the status/info will be nil
-			r.cancelMirrorMonitoring(radosNamespaceChannelKeyName(cephBlockPoolRadosNamespace.Namespace, poolAndRadosNamespaceName))
 		}
 		err = csi.SaveClusterConfig(r.context.Clientset, buildClusterID(cephBlockPoolRadosNamespace), cephCluster.Namespace, r.clusterInfo, nil)
 		if err != nil {
@@ -258,6 +227,19 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque
 		r.updateStatus(r.client, namespacedName, cephv1.ConditionReady)
 		return reconcile.Result{}, nil
 	}
+
+	// cephversion check is only required for enabling mirroring
+	if cephBlockPoolRadosNamespace.Spec.Mirroring != nil {
+		// Get CephCluster version
+		cephVersion, err := opcontroller.GetImageVersion(cephCluster)
+		if err != nil {
+			return opcontroller.ImmediateRetryResult, errors.Wrapf(err, "failed to fetch ceph version from cephcluster %q running in namespace %q", cephCluster.Name, cephCluster.Namespace)
+		}
+		if cephVersion != nil {
+			r.clusterInfo.CephVersion = *cephVersion
+		}
+	}
+
 	// Build the NamespacedName to fetch the CephBlockPool and make sure it exists, if not we cannot
 	// create the rados namespace
 	cephBlockPool := &cephv1.CephBlockPool{}
@@ -433,23 +415,6 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcileMirroring(cephBlockPoolR
 		return errors.Wrapf(err, "failed to get mirroring info for the radosnamespace %q", poolAndRadosNamespaceName)
 	}
 
-	// Initialize the channel for radosNamespace
-	// This allows us to track multiple radosNamespace in the same namespace
-	radosNamespaceChannelKey := radosNamespaceChannelKeyName(cephBlockPool.Namespace, poolAndRadosNamespaceName)
-	_, radosNamespaceContextsExists := r.radosNamespaceContexts[radosNamespaceChannelKey]
-	if !radosNamespaceContextsExists {
-		internalCtx, internalCancel := context.WithCancel(r.opManagerContext)
-		r.radosNamespaceContexts[radosNamespaceChannelKey] = &mirrorHealth{
-			internalCtx:    internalCtx,
-			internalCancel: internalCancel,
-		}
-	}
-	monitoringSpec := cephv1.NamedPoolSpec{
-		Name:     poolAndRadosNamespaceName, // use the name of the blockpool/radosNamespace
-		PoolSpec: cephBlockPool.Spec.PoolSpec,
-	}
-	checker := cephclient.NewMirrorChecker(r.context, r.client, r.clusterInfo, types.NamespacedName{Name: cephBlockPoolRadosNamespace.Name, Namespace: cephBlockPoolRadosNamespace.Namespace}, &monitoringSpec, cephBlockPoolRadosNamespace)
-
 	if cephBlockPoolRadosNamespace.Spec.Mirroring != nil {
 		mirroringDisabled := checkBlockPoolMirroring(cephBlockPool)
 		if mirroringDisabled {
@@ -466,19 +431,6 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcileMirroring(cephBlockPoolR
 		if err != nil {
 			return errors.Wrapf(err, "failed to enable snapshot scheduling for rbd rados namespace %q", poolAndRadosNamespaceName)
 		}
-
-		// Run the goroutine to update the mirroring status
-		// use the monitoring settings from the cephBlockPool CR
-		if !cephBlockPool.Spec.StatusCheck.Mirror.Disabled {
-			logger.Debugf("starting mirror monitoring for radosnamespace %q", poolAndRadosNamespaceName)
-			// Start monitoring of the radosNamespace
-			if r.radosNamespaceContexts[radosNamespaceChannelKey].started {
-				logger.Debug("radosnamespace monitoring go routine already running!")
-			} else {
-				r.radosNamespaceContexts[radosNamespaceChannelKey].started = true
-				go checker.CheckMirroring(r.radosNamespaceContexts[radosNamespaceChannelKey].internalCtx)
-			}
-		}
 	}
 
 	if cephBlockPoolRadosNamespace.Spec.Mirroring == nil && mirrorInfo.Mode != "disabled" {
@@ -498,31 +450,5 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcileMirroring(cephBlockPoolR
 			return errors.Wrap(err, "failed to disable rbd rados namespace mirroring")
 		}
 	}
-
-	if cephBlockPool.Spec.StatusCheck.Mirror.Disabled {
-		// Stop monitoring the mirroring status of this radosNamespace
-		if radosNamespaceContextsExists && r.radosNamespaceContexts[radosNamespaceChannelKey].started {
-			r.cancelMirrorMonitoring(radosNamespaceChannelKey)
-			// Reset the MirrorHealthCheckSpec
-			checker.UpdateStatusMirroring(nil, nil, nil, "")
-		}
-	}
-
 	return nil
 }
-
-func radosNamespaceChannelKeyName(poolAndRadosNamespaceName, namespace string) string {
-	return types.NamespacedName{Namespace: namespace, Name: poolAndRadosNamespaceName}.String()
-}
-
-// cancel mirror monitoring. This is a noop if monitoring is not running.
-func (r *ReconcileCephBlockPoolRadosNamespace) cancelMirrorMonitoring(channelKey string) {
-	_, poolContextExists := r.radosNamespaceContexts[channelKey]
-	if poolContextExists {
-		// Cancel the context to stop the go routine
-		r.radosNamespaceContexts[channelKey].internalCancel()
-
-		// Remove ceph radosNamespace from the map
-		delete(r.radosNamespaceContexts, channelKey)
-	}
-}
diff --git a/pkg/operator/ceph/pool/status.go b/pkg/operator/ceph/pool/status.go
index 6d19a5ec4..e9de744fd 100644
--- a/pkg/operator/ceph/pool/status.go
+++ b/pkg/operator/ceph/pool/status.go
@@ -18,19 +18,22 @@ limitations under the License.
 package pool
 
 import (
+	"context"
+	"time"
+
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
-	cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
 	opcontroller "github.com/rook/rook/pkg/operator/ceph/controller"
 	"github.com/rook/rook/pkg/operator/ceph/reporting"
 	"github.com/rook/rook/pkg/operator/k8sutil"
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 // updateStatus updates a pool CR with the given status
-func (r *ReconcileCephBlockPool) updateStatus(poolName types.NamespacedName, status cephv1.ConditionType, observedGeneration int64) {
+func updateStatus(ctx context.Context, client client.Client, poolName types.NamespacedName, status cephv1.ConditionType, observedGeneration int64) {
 	pool := &cephv1.CephBlockPool{}
-	err := r.client.Get(r.opManagerContext, poolName, pool)
+	err := client.Get(ctx, poolName, pool)
 	if err != nil {
 		if kerrors.IsNotFound(err) {
 			logger.Debug("CephBlockPool resource not found. Ignoring since object must be deleted.")
@@ -44,23 +47,91 @@ func (r *ReconcileCephBlockPool) updateStatus(poolName types.NamespacedName, sta
 		pool.Status = &cephv1.CephBlockPoolStatus{}
 	}
 
-	// add pool ID to the status
-	if status == cephv1.ConditionReady && pool.Status.PoolID == 0 {
-		r.updatePoolID(pool)
-	}
-
 	pool.Status.Phase = status
 	updateStatusInfo(pool)
 	if observedGeneration != k8sutil.ObservedGenerationNotAvailable {
 		pool.Status.ObservedGeneration = observedGeneration
 	}
-	if err := reporting.UpdateStatus(r.client, pool); err != nil {
+	if err := reporting.UpdateStatus(client, pool); err != nil {
 		logger.Warningf("failed to set pool %q status to %q. %v", pool.Name, status, err)
 		return
 	}
 	logger.Debugf("pool %q status updated to %q", poolName, status)
 }
 
+// updateStatusBucket updates an object with a given status
+func (c *mirrorChecker) updateStatusMirroring(mirrorStatus *cephv1.PoolMirroringStatusSummarySpec, mirrorInfo *cephv1.PoolMirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) {
+	blockPool := &cephv1.CephBlockPool{}
+	if err := c.client.Get(c.clusterInfo.Context, c.namespacedName, blockPool); err != nil {
+		if kerrors.IsNotFound(err) {
+			logger.Debug("CephBlockPool resource not found. Ignoring since object must be deleted.")
+			return
+		}
+		logger.Warningf("failed to retrieve ceph block pool %q to update mirroring status. %v", c.namespacedName.Name, err)
+		return
+	}
+	if blockPool.Status == nil {
+		blockPool.Status = &cephv1.CephBlockPoolStatus{}
+	}
+
+	// Update the CephBlockPool CR status field
+	blockPool.Status.MirroringStatus, blockPool.Status.MirroringInfo, blockPool.Status.SnapshotScheduleStatus = toCustomResourceStatus(blockPool.Status.MirroringStatus, mirrorStatus, blockPool.Status.MirroringInfo, mirrorInfo, blockPool.Status.SnapshotScheduleStatus, snapSchedStatus, details)
+	if err := reporting.UpdateStatus(c.client, blockPool); err != nil {
+		logger.Errorf("failed to set ceph block pool %q mirroring status. %v", c.namespacedName.Name, err)
+		return
+	}
+
+	logger.Debugf("ceph block pool %q mirroring status updated", c.namespacedName.Name)
+}
+
+func toCustomResourceStatus(currentStatus *cephv1.MirroringStatusSpec, mirroringStatus *cephv1.PoolMirroringStatusSummarySpec,
+	currentInfo *cephv1.MirroringInfoSpec, mirroringInfo *cephv1.PoolMirroringInfo,
+	currentSnapSchedStatus *cephv1.SnapshotScheduleStatusSpec, snapSchedStatus []cephv1.SnapshotSchedulesSpec,
+	details string) (*cephv1.MirroringStatusSpec, *cephv1.MirroringInfoSpec, *cephv1.SnapshotScheduleStatusSpec) {
+	mirroringStatusSpec := &cephv1.MirroringStatusSpec{}
+	mirroringInfoSpec := &cephv1.MirroringInfoSpec{}
+	snapshotScheduleStatusSpec := &cephv1.SnapshotScheduleStatusSpec{}
+
+	// mirroringStatus will be nil in case of an error to fetch it
+	if mirroringStatus != nil {
+		mirroringStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339)
+		mirroringStatusSpec.Summary = mirroringStatus
+	}
+
+	// Always display the details, typically an error
+	mirroringStatusSpec.Details = details
+
+	if currentStatus != nil {
+		mirroringStatusSpec.LastChanged = currentStatus.LastChanged
+	}
+
+	// mirroringInfo will be nil in case of an error to fetch it
+	if mirroringInfo != nil {
+		mirroringInfoSpec.LastChecked = time.Now().UTC().Format(time.RFC3339)
+		mirroringInfoSpec.PoolMirroringInfo = mirroringInfo
+	}
+	// Always display the details, typically an error
+	mirroringInfoSpec.Details = details
+
+	if currentInfo != nil {
+		mirroringInfoSpec.LastChanged = currentInfo.LastChecked
+	}
+
+	// snapSchedStatus will be nil in case of an error to fetch it
+	if len(snapSchedStatus) != 0 {
+		snapshotScheduleStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339)
+		snapshotScheduleStatusSpec.SnapshotSchedules = snapSchedStatus
+	}
+	// Always display the details, typically an error
+	snapshotScheduleStatusSpec.Details = details
+
+	if currentSnapSchedStatus != nil {
+		snapshotScheduleStatusSpec.LastChanged = currentSnapSchedStatus.LastChecked
+	}
+
+	return mirroringStatusSpec, mirroringInfoSpec, snapshotScheduleStatusSpec
+}
+
 func updateStatusInfo(cephBlockPool *cephv1.CephBlockPool) {
 	m := make(map[string]string)
 	if cephBlockPool.Status.Phase == cephv1.ConditionReady && cephBlockPool.Spec.Mirroring.Enabled {
@@ -84,14 +155,3 @@ func updateStatusInfo(cephBlockPool *cephv1.CephBlockPool) {
 
 	cephBlockPool.Status.Info = m
 }
-
-func (r *ReconcileCephBlockPool) updatePoolID(cephBlockPool *cephv1.CephBlockPool) {
-	poolName := cephBlockPool.ToNamedPoolSpec().Name
-	poolDetails, err := cephclient.GetPoolDetails(r.context, r.clusterInfo, poolName)
-	if err != nil {
-		logger.Warningf("failed to get pool details for cephBlockPool %q", poolName)
-		return
-	}
-	logger.Infof("set pool ID %d to cephBlockPool %q status", poolDetails.Number, poolName)
-	cephBlockPool.Status.PoolID = poolDetails.Number
-}


Test patch:
diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml
index 42a7d1207..ad5e75125 100644
--- a/.github/workflows/canary-integration-test.yml
+++ b/.github/workflows/canary-integration-test.yml
@@ -70,21 +70,6 @@ jobs:
           mgr_raw=$(kubectl -n rook-ceph exec $toolbox -- ceph mgr dump -f json|jq --raw-output .active_addr)
           timeout 60 sh -c "until kubectl -n rook-ceph exec $toolbox -- curl --silent --show-error ${mgr_raw%%:*}:9283; do echo 'waiting for mgr prometheus exporter to be ready' && sleep 1; done"
 
-      - name: test osd.0 auth recovery from keyring file
-        run: |
-          toolbox=$(kubectl get pod -l app=rook-ceph-tools -n rook-ceph -o jsonpath='{.items[*].metadata.name}')
-          osd_id=0
-          osd_pod=$(kubectl get pod -l app=rook-ceph-osd,osd=$osd_id -n rook-ceph -o jsonpath='{.items[*].metadata.name}')
-          if [ $osd_pod ]; then
-            timeout 15 sh -c "until kubectl -n rook-ceph exec $toolbox -- ceph auth del osd.$osd_id ; do sleep 1 && echo 'waiting for osd auth to be deleted'; done";
-            kubectl -n rook-ceph delete pod $osd_pod;
-            timeout 60 sh -c "until kubectl -n rook-ceph exec $toolbox -- ceph auth get osd.$osd_id ; do sleep 1 && echo 'waiting for osd auth to be recovered'; done";
-            osd_pod=$(kubectl get pod -l app=rook-ceph-osd,osd=$osd_id -n rook-ceph -o jsonpath='{.items[*].metadata.name}');
-            kubectl -n rook-ceph wait --for=condition=Ready pod/$osd_pod --timeout=120s;
-          else
-            echo "osd $osd_id not found, skipping test";
-          fi
-
       - name: test external script create-external-cluster-resources.py
         run: |
           toolbox=$(kubectl get pod -l app=rook-ceph-tools -n rook-ceph -o jsonpath='{.items[*].metadata.name}')
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index d9753c4f4..704862473 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -46,7 +46,7 @@ jobs:
           go-version: "1.22"
 
       - name: Setup jq
-        uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1
+        uses: dcarbone/install-jq-action@8867ddb4788346d7c22b72ea2e2ffe4d514c7bcb # v2.1.0
         with:
           version: "${{ inputs.version }}"
 
diff --git a/pkg/daemon/ceph/client/mirror_health_test.go b/pkg/daemon/ceph/client/mirror_health_test.go
deleted file mode 100644
index 429517439..000000000
--- a/pkg/daemon/ceph/client/mirror_health_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package client
-
-import (
-	"testing"
-
-	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestToCustomResourceStatus(t *testing.T) {
-	mirroringStatus := &cephv1.MirroringStatusSummarySpec{}
-	mirroringStatus.Health = "HEALTH_OK"
-	mirroringInfo := &cephv1.MirroringInfo{
-		Mode:     "pool",
-		SiteName: "rook-ceph-emea",
-		Peers: []cephv1.PeersSpec{
-			{UUID: "82656994-3314-4996-ac4c-263c2c9fd081"},
-		},
-	}
-
-	// Test 1: Empty so it's disabled
-	{
-		newMirroringStatus, newMirroringInfo, _ := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, []cephv1.SnapshotSchedulesSpec{}, "")
-		assert.NotEmpty(t, newMirroringStatus.MirroringStatus)
-		assert.Equal(t, "HEALTH_OK", newMirroringStatus.MirroringStatus.Summary.Health)
-		assert.Equal(t, "pool", newMirroringInfo.Mode)
-	}
-
-	// Test 2: snap sched
-	{
-		snapSchedStatus := []cephv1.SnapshotSchedulesSpec{
-			{
-				Pool:  "my-pool",
-				Image: "pool/image",
-			},
-		}
-		newMirroringStatus, newMirroringInfo, newSnapshotScheduleStatus := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, snapSchedStatus, "")
-		assert.NotEmpty(t, newMirroringStatus.MirroringStatus)
-		assert.Equal(t, "HEALTH_OK", newMirroringStatus.MirroringStatus.Summary.Health)
-		assert.NotEmpty(t, newMirroringInfo.Mode, "pool")
-		assert.NotEmpty(t, newSnapshotScheduleStatus)
-	}
-}
diff --git a/pkg/operator/ceph/cluster/mon/health_test.go b/pkg/operator/ceph/cluster/mon/health_test.go
index 90a778dbc..9ae4cbe3d 100644
--- a/pkg/operator/ceph/cluster/mon/health_test.go
+++ b/pkg/operator/ceph/cluster/mon/health_test.go
@@ -251,6 +251,30 @@ func TestTrackMonsOutOfQuorum(t *testing.T) {
 	assert.Equal(t, "", cm.Data[opcontroller.OutOfQuorumKey])
 }
 
+func TestSkipMonFailover(t *testing.T) {
+	c := New(context.TODO(), &clusterd.Context{}, "ns", cephv1.ClusterSpec{}, nil)
+	c.ClusterInfo = clienttest.CreateTestClusterInfo(1)
+	monName := "arb"
+
+	t.Run("don't skip failover for non-stretch", func(t *testing.T) {
+		assert.NoError(t, c.allowFailover(monName))
+	})
+
+	t.Run("don't skip failover for non-arbiter", func(t *testing.T) {
+		c.spec.Mon.Count = 5
+		c.spec.Mon.StretchCluster = &cephv1.StretchClusterSpec{
+			Zones: []cephv1.MonZoneSpec{
+				{Name: "a"},
+				{Name: "b"},
+				{Name: "c", Arbiter: true},
+			},
+		}
+
+		assert.NoError(t, c.allowFailover(monName))
+	})
+
+}
+
 func TestEvictMonOnSameNode(t *testing.T) {
 	ctx := context.TODO()
 	clientset := test.New(t, 1)
diff --git a/pkg/operator/ceph/csi/ceph_connection_test.go b/pkg/operator/ceph/csi/ceph_connection_test.go
index b3e241a63..c2f6f4396 100644
--- a/pkg/operator/ceph/csi/ceph_connection_test.go
+++ b/pkg/operator/ceph/csi/ceph_connection_test.go
@@ -24,7 +24,6 @@ import (
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 	"github.com/rook/rook/pkg/client/clientset/versioned/scheme"
 	clienttest "github.com/rook/rook/pkg/daemon/ceph/client/test"
-	"github.com/rook/rook/pkg/operator/k8sutil"
 	"github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -38,7 +37,6 @@ func TestCreateUpdateCephConnection(t *testing.T) {
 	c.Namespace = ns
 	c.SetName("testcluster")
 	c.NamespacedName()
-	t.Setenv(k8sutil.PodNamespaceEnvVar, ns)
 
 	cluster := &cephv1.CephCluster{
 		ObjectMeta: metav1.ObjectMeta{
diff --git a/pkg/operator/ceph/csi/config_test.go b/pkg/operator/ceph/csi/config_test.go
index 8ac0c45c9..089d0ae5a 100644
--- a/pkg/operator/ceph/csi/config_test.go
+++ b/pkg/operator/ceph/csi/config_test.go
@@ -25,7 +25,6 @@ import (
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 	"github.com/rook/rook/pkg/client/clientset/versioned/scheme"
 	clienttest "github.com/rook/rook/pkg/daemon/ceph/client/test"
-	"github.com/rook/rook/pkg/operator/k8sutil"
 	"github.com/stretchr/testify/assert"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
@@ -49,9 +48,6 @@ func TestCreateUpdateClientProfile(t *testing.T) {
 	c.Namespace = ns
 	c.SetName("testcluster")
 	c.NamespacedName()
-	c.SetName(c.Namespace)
-	t.Setenv(k8sutil.PodNamespaceEnvVar, ns)
-
 	clusterName := "testClusterName"
 	cephBlockPoolRadosNamespacedName := types.NamespacedName{Namespace: ns, Name: "cephBlockPoolRadosNames"}
 	cephSubVolGrpNamespacedName := types.NamespacedName{Namespace: ns, Name: "cephSubVolumeGroupNames"}
diff --git a/pkg/operator/ceph/csi/operator_config_test.go b/pkg/operator/ceph/csi/operator_config_test.go
index a260a628f..33f10c2a5 100644
--- a/pkg/operator/ceph/csi/operator_config_test.go
+++ b/pkg/operator/ceph/csi/operator_config_test.go
@@ -88,4 +88,5 @@ func TestReconcileCSI_createOrUpdateOperatorConfig(t *testing.T) {
 	err = cl.Get(context.TODO(), types.NamespacedName{Name: opConfigCRName, Namespace: r.opConfig.OperatorNamespace}, opConfig)
 	assert.NoError(t, err)
 	assert.Equal(t, *opConfig.Spec.DriverSpecDefaults.EnableMetadata, false)
+	assert.Equal(t, opConfig.Spec.DriverSpecDefaults.Encryption.ConfigMapRef, v1.LocalObjectReference{Name: "rook-ceph-csi-kms-config"})
 }
diff --git a/pkg/operator/ceph/object/objectstore_test.go b/pkg/operator/ceph/object/objectstore_test.go
index f384d6c70..ee5aa4c83 100644
--- a/pkg/operator/ceph/object/objectstore_test.go
+++ b/pkg/operator/ceph/object/objectstore_test.go
@@ -152,7 +152,7 @@ const (
   "notif_pool": "%[1]s:store-a.log.notif"
 }`
 
-	objectZonegroupJson = `{
+	objectZonegroupJsonTempl = `{
     "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a",
     "name": "store-a",
     "api_name": "test",
@@ -174,14 +174,14 @@ const (
     ],
     "placement_targets": [
         {
-            "name": "default-placement",
+            "name": "%[1]s",
             "tags": [],
             "storage_classes": [
                 "STANDARD"
             ]
         }
     ],
-    "default_placement": "default-placement",
+    "default_placement": "%[1]s",
     "realm_id": "29e28253-be54-4581-90dd-206020d2fcdd",
     "sync_policy": {
         "groups": []
@@ -229,6 +229,7 @@ func TestReconcileRealm(t *testing.T) {
 
 func TestConfigureStoreWithSharedPools(t *testing.T) {
 	sharedMetaPoolAlreadySet, sharedDataPoolAlreadySet := "", ""
+	defaultPlacement := defaultPlacementCephConfigName
 	zoneGetCalled := false
 	zoneSetCalled := false
 	zoneGroupGetCalled := false
@@ -273,7 +274,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) {
 		} else if args[0] == "zonegroup" {
 			if args[1] == "get" {
 				zoneGroupGetCalled = true
-				return objectZonegroupJson, nil
+				return fmt.Sprintf(objectZonegroupJsonTempl, defaultPlacement), nil
 			} else if args[1] == "set" {
 				zoneGroupSetCalled = true
 				for _, arg := range args {
@@ -287,7 +288,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) {
 					}
 					return string(inBytes), nil
 				}
-				return objectZonegroupJson, nil
+				return fmt.Sprintf(objectZonegroupJsonTempl, defaultPlacement), nil
 			}
 		}
 		return "", errors.Errorf("unexpected ceph command %q", args)
@@ -330,7 +331,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) {
 		assert.True(t, zoneGroupGetCalled)
 		assert.False(t, zoneGroupSetCalled) // zone group is set only if extra pool placements specified
 	})
-	t.Run("configure with new default placement", func(t *testing.T) {
+	t.Run("configure with default placement", func(t *testing.T) {
 		sharedPools := cephv1.ObjectSharedPoolsSpec{
 			PoolPlacements: []cephv1.PoolPlacementSpec{
 				{
@@ -341,22 +342,22 @@ func TestConfigureStoreWithSharedPools(t *testing.T) {
 				},
 			},
 		}
+		defaultPlacement = "default"
 		err := ConfigureSharedPoolsForZone(context, sharedPools)
 		assert.NoError(t, err)
 		assert.True(t, zoneGetCalled)
 		assert.True(t, zoneSetCalled)
 		assert.False(t, placementModifyCalled) // mock returns applied namespases, no workaround needed
 		assert.True(t, zoneGroupGetCalled)
-		assert.True(t, zoneGroupSetCalled)
+		assert.False(t, zoneGroupSetCalled) // zone group is set only if extra pool placements specified
 	})
 	t.Run("data pool already set", func(t *testing.T) {
-		// reset
-		zoneGroupSetCalled = false
 		// Simulate that the data pool has already been set and the zone update can be skipped
 		sharedPools := cephv1.ObjectSharedPoolsSpec{
 			MetadataPoolName: "test-meta",
 			DataPoolName:     "test-data",
 		}
+		defaultPlacement = defaultPlacementCephConfigName
 		sharedMetaPoolAlreadySet, sharedDataPoolAlreadySet = "test-meta", "test-data"
 		zoneGetCalled = false
 		zoneSetCalled = false
diff --git a/pkg/operator/ceph/object/shared_pools_test.go b/pkg/operator/ceph/object/shared_pools_test.go
index 81f26b799..f40306141 100644
--- a/pkg/operator/ceph/object/shared_pools_test.go
+++ b/pkg/operator/ceph/object/shared_pools_test.go
@@ -630,7 +630,7 @@ func Test_toZonePlacementPools(t *testing.T) {
 			},
 		},
 		{
-			name: "shared pools not removed if default placement set",
+			name: "default placement overrides shared pools",
 			args: args{
 				spec: cephv1.ObjectSharedPoolsSpec{
 					MetadataPoolName:                   "meta",
@@ -655,19 +655,6 @@ func Test_toZonePlacementPools(t *testing.T) {
 				ns: "rgw-instance",
 			},
 			want: map[string]ZonePlacementPool{
-				defaultPlacementCephConfigName: {
-					Key: defaultPlacementCephConfigName,
-					Val: ZonePlacementPoolVal{
-						DataExtraPool: "meta:rgw-instance.buckets.non-ec",
-						IndexPool:     "meta:rgw-instance.buckets.index",
-						StorageClasses: map[string]ZonePlacementStorageClass{
-							"STANDARD": {
-								DataPool: "data:rgw-instance.buckets.data",
-							},
-						},
-						InlineData: true,
-					},
-				},
 				"some_name": {
 					Key: "some_name",
 					Val: ZonePlacementPoolVal{
@@ -1457,156 +1444,6 @@ func Test_adjustZonePlacementPools(t *testing.T) {
             }
         }
     ]
-}`,
-			wantChanged: true,
-			wantErr:     false,
-		},
-		{
-			name: "sharedPools placement not removed if default set",
-			args: args{
-				beforeJSON: `{
-    "id": "f539c2c0-e1ed-4c42-9294-41742352eeae",
-    "name": "test",
-    "placement_pools": [
-        {
-            "key": "default-placement",
-            "val": {
-                "index_pool": "test.rgw.buckets.index",
-                "storage_classes": {
-                    "STANDARD": {
-                        "data_pool": "test.rgw.buckets.data"
-                    }
-                },
-                "data_extra_pool": "test.rgw.buckets.non-ec",
-                "index_type": 5,
-                "inline_data": true
-            }
-        }
-    ]
-}`,
-				spec: cephv1.ObjectSharedPoolsSpec{
-					MetadataPoolName:                   "meta-pool",
-					DataPoolName:                       "data-pool",
-					PreserveRadosNamespaceDataOnDelete: false,
-					PoolPlacements: []cephv1.PoolPlacementSpec{
-						{
-							Name:              "slow",
-							Default:           true,
-							MetadataPoolName:  "slow-meta",
-							DataPoolName:      "slow-data",
-							DataNonECPoolName: "slow-non-ec",
-							StorageClasses:    []cephv1.PlacementStorageClassSpec{},
-						},
-					},
-				},
-			},
-			wantJSON: `{
-    "id": "f539c2c0-e1ed-4c42-9294-41742352eeae",
-    "name": "test",
-    "placement_pools": [
-        {
-            "key": "default-placement",
-            "val": {
-                "index_pool": "meta-pool:test.buckets.index",
-                "storage_classes": {
-                    "STANDARD": {
-                        "data_pool": "data-pool:test.buckets.data"
-                    }
-                },
-                "data_extra_pool": "meta-pool:test.buckets.non-ec",
-                "index_type": 5,
-                "inline_data": true
-            }
-        },
-        {
-            "key": "slow",
-            "val": {
-                "index_pool": "slow-meta:test.slow.index",
-                "storage_classes": {
-                    "STANDARD": {
-                        "data_pool": "slow-data:test.slow.data"
-                    }
-                },
-                "data_extra_pool": "slow-non-ec:test.slow.data.non-ec",
-                "inline_data": true
-            }
-        }
-    ]
-}`,
-			wantChanged: true,
-			wantErr:     false,
-		},
-		{
-			name: "if sharedPools not set and default placement is set, then default placements values are copied to 'default-placement'",
-			args: args{
-				beforeJSON: `{
-    "id": "f539c2c0-e1ed-4c42-9294-41742352eeae",
-    "name": "test",
-    "placement_pools": [
-        {
-            "key": "default-placement",
-            "val": {
-                "index_pool": "test.rgw.buckets.index",
-                "storage_classes": {
-                    "STANDARD": {
-                        "data_pool": "test.rgw.buckets.data"
-                    }
-                },
-                "data_extra_pool": "test.rgw.buckets.non-ec",
-                "index_type": 5,
-                "inline_data": true
-            }
-        }
-    ]
-}`,
-				spec: cephv1.ObjectSharedPoolsSpec{
-					MetadataPoolName:                   "",
-					DataPoolName:                       "",
-					PreserveRadosNamespaceDataOnDelete: false,
-					PoolPlacements: []cephv1.PoolPlacementSpec{
-						{
-							Name:              "slow",
-							Default:           true,
-							MetadataPoolName:  "slow-meta",
-							DataPoolName:      "slow-data",
-							DataNonECPoolName: "slow-non-ec",
-							StorageClasses:    []cephv1.PlacementStorageClassSpec{},
-						},
-					},
-				},
-			},
-			wantJSON: `{
-    "id": "f539c2c0-e1ed-4c42-9294-41742352eeae",
-    "name": "test",
-    "placement_pools": [
-        {
-            "key": "default-placement",
-            "val": {
-                "index_pool": "slow-meta:test.slow.index",
-                "storage_classes": {
-                    "STANDARD": {
-                        "data_pool": "slow-data:test.slow.data"
-                    }
-                },
-                "data_extra_pool": "slow-non-ec:test.slow.data.non-ec",
-                "index_type": 5,
-                "inline_data": true
-            }
-        },
-        {
-            "key": "slow",
-            "val": {
-                "index_pool": "slow-meta:test.slow.index",
-                "storage_classes": {
-                    "STANDARD": {
-                        "data_pool": "slow-data:test.slow.data"
-                    }
-                },
-                "data_extra_pool": "slow-non-ec:test.slow.data.non-ec",
-                "inline_data": true
-            }
-        }
-    ]
 }`,
 			wantChanged: true,
 			wantErr:     false,
diff --git a/pkg/operator/ceph/pool/controller_test.go b/pkg/operator/ceph/pool/controller_test.go
index 7804f277d..d444e92e4 100644
--- a/pkg/operator/ceph/pool/controller_test.go
+++ b/pkg/operator/ceph/pool/controller_test.go
@@ -635,14 +635,12 @@ func TestConfigureRBDStats(t *testing.T) {
 			logger.Infof("Command: %s %v", command, args)
 			if args[0] == "config" && args[2] == "mgr" && args[3] == "mgr/prometheus/rbd_stats_pools" {
 				if args[1] == "set" {
-					mockedPools = args[4]
 					return "", nil
 				}
 				if args[1] == "get" {
 					return mockedPools, nil
 				}
 				if args[1] == "rm" {
-					mockedPools = ""
 					return "", nil
 				}
 			}
@@ -703,6 +701,7 @@ func TestConfigureRBDStats(t *testing.T) {
 	monStore := config.GetMonStore(context, clusterInfo)
 	e := monStore.Set("mgr", "mgr/prometheus/rbd_stats_pools", "pool1,pool2")
 	assert.Nil(t, e)
+	mockedPools = "my-pool-with-rbd-stats,pool1,pool2"
 	e = configureRBDStats(context, clusterInfo, "")
 	assert.Nil(t, e)
 
@@ -711,6 +710,7 @@ func TestConfigureRBDStats(t *testing.T) {
 	assert.Equal(t, "my-pool-with-rbd-stats,pool1,pool2", rbdStatsPools)
 
 	// Case 6: Deleted CephBlockPool should be excluded from config
+	mockedPools = "pool1,pool2"
 	err = configureRBDStats(context, clusterInfo, "my-pool-with-rbd-stats")
 	assert.Nil(t, err)
 
@@ -726,7 +726,7 @@ func TestConfigureRBDStats(t *testing.T) {
 
 	rbdStatsPools, err = monStore.Get("mgr", "mgr/prometheus/rbd_stats_pools")
 	assert.Nil(t, err)
-	assert.Equal(t, "my-pool-with-rbd-stats,pool1,pool2", rbdStatsPools)
+	assert.Equal(t, "pool1,pool2", rbdStatsPools)
 
 	// Case 8: Two CephBlockPools with EnableRBDStats:false & EnableRBDStats:true.
 	// SetConfig returns an error
@@ -738,111 +738,5 @@ func TestConfigureRBDStats(t *testing.T) {
 	}
 	err = configureRBDStats(context, clusterInfo, "")
 	assert.NotNil(t, err)
-}
-
-func TestGenerateStatsPoolList(t *testing.T) {
-	tests := []struct {
-		name               string
-		existingStatsPools []string
-		rookStatsPools     []string
-		removePools        []string
-		expectedOutput     string
-	}{
-		// Basic cases
-		{
-			name:               "Empty lists",
-			existingStatsPools: []string{},
-			rookStatsPools:     []string{},
-			removePools:        []string{},
-			expectedOutput:     "",
-		},
-		{
-			name:               "Single-item lists, no removal",
-			existingStatsPools: []string{"p1"},
-			rookStatsPools:     []string{"p2"},
-			removePools:        []string{},
-			expectedOutput:     "p1,p2",
-		},
-		// Overlap and duplicates
-		{
-			name:               "Overlapping pools, some to remove",
-			existingStatsPools: []string{"p1", "p2", "p3"},
-			rookStatsPools:     []string{"p2", "p4", "p5"},
-			removePools:        []string{"p1", "p5"},
-			expectedOutput:     "p2,p3,p4",
-		},
-		{
-			name:               "Non-overlapping lists",
-			existingStatsPools: []string{"p1", "p2"},
-			rookStatsPools:     []string{"p3", "p4"},
-			removePools:        []string{},
-			expectedOutput:     "p1,p2,p3,p4",
-		},
-		// All pools removed
-		{
-			name:               "All pools removed",
-			existingStatsPools: []string{"p1", "p2"},
-			rookStatsPools:     []string{"p2", "p3"},
-			removePools:        []string{"p1", "p2", "p3"},
-			expectedOutput:     "",
-		},
-		// Mixed scenarios with edge cases
-		{
-			name:               "Only removed pools",
-			existingStatsPools: []string{"p1", "p2"},
-			rookStatsPools:     []string{"p2", "p3"},
-			removePools:        []string{"p1", "p2", "p3", "p4"},
-			expectedOutput:     "",
-		},
-		{
-			name:               "Duplicate pools across lists",
-			existingStatsPools: []string{"p1", "p2", "p1"},
-			rookStatsPools:     []string{"p2", "p3", "p3"},
-			removePools:        []string{},
-			expectedOutput:     "p1,p2,p3",
-		},
-		{
-			name:               "Empty string in pools",
-			existingStatsPools: []string{"p1", ""},
-			rookStatsPools:     []string{"p2", ""},
-			removePools:        []string{""},
-			expectedOutput:     "p1,p2",
-		},
-		{
-			name:               "Empty string in remove pools",
-			existingStatsPools: []string{"p1", "p2"},
-			rookStatsPools:     []string{"p3", "p4"},
-			removePools:        []string{""},
-			expectedOutput:     "p1,p2,p3,p4",
-		},
-		{
-			name:               "All lists empty strings",
-			existingStatsPools: []string{""},
-			rookStatsPools:     []string{""},
-			removePools:        []string{""},
-			expectedOutput:     "",
-		},
-		// Larger cases
-		{
-			name:               "Large unique pool list",
-			existingStatsPools: []string{"p1", "p2", "p3", "p4"},
-			rookStatsPools:     []string{"p5", "p6", "p7", "p8"},
-			removePools:        []string{"p1", "p8"},
-			expectedOutput:     "p2,p3,p4,p5,p6,p7",
-		},
-		{
-			name:               "Large list with many duplicates",
-			existingStatsPools: []string{"p1", "p2", "p3", "p2", "p1"},
-			rookStatsPools:     []string{"p2", "p3", "p3", "p4", "p1"},
-			removePools:        []string{"p4"},
-			expectedOutput:     "p1,p2,p3",
-		},
-	}
 
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			result := generateStatsPoolList(tt.existingStatsPools, tt.rookStatsPools, tt.removePools)
-			assert.Equal(t, tt.expectedOutput, result)
-		})
-	}
 }
diff --git a/pkg/operator/ceph/pool/radosnamespace/controller_test.go b/pkg/operator/ceph/pool/radosnamespace/controller_test.go
index d940c3497..48971f46c 100644
--- a/pkg/operator/ceph/pool/radosnamespace/controller_test.go
+++ b/pkg/operator/ceph/pool/radosnamespace/controller_test.go
@@ -27,8 +27,7 @@ import (
 	"github.com/rook/rook/pkg/clusterd"
 	opcontroller "github.com/rook/rook/pkg/operator/ceph/controller"
 	"github.com/rook/rook/pkg/operator/ceph/csi"
-	"github.com/rook/rook/pkg/operator/ceph/version"
-	cephver "github.com/rook/rook/pkg/operator/ceph/version"
+
 	"github.com/rook/rook/pkg/operator/k8sutil"
 	testop "github.com/rook/rook/pkg/operator/test"
 	exectest "github.com/rook/rook/pkg/util/exec/test"
@@ -39,7 +38,6 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/client-go/kubernetes"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
@@ -122,14 +120,15 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		},
 		Spec: cephv1.ClusterSpec{
 			CephVersion: cephv1.CephVersionSpec{
-				Image:           "ceph/ceph:v14.2.9",
+				Image:           "ceph/ceph:v20.0.0",
 				ImagePullPolicy: v1.PullIfNotPresent,
 			},
 		},
 		Status: cephv1.ClusterStatus{
 			Phase: "",
 			CephVersion: &cephv1.ClusterVersion{
-				Version: "14.2.9-0",
+				Version: "20.0.0-0",
+				Image:   "ceph/ceph:v20.0.0",
 			},
 			CephStatus: &cephv1.CephStatus{
 				Health: "",
@@ -167,7 +166,7 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 			Phase: "",
 		},
 	}
-	cephBlockPool.Spec.StatusCheck.Mirror.Disabled = true
+
 	t.Run("error - ceph blockpool not ready", func(t *testing.T) {
 		res, err := r.Reconcile(ctx, req)
 		assert.NoError(t, err)
@@ -218,15 +217,11 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &version.Reef, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		// Enable CSI
@@ -275,9 +270,6 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 			opManagerContext: ctx,
 			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &version.Reef, nil
-		}
 
 		// Enable CSI
 		csi.EnableRBD = true
@@ -338,15 +330,11 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &version.Reef, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		res, err := r.Reconcile(ctx, req)
@@ -387,23 +375,20 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &version.Reef, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		res, err := r.Reconcile(ctx, req)
-		assert.Error(t, err)
+		assert.NoError(t, err)
 		assert.False(t, res.Requeue)
 	})
 
 	t.Run("test rbd rados namespace mirroring enabled and blockpool mirroring is also enabled and non empty rados namespace but less ceph version", func(t *testing.T) {
+		cephCluster.Status.CephVersion.Version = "14.2.9"
 		remoteNamespace := "test-1"
 		cephBlockPoolRadosNamespace.Spec.Mirroring = &cephv1.RadosNamespaceMirroring{
 			RemoteNamespace: &remoteNamespace,
@@ -439,20 +424,17 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &version.Reef, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		res, err := r.Reconcile(ctx, req)
 		assert.Error(t, err)
 		assert.False(t, res.Requeue)
+		cephCluster.Status.CephVersion.Version = "20.0.0"
 	})
 
 	t.Run("test rbd rados namespace mirroring enabled and blockpool mirroring is also enabled and non empty rados namespace and correct ceph version", func(t *testing.T) {
@@ -491,15 +473,11 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &cephver.CephVersion{Major: 20, Minor: 0, Extra: 0}, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		res, err := r.Reconcile(ctx, req)
@@ -546,15 +524,11 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &cephver.CephVersion{Major: 20, Minor: 0, Extra: 0}, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		res, err := r.Reconcile(ctx, req)
@@ -605,15 +579,11 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) {
 		s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{})
 		// Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client.
 		r = &ReconcileCephBlockPoolRadosNamespace{
-			client:                 cl,
-			scheme:                 s,
-			context:                c,
-			opManagerContext:       context.TODO(),
-			opConfig:               opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
-			radosNamespaceContexts: make(map[string]*mirrorHealth),
-		}
-		detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) {
-			return &version.Reef, nil
+			client:           cl,
+			scheme:           s,
+			context:          c,
+			opManagerContext: context.TODO(),
+			opConfig:         opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"},
 		}
 
 		res, err := r.Reconcile(ctx, req)
diff --git a/pkg/operator/ceph/pool/status_test.go b/pkg/operator/ceph/pool/status_test.go
index cdcba99e4..e34b58282 100644
--- a/pkg/operator/ceph/pool/status_test.go
+++ b/pkg/operator/ceph/pool/status_test.go
@@ -25,6 +25,41 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func TestToCustomResourceStatus(t *testing.T) {
+	mirroringStatus := &cephv1.PoolMirroringStatusSummarySpec{}
+	mirroringStatus.Health = "HEALTH_OK"
+	mirroringInfo := &cephv1.PoolMirroringInfo{
+		Mode:     "pool",
+		SiteName: "rook-ceph-emea",
+		Peers: []cephv1.PeersSpec{
+			{UUID: "82656994-3314-4996-ac4c-263c2c9fd081"},
+		},
+	}
+
+	// Test 1: Empty so it's disabled
+	{
+		newMirroringStatus, newMirroringInfo, _ := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, []cephv1.SnapshotSchedulesSpec{}, "")
+		assert.NotEmpty(t, newMirroringStatus.Summary)
+		assert.Equal(t, "HEALTH_OK", newMirroringStatus.Summary.Health)
+		assert.Equal(t, "pool", newMirroringInfo.Mode)
+	}
+
+	// Test 2: snap sched
+	{
+		snapSchedStatus := []cephv1.SnapshotSchedulesSpec{
+			{
+				Pool:  "my-pool",
+				Image: "pool/image",
+			},
+		}
+		newMirroringStatus, newMirroringInfo, newSnapshotScheduleStatus := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, snapSchedStatus, "")
+		assert.NotEmpty(t, newMirroringStatus.Summary)
+		assert.Equal(t, "HEALTH_OK", newMirroringStatus.Summary.Health)
+		assert.NotEmpty(t, newMirroringInfo.Mode, "pool")
+		assert.NotEmpty(t, newSnapshotScheduleStatus)
+	}
+}
+
 func TestUpdateStatusInfo(t *testing.T) {
 
 	cephBlockPoolReplicated := &cephv1.CephBlockPool{