@@ -32,6 +32,7 @@ import (
32
32
"github.com/red-hat-storage/ocs-client-operator/pkg/utils"
33
33
34
34
"github.com/go-logr/logr"
35
+ groupsnapapi "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumegroupsnapshot/v1alpha1"
35
36
snapapi "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1"
36
37
providerclient "github.com/red-hat-storage/ocs-operator/v4/services/provider/client"
37
38
corev1 "k8s.io/api/core/v1"
@@ -110,6 +111,7 @@ func (r *StorageClaimReconciler) SetupWithManager(mgr ctrl.Manager) error {
110
111
For (& v1alpha1.StorageClaim {}, builder .WithPredicates (predicate.GenerationChangedPredicate {})).
111
112
Owns (& storagev1.StorageClass {}).
112
113
Owns (& snapapi.VolumeSnapshotClass {}).
114
+ Owns (& groupsnapapi.VolumeGroupSnapshotClass {}).
113
115
Complete (r )
114
116
}
115
117
@@ -119,6 +121,7 @@ func (r *StorageClaimReconciler) SetupWithManager(mgr ctrl.Manager) error {
119
121
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;delete
120
122
//+kubebuilder:rbac:groups=storage.k8s.io,resources=storageclasses,verbs=get;list;watch;create;update;patch;delete
121
123
//+kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotclasses,verbs=get;list;watch;create;delete
124
+ //+kubebuilder:rbac:groups=groupsnapshot.storage.k8s.io,resources=volumegroupsnapshotclasses,verbs=get;list;watch;create;delete
122
125
//+kubebuilder:rbac:groups=core,resources=persistentvolumes,verbs=get;list;watch
123
126
//+kubebuilder:rbac:groups=snapshot.storage.k8s.io,resources=volumesnapshotcontents,verbs=get;list;watch
124
127
@@ -327,12 +330,14 @@ func (r *StorageClaimReconciler) reconcilePhases() (reconcile.Result, error) {
327
330
// Go over the received objects and operate on them accordingly.
328
331
for _ , resource := range resources {
329
332
data := map [string ]string {}
333
+ labels := map [string ]string {}
330
334
err = json .Unmarshal (resource .Data , & data )
331
335
if err != nil {
332
336
return reconcile.Result {}, fmt .Errorf ("failed to unmarshal StorageClaim configuration response: %v" , err )
333
337
}
334
338
335
339
// Create the received resources, if necessary.
340
+ storageID := getMD5Hash (string (r .storageClaim .UID )) + r .storageClaimHash
336
341
switch resource .Kind {
337
342
case "Secret" :
338
343
secret := & corev1.Secret {}
@@ -398,6 +403,8 @@ func (r *StorageClaimReconciler) reconcilePhases() (reconcile.Result, error) {
398
403
// storageclaim is clusterscoped resources using its
399
404
// hash as the clusterID
400
405
data ["clusterID" ] = r .storageClaimHash
406
+ labels ["ramendr.openshift.io/replicationID" ] = r .storageClaimHash
407
+ labels ["ramendr.openshift.io/storageID" ] = storageID
401
408
if resource .Name == "cephfs" {
402
409
volumeSnapshotClass = r .getCephFSVolumeSnapshotClass (data )
403
410
} else if resource .Name == "ceph-rbd" {
@@ -407,6 +414,24 @@ func (r *StorageClaimReconciler) reconcilePhases() (reconcile.Result, error) {
407
414
if err := r .createOrReplaceVolumeSnapshotClass (volumeSnapshotClass ); err != nil {
408
415
return reconcile.Result {}, fmt .Errorf ("failed to create or update VolumeSnapshotClass: %s" , err )
409
416
}
417
+ case "VolumeGroupSnapshotClass" :
418
+ var volumeGroupSnapshotClass * groupsnapapi.VolumeGroupSnapshotClass
419
+ data ["csi.storage.k8s.io/snapshotter-secret-namespace" ] = r .OperatorNamespace
420
+ // generate a new clusterID for cephfs subvolumegroup, as
421
+ // storageclaim is clusterscoped resources using its
422
+ // hash as the clusterID
423
+ data ["clusterID" ] = r .storageClaimHash
424
+ labels ["ramendr.openshift.io/replicationID" ] = r .storageClaimHash
425
+ labels ["ramendr.openshift.io/storageID" ] = storageID
426
+ if resource .Name == "cephfs" {
427
+ volumeGroupSnapshotClass = r .getCephFSVolumeGroupSnapshotClass (data , labels )
428
+ } else if resource .Name == "ceph-rbd" {
429
+ volumeGroupSnapshotClass = r .getCephRBDVolumeGroupSnapshotClass (data , labels )
430
+ }
431
+ utils .AddAnnotation (volumeGroupSnapshotClass , storageClaimAnnotation , r .storageClaim .Name )
432
+ if err := r .createOrReplaceVolumeGroupSnapshotClass (volumeGroupSnapshotClass ); err != nil {
433
+ return reconcile.Result {}, fmt .Errorf ("failed to create or update volumeGroupSnapshot: %s" , err )
434
+ }
410
435
}
411
436
}
412
437
@@ -651,6 +676,68 @@ func (r *StorageClaimReconciler) hasVolumeSnapshotContents() (bool, error) {
651
676
return false , nil
652
677
}
653
678
679
+ func (r * StorageClaimReconciler ) getCephFSVolumeGroupSnapshotClass (data map [string ]string , labels map [string ]string ) * groupsnapapi.VolumeGroupSnapshotClass {
680
+ volumgroupesnapshotclass := & groupsnapapi.VolumeGroupSnapshotClass {
681
+ ObjectMeta : metav1.ObjectMeta {
682
+ Name : r .storageClaim .Name ,
683
+ Labels : labels ,
684
+ },
685
+ Driver : csi .GetCephFSDriverName (),
686
+ DeletionPolicy : snapapi .VolumeSnapshotContentDelete ,
687
+ Parameters : data ,
688
+ }
689
+ return volumgroupesnapshotclass
690
+ }
691
+
692
+ func (r * StorageClaimReconciler ) getCephRBDVolumeGroupSnapshotClass (data map [string ]string , labels map [string ]string ) * groupsnapapi.VolumeGroupSnapshotClass {
693
+ volumegroupsnapshotclass := & groupsnapapi.VolumeGroupSnapshotClass {
694
+ ObjectMeta : metav1.ObjectMeta {
695
+ Name : r .storageClaim .Name ,
696
+ Labels : labels ,
697
+ },
698
+ Driver : csi .GetRBDDriverName (),
699
+ DeletionPolicy : snapapi .VolumeSnapshotContentDelete ,
700
+ Parameters : data ,
701
+ }
702
+ return volumegroupsnapshotclass
703
+ }
704
+
705
+ func (r * StorageClaimReconciler ) createOrReplaceVolumeGroupSnapshotClass (volumeGroupSnapshotClass * groupsnapapi.VolumeGroupSnapshotClass ) error {
706
+ existing := & groupsnapapi.VolumeGroupSnapshotClass {}
707
+ existing .Name = r .storageClaim .Name
708
+
709
+ if err := r .own (volumeGroupSnapshotClass ); err != nil {
710
+ return fmt .Errorf ("failed to own volumegroupsnapshotclass: %v" , err )
711
+ }
712
+
713
+ if err := r .get (existing ); err != nil && ! errors .IsNotFound (err ) {
714
+ return fmt .Errorf ("failed to get VolumeGroupSnapshotClass: %v" , err )
715
+ }
716
+
717
+ // If present then compare the existing VolumeGroupSnapshotClass parameters with
718
+ // the received VolumeGroupSnapshotClass parameters, and only proceed if they differ.
719
+ if reflect .DeepEqual (existing .Parameters , volumeGroupSnapshotClass .Parameters ) {
720
+ return nil
721
+ }
722
+
723
+ // VolumeGroupSnapshotClass already exists, but parameters have changed. Delete the existing VolumeGroupSnapshotClass and create a new one.
724
+ if existing .UID != "" {
725
+ // Since we have to update the existing VolumeGroupSnapshotClass, so we will delete the existing VolumeGroupSnapshotClass and create a new one.
726
+ r .log .Info ("VolumeGroupSnapshotClass needs to be updated, deleting it." , "Name" , existing .Name )
727
+
728
+ // Delete the VolumeGroupSnapshotClass.
729
+ if err := r .delete (existing ); err != nil {
730
+ r .log .Error (err , "Failed to delete VolumeGroupSnapshotClass." , "Name" , existing .Name )
731
+ return fmt .Errorf ("failed to delete VolumeGroupSnapshotClass: %v" , err )
732
+ }
733
+ }
734
+ r .log .Info ("Creating VolumeGroupSnapshotClass." , "Name" , existing .Name )
735
+ if err := r .Client .Create (r .ctx , volumeGroupSnapshotClass ); err != nil {
736
+ return fmt .Errorf ("failed to create VolumeGroupSnapshotClass: %v" , err )
737
+ }
738
+ return nil
739
+ }
740
+
654
741
func getMD5Hash (text string ) string {
655
742
hash := md5 .Sum ([]byte (text ))
656
743
return hex .EncodeToString (hash [:])
0 commit comments