From a3457da7279e2545d4675491791dbf9dc7fa678b Mon Sep 17 00:00:00 2001
From: Praveen M <m.praveen@ibm.com>
Date: Mon, 5 Aug 2024 17:34:31 +0530
Subject: [PATCH] rbd: controller to regenerate volume group omap data

This commit adds new controller that watches for the
VolumeGroupReplicationContent and regenerates the OMAP data if
it doesn't exists.

Signed-off-by: Praveen M <m.praveen@ibm.com>
---
 cmd/cephcsi.go                                |   2 +
 .../rbd/kubernetes/csi-provisioner-rbac.yaml  |   6 +
 go.mod                                        |   1 +
 go.sum                                        |   2 +
 internal/controller/controller.go             |  11 +-
 .../volumegroupreplicationcontent.go          | 247 ++++++++
 .../csi-addons/kubernetes-csi-addons/LICENSE  | 202 +++++++
 .../v1alpha1/groupversion_info.go             |  36 ++
 .../v1alpha1/volumegroupreplication_types.go  | 105 ++++
 .../volumegroupreplicationclass_types.go      |  67 ++
 .../volumegroupreplicationcontent_types.go    | 101 ++++
 .../v1alpha1/volumereplication_types.go       | 131 ++++
 .../v1alpha1/volumereplicationclass_types.go  |  69 +++
 .../v1alpha1/zz_generated.deepcopy.go         | 570 ++++++++++++++++++
 vendor/modules.txt                            |   4 +
 .../controller-runtime/pkg/scheme/scheme.go   |  93 +++
 16 files changed, 1645 insertions(+), 2 deletions(-)
 create mode 100644 internal/controller/volumegroup/volumegroupreplicationcontent.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/LICENSE
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/groupversion_info.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplication_types.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationclass_types.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationcontent_types.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplication_types.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplicationclass_types.go
 create mode 100644 vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/zz_generated.deepcopy.go
 create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go

diff --git a/cmd/cephcsi.go b/cmd/cephcsi.go
index bc6e1c7a3..b56b0cef7 100644
--- a/cmd/cephcsi.go
+++ b/cmd/cephcsi.go
@@ -26,6 +26,7 @@ import (
 	"github.com/ceph/ceph-csi/internal/cephfs"
 	"github.com/ceph/ceph-csi/internal/controller"
 	"github.com/ceph/ceph-csi/internal/controller/persistentvolume"
+	"github.com/ceph/ceph-csi/internal/controller/volumegroup"
 	"github.com/ceph/ceph-csi/internal/liveness"
 	nfsdriver "github.com/ceph/ceph-csi/internal/nfs/driver"
 	rbddriver "github.com/ceph/ceph-csi/internal/rbd/driver"
@@ -294,6 +295,7 @@ func setPIDLimit(conf *util.Config) {
 func initControllers() {
 	// Add list of controller here.
 	persistentvolume.Init()
+	volumegroup.Init()
 }
 
 func validateCloneDepthFlag(conf *util.Config) {
diff --git a/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml b/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
index dc714bc45..41118de60 100644
--- a/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
+++ b/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
@@ -75,6 +75,12 @@ rules:
   - apiGroups: ["groupsnapshot.storage.k8s.io"]
     resources: ["volumegroupsnapshotcontents/status"]
     verbs: ["update", "patch"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumegroupreplicationcontents"]
+    verbs: ["get", "list", "watch"]
+  - apiGroups: ["replication.storage.openshift.io"]
+    resources: ["volumegroupreplicationclasses"]
+    verbs: ["get"]
 ---
 kind: ClusterRoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
diff --git a/go.mod b/go.mod
index 7c6540385..e31ae32c9 100644
--- a/go.mod
+++ b/go.mod
@@ -48,6 +48,7 @@ require (
 require (
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
 	github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0
+	github.com/csi-addons/kubernetes-csi-addons v0.9.0
 )
 
 require (
diff --git a/go.sum b/go.sum
index 096fda65e..f530aebdf 100644
--- a/go.sum
+++ b/go.sum
@@ -1519,6 +1519,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/csi-addons/kubernetes-csi-addons v0.9.0 h1:Hhb44WcrxtbzmpLY+uqX+DBWCI6HgA/rwQMPyvsyCc8=
+github.com/csi-addons/kubernetes-csi-addons v0.9.0/go.mod h1:/YROZDdEi1N/1Ls9rdU5W2VNjm8MK7HHApl8W4Sqt9s=
 github.com/csi-addons/spec v0.2.1-0.20241104111131-27825f744db5 h1:j9NaWj5KmzEVarmsjxS/NDAhes6Uzq1qhkUGHvDlVBk=
 github.com/csi-addons/spec v0.2.1-0.20241104111131-27825f744db5/go.mod h1:Mwq4iLiUV4s+K1bszcWU6aMsR5KPsbIYzzszJ6+56vI=
 github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
diff --git a/internal/controller/controller.go b/internal/controller/controller.go
index 5c4693d7d..53dff8fec 100644
--- a/internal/controller/controller.go
+++ b/internal/controller/controller.go
@@ -20,7 +20,10 @@ import (
 
 	"github.com/ceph/ceph-csi/internal/util/log"
 
-	"k8s.io/apimachinery/pkg/runtime"
+	replicationv1alpha1 "github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1"
+	apiruntime "k8s.io/apimachinery/pkg/runtime"
+	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/leaderelection/resourcelock"
 	clientConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
@@ -62,6 +65,9 @@ func addToManager(mgr manager.Manager, config Config) error {
 
 // Start will start all the registered managers.
 func Start(config Config) error {
+	scheme := apiruntime.NewScheme()
+	utilruntime.Must(replicationv1alpha1.AddToScheme(scheme))
+	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
 	electionID := config.DriverName + "-" + config.Namespace
 	opts := manager.Options{
 		LeaderElection: true,
@@ -70,11 +76,12 @@ func Start(config Config) error {
 		LeaderElectionNamespace:    config.Namespace,
 		LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
 		LeaderElectionID:           electionID,
+		Scheme:                     scheme,
 	}
 
 	kubeConfig := clientConfig.GetConfigOrDie()
 	coreKubeConfig := rest.CopyConfig(kubeConfig)
-	coreKubeConfig.ContentType = runtime.ContentTypeProtobuf
+	coreKubeConfig.ContentType = apiruntime.ContentTypeProtobuf
 	mgr, err := manager.New(coreKubeConfig, opts)
 	if err != nil {
 		log.ErrorLogMsg("failed to create manager %s", err)
diff --git a/internal/controller/volumegroup/volumegroupreplicationcontent.go b/internal/controller/volumegroup/volumegroupreplicationcontent.go
new file mode 100644
index 000000000..ebe3f67fd
--- /dev/null
+++ b/internal/controller/volumegroup/volumegroupreplicationcontent.go
@@ -0,0 +1,247 @@
+/*
+Copyright 2025 The Ceph-CSI Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package volumegroup
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"strings"
+
+	replicationv1alpha1 "github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1"
+	corev1 "k8s.io/api/core/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/api/meta"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller"
+	"sigs.k8s.io/controller-runtime/pkg/handler"
+	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+	"sigs.k8s.io/controller-runtime/pkg/source"
+
+	ctrl "github.com/ceph/ceph-csi/internal/controller"
+	"github.com/ceph/ceph-csi/internal/rbd"
+	"github.com/ceph/ceph-csi/internal/util"
+	"github.com/ceph/ceph-csi/internal/util/log"
+)
+
+type ReconcileVGRContent struct {
+	client client.Client
+	config ctrl.Config
+	Locks  *util.VolumeLocks
+}
+
+var (
+	_ reconcile.Reconciler = &ReconcileVGRContent{}
+	_ ctrl.Manager         = &ReconcileVGRContent{}
+)
+
+const (
+	secretNameParameterName      = "replication.storage.openshift.io/group-replication-secret-name"
+	secretNamespaceParameterName = "replication.storage.openshift.io/group-replication-secret-namespace"
+
+	volumeGroupReplicationContentResourceName = "VolumeGroupReplicationContent"
+	volumeGroupReplicationClassResourceName   = "VolumeGroupReplicationClass"
+)
+
+// Init will add the ReconcileVGRContent to the list.
+func Init() {
+	// add ReconcileVGRContent to the list
+	ctrl.ControllerList = append(ctrl.ControllerList, &ReconcileVGRContent{})
+}
+
+// Add adds the newVGRContentReconciler.
+func (r *ReconcileVGRContent) Add(mgr manager.Manager, config ctrl.Config) error {
+	return add(mgr, newVGRContentReconciler(mgr, config))
+}
+
+// newVGRContentReconciler returns a ReconcileVGRContent.
+func newVGRContentReconciler(mgr manager.Manager, config ctrl.Config) reconcile.Reconciler {
+	r := &ReconcileVGRContent{
+		client: mgr.GetClient(),
+		config: config,
+		Locks:  util.NewVolumeLocks(),
+	}
+
+	return r
+}
+
+func ensureCRDsInstalled(mgr manager.Manager) (bool, error) {
+	crdsInstalled := true
+	missingCRDs := []string{}
+
+	gvk := metav1.PartialObjectMetadata{}
+	gvk.SetGroupVersionKind(replicationv1alpha1.GroupVersion.WithKind(volumeGroupReplicationContentResourceName))
+	_, err := mgr.GetRESTMapper().RESTMapping(gvk.GroupVersionKind().GroupKind(), gvk.GroupVersionKind().Version)
+	if err != nil {
+		if !meta.IsNoMatchError(err) {
+			return false, err
+		}
+
+		crdsInstalled = false
+		missingCRDs = append(missingCRDs, volumeGroupReplicationContentResourceName)
+	}
+
+	gvk.SetGroupVersionKind(replicationv1alpha1.GroupVersion.WithKind(volumeGroupReplicationClassResourceName))
+	_, err = mgr.GetRESTMapper().RESTMapping(gvk.GroupVersionKind().GroupKind(), gvk.GroupVersionKind().Version)
+	if err != nil {
+		if !meta.IsNoMatchError(err) {
+			return false, err
+		}
+
+		crdsInstalled = false
+		missingCRDs = append(missingCRDs, volumeGroupReplicationClassResourceName)
+	}
+
+	if !crdsInstalled {
+		log.ErrorLogMsg("Required CRDs (%s) are not installed", strings.Join(missingCRDs, ", "))
+	}
+
+	return crdsInstalled, nil
+}
+
+func add(mgr manager.Manager, r reconcile.Reconciler) error {
+	// Ensure the required CRDs are installed.
+	installed, err := ensureCRDsInstalled(mgr)
+	if err != nil {
+		return err
+	}
+	if !installed {
+		log.ErrorLogMsg("Skipping controller creation for VolumeGroupReplicationContent. Please install the missing CRDs.")
+
+		return nil
+	}
+
+	// Create a new controller
+	c, err := controller.New(
+		"vgrcontent-controller",
+		mgr,
+		controller.Options{MaxConcurrentReconciles: 1, Reconciler: r})
+	if err != nil {
+		return err
+	}
+
+	// Watch for changes to VolumeGroupReplicationContent
+	err = c.Watch(source.Kind(
+		mgr.GetCache(),
+		&replicationv1alpha1.VolumeGroupReplicationContent{},
+		&handler.TypedEnqueueRequestForObject[*replicationv1alpha1.VolumeGroupReplicationContent]{}),
+	)
+	if err != nil {
+		return fmt.Errorf("failed to watch the changes: %w", err)
+	}
+
+	return nil
+}
+
+func (r *ReconcileVGRContent) getSecrets(
+	ctx context.Context,
+	name,
+	namespace string,
+) (map[string]string, error) {
+	if name == "" || namespace == "" {
+		return nil, errors.New("secret name or secret namespace is empty")
+	}
+	secret := &corev1.Secret{}
+	err := r.client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, secret)
+	if err != nil {
+		return nil, fmt.Errorf("error getting secret %s in namespace %s: %w", name, namespace, err)
+	}
+
+	secrets := map[string]string{}
+	for key, value := range secret.Data {
+		secrets[key] = string(value)
+	}
+
+	return secrets, nil
+}
+
+func (r *ReconcileVGRContent) reconcileVGRContent(ctx context.Context, obj runtime.Object) error {
+	vgrc, ok := obj.(*replicationv1alpha1.VolumeGroupReplicationContent)
+	if !ok {
+		return nil
+	}
+	if vgrc.Spec.Provisioner != r.config.DriverName {
+		return nil
+	}
+
+	reqName := vgrc.Name
+	groupHandle := vgrc.Spec.VolumeGroupReplicationHandle
+	volumeIds := vgrc.Spec.Source.VolumeHandles
+
+	if groupHandle == "" {
+		return errors.New("volume group replication handle is empty")
+	}
+
+	vgrClass := &replicationv1alpha1.VolumeGroupReplicationClass{}
+	err := r.client.Get(ctx, types.NamespacedName{Name: vgrc.Spec.VolumeGroupReplicationClassName}, vgrClass)
+	if err != nil {
+		return err
+	}
+
+	if ok = r.Locks.TryAcquire(groupHandle); !ok {
+		return fmt.Errorf("failed to acquire lock for group handle %s", groupHandle)
+	}
+	defer r.Locks.Release(groupHandle)
+
+	parameters := vgrClass.Spec.Parameters
+	secretName := vgrClass.Spec.Parameters[secretNameParameterName]
+	secretNamespace := vgrClass.Spec.Parameters[secretNamespaceParameterName]
+
+	secrets, err := r.getSecrets(ctx, secretName, secretNamespace)
+	if err != nil {
+		return err
+	}
+
+	mgr := rbd.NewManager(r.config.InstanceID, parameters, secrets)
+	defer mgr.Destroy(ctx)
+
+	groupID, err := mgr.RegenerateVolumeGroupJournal(ctx, groupHandle, reqName, volumeIds)
+	if err != nil {
+		return err
+	}
+	if groupID != groupHandle {
+		log.DebugLog(ctx, "groupHandle changed from %s to %s", groupHandle, groupID)
+	}
+
+	return nil
+}
+
+// Reconcile reconciles the VolumeGroupReplicationContent object and creates a new omap entries
+// for the volume group.
+func (r *ReconcileVGRContent) Reconcile(ctx context.Context,
+	request reconcile.Request,
+) (reconcile.Result, error) {
+	vgrc := &replicationv1alpha1.VolumeGroupReplicationContent{}
+	err := r.client.Get(ctx, request.NamespacedName, vgrc)
+	if err != nil {
+		if apierrors.IsNotFound(err) {
+			return reconcile.Result{}, nil
+		}
+
+		return reconcile.Result{}, err
+	}
+
+	// Proceed with reconciliation only if the object is not marked for deletion.
+	if vgrc.GetDeletionTimestamp().IsZero() {
+		err = r.reconcileVGRContent(ctx, vgrc)
+	}
+
+	return reconcile.Result{}, err
+}
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/LICENSE b/vendor/github.com/csi-addons/kubernetes-csi-addons/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/groupversion_info.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/groupversion_info.go
new file mode 100644
index 000000000..37182b68d
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/groupversion_info.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2022 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v1alpha1 contains API Schema definitions for the replication.storage v1alpha1 API group
+// +kubebuilder:object:generate=true
+// +groupName=replication.storage.openshift.io
+package v1alpha1
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+	// GroupVersion is group version used to register these objects
+	GroupVersion = schema.GroupVersion{Group: "replication.storage.openshift.io", Version: "v1alpha1"}
+
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+	// AddToScheme adds the types in this group-version to the given scheme.
+	AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplication_types.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplication_types.go
new file mode 100644
index 000000000..8ad2bff70
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplication_types.go
@@ -0,0 +1,105 @@
+/*
+Copyright 2024 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// VolumeGroupReplicationSpec defines the desired state of VolumeGroupReplication
+type VolumeGroupReplicationSpec struct {
+	// volumeGroupReplicationClassName is the volumeGroupReplicationClass name for this VolumeGroupReplication resource
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="volumeGroupReplicationClassName is immutable"
+	VolumeGroupReplicationClassName string `json:"volumeGroupReplicationClassName"`
+
+	// volumeReplicationClassName is the volumeReplicationClass name for VolumeReplication object
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="volumReplicationClassName is immutable"
+	VolumeReplicationClassName string `json:"volumeReplicationClassName"`
+
+	// Name of the VolumeReplication object created for this volumeGroupReplication
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="volumeReplicationName is immutable"
+	VolumeReplicationName string `json:"volumeReplicationName,omitempty"`
+
+	// Name of the VolumeGroupReplicationContent object created for this volumeGroupReplication
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="volumeGroupReplicationContentName is immutable"
+	VolumeGroupReplicationContentName string `json:"volumeGroupReplicationContentName,omitempty"`
+
+	// Source specifies where a group replications will be created from.
+	// This field is immutable after creation.
+	// Required.
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="source is immutable"
+	Source VolumeGroupReplicationSource `json:"source"`
+
+	// ReplicationState represents the replication operation to be performed on the group.
+	// Supported operations are "primary", "secondary" and "resync"
+	// +kubebuilder:validation:Required
+	ReplicationState ReplicationState `json:"replicationState"`
+
+	// AutoResync represents the group to be auto resynced when
+	// ReplicationState is "secondary"
+	// +kubebuilder:default:=false
+	AutoResync bool `json:"autoResync"`
+}
+
+// VolumeGroupReplicationSource specifies the source for the the volumeGroupReplication
+type VolumeGroupReplicationSource struct {
+	// Selector is a label query over persistent volume claims that are to be
+	// grouped together for replication.
+	// +optional
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="selector is immutable"
+	Selector *metav1.LabelSelector `json:"selector,omitempty"`
+}
+
+// VolumeGroupReplicationStatus defines the observed state of VolumeGroupReplication
+type VolumeGroupReplicationStatus struct {
+	VolumeReplicationStatus `json:",inline"`
+	// PersistentVolumeClaimsRefList is the list of PVCs for the volume group replication.
+	// The maximum number of allowed PVCs in the group is 100.
+	// +optional
+	PersistentVolumeClaimsRefList []corev1.LocalObjectReference `json:"persistentVolumeClaimsRefList,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+
+// VolumeGroupReplication is the Schema for the volumegroupreplications API
+type VolumeGroupReplication struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   VolumeGroupReplicationSpec   `json:"spec,omitempty"`
+	Status VolumeGroupReplicationStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// VolumeGroupReplicationList contains a list of VolumeGroupReplication
+type VolumeGroupReplicationList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []VolumeGroupReplication `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&VolumeGroupReplication{}, &VolumeGroupReplicationList{})
+}
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationclass_types.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationclass_types.go
new file mode 100644
index 000000000..972bcd1ba
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationclass_types.go
@@ -0,0 +1,67 @@
+/*
+Copyright 2024 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// VolumeGroupReplicationClassSpec specifies parameters that an underlying storage system uses
+// when creating a volumegroup replica. A specific VolumeGroupReplicationClass is used by specifying
+// its name in a VolumeGroupReplication object.
+// +kubebuilder:validation:XValidation:rule="has(self.parameters) == has(oldSelf.parameters)",message="parameters are immutable"
+type VolumeGroupReplicationClassSpec struct {
+	// Provisioner is the name of storage provisioner
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="provisioner is immutable"
+	Provisioner string `json:"provisioner"`
+	// Parameters is a key-value map with storage provisioner specific configurations for
+	// creating volume group replicas
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="parameters are immutable"
+	Parameters map[string]string `json:"parameters,omitempty"`
+}
+
+// VolumeGroupReplicationClassStatus defines the observed state of VolumeGroupReplicationClass
+type VolumeGroupReplicationClassStatus struct {
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:resource:scope=Cluster
+
+// VolumeGroupReplicationClass is the Schema for the volumegroupreplicationclasses API
+type VolumeGroupReplicationClass struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   VolumeGroupReplicationClassSpec   `json:"spec,omitempty"`
+	Status VolumeGroupReplicationClassStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// VolumeGroupReplicationClassList contains a list of VolumeGroupReplicationClass
+type VolumeGroupReplicationClassList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []VolumeGroupReplicationClass `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&VolumeGroupReplicationClass{}, &VolumeGroupReplicationClassList{})
+}
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationcontent_types.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationcontent_types.go
new file mode 100644
index 000000000..fcbb7a95a
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumegroupreplicationcontent_types.go
@@ -0,0 +1,101 @@
+/*
+Copyright 2024 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// VolumeGroupReplicationContentSpec defines the desired state of VolumeGroupReplicationContent
+type VolumeGroupReplicationContentSpec struct {
+	// VolumeGroupreplicationRef specifies the VolumeGroupReplication object to which this
+	// VolumeGroupReplicationContent object is bound.
+	// VolumeGroupReplication.Spec.VolumeGroupReplicationContentName field must reference to
+	// this VolumeGroupReplicationContent's name for the bidirectional binding to be valid.
+	// For a pre-existing VolumeGroupReplicationContent object, name and namespace of the
+	// VolumeGroupReplication object MUST be provided for binding to happen.
+	// This field is immutable after creation.
+	// Required.
+	// +kubebuilder:validation:XValidation:rule="has(self.name) && has(self.__namespace__)",message="both volumeGroupReplicationRef.name and volumeGroupReplicationRef.namespace must be set"
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="volumeGroupReplicationRef is immutable"
+	VolumeGroupReplicationRef corev1.ObjectReference `json:"volumeGroupReplicationRef"`
+
+	// VolumeGroupReplicationHandle is a unique id returned by the CSI driver
+	// to identify the VolumeGroupReplication on the storage system.
+	VolumeGroupReplicationHandle string `json:"volumeGroupReplicationHandle"`
+
+	// provisioner is the name of the CSI driver used to create the physical
+	// volume group on
+	// the underlying storage system.
+	// This MUST be the same as the name returned by the CSI GetPluginName() call for
+	// that driver.
+	// Required.
+	Provisioner string `json:"provisioner"`
+
+	// VolumeGroupReplicationClassName is the name of the VolumeGroupReplicationClass from
+	// which this group replication was (or will be) created.
+	// +optional
+	VolumeGroupReplicationClassName string `json:"volumeGroupReplicationClassName"`
+
+	// Source specifies whether the snapshot is (or should be) dynamically provisioned
+	// or already exists, and just requires a Kubernetes object representation.
+	// This field is immutable after creation.
+	// Required.
+	Source VolumeGroupReplicationContentSource `json:"source"`
+}
+
+// VolumeGroupReplicationContentSource represents the CSI source of a group replication.
+type VolumeGroupReplicationContentSource struct {
+	// VolumeHandles is a list of volume handles on the backend to be grouped
+	// and replicated.
+	VolumeHandles []string `json:"volumeHandles"`
+}
+
+// VolumeGroupReplicationContentStatus defines the status of VolumeGroupReplicationContent
+type VolumeGroupReplicationContentStatus struct {
+	// PersistentVolumeRefList is the list of of PV for the group replication
+	// The maximum number of allowed PV in the group is 100.
+	// +optional
+	PersistentVolumeRefList []corev1.LocalObjectReference `json:"persistentVolumeRefList,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:resource:scope=Cluster
+
+// VolumeGroupReplicationContent is the Schema for the volumegroupreplicationcontents API
+type VolumeGroupReplicationContent struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   VolumeGroupReplicationContentSpec   `json:"spec,omitempty"`
+	Status VolumeGroupReplicationContentStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// VolumeGroupReplicationContentList contains a list of VolumeGroupReplicationContent
+type VolumeGroupReplicationContentList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []VolumeGroupReplicationContent `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&VolumeGroupReplicationContent{}, &VolumeGroupReplicationContentList{})
+}
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplication_types.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplication_types.go
new file mode 100644
index 000000000..d9fca40ad
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplication_types.go
@@ -0,0 +1,131 @@
+/*
+Copyright 2022 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const (
+	VolumeReplicationNameAnnotation = "replication.storage.openshift.io/volume-replication-name"
+)
+
+// ReplicationState represents the replication operations to be performed on the volume.
+// +kubebuilder:validation:Enum=primary;secondary;resync
+type ReplicationState string
+
+const (
+	// Primary ReplicationState enables mirroring and promotes the volume to primary.
+	Primary ReplicationState = "primary"
+
+	// Secondary ReplicationState demotes the volume to secondary and resyncs the volume if out of sync.
+	Secondary ReplicationState = "secondary"
+
+	// Resync option resyncs the volume.
+	Resync ReplicationState = "resync"
+)
+
+// State captures the latest state of the replication operation.
+type State string
+
+const (
+	// PrimaryState represents the Primary replication state.
+	PrimaryState State = "Primary"
+
+	// SecondaryState represents the Secondary replication state.
+	SecondaryState State = "Secondary"
+
+	// UnknownState represents the Unknown replication state.
+	UnknownState State = "Unknown"
+)
+
+// VolumeReplicationSpec defines the desired state of VolumeReplication.
+type VolumeReplicationSpec struct {
+	// VolumeReplicationClass is the VolumeReplicationClass name for this VolumeReplication resource
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="volumeReplicationClass is immutable"
+	VolumeReplicationClass string `json:"volumeReplicationClass"`
+
+	// ReplicationState represents the replication operation to be performed on the volume.
+	// Supported operations are "primary", "secondary" and "resync"
+	// +kubebuilder:validation:Required
+	ReplicationState ReplicationState `json:"replicationState"`
+
+	// DataSource represents the object associated with the volume
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="dataSource is immutable"
+	DataSource corev1.TypedLocalObjectReference `json:"dataSource"`
+
+	// AutoResync represents the volume to be auto resynced when
+	// ReplicationState is "secondary"
+	// +kubebuilder:default:=false
+	AutoResync bool `json:"autoResync"`
+
+	// replicationHandle represents an existing (but new) replication id
+	// +kubebuilder:validation:Optional
+	ReplicationHandle string `json:"replicationHandle"`
+}
+
+// VolumeReplicationStatus defines the observed state of VolumeReplication.
+type VolumeReplicationStatus struct {
+	State   State  `json:"state,omitempty"`
+	Message string `json:"message,omitempty"`
+	// Conditions are the list of conditions and their status.
+	Conditions []metav1.Condition `json:"conditions,omitempty"`
+	// observedGeneration is the last generation change the operator has dealt with
+	// +optional
+	ObservedGeneration int64            `json:"observedGeneration,omitempty"`
+	LastStartTime      *metav1.Time     `json:"lastStartTime,omitempty"`
+	LastCompletionTime *metav1.Time     `json:"lastCompletionTime,omitempty"`
+	LastSyncTime       *metav1.Time     `json:"lastSyncTime,omitempty"`
+	LastSyncBytes      *int64           `json:"lastSyncBytes,omitempty"`
+	LastSyncDuration   *metav1.Duration `json:"lastSyncDuration,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:printcolumn:JSONPath=".metadata.creationTimestamp",name=Age,type=date
+// +kubebuilder:printcolumn:JSONPath=".spec.volumeReplicationClass",name=volumeReplicationClass,type=string
+// +kubebuilder:printcolumn:JSONPath=".spec.dataSource.name",name=pvcName,type=string
+// +kubebuilder:printcolumn:JSONPath=".spec.replicationState",name=desiredState,type=string
+// +kubebuilder:printcolumn:JSONPath=".status.state",name=currentState,type=string
+// +kubebuilder:resource:shortName=vr
+
+// VolumeReplication is the Schema for the volumereplications API.
+type VolumeReplication struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	// +kubebuilder:validation:Required
+	Spec VolumeReplicationSpec `json:"spec"`
+
+	Status VolumeReplicationStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// VolumeReplicationList contains a list of VolumeReplication.
+type VolumeReplicationList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []VolumeReplication `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&VolumeReplication{}, &VolumeReplicationList{})
+}
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplicationclass_types.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplicationclass_types.go
new file mode 100644
index 000000000..25632a049
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/volumereplicationclass_types.go
@@ -0,0 +1,69 @@
+/*
+Copyright 2022 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// VolumeReplicationClassSpec specifies parameters that an underlying storage system uses
+// when creating a volume replica. A specific VolumeReplicationClass is used by specifying
+// its name in a VolumeReplication object.
+// +kubebuilder:validation:XValidation:rule="has(self.parameters) == has(oldSelf.parameters)",message="parameters are immutable"
+type VolumeReplicationClassSpec struct {
+	// Provisioner is the name of storage provisioner
+	// +kubebuilder:validation:Required
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="provisioner is immutable"
+	Provisioner string `json:"provisioner"`
+	// Parameters is a key-value map with storage provisioner specific configurations for
+	// creating volume replicas
+	// +kubebuilder:validation:Optional
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="parameters are immutable"
+	Parameters map[string]string `json:"parameters,omitempty"`
+}
+
+// VolumeReplicationClassStatus defines the observed state of VolumeReplicationClass.
+type VolumeReplicationClassStatus struct{}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Cluster,shortName=vrc
+// +kubebuilder:printcolumn:JSONPath=".spec.provisioner",name=provisioner,type=string
+
+// VolumeReplicationClass is the Schema for the volumereplicationclasses API.
+type VolumeReplicationClass struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	// +kubebuilder:validation:Required
+	Spec VolumeReplicationClassSpec `json:"spec"`
+
+	Status VolumeReplicationClassStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// VolumeReplicationClassList contains a list of VolumeReplicationClass.
+type VolumeReplicationClassList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []VolumeReplicationClass `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&VolumeReplicationClass{}, &VolumeReplicationClassList{})
+}
diff --git a/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 000000000..dcfe62b46
--- /dev/null
+++ b/vendor/github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,570 @@
+//go:build !ignore_autogenerated
+
+/*
+Copyright 2022 The Kubernetes-CSI-Addons Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplication) DeepCopyInto(out *VolumeGroupReplication) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplication.
+func (in *VolumeGroupReplication) DeepCopy() *VolumeGroupReplication {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplication)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeGroupReplication) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationClass) DeepCopyInto(out *VolumeGroupReplicationClass) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationClass.
+func (in *VolumeGroupReplicationClass) DeepCopy() *VolumeGroupReplicationClass {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationClass)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeGroupReplicationClass) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationClassList) DeepCopyInto(out *VolumeGroupReplicationClassList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]VolumeGroupReplicationClass, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationClassList.
+func (in *VolumeGroupReplicationClassList) DeepCopy() *VolumeGroupReplicationClassList {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationClassList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeGroupReplicationClassList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationClassSpec) DeepCopyInto(out *VolumeGroupReplicationClassSpec) {
+	*out = *in
+	if in.Parameters != nil {
+		in, out := &in.Parameters, &out.Parameters
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationClassSpec.
+func (in *VolumeGroupReplicationClassSpec) DeepCopy() *VolumeGroupReplicationClassSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationClassSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationClassStatus) DeepCopyInto(out *VolumeGroupReplicationClassStatus) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationClassStatus.
+func (in *VolumeGroupReplicationClassStatus) DeepCopy() *VolumeGroupReplicationClassStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationClassStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationContent) DeepCopyInto(out *VolumeGroupReplicationContent) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationContent.
+func (in *VolumeGroupReplicationContent) DeepCopy() *VolumeGroupReplicationContent {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationContent)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeGroupReplicationContent) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationContentList) DeepCopyInto(out *VolumeGroupReplicationContentList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]VolumeGroupReplicationContent, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationContentList.
+func (in *VolumeGroupReplicationContentList) DeepCopy() *VolumeGroupReplicationContentList {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationContentList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeGroupReplicationContentList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationContentSource) DeepCopyInto(out *VolumeGroupReplicationContentSource) {
+	*out = *in
+	if in.VolumeHandles != nil {
+		in, out := &in.VolumeHandles, &out.VolumeHandles
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationContentSource.
+func (in *VolumeGroupReplicationContentSource) DeepCopy() *VolumeGroupReplicationContentSource {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationContentSource)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationContentSpec) DeepCopyInto(out *VolumeGroupReplicationContentSpec) {
+	*out = *in
+	out.VolumeGroupReplicationRef = in.VolumeGroupReplicationRef
+	in.Source.DeepCopyInto(&out.Source)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationContentSpec.
+func (in *VolumeGroupReplicationContentSpec) DeepCopy() *VolumeGroupReplicationContentSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationContentSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationContentStatus) DeepCopyInto(out *VolumeGroupReplicationContentStatus) {
+	*out = *in
+	if in.PersistentVolumeRefList != nil {
+		in, out := &in.PersistentVolumeRefList, &out.PersistentVolumeRefList
+		*out = make([]corev1.LocalObjectReference, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationContentStatus.
+func (in *VolumeGroupReplicationContentStatus) DeepCopy() *VolumeGroupReplicationContentStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationContentStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationList) DeepCopyInto(out *VolumeGroupReplicationList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]VolumeGroupReplication, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationList.
+func (in *VolumeGroupReplicationList) DeepCopy() *VolumeGroupReplicationList {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeGroupReplicationList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationSource) DeepCopyInto(out *VolumeGroupReplicationSource) {
+	*out = *in
+	if in.Selector != nil {
+		in, out := &in.Selector, &out.Selector
+		*out = new(v1.LabelSelector)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationSource.
+func (in *VolumeGroupReplicationSource) DeepCopy() *VolumeGroupReplicationSource {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationSource)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationSpec) DeepCopyInto(out *VolumeGroupReplicationSpec) {
+	*out = *in
+	in.Source.DeepCopyInto(&out.Source)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationSpec.
+func (in *VolumeGroupReplicationSpec) DeepCopy() *VolumeGroupReplicationSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeGroupReplicationStatus) DeepCopyInto(out *VolumeGroupReplicationStatus) {
+	*out = *in
+	in.VolumeReplicationStatus.DeepCopyInto(&out.VolumeReplicationStatus)
+	if in.PersistentVolumeClaimsRefList != nil {
+		in, out := &in.PersistentVolumeClaimsRefList, &out.PersistentVolumeClaimsRefList
+		*out = make([]corev1.LocalObjectReference, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeGroupReplicationStatus.
+func (in *VolumeGroupReplicationStatus) DeepCopy() *VolumeGroupReplicationStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeGroupReplicationStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplication) DeepCopyInto(out *VolumeReplication) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplication.
+func (in *VolumeReplication) DeepCopy() *VolumeReplication {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplication)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeReplication) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationClass) DeepCopyInto(out *VolumeReplicationClass) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationClass.
+func (in *VolumeReplicationClass) DeepCopy() *VolumeReplicationClass {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationClass)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeReplicationClass) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationClassList) DeepCopyInto(out *VolumeReplicationClassList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]VolumeReplicationClass, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationClassList.
+func (in *VolumeReplicationClassList) DeepCopy() *VolumeReplicationClassList {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationClassList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeReplicationClassList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationClassSpec) DeepCopyInto(out *VolumeReplicationClassSpec) {
+	*out = *in
+	if in.Parameters != nil {
+		in, out := &in.Parameters, &out.Parameters
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationClassSpec.
+func (in *VolumeReplicationClassSpec) DeepCopy() *VolumeReplicationClassSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationClassSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationClassStatus) DeepCopyInto(out *VolumeReplicationClassStatus) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationClassStatus.
+func (in *VolumeReplicationClassStatus) DeepCopy() *VolumeReplicationClassStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationClassStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationList) DeepCopyInto(out *VolumeReplicationList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]VolumeReplication, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationList.
+func (in *VolumeReplicationList) DeepCopy() *VolumeReplicationList {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *VolumeReplicationList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationSpec) DeepCopyInto(out *VolumeReplicationSpec) {
+	*out = *in
+	in.DataSource.DeepCopyInto(&out.DataSource)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationSpec.
+func (in *VolumeReplicationSpec) DeepCopy() *VolumeReplicationSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VolumeReplicationStatus) DeepCopyInto(out *VolumeReplicationStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]v1.Condition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	if in.LastStartTime != nil {
+		in, out := &in.LastStartTime, &out.LastStartTime
+		*out = (*in).DeepCopy()
+	}
+	if in.LastCompletionTime != nil {
+		in, out := &in.LastCompletionTime, &out.LastCompletionTime
+		*out = (*in).DeepCopy()
+	}
+	if in.LastSyncTime != nil {
+		in, out := &in.LastSyncTime, &out.LastSyncTime
+		*out = (*in).DeepCopy()
+	}
+	if in.LastSyncBytes != nil {
+		in, out := &in.LastSyncBytes, &out.LastSyncBytes
+		*out = new(int64)
+		**out = **in
+	}
+	if in.LastSyncDuration != nil {
+		in, out := &in.LastSyncDuration, &out.LastSyncDuration
+		*out = new(v1.Duration)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeReplicationStatus.
+func (in *VolumeReplicationStatus) DeepCopy() *VolumeReplicationStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(VolumeReplicationStatus)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 16e913915..e0b161b99 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -265,6 +265,9 @@ github.com/coreos/go-semver/semver
 github.com/coreos/go-systemd/v22/daemon
 github.com/coreos/go-systemd/v22/dbus
 github.com/coreos/go-systemd/v22/journal
+# github.com/csi-addons/kubernetes-csi-addons v0.9.0
+## explicit; go 1.22.0
+github.com/csi-addons/kubernetes-csi-addons/api/replication.storage/v1alpha1
 # github.com/csi-addons/spec v0.2.1-0.20241104111131-27825f744db5
 ## explicit
 github.com/csi-addons/spec/lib/go/encryptionkeyrotation
@@ -2067,6 +2070,7 @@ sigs.k8s.io/controller-runtime/pkg/metrics/server
 sigs.k8s.io/controller-runtime/pkg/predicate
 sigs.k8s.io/controller-runtime/pkg/reconcile
 sigs.k8s.io/controller-runtime/pkg/recorder
+sigs.k8s.io/controller-runtime/pkg/scheme
 sigs.k8s.io/controller-runtime/pkg/source
 sigs.k8s.io/controller-runtime/pkg/webhook
 sigs.k8s.io/controller-runtime/pkg/webhook/admission
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
new file mode 100644
index 000000000..55ebe2177
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
@@ -0,0 +1,93 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package scheme contains utilities for gradually building Schemes,
+// which contain information associating Go types with Kubernetes
+// groups, versions, and kinds.
+//
+// Each API group should define a utility function
+// called AddToScheme for adding its types to a Scheme:
+//
+//	 // in package myapigroupv1...
+//	var (
+//		SchemeGroupVersion = schema.GroupVersion{Group: "my.api.group", Version: "v1"}
+//		SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
+//		AddToScheme = SchemeBuilder.AddToScheme
+//	)
+//
+//	func init() {
+//		SchemeBuilder.Register(&MyType{}, &MyTypeList)
+//	}
+//	var (
+//		scheme *runtime.Scheme = runtime.NewScheme()
+//	)
+//
+// This also true of the built-in Kubernetes types.  Then, in the entrypoint for
+// your manager, assemble the scheme containing exactly the types you need,
+// panicing if scheme registration failed. For instance, if our controller needs
+// types from the core/v1 API group (e.g. Pod), plus types from my.api.group/v1:
+//
+//	func init() {
+//		utilruntime.Must(myapigroupv1.AddToScheme(scheme))
+//		utilruntime.Must(kubernetesscheme.AddToScheme(scheme))
+//	}
+//
+//	func main() {
+//		mgr := controllers.NewManager(context.Background(), controllers.GetConfigOrDie(), manager.Options{
+//			Scheme: scheme,
+//		})
+//		// ...
+//	}
+package scheme
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds.
+type Builder struct {
+	GroupVersion schema.GroupVersion
+	runtime.SchemeBuilder
+}
+
+// Register adds one or more objects to the SchemeBuilder so they can be added to a Scheme.  Register mutates bld.
+func (bld *Builder) Register(object ...runtime.Object) *Builder {
+	bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
+		scheme.AddKnownTypes(bld.GroupVersion, object...)
+		metav1.AddToGroupVersion(scheme, bld.GroupVersion)
+		return nil
+	})
+	return bld
+}
+
+// RegisterAll registers all types from the Builder argument.  RegisterAll mutates bld.
+func (bld *Builder) RegisterAll(b *Builder) *Builder {
+	bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...)
+	return bld
+}
+
+// AddToScheme adds all registered types to s.
+func (bld *Builder) AddToScheme(s *runtime.Scheme) error {
+	return bld.SchemeBuilder.AddToScheme(s)
+}
+
+// Build returns a new Scheme containing the registered types.
+func (bld *Builder) Build() (*runtime.Scheme, error) {
+	s := runtime.NewScheme()
+	return s, bld.AddToScheme(s)
+}