Skip to content

Implement the changes for ClientProfileReplication#522

Open
rewantsoni wants to merge 6 commits into
ceph:mainfrom
rewantsoni:api-replication
Open

Implement the changes for ClientProfileReplication#522
rewantsoni wants to merge 6 commits into
ceph:mainfrom
rewantsoni:api-replication

Conversation

@rewantsoni

@rewantsoni rewantsoni commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Describe what this PR does

Implement the changes for clientProfileReplication. The doc for the design was added in the PR #489

Is there anything that requires special attention

Is the change backward compatible?
Yes, the clientProfileMapping works along with clientProfileReplication.

Are there concerns around backward compatibility?
No.

Provide any external context for the change, if any.

Checklist:

  • Commit Message Formatting: Commit titles and messages follow guidelines in the developer guide.
  • Reviewed the developer guide on Submitting a Pull Request
  • Pending release notes updated with breaking and/or notable changes for the next major release.
  • Documentation has been updated, if necessary.
  • Unit tests have been added, if necessary.
  • Integration tests have been added, if necessary.

@rewantsoni rewantsoni changed the title Api replication Implement the changes for ClientProfileReplication Jun 25, 2026
@rewantsoni
rewantsoni force-pushed the api-replication branch 2 times, most recently from 11f55b2 to 13d5e15 Compare June 29, 2026 14:32
@rewantsoni

Copy link
Copy Markdown
Contributor Author

Testing:

rewantsoni@Rewants-MacBook-Pro ~/work/odf/ceph-csi-operator api-replication* ❯ k get clientprofile -oyaml
apiVersion: v1
items:
- apiVersion: csi.ceph.io/v1
  kind: ClientProfile
  metadata:
    creationTimestamp: "2026-06-30T06:54:32Z"
    finalizers:
    - csi.ceph.com/cleanup
    generation: 1
    name: clientprofile-sample
    namespace: ceph-csi-operator-system
    resourceVersion: "14150"
    uid: cdbb0f39-8816-456f-90fc-08b888b3848e
  spec:
    cephConnectionRef:
      name: cephconnection-sample
    rbd:
      radosNamespace: dummy
  status:
    message: ClientProfile reconciled successfully
    phase: Ready
kind: List
metadata:
  resourceVersion: ""
---
rewantsoni@Rewants-MacBook-Pro ~/work/odf/ceph-csi-operator api-replication* ❯ k get clientprofilereplication -oyaml
apiVersion: v1
items:
- apiVersion: csi.ceph.io/v1
  kind: ClientProfileReplication
  metadata:
    creationTimestamp: "2026-06-30T07:03:07Z"
    generation: 1
    name: clientprofilereplication-sample
    namespace: ceph-csi-operator-system
    resourceVersion: "16131"
    uid: 335bf9d2-86ec-4877-813d-96f690d2cd3e
  spec:
    localClientProfile: clientprofile-sample
    rbd:
      poolMapping:
      - name: pool1
        remoteID: "1"
      - name: pool2
        remoteID: "2"
    remoteClientProfile: clientprofile-sample-remote
  status:
    message: accepted
    phase: Ready
kind: List
metadata:
  resourceVersion: ""
---
rewantsoni@Rewants-MacBook-Pro ~/work/odf/ceph-csi-operator api-replication* ❯ k get cm ceph-csi-config -oyaml | yq '.data."config.json"' | jq
[
  {
    "clusterID": "clientprofile-sample",
    "monitors": [
      "10.0.43.14:3300"
    ],
    "cephFS": {
      "kernelMountOptions": "",
      "fuseMountOptions": "",
      "controllerPublishSecretRef": {}
    },
    "rbd": {
      "radosNamespace": "dummy",
      "controllerPublishSecretRef": {},
      "nodePublishSecretRef": {}
    },
    "nfs": {},
    "nvmeof": {
      "controllerPublishSecretRef": {}
    },
    "readAffinity": {},
    "replicationDestination": {
      "remoteClusterID": "clientprofile-sample-remote",
      "rbd": {
        "remotePoolMapping": {
          "pool1": {
            "poolID": "1"
          },
          "pool2": {
            "poolID": "2"
          }
        }
      }
    }
  }
]


**Multiple ClientProfileReplication**

apiVersion: v1
items:
- apiVersion: csi.ceph.io/v1
  kind: ClientProfileReplication
  metadata:
    creationTimestamp: "2026-06-30T07:03:07Z"
    generation: 1
    name: clientprofilereplication-sample
    namespace: ceph-csi-operator-system
    resourceVersion: "16131"
    uid: 335bf9d2-86ec-4877-813d-96f690d2cd3e
  spec:
    localClientProfile: clientprofile-sample
    rbd:
      poolMapping:
      - name: pool1
        remoteID: "1"
      - name: pool2
        remoteID: "2"
    remoteClientProfile: clientprofile-sample-remote
  status:
    message: accepted
    phase: Ready
- apiVersion: csi.ceph.io/v1
  kind: ClientProfileReplication
  metadata:
    creationTimestamp: "2026-06-30T07:07:53Z"
    generation: 1
    name: clientprofilereplication-sample-2
    namespace: ceph-csi-operator-system
    resourceVersion: "17703"
    uid: f6b9b163-796a-4691-96f4-e6b0836af4e7
  spec:
    localClientProfile: clientprofile-sample
    remoteClientProfile: clientprofile-sample-remote
  status:
    message: 'rejected: another ClientProfileReplication ''clientprofilereplication-sample''
      is already active for localClientProfile ''clientprofile-sample'''
    phase: Rejected
kind: List
metadata:
  resourceVersion: ""

@rewantsoni
rewantsoni marked this pull request as ready for review June 30, 2026 07:11

@Madhu-1 Madhu-1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the documentation and helm charts for this new CR creation

@@ -0,0 +1,108 @@
/*
Copyright 2024.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2026

app.kubernetes.io/managed-by: kustomize
name: clientprofilereplication-sample
spec:
# TODO(user): Add fields here

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an example here

RBD *remoteRBDDetails `json:"rbd,omitempty"`
}

type remoteRBDDetails struct {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RBD ro Rbd

@@ -0,0 +1,219 @@
/*
Copyright 2024.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2026

// Step 3: Conflict detection - oldest CR wins
// Sort by creation timestamp (oldest first)
sort.Slice(cprList.Items, func(i, j int) bool {
return cprList.Items[i].CreationTimestamp.Before(&cprList.Items[j].CreationTimestamp)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creation timestamp will be in seconds? can we also consider the name of the CR as tie breaker to get the same sorted slice always

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be in timestamp format, so it will capture seconds as well, yes I will add the CR name as well as a tie breaker

r.clientProfile.Status.Phase = csiv1.ClientProfilePhaseFailed
r.clientProfile.Status.Message = fmt.Sprintf("failed to remove finalizer: %v", err)
return err
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont we need return nil here to avoid status update to Ready for cleanup?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The status will be updated irrespective what the reconcile returns

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After removing the finalizer we should not be setting the status as Ready

}
}

if len(readyCRs) > 1 {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this need to be moved below cleanup?

Comment thread internal/controller/clientprofilereplication_controller.go
// Step 4: Update status based on whether this CR is the winner
if r.clientProfileReplication.Name == winner.Name && r.clientProfileReplication.Namespace == winner.Namespace {
r.log.Info("this CR is the winner, marking as Ready")
r.clientProfileReplication.Status.Phase = csiv1.ClientProfileReplicationPhaseReady

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont we need finalizers on the CR to ensure we dont leave any stale values in the configmap?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the clientProfileReplication is deleted, it will also trigger the clientProfile controller so it should eventually update the configmap to remove the value

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about the controller restart, if it works between restarts we are good

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The record is constructed each time and is overwritten. So if a clientProfileReplication is deleted when controller is down, as soon as controller is brought up again it will be removed from the configmap


reconcileErr := r.reconcilePhases()

statusErr := r.Status().Update(r.ctx, &r.clientProfile)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in line 196, can we add finalizer only when r.cleanup is not set

@rewantsoni
rewantsoni force-pushed the api-replication branch 2 times, most recently from 74c24dd to a2b3e90 Compare July 8, 2026 08:46
@rewantsoni
rewantsoni requested a review from Madhu-1 July 9, 2026 16:27
this commit does the following:
1. add the api changes required for clientProfileReplication and
   ClientProfile
2. Scaffolding the api/controller
3. add the generated changes

Signed-off-by: Rewant Soni <resoni@redhat.com>
implement the clientProfileReplication controller

Signed-off-by: Rewant Soni <resoni@redhat.com>
add clientProfile controller implementation to add the
replicationDestinationInfo to the ceph csi configmap

Signed-off-by: Rewant Soni <resoni@redhat.com>
Signed-off-by: Rewant Soni <resoni@redhat.com>
Signed-off-by: Rewant Soni <resoni@redhat.com>
Signed-off-by: Rewant Soni <resoni@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants