@@ -26,6 +26,8 @@ import (
26
26
27
27
volumehelper "sigs.k8s.io/azurefile-csi-driver/pkg/util"
28
28
29
+ "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/sas"
30
+ "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service"
29
31
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage"
30
32
"github.com/Azure/azure-storage-file-go/azfile"
31
33
"github.com/container-storage-interface/spec/lib/go/csi"
@@ -104,6 +106,11 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
104
106
}
105
107
106
108
if acquired := d .volumeLocks .TryAcquire (volName ); ! acquired {
109
+ // logging the job status if it's volume cloning
110
+ if req .GetVolumeContentSource () != nil {
111
+ jobState , percent , err := getAzcopyJob (volName )
112
+ klog .V (2 ).Infof ("azcopy job status: %s, copy percent: %s%%, error: %v" , jobState , percent , err )
113
+ }
107
114
return nil , status .Errorf (codes .Aborted , volumeOperationAlreadyExistsFmt , volName )
108
115
}
109
116
defer d .volumeLocks .Release (volName )
@@ -516,7 +523,16 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
516
523
}
517
524
518
525
var volumeID string
519
- mc := metrics .NewMetricContext (azureFileCSIDriverName , "controller_create_volume" , d .cloud .ResourceGroup , subsID , d .Name )
526
+ requestName := "controller_create_volume"
527
+ if req .GetVolumeContentSource () != nil {
528
+ switch req .VolumeContentSource .Type .(type ) {
529
+ case * csi.VolumeContentSource_Snapshot :
530
+ requestName = "controller_create_volume_from_snapshot"
531
+ case * csi.VolumeContentSource_Volume :
532
+ requestName = "controller_create_volume_from_volume"
533
+ }
534
+ }
535
+ mc := metrics .NewMetricContext (azureFileCSIDriverName , requestName , d .cloud .ResourceGroup , subsID , d .Name )
520
536
isOperationSucceeded := false
521
537
defer func () {
522
538
mc .ObserveOperationWithResult (isOperationSucceeded , VolumeID , volumeID )
@@ -543,9 +559,20 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
543
559
}
544
560
return nil , status .Errorf (codes .Internal , "failed to create file share(%s) on account(%s) type(%s) subsID(%s) rg(%s) location(%s) size(%d), error: %v" , validFileShareName , account , sku , subsID , resourceGroup , location , fileShareSize , err )
545
561
}
562
+ if req .GetVolumeContentSource () != nil {
563
+ accountKeyCopy , err := d .GetStorageAccesskey (ctx , accountOptions , req .GetSecrets (), secretName , secretNamespace )
564
+ if err != nil {
565
+ return nil , status .Errorf (codes .Internal , "failed to GetStorageAccesskey on account(%s) rg(%s), error: %v" , accountOptions .Name , accountOptions .ResourceGroup , err )
566
+ }
567
+ if err := d .copyVolume (ctx , req , accountKeyCopy , shareOptions , storageEndpointSuffix ); err != nil {
568
+ return nil , err
569
+ }
570
+ // storeAccountKey is not needed here since copy volume is only using SAS token
571
+ storeAccountKey = false
572
+ }
546
573
klog .V (2 ).Infof ("create file share %s on storage account %s successfully" , validFileShareName , accountName )
547
574
548
- if isDiskFsType (fsType ) && ! strings .HasSuffix (diskName , vhdSuffix ) {
575
+ if isDiskFsType (fsType ) && ! strings .HasSuffix (diskName , vhdSuffix ) && req . GetVolumeContentSource () == nil {
549
576
if accountKey == "" {
550
577
if accountKey , err = d .GetStorageAccesskey (ctx , accountOptions , req .GetSecrets (), secretName , secretNamespace ); err != nil {
551
578
return nil , status .Errorf (codes .Internal , "failed to GetStorageAccesskey on account(%s) rg(%s), error: %v" , accountOptions .Name , accountOptions .ResourceGroup , err )
@@ -619,6 +646,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
619
646
VolumeId : volumeID ,
620
647
CapacityBytes : capacityBytes ,
621
648
VolumeContext : parameters ,
649
+ ContentSource : req .GetVolumeContentSource (),
622
650
},
623
651
}, nil
624
652
}
@@ -686,6 +714,18 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
686
714
return & csi.DeleteVolumeResponse {}, nil
687
715
}
688
716
717
+ func (d * Driver ) copyVolume (ctx context.Context , req * csi.CreateVolumeRequest , accountKey string , shareOptions * fileclient.ShareOptions , storageEndpointSuffix string ) error {
718
+ vs := req .VolumeContentSource
719
+ switch vs .Type .(type ) {
720
+ case * csi.VolumeContentSource_Snapshot :
721
+ return status .Errorf (codes .InvalidArgument , "copy volume from volumeSnapshot is not supported" )
722
+ case * csi.VolumeContentSource_Volume :
723
+ return d .copyFileShare (ctx , req , accountKey , shareOptions , storageEndpointSuffix )
724
+ default :
725
+ return status .Errorf (codes .InvalidArgument , "%v is not a proper volume source" , vs )
726
+ }
727
+ }
728
+
689
729
// ControllerGetVolume get volume
690
730
func (d * Driver ) ControllerGetVolume (context.Context , * csi.ControllerGetVolumeRequest ) (* csi.ControllerGetVolumeResponse , error ) {
691
731
return nil , status .Error (codes .Unimplemented , "" )
@@ -1243,3 +1283,27 @@ func isValidVolumeCapabilities(volCaps []*csi.VolumeCapability) error {
1243
1283
}
1244
1284
return nil
1245
1285
}
1286
+
1287
+ func generateSASToken (accountName , accountKey , storageEndpointSuffix string , expiryTime int ) (string , error ) {
1288
+ credential , err := service .NewSharedKeyCredential (accountName , accountKey )
1289
+ if err != nil {
1290
+ return "" , status .Errorf (codes .Internal , fmt .Sprintf ("failed to generate sas token in creating new shared key credential, accountName: %s, err: %s" , accountName , err .Error ()))
1291
+ }
1292
+ serviceClient , err := service .NewClientWithSharedKeyCredential (fmt .Sprintf ("https://%s.file.%s/" , accountName , storageEndpointSuffix ), credential , nil )
1293
+ if err != nil {
1294
+ return "" , status .Errorf (codes .Internal , fmt .Sprintf ("failed to generate sas token in creating new client with shared key credential, accountName: %s, err: %s" , accountName , err .Error ()))
1295
+ }
1296
+ nowTime := time .Now ()
1297
+ sasURL , err := serviceClient .GetSASURL (
1298
+ sas.AccountResourceTypes {Object : true , Service : true , Container : true },
1299
+ sas.AccountPermissions {Read : true , List : true , Write : true },
1300
+ time .Now ().Add (time .Duration (expiryTime )* time .Minute ), & service.GetSASURLOptions {StartTime : & nowTime })
1301
+ if err != nil {
1302
+ return "" , err
1303
+ }
1304
+ u , err := url .Parse (sasURL )
1305
+ if err != nil {
1306
+ return "" , err
1307
+ }
1308
+ return "?" + u .RawQuery , nil
1309
+ }
0 commit comments