@@ -18,6 +18,7 @@ package csi
18
18
19
19
import (
20
20
"encoding/json"
21
+ "errors"
21
22
"fmt"
22
23
"math"
23
24
"reflect"
@@ -477,6 +478,11 @@ func (s *OsdCsiServer) CreateVolume(
477
478
return nil , status .Error (codes .InvalidArgument , "Name must be provided" )
478
479
}
479
480
481
+ if req .VolumeContentSource != nil && req .VolumeContentSource .GetSnapshot () != nil {
482
+ clogger .WithContext (ctx ).Infof ("csi.CreateVolume restoring snapshot to Volume: %s" , req .GetName ())
483
+ return s .restoreSnapshot (ctx , req )
484
+ }
485
+
480
486
// Get parameters
481
487
spec , locator , source , err := s .specHandler .SpecFromOpts (req .GetParameters ())
482
488
if err != nil {
@@ -632,6 +638,88 @@ func (s *OsdCsiServer) CreateVolume(
632
638
}, nil
633
639
}
634
640
641
+ func (s * OsdCsiServer ) restoreSnapshot (ctx context.Context ,
642
+ req * csi.CreateVolumeRequest ,
643
+ ) (resp * csi.CreateVolumeResponse , err error ) {
644
+ snapshot := req .VolumeContentSource .GetSnapshot ()
645
+ if snapshot == nil {
646
+ return nil , errors .New ("snapshot fetched is not accurate or does not exist" )
647
+ }
648
+
649
+ cloudBackupClient , err := s .getCloudBackupClient (ctx )
650
+ cloudBackupClientAvailable := cloudBackupClient != nil
651
+ cloudBackupDriverDisabled := sdk .IsErrorUnavailable (err )
652
+ if (err != nil && ! cloudBackupDriverDisabled ) || cloudBackupClient == nil {
653
+ return nil , err
654
+ }
655
+
656
+ csiSnapshotID := snapshot .GetSnapshotId ()
657
+ if len (csiSnapshotID ) == 0 {
658
+ return nil , status .Error (codes .InvalidArgument , "Snapshot id must be provided" )
659
+ }
660
+
661
+ var backupStatus * api.SdkCloudBackupStatusResponse
662
+ if cloudBackupClientAvailable && ! cloudBackupDriverDisabled {
663
+ // Check if snapshot has been created but is in error state
664
+ backupStatus , err = cloudBackupClient .Status (ctx , & api.SdkCloudBackupStatusRequest {
665
+ TaskId : csiSnapshotID ,
666
+ })
667
+ }
668
+
669
+ isSnapshotIDPresentInCloud := true
670
+ if backupStatus != nil {
671
+ _ , isSnapshotIDPresentInCloud = backupStatus .Statuses [csiSnapshotID ]
672
+ }
673
+
674
+ if (sdk .IsErrorNotFound (err ) && ! cloudBackupDriverDisabled && cloudBackupClientAvailable ) || ! isSnapshotIDPresentInCloud {
675
+
676
+ return
677
+ }
678
+
679
+ resp , err = s .restoreCloudSnapshot (ctx , req )
680
+ return
681
+
682
+ }
683
+
684
+ func (s * OsdCsiServer ) restoreCloudSnapshot (ctx context.Context ,
685
+ req * csi.CreateVolumeRequest ,
686
+ ) (resp * csi.CreateVolumeResponse , err error ) {
687
+ cloudBackupClient , err := s .getCloudBackupClient (ctx )
688
+ if err != nil {
689
+ return nil , err
690
+ }
691
+ // Get parameters
692
+ _ , locator , _ , err := s .specHandler .SpecFromOpts (req .GetParameters ())
693
+ if err != nil {
694
+ e := fmt .Sprintf ("Unable to get parameters: %s\n " , err .Error ())
695
+ clogger .WithContext (ctx ).Errorln (e )
696
+ return nil , status .Error (codes .InvalidArgument , e )
697
+ }
698
+
699
+ csiSnapshotID := req .VolumeContentSource .GetSnapshot ().GetSnapshotId ()
700
+
701
+ credentialID := locator .VolumeLabels [osdSnapshotCredentialIDKey ]
702
+
703
+ snapResp , err := cloudBackupClient .Restore (ctx , & api.SdkCloudBackupRestoreRequest {
704
+ BackupId : csiSnapshotID ,
705
+ RestoreVolumeName : req .GetName (),
706
+ TaskId : req .GetName (),
707
+ Locator : locator ,
708
+ CredentialId : credentialID ,
709
+ })
710
+ if nil != err {
711
+ return nil , err
712
+ }
713
+
714
+ resp = & csi.CreateVolumeResponse {
715
+ Volume : & csi.Volume {
716
+ VolumeId : snapResp .GetRestoreVolumeId (),
717
+ ContentSource : req .VolumeContentSource ,
718
+ },
719
+ }
720
+ return
721
+ }
722
+
635
723
func getClonedPVCMetadata (locator * api.VolumeLocator ) map [string ]string {
636
724
metadataLabels := map [string ]string {}
637
725
pvcName , ok := locator .VolumeLabels [intreePvcNameKey ]
0 commit comments