Skip to content

rbd: implement GetReplicationDestinationInfo for volumes and groups - #6366

Open
rewantsoni wants to merge 7 commits into
ceph:develfrom
rewantsoni:implement-replication
Open

rbd: implement GetReplicationDestinationInfo for volumes and groups#6366
rewantsoni wants to merge 7 commits into
ceph:develfrom
rewantsoni:implement-replication

Conversation

@rewantsoni

@rewantsoni rewantsoni commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Describe what this PR does

Implement the change for the GetReplicationDestinationInfo RPC as per the design proposal in #6316

Is there anything that requires special attention

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.

Show available bot commands

These commands are normally not required, but in case of issues, leave any of
the following bot commands in an otherwise empty comment in this PR:

  • /retest ci/centos/<job-name>: retest the <job-name> after unrelated
    failure (please report the failure too!)

@rewantsoni
rewantsoni force-pushed the implement-replication branch 5 times, most recently from cef70f8 to 6180c2c Compare July 1, 2026 08:02
@rewantsoni
rewantsoni marked this pull request as ready for review July 16, 2026 08:38
@rewantsoni

Copy link
Copy Markdown
Contributor Author

Testing:

configmap:
[
  {
    "clusterID": "9e95757b-963f-4011-a4dd-1848d1f799cb",
    "monitors": [
      "10.0.15.28:3300",
      "10.0.28.165:3300",
      "10.0.38.212:3300"
    ],
    "cephFS": {
      "subvolumeGroup": "client-1",
      "kernelMountOptions": "ms_mode=prefer-crc",
      "fuseMountOptions": "",
      "radosNamespace": "client-1",
      "controllerPublishSecretRef": {
        "name": "csi-cephfs-provisioner-9e95757b-963f-4011-a4dd-1848d1f799cb",
        "namespace": "openshift-storage"
      }
    },
    "rbd": {
      "radosNamespace": "client-1",
      "controllerPublishSecretRef": {
        "name": "csi-rbd-provisioner-9e95757b-963f-4011-a4dd-1848d1f799cb",
        "namespace": "openshift-storage"
      },
      "nodePublishSecretRef": {}
    },
    "nfs": {},
    "nvmeof": {
      "controllerPublishSecretRef": {}
    },
    "readAffinity": {
      "enabled": true,
      "crushLocationLabels": [
        "kubernetes.io/hostname",
        "topology.kubernetes.io/region",
        "topology.kubernetes.io/zone",
        "topology.rook.io/datacenter",
        "topology.rook.io/room",
        "topology.rook.io/pod",
        "topology.rook.io/pdu",
        "topology.rook.io/row",
        "topology.rook.io/rack",
        "topology.rook.io/chassis"
      ]
    },
    "replicationDestination": {
      "remoteClusterID": "1465416b-2258-4cc1-80ec-066a90272d5e",
      "rbd": {
        "remotePoolMapping": {
          "ocs-storagecluster-cephblockpool": {
            "poolID": "2"
          }
        }
      }
    }
  }
]

rewantsoni@Mac ~/work/scripts ❯ k get pv pvc-dfc0c3ff-65ff-4cc0-8c3e-d3211fe60f68 -oyaml | yq .spec.csi.volumeHandle
0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-7b993f10-5d0c-4b96-a377-d1b9b34af8a4

sh-5.1# /tmp/grpcurl -plaintext -unix -import-path /tmp/proto -proto replication.proto -d '{"replication_source":{"volume":{"volume_id":"0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-
7b993f10-5d0c-4b96-a377-d1b9b34af8a4"}},"secrets":{"userID":"csi-rbd-provisioner-ceph-user-g1-9e95757b-963f-4011-a4dd-1848d1f799cb","userKey":"AQBA0lRqQ29cMhAAvZd0vqWUc3nmt08U5P0vHA=="}}' /csi/csi-addo
ns.sock replication.Controller/GetReplicationDestinationInfo
{
  "replicationDestination": {
    "volume": {
      "volumeId": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-7b993f10-5d0c-4b96-a377-d1b9b34af8a4"
    }
  }
}

For Group


sh-5.1# /tmp/grpcurl -plaintext -unix -import-path /tmp/proto -proto replication.proto -d '{"replication_source":{"volumegroup":{"volume_group_id":"0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-000000
0000000002-eb55e868-e30b-443f-b7a5-a91316233c80"}},"secrets":{"userID":"csi-rbd-provisioner-ceph-user-g1-9e95757b-963f-4011-a4dd-1848d1f799cb","userKey":"AQBA0lRqQ29cMhAAvZd0vqWUc3nmt08U5P0vHA=="}}' /c
si/csi-addons.sock replication.Controller/GetReplicationDestinationInfo
{
  "replicationDestination": {
    "volumegroup": {
      "volumeGroupId": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-eb55e868-e30b-443f-b7a5-a91316233c80",
      "volumeIds": {
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-090f42f3-9ed9-4ee5-b7b2-8a0d97849efa": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-090f42f3-9ed9-4ee5-b7b2-
8a0d97849efa",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-0d3cff5c-5b14-4635-b68a-935e92eacbee": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-0d3cff5c-5b14-4635-b68a-
935e92eacbee",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-273f45d6-d750-48a6-811c-f17d218859ab": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-273f45d6-d750-48a6-811c-
f17d218859ab",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-2d53cb41-399d-43b7-8974-e81b23b39111": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-2d53cb41-399d-43b7-8974-
e81b23b39111",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-41e7dc53-53e0-40cc-a3a7-38db04415e59": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-41e7dc53-53e0-40cc-a3a7-
38db04415e59",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-78428e9c-fbd8-484a-afc6-ca11ddef092c": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-78428e9c-fbd8-484a-afc6-
ca11ddef092c",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-7b993f10-5d0c-4b96-a377-d1b9b34af8a4": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-7b993f10-5d0c-4b96-a377-
d1b9b34af8a4",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-80fedfc6-b125-4617-b7ad-6eb2ce06b264": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-80fedfc6-b125-4617-b7ad-
6eb2ce06b264",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-abee2272-9870-4981-a82d-312ddcb47660": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-abee2272-9870-4981-a82d-
312ddcb47660",
        "0001-0024-9e95757b-963f-4011-a4dd-1848d1f799cb-0000000000000002-cc52668e-ed9a-4485-8483-525cc897403b": "0001-0024-1465416b-2258-4cc1-80ec-066a90272d5e-0000000000000002-cc52668e-ed9a-4485-8483-
525cc897403b"
      }
    }
  }
}

@Rakshith-R
Rakshith-R requested a review from a team July 17, 2026 05:33
Comment thread internal/csi-addons/rbd/replication.go Outdated
}
srcVolumeID, err := vol.GetID(ctx)
if err != nil {
return "", status.Error(codes.Internal, err.Error())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would double wrap grpc status errors. getDestinationVolumeID should return plain fmt.Errorf errors. Only the RPC handlers should apply status.Error.

Comment thread internal/csi-addons/rbd/replication.go Outdated
}

// Decompose the source volume ID to get pool ID
var sourceID util.CSIIdentifier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This helper has code duplication with getDestinationIDFromCSIID.
Can we extract the params here and delegates to getDestinationIDFromCSIID?

Comment thread internal/csi-addons/rbd/replication.go Outdated
// Parse the remote pool ID from string to int64
parsedPoolID, err := strconv.ParseInt(remotePoolDetails.PoolID, 10, 64)
if err != nil {
return "", err

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

More info could be added?

Suggested change
return "", err
return "", fmt.Errorf("invalid poolID %q for pool %q in cluster %q: %w", remotePoolDetails.PoolID, poolName, clusterID, err)

req *replication.GetReplicationDestinationInfoRequest,
) (*replication.GetReplicationDestinationInfoResponse, error) {
// Validate request
if req.GetReplicationSource() == nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why not validate for empty secrets too?

Comment thread internal/csi-addons/rbd/replication.go Outdated
}
}

// getVolumeReplicationDestinationInfo handles volume replication destination info.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// getVolumeReplicationDestinationInfo handles volume replication destination info.
// getVolumeReplicationDestinationInfo extracts the RBD volume information
// from the volumeID and maps it to the destination cluster and pool using
// the replicationDestination configuration from the CSI ConfigMap.

Comment thread internal/csi-addons/rbd/replication.go Outdated
// Decompose the source volume ID to get pool ID
var sourceID util.CSIIdentifier
if err := sourceID.DecomposeCSIID(srcVolumeID); err != nil {
return "", fmt.Errorf("failed to decompose source volume ID: %w", err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
return "", fmt.Errorf("failed to decompose source volume ID: %w", err)
return "", fmt.Errorf("failed to decompose source volume ID %q: %w", srcVolumeID, err)

Comment thread internal/csi-addons/rbd/replication.go Outdated
return "", fmt.Errorf("failed to decompose source volume ID: %w", err)
}

remoteClusterID := destInfo.RemoteClusterID

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If its a required field, then probably more this before doing DecomposeCSIID?

Comment thread internal/csi-addons/rbd/replication.go Outdated

remoteClusterID := destInfo.RemoteClusterID
if remoteClusterID == "" {
return "", errors.New("remote cluster ID is empty in replication destination config")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

doesn't say which source cluster's config is broken

Suggested change
return "", errors.New("remote cluster ID is empty in replication destination config")
return "", fmt.Errorf("remoteClusterID is empty in replicationDestination for cluster %q", clusterID)


// If no destination configured, return the same ID
if destInfo == nil {
log.DebugLog(ctx, "no replication destination configured for cluster %s, assuming same ID", clusterID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

may be WarningLog?

Suggested change
log.DebugLog(ctx, "no replication destination configured for cluster %s, assuming same ID", clusterID)
log.WarningLog(ctx, "replicationDestination not configured for cluster %s, returning source volume ID unchanged", clusterID)

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.

I think we should keep it as debug, adding a ClientProfileReplication might not be required and it's not a warn message it's a choice of the user to create it

Comment thread internal/csi-addons/rbd/replication.go Outdated
return "", fmt.Errorf("failed to compose destination volume ID: %w", err)
}

log.UsefulLog(ctx, "mapped source volume %s to destination volume %s", srcVolumeID, destVolumeID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
log.UsefulLog(ctx, "mapped source volume %s to destination volume %s", srcVolumeID, destVolumeID)
log.UsefulLog(ctx, "mapped source ID %s to destination ID %s", srcVolumeID, destVolumeID)

@rewantsoni
rewantsoni force-pushed the implement-replication branch 4 times, most recently from 4451914 to 2ffd5f3 Compare July 28, 2026 11:21
@rewantsoni
rewantsoni force-pushed the implement-replication branch from 2ffd5f3 to 79d9e7a Compare July 28, 2026 11:29
@nixpanic

Copy link
Copy Markdown
Member

Maybe rename this PR to something like this?

rbd: implement GetReplicationDestinationInfo for volumes and groups

@rewantsoni rewantsoni changed the title implement the change for GetReplicationDestinationInfo rbd: implement GetReplicationDestinationInfo for volumes and groups Jul 28, 2026
@mergify mergify Bot added the component/rbd Issues related to RBD label Jul 28, 2026
@rewantsoni
rewantsoni force-pushed the implement-replication branch from 79d9e7a to 486d005 Compare July 28, 2026 16:57
@Rakshith-R
Rakshith-R requested a review from Copilot July 29, 2026 09:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support in the RBD CSI-Addons replication service for the new GetReplicationDestinationInfo RPC, enabling DR orchestrators to map source volume/volume-group CSI IDs to their corresponding destination IDs across mirrored clusters (including optional pool ID remapping via ConfigMap).

Changes:

  • Vendor-bump github.com/csi-addons/spec and regenerate protobuf/grpc stubs to include the new RPC + capability enum.
  • Implement GetReplicationDestinationInfo in the RBD CSI-Addons replication server for both volumes and volume groups, including replicationDestination ConfigMap schema support.
  • Extend cluster mapping utilities/tests and add unit tests for destination-ID mapping and basic RPC request validation.

Reviewed changes

Copilot reviewed 10 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/csi-addons/rbd/replication.go Implements the new RPC and ID mapping helper for volumes and volume groups.
internal/csi-addons/rbd/replication_destination_test.go Adds unit tests for destination ID mapping logic and request validation.
internal/csi-addons/rbd/identity.go Advertises the new CSI-Addons replication capability.
internal/util/csiconfig.go Adds accessor for replication destination config from CSI config.
internal/util/cluster_mapping.go Adds helper to resolve mapped cluster IDs (cluster-mapping.json).
internal/util/cluster_mapping_test.go Adds unit tests for mapped cluster ID resolution.
api/deploy/kubernetes/csi-config-map.go Extends CSI config schema with replication destination configuration.
vendor/github.com/ceph/ceph-csi/api/deploy/kubernetes/csi-config-map.go Vendored copy of the CSI config schema update.
PendingReleaseNotes.md Documents the new RPC and configuration behavior.
docs/design/proposals/replication-destination-info.md Updates design proposal with capability advertisement details.
go.mod / go.sum Updates dependency version for csi-addons spec.
vendor/modules.txt Updates vendored module versions.
vendor/github.com/csi-addons/spec/lib/go/replication/replication.pb.go Vendored protobuf changes for new messages/types.
vendor/github.com/csi-addons/spec/lib/go/replication/replication_grpc.pb.go Vendored grpc service changes for new RPC.
vendor/github.com/csi-addons/spec/lib/go/identity/identity.pb.go Vendored capability enum update.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1246 to +1250
// Decompose the source ID
var sourceID util.CSIIdentifier
if err := sourceID.DecomposeCSIID(srcID); err != nil {
return "", fmt.Errorf("failed to decompose source volume ID %q: %w", srcID, err)
}
Comment on lines +1067 to +1072
rbdVol, err := mgr.GetVolumeByID(ctx, volumeID)
if err != nil {
log.ErrorLog(ctx, "failed to get volume with id %q: %v", volumeID, err)

return nil, getGRPCError(err)
}

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.

We shouldn't destroy the volume

Comment thread internal/csi-addons/rbd/replication.go Outdated
Comment on lines +1203 to +1207
destVolID, err := getDestinationIDFromCSIID(ctx, sourceVolID, localClusterID, poolName, util.CsiConfigFile)
if err != nil {
log.ErrorLog(ctx, "failed to get destination ID for volume %q: %v", sourceVolID, err)

return nil, status.Error(codes.Internal, err.Error())
return "", fmt.Errorf("failed to compose destination ID: %w", err)
}

log.UsefulLog(ctx, "mapped source ID %s to destination ID %s", srcID, destCSIID)

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.

I think it would be good to have the new mapped ID in UseFulLog so that we can backtrack in case of any errors

Comment thread PendingReleaseNotes.md Outdated
Comment on lines +7 to +17
1. Added `GetReplicationDestinationInfo` RPC to map source volume/volume
group IDs to destination IDs across mirrored clusters. This enables DR
orchestrators to discover the correct destination volume IDs when pools
have different IDs across clusters. The RPC supports:
- Volume replication: Maps source volume ID to destination volume ID
- Volume group replication: Maps source group ID and all member volume
IDs to their destination IDs
- Pool name-based mapping via `replicationDestination` ConfigMap
configuration
- Backward compatibility with existing cluster-mapping.json via
ClientProfileMapping integration
@rewantsoni
rewantsoni force-pushed the implement-replication branch 2 times, most recently from 738fdaa to bd1bb11 Compare July 30, 2026 04:45
Update the replication destination info proposal to document that
the GET_REPLICATION_DESTINATION_INFO capability must be advertised
via GetCapabilities RPC.

This allows DR orchestrators to discover whether the driver supports
the GetReplicationDestinationInfo feature.

Signed-off-by: Rewant Soni <resoni@redhat.com>
Add ReplicationDestinationInfo, RemoteRBDDetails, and RemotePoolDetails
structures to the ClusterInfo ConfigMap schema. This enables CSI driver
to map source volume/group IDs to destination volume/group IDs when
pool IDs differ across mirrored clusters.

Signed-off-by: Rewant Soni <resoni@redhat.com>
Update csi-addons/spec from b5a7205f6a79 to d4a373713b9a to include
GetReplicationDestinationInfo RPC definitions for volume and volume
group replication.

Signed-off-by: Rewant Soni <resoni@redhat.com>
@rewantsoni
rewantsoni force-pushed the implement-replication branch from bd1bb11 to af236c2 Compare July 30, 2026 04:47
Add GetReplicationDestinationInfo RPC implementation for both volume
and volume group replication. This RPC maps source volume/group IDs to
destination IDs by using the replicationDestination configuration from
the ConfigMap.

Signed-off-by: Rewant Soni <resoni@redhat.com>
Add GET_REPLICATION_DESTINATION_INFO to the list of advertised
capabilities in GetCapabilities RPC.

The capability is advertised on controller servers and applies to both
volume and volume group replication, as both are handled by the same
Replication Controller service.

Signed-off-by: Rewant Soni <resoni@redhat.com>
Add unit tests for GetReplicationDestinationInfo RPC

Signed-off-by: Rewant Soni <resoni@redhat.com>
Document the new GetReplicationDestinationInfo RPC feature in the
pending release notes for v3.18.

This RPC enables DR orchestrators to map source volume/volume group IDs
to destination IDs across mirrored clusters when pools have different
IDs, supporting both single volumes and volume groups with pool-based
mapping configuration.

Signed-off-by: Rewant Soni <resoni@redhat.com>
@rewantsoni
rewantsoni force-pushed the implement-replication branch from af236c2 to 26e6c47 Compare July 30, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/rbd Issues related to RBD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants