@@ -18,6 +18,7 @@ package common_controller
18
18
19
19
import (
20
20
"context"
21
+ "crypto/sha256"
21
22
"fmt"
22
23
"time"
23
24
@@ -459,16 +460,24 @@ func (ctrl *csiSnapshotCommonController) syncUnreadyGroupSnapshot(groupSnapshot
459
460
return fmt .Errorf ("VolumeGroupSnapshotHandle should not be set in the group snapshot content for dynamic provisioning for group snapshot %s" , uniqueGroupSnapshotName )
460
461
}
461
462
462
- newGroupSnapshot , err := ctrl .bindandUpdateVolumeGroupSnapshot (contentObj , groupSnapshot )
463
+ // TODO(leonardoce): introduce a current context in this function
464
+ newGroupSnapshotContentObj , err := ctrl .createSnapshotsForGroupSnapshotContent (context .TODO (), contentObj , groupSnapshot )
465
+ if err != nil {
466
+ klog .V (4 ).Infof ("createSnapshotsForGroupSnapshotContent[%s]: failed to create snapshots and snapshotcontents for group snapshot %v: %v" ,
467
+ contentObj .Name , groupSnapshot .Name , err .Error ())
468
+ return err
469
+ }
470
+
471
+ updatedGroupSnapshot , err := ctrl .bindandUpdateVolumeGroupSnapshot (newGroupSnapshotContentObj , groupSnapshot )
463
472
if err != nil {
464
473
klog .V (4 ).Infof ("bindandUpdateVolumeGroupSnapshot[%s]: failed to bind group snapshot content [%s] to group snapshot %v" , uniqueGroupSnapshotName , contentObj .Name , err )
465
474
return err
466
475
}
467
- klog .V (5 ).Infof ("bindandUpdateVolumeGroupSnapshot %v" , newGroupSnapshot )
476
+ klog .V (5 ).Infof ("bindandUpdateVolumeGroupSnapshot %v" , updatedGroupSnapshot )
468
477
return nil
469
478
}
470
479
471
- // If we reach here, it is a dynamically provisioned group snapshot, and the VolumeGroupSnapshotContent object is not yet created.
480
+ // If reach here, it is a dynamically provisioned group snapshot, and the VolumeGroupSnapshotContent object is not yet created.
472
481
var groupSnapshotContent * crdv1alpha1.VolumeGroupSnapshotContent
473
482
if groupSnapshotContent , err = ctrl .createGroupSnapshotContent (groupSnapshot ); err != nil {
474
483
ctrl .updateGroupSnapshotErrorStatusWithEvent (groupSnapshot , true , v1 .EventTypeWarning , "GroupSnapshotContentCreationFailed" , fmt .Sprintf ("failed to create group snapshot content with error %v" , err ))
@@ -485,6 +494,182 @@ func (ctrl *csiSnapshotCommonController) syncUnreadyGroupSnapshot(groupSnapshot
485
494
return nil
486
495
}
487
496
497
+ func (ctrl * csiSnapshotCommonController ) createSnapshotsForGroupSnapshotContent (
498
+ ctx context.Context ,
499
+ groupSnapshotContent * crdv1alpha1.VolumeGroupSnapshotContent ,
500
+ groupSnapshot * crdv1alpha1.VolumeGroupSnapshot ,
501
+ ) (* crdv1alpha1.VolumeGroupSnapshotContent , error ) {
502
+ // No status is present, or no volume snapshot was provisioned.
503
+ // Let's wait for the snapshotter sidecar to fill it.
504
+ if groupSnapshotContent .Status == nil || len (groupSnapshotContent .Status .VolumeSnapshotHandlePairList ) == 0 {
505
+ return groupSnapshotContent , nil
506
+ }
507
+
508
+ // The contents of the volume group snapshot class are needed to set the
509
+ // metadata containing the secrets to recover the snapshots
510
+ if groupSnapshot .Spec .VolumeGroupSnapshotClassName == nil {
511
+ return groupSnapshotContent , fmt .Errorf (
512
+ "createSnapshotsForGroupSnapshotContent: internal error: cannot find reference to volume group snapshot class" )
513
+ }
514
+
515
+ groupSnapshotClass , err := ctrl .groupSnapshotClassLister .Get (* groupSnapshot .Spec .VolumeGroupSnapshotClassName )
516
+ if err != nil {
517
+ return groupSnapshotContent , fmt .Errorf (
518
+ "createSnapshotsForGroupSnapshotContent: failed to get volume snapshot class %s: %q" ,
519
+ * groupSnapshot .Spec .VolumeGroupSnapshotClassName , err )
520
+ }
521
+
522
+ groupSnapshotSecret , err := utils .GetGroupSnapshotSecretReference (
523
+ utils .GroupSnapshotterSecretParams ,
524
+ groupSnapshotClass .Parameters ,
525
+ groupSnapshotContent .GetObjectMeta ().GetName (), nil )
526
+ if err != nil {
527
+ return groupSnapshotContent , fmt .Errorf (
528
+ "createSnapshotsForGroupSnapshotContent: failed to get secret reference for group snapshot content %s: %v" ,
529
+ groupSnapshotContent .Name , err )
530
+ }
531
+
532
+ // TODO(leonardoce): this API server call is very expensive. We need to introduce a
533
+ // PV lister on the controller and an indexer on spec.csi.driver + "^" + spec.csi.volumeHandle
534
+ // to be used for fast lookups
535
+ pvs , err := ctrl .client .CoreV1 ().PersistentVolumes ().List (context .TODO (), metav1.ListOptions {})
536
+ if err != nil {
537
+ return groupSnapshotContent , fmt .Errorf ("createSnapshotsForGroupSnapshotContent: error get PersistentVolumes list from API server: %v" , err )
538
+ }
539
+
540
+ // Phase 1: create the VolumeSnapshotContent and VolumeSnapshot objects
541
+ klog .V (4 ).Infof (
542
+ "createSnapshotsForGroupSnapshotContent[%s]: creating volumesnapshots and volumesnapshotcontent for group snapshot content" ,
543
+ groupSnapshotContent .Name )
544
+
545
+ groupSnapshotContent .Status .PVVolumeSnapshotContentList = make (
546
+ []crdv1alpha1.PVVolumeSnapshotContentPair ,
547
+ len (groupSnapshotContent .Status .VolumeSnapshotHandlePairList ),
548
+ )
549
+ for i , snapshot := range groupSnapshotContent .Status .VolumeSnapshotHandlePairList {
550
+ snapshotHandle := snapshot .SnapshotHandle
551
+ volumeHandle := snapshot .VolumeHandle
552
+
553
+ pv := utils .GetPersistentVolumeFromHandle (pvs , groupSnapshotContent .Spec .Driver , volumeHandle )
554
+ if pv == nil {
555
+ klog .Errorf (
556
+ "updateGroupSnapshotContentStatus: unable to find PV for volumeHandle:[%s] and CSI driver:[%s]" ,
557
+ volumeHandle ,
558
+ groupSnapshotContent .Spec .Driver )
559
+ }
560
+
561
+ volumeSnapshotContentName := getSnapshotContentNameForVolumeGroupSnapshotContent (
562
+ string (groupSnapshotContent .UID ), volumeHandle )
563
+
564
+ volumeSnapshotName := getSnapshotNameForVolumeGroupSnapshotContent (
565
+ string (groupSnapshotContent .UID ), volumeHandle )
566
+
567
+ volumeSnapshotNamespace := groupSnapshotContent .Spec .VolumeGroupSnapshotRef .Namespace
568
+
569
+ volumeSnapshotContent := & crdv1.VolumeSnapshotContent {
570
+ ObjectMeta : metav1.ObjectMeta {
571
+ Name : volumeSnapshotContentName ,
572
+ },
573
+ Spec : crdv1.VolumeSnapshotContentSpec {
574
+ VolumeSnapshotRef : v1.ObjectReference {
575
+ Kind : "VolumeSnapshot" ,
576
+ Name : volumeSnapshotName ,
577
+ Namespace : volumeSnapshotNamespace ,
578
+ },
579
+ DeletionPolicy : groupSnapshotContent .Spec .DeletionPolicy ,
580
+ Driver : groupSnapshotContent .Spec .Driver ,
581
+ Source : crdv1.VolumeSnapshotContentSource {
582
+ SnapshotHandle : & snapshotHandle ,
583
+ },
584
+ },
585
+ // The status will be set by VolumeSnapshotContent reconciler
586
+ // in the CSI snapshotter sidecar.
587
+ }
588
+
589
+ if pv != nil {
590
+ volumeSnapshotContent .Spec .SourceVolumeMode = pv .Spec .VolumeMode
591
+ }
592
+
593
+ if groupSnapshotSecret != nil {
594
+ klog .V (5 ).Infof ("createSnapshotsForGroupSnapshotContent: set annotation [%s] on volume snapshot content [%s]." , utils .AnnDeletionSecretRefName , volumeSnapshotContent .Name )
595
+ metav1 .SetMetaDataAnnotation (& volumeSnapshotContent .ObjectMeta , utils .AnnDeletionSecretRefName , groupSnapshotSecret .Name )
596
+
597
+ klog .V (5 ).Infof ("createSnapshotsForGroupSnapshotContent: set annotation [%s] on volume snapshot content [%s]." , utils .AnnDeletionSecretRefNamespace , volumeSnapshotContent .Name )
598
+ metav1 .SetMetaDataAnnotation (& volumeSnapshotContent .ObjectMeta , utils .AnnDeletionSecretRefNamespace , groupSnapshotSecret .Namespace )
599
+ }
600
+
601
+ label := make (map [string ]string )
602
+ label [utils .VolumeGroupSnapshotNameLabel ] = groupSnapshotContent .Spec .VolumeGroupSnapshotRef .Name
603
+ volumeSnapshot := & crdv1.VolumeSnapshot {
604
+ ObjectMeta : metav1.ObjectMeta {
605
+ Name : volumeSnapshotName ,
606
+ Namespace : volumeSnapshotNamespace ,
607
+ Labels : label ,
608
+ Finalizers : []string {utils .VolumeSnapshotInGroupFinalizer },
609
+ },
610
+ Spec : crdv1.VolumeSnapshotSpec {
611
+ Source : crdv1.VolumeSnapshotSource {
612
+ VolumeSnapshotContentName : & volumeSnapshotContentName ,
613
+ },
614
+ },
615
+ // The status will be set by VolumeSnapshot reconciler
616
+ }
617
+
618
+ _ , err := ctrl .clientset .SnapshotV1 ().VolumeSnapshotContents ().Create (ctx , volumeSnapshotContent , metav1.CreateOptions {})
619
+ if err != nil && ! apierrs .IsAlreadyExists (err ) {
620
+ return groupSnapshotContent , fmt .Errorf (
621
+ "createSnapshotsForGroupSnapshotContent: creating volumesnapshotcontent %w" , err )
622
+ }
623
+
624
+ _ , err = ctrl .clientset .SnapshotV1 ().VolumeSnapshots (volumeSnapshotNamespace ).Create (ctx , volumeSnapshot , metav1.CreateOptions {})
625
+ if err != nil && ! apierrs .IsAlreadyExists (err ) {
626
+ return groupSnapshotContent , fmt .Errorf (
627
+ "createSnapshotsForGroupSnapshotContent: creating volumesnapshot %w" , err )
628
+ }
629
+
630
+ groupSnapshotContent .Status .PVVolumeSnapshotContentList [i ] = crdv1alpha1.PVVolumeSnapshotContentPair {
631
+ VolumeSnapshotContentRef : v1.LocalObjectReference {
632
+ Name : volumeSnapshotContentName ,
633
+ },
634
+ }
635
+ if pv != nil {
636
+ groupSnapshotContent .Status .PVVolumeSnapshotContentList [i ].PersistentVolumeRef = v1.LocalObjectReference {
637
+ Name : pv .Name ,
638
+ }
639
+ }
640
+ }
641
+
642
+ // Phase 2: set the backlinks
643
+ var patches []utils.PatchOp
644
+ patches = append (patches , utils.PatchOp {
645
+ Op : "replace" ,
646
+ Path : "/status/pvVolumeSnapshotContentList" ,
647
+ Value : groupSnapshotContent .Status .PVVolumeSnapshotContentList ,
648
+ })
649
+
650
+ newGroupSnapshotObj , err := utils .PatchVolumeGroupSnapshotContent (
651
+ groupSnapshotContent ,
652
+ patches ,
653
+ ctrl .clientset ,
654
+ "status" )
655
+ if err != nil {
656
+ return nil , newControllerUpdateError (utils .GroupSnapshotKey (groupSnapshot ), err .Error ())
657
+ }
658
+
659
+ return newGroupSnapshotObj , nil
660
+ }
661
+
662
+ // getSnapshotNameForVolumeGroupSnapshotContent returns a unique snapshot name for a VolumeGroupSnapshotContent.
663
+ func getSnapshotNameForVolumeGroupSnapshotContent (groupSnapshotContentUUID , volumeHandle string ) string {
664
+ return fmt .Sprintf ("snapshot-%x" , sha256 .Sum256 ([]byte (groupSnapshotContentUUID + volumeHandle )))
665
+ }
666
+
667
+ // getSnapshotContentNameForVolumeGroupSnapshotContent returns a unique content name for the
668
+ // passed in VolumeGroupSnapshotContent.
669
+ func getSnapshotContentNameForVolumeGroupSnapshotContent (groupSnapshotContentUUID , volumeHandle string ) string {
670
+ return fmt .Sprintf ("snapcontent-%x" , sha256 .Sum256 ([]byte (groupSnapshotContentUUID + volumeHandle )))
671
+ }
672
+
488
673
// getPreprovisionedGroupSnapshotContentFromStore tries to find a pre-provisioned
489
674
// volume group snapshot content object from group snapshot content cache store
490
675
// for the passed in VolumeGroupSnapshot.
0 commit comments