@@ -59,8 +59,6 @@ const (
59
59
MSI = "MSI"
60
60
SPN = "SPN"
61
61
authorizationPermissionMismatch = "AuthorizationPermissionMismatch"
62
-
63
- waitForAzCopyInterval = 2 * time .Second
64
62
)
65
63
66
64
// CreateVolume provisions a volume
@@ -79,19 +77,12 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
79
77
return nil , status .Error (codes .InvalidArgument , err .Error ())
80
78
}
81
79
82
- if acquired := d .volumeLocks .TryAcquire (volName ); ! acquired {
83
- // logging the job status if it's volume cloning
84
- if req .GetVolumeContentSource () != nil {
85
- jobState , percent , err := d .azcopy .GetAzcopyJob (volName , []string {})
86
- klog .V (2 ).Infof ("azcopy job status: %s, copy percent: %s%%, error: %v" , jobState , percent , err )
87
- }
88
- return nil , status .Errorf (codes .Aborted , volumeOperationAlreadyExistsFmt , volName )
89
- }
90
- defer d .volumeLocks .Release (volName )
91
-
92
80
volSizeBytes := int64 (req .GetCapacityRange ().GetRequiredBytes ())
93
81
requestGiB := int (util .RoundUpGiB (volSizeBytes ))
94
82
83
+ volContentSource := req .GetVolumeContentSource ()
84
+ secrets := req .GetSecrets ()
85
+
95
86
parameters := req .GetParameters ()
96
87
if parameters == nil {
97
88
parameters = make (map [string ]string )
@@ -341,10 +332,31 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
341
332
GetLatestAccountKey : getLatestAccountKey ,
342
333
}
343
334
335
+ containerName = replaceWithMap (containerName , containerNameReplaceMap )
336
+ validContainerName := containerName
337
+ if validContainerName == "" {
338
+ validContainerName = volName
339
+ if containerNamePrefix != "" {
340
+ validContainerName = containerNamePrefix + "-" + volName
341
+ }
342
+ validContainerName = getValidContainerName (validContainerName , protocol )
343
+ setKeyValueInMap (parameters , containerNameField , validContainerName )
344
+ }
345
+
346
+ if acquired := d .volumeLocks .TryAcquire (volName ); ! acquired {
347
+ // logging the job status if it's volume cloning
348
+ if volContentSource != nil {
349
+ jobState , percent , err := d .azcopy .GetAzcopyJob (validContainerName , []string {})
350
+ return nil , status .Errorf (codes .Aborted , volumeOperationAlreadyExistsWithAzcopyFmt , volName , jobState , percent , err )
351
+ }
352
+ return nil , status .Errorf (codes .Aborted , volumeOperationAlreadyExistsFmt , volName )
353
+ }
354
+ defer d .volumeLocks .Release (volName )
355
+
344
356
var volumeID string
345
357
requestName := "controller_create_volume"
346
- if req . GetVolumeContentSource () != nil {
347
- switch req . VolumeContentSource .Type .(type ) {
358
+ if volContentSource != nil {
359
+ switch volContentSource .Type .(type ) {
348
360
case * csi.VolumeContentSource_Snapshot :
349
361
requestName = "controller_create_volume_from_snapshot"
350
362
case * csi.VolumeContentSource_Volume :
@@ -357,9 +369,39 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
357
369
mc .ObserveOperationWithResult (isOperationSucceeded , VolumeID , volumeID )
358
370
}()
359
371
372
+ var srcAzcopyAuthEnv []string
373
+ var srcSubscriptionID , srcResourceGroupName , srcAccountName , srcContainerName , srcPath , srcAccountSASToken string
374
+ if volContentSource != nil {
375
+ switch volContentSource .Type .(type ) {
376
+ case * csi.VolumeContentSource_Snapshot :
377
+ return nil , status .Errorf (codes .InvalidArgument , "VolumeContentSource Snapshot is not yet implemented" )
378
+ case * csi.VolumeContentSource_Volume :
379
+ var srcVolumeID string
380
+ if volContentSource .GetVolume () != nil {
381
+ srcVolumeID = volContentSource .GetVolume ().GetVolumeId ()
382
+ }
383
+ srcResourceGroupName , srcAccountName , srcContainerName , _ , srcSubscriptionID , err = GetContainerInfo (srcVolumeID )
384
+ if err != nil {
385
+ return nil , status .Error (codes .NotFound , err .Error ())
386
+ }
387
+ srcAccountOptions := & azure.AccountOptions {
388
+ Name : srcAccountName ,
389
+ SubscriptionID : srcSubscriptionID ,
390
+ ResourceGroup : srcResourceGroupName ,
391
+ GetLatestAccountKey : getLatestAccountKey ,
392
+ }
393
+ srcAccountSASToken , srcAzcopyAuthEnv , err = d .getAzcopyAuth (ctx , srcAccountName , "" , storageEndpointSuffix , srcAccountOptions , secrets , secretName , secretNamespace )
394
+ if err != nil {
395
+ return nil , status .Errorf (codes .Internal , "failed to getAzcopyAuth on account(%s) rg(%s), error: %v" , accountOptions .Name , accountOptions .ResourceGroup , err )
396
+ }
397
+ srcPath = fmt .Sprintf ("https://%s.blob.%s/%s" , srcAccountName , storageEndpointSuffix , srcContainerName )
398
+ default :
399
+ return nil , status .Errorf (codes .InvalidArgument , "VolumeContentSource is not recognized: %v" , volContentSource )
400
+ }
401
+ }
402
+
360
403
var accountKey string
361
404
accountName := account
362
- secrets := req .GetSecrets ()
363
405
if len (secrets ) == 0 && accountName == "" {
364
406
if v , ok := d .volMap .Load (volName ); ok {
365
407
accountName = v .(string )
@@ -413,31 +455,26 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
413
455
secrets = createStorageAccountSecret (accountName , accountKey )
414
456
}
415
457
416
- // replace pv/pvc name namespace metadata in subDir
417
- containerName = replaceWithMap ( containerName , containerNameReplaceMap )
418
- validContainerName := containerName
419
- if validContainerName == "" {
420
- validContainerName = volName
421
- if containerNamePrefix != "" {
422
- validContainerName = containerNamePrefix + "-" + volName
458
+ dstAzcopyAuthEnv := srcAzcopyAuthEnv
459
+ dstAccountSASToken := srcAccountSASToken
460
+ if volContentSource != nil {
461
+ if srcSubscriptionID != subsID || srcResourceGroupName != resourceGroup || srcAccountName != accountName {
462
+ if dstAccountSASToken , dstAzcopyAuthEnv , err = d . getAzcopyAuth ( ctx , accountName , accountKey , storageEndpointSuffix , accountOptions , secrets , secretName , secretNamespace ); err != nil {
463
+ return nil , status . Errorf ( codes . Internal , "failed to getAzcopyAuth on account(%s) rg(%s), error: %v" , accountOptions . Name , accountOptions . ResourceGroup , err )
464
+ }
423
465
}
424
- validContainerName = getValidContainerName (validContainerName , protocol )
425
- setKeyValueInMap (parameters , containerNameField , validContainerName )
426
466
}
427
467
428
- if req .GetVolumeContentSource () != nil {
429
- accountSASToken , authAzcopyEnv , err := d .getAzcopyAuth (ctx , accountName , accountKey , storageEndpointSuffix , accountOptions , secrets , secretName , secretNamespace )
430
- if err != nil {
431
- return nil , status .Errorf (codes .Internal , "failed to getAzcopyAuth on account(%s) rg(%s), error: %v" , accountOptions .Name , accountOptions .ResourceGroup , err )
432
- }
433
- if err := d .copyVolume (req , accountSASToken , authAzcopyEnv , validContainerName , storageEndpointSuffix ); err != nil {
468
+ klog .V (2 ).Infof ("begin to create container(%s) on account(%s) type(%s) subsID(%s) rg(%s) location(%s) size(%d)" , validContainerName , accountName , storageAccountType , subsID , resourceGroup , location , requestGiB )
469
+ if err := d .CreateBlobContainer (ctx , subsID , resourceGroup , accountName , validContainerName , secrets ); err != nil {
470
+ return nil , status .Errorf (codes .Internal , "failed to create container(%s) on account(%s) type(%s) rg(%s) location(%s) size(%d), error: %v" , validContainerName , accountName , storageAccountType , resourceGroup , location , requestGiB , err )
471
+ }
472
+
473
+ if volContentSource != nil {
474
+ dstPath := fmt .Sprintf ("https://%s.blob.%s/%s" , accountName , storageEndpointSuffix , validContainerName )
475
+ if err := d .copyBlobContainer (dstAzcopyAuthEnv , srcPath , srcAccountSASToken , dstPath , dstAccountSASToken , validContainerName ); err != nil {
434
476
return nil , err
435
477
}
436
- } else {
437
- klog .V (2 ).Infof ("begin to create container(%s) on account(%s) type(%s) subsID(%s) rg(%s) location(%s) size(%d)" , validContainerName , accountName , storageAccountType , subsID , resourceGroup , location , requestGiB )
438
- if err := d .CreateBlobContainer (ctx , subsID , resourceGroup , accountName , validContainerName , secrets ); err != nil {
439
- return nil , status .Errorf (codes .Internal , "failed to create container(%s) on account(%s) type(%s) rg(%s) location(%s) size(%d), error: %v" , validContainerName , accountName , storageAccountType , resourceGroup , location , requestGiB , err )
440
- }
441
478
}
442
479
443
480
if storeAccountKey && len (req .GetSecrets ()) == 0 {
@@ -478,7 +515,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
478
515
VolumeId : volumeID ,
479
516
CapacityBytes : req .GetCapacityRange ().GetRequiredBytes (),
480
517
VolumeContext : parameters ,
481
- ContentSource : req . GetVolumeContentSource () ,
518
+ ContentSource : volContentSource ,
482
519
},
483
520
}, nil
484
521
}
@@ -724,71 +761,45 @@ func (d *Driver) DeleteBlobContainer(ctx context.Context, subsID, resourceGroupN
724
761
})
725
762
}
726
763
727
- // CopyBlobContainer copies a blob container in the same storage account
728
- func (d * Driver ) copyBlobContainer (req * csi.CreateVolumeRequest , accountSasToken string , authAzcopyEnv []string , dstContainerName , storageEndpointSuffix string ) error {
729
- var sourceVolumeID string
730
- if req .GetVolumeContentSource () != nil && req .GetVolumeContentSource ().GetVolume () != nil {
731
- sourceVolumeID = req .GetVolumeContentSource ().GetVolume ().GetVolumeId ()
764
+ // copyBlobContainer copies source volume content into a destination volume
765
+ func (d * Driver ) copyBlobContainer (authAzcopyEnv []string , srcPath string , srcAccountSASToken string , dstPath string , dstAccountSASToken string , dstContainerName string ) error {
732
766
733
- }
734
- resourceGroupName , accountName , srcContainerName , _ , _ , err := GetContainerInfo (sourceVolumeID ) //nolint:dogsled
735
- if err != nil {
736
- return status .Error (codes .NotFound , err .Error ())
737
- }
738
- if srcContainerName == "" || dstContainerName == "" {
739
- return fmt .Errorf ("srcContainerName(%s) or dstContainerName(%s) is empty" , srcContainerName , dstContainerName )
767
+ if srcPath == "" || dstPath == "" || dstContainerName == "" {
768
+ return fmt .Errorf ("srcPath(%s) or dstPath(%s) or dstContainerName(%s) is empty" , srcPath , dstPath , dstContainerName )
740
769
}
741
770
742
- timeAfter := time .After (time .Duration (d .waitForAzCopyTimeoutMinutes ) * time .Minute )
743
- timeTick := time .Tick (waitForAzCopyInterval )
744
- srcPath := fmt .Sprintf ("https://%s.blob.%s/%s%s" , accountName , storageEndpointSuffix , srcContainerName , accountSasToken )
745
- dstPath := fmt .Sprintf ("https://%s.blob.%s/%s%s" , accountName , storageEndpointSuffix , dstContainerName , accountSasToken )
746
-
747
771
jobState , percent , err := d .azcopy .GetAzcopyJob (dstContainerName , authAzcopyEnv )
748
772
klog .V (2 ).Infof ("azcopy job status: %s, copy percent: %s%%, error: %v" , jobState , percent , err )
749
- if jobState == util .AzcopyJobError || jobState == util .AzcopyJobCompleted {
773
+ switch jobState {
774
+ case util .AzcopyJobError , util .AzcopyJobCompleted :
750
775
return err
751
- }
752
- klog .V (2 ).Infof ("begin to copy blob container %s to %s" , srcContainerName , dstContainerName )
753
- for {
754
- select {
755
- case <- timeTick :
756
- jobState , percent , err := d .azcopy .GetAzcopyJob (dstContainerName , authAzcopyEnv )
757
- klog .V (2 ).Infof ("azcopy job status: %s, copy percent: %s%%, error: %v" , jobState , percent , err )
758
- switch jobState {
759
- case util .AzcopyJobError , util .AzcopyJobCompleted :
760
- return err
761
- case util .AzcopyJobNotFound :
762
- klog .V (2 ).Infof ("copy blob container %s to %s" , srcContainerName , dstContainerName )
763
- cmd := exec .Command ("azcopy" , "copy" , srcPath , dstPath , "--recursive" , "--check-length=false" )
764
- if len (authAzcopyEnv ) > 0 {
765
- cmd .Env = append (os .Environ (), authAzcopyEnv ... )
766
- }
767
- out , copyErr := cmd .CombinedOutput ()
768
- if copyErr != nil {
769
- klog .Warningf ("CopyBlobContainer(%s, %s, %s) failed with error(%v): %v" , resourceGroupName , accountName , dstPath , copyErr , string (out ))
770
- } else {
771
- klog .V (2 ).Infof ("copied blob container %s to %s successfully" , srcContainerName , dstContainerName )
772
- }
773
- return copyErr
776
+ case util .AzcopyJobRunning :
777
+ return fmt .Errorf ("wait for the existing AzCopy job to complete, current copy percentage is %s%%" , percent )
778
+ case util .AzcopyJobNotFound :
779
+ klog .V (2 ).Infof ("copy blob container %s to %s" , srcPath , dstContainerName )
780
+ execFunc := func () error {
781
+ cmd := exec .Command ("azcopy" , "copy" , srcPath + srcAccountSASToken , dstPath + dstAccountSASToken , "--recursive" , "--check-length=false" , "--s2s-preserve-access-tier=false" )
782
+ if len (authAzcopyEnv ) > 0 {
783
+ cmd .Env = append (os .Environ (), authAzcopyEnv ... )
784
+ }
785
+ if out , err := cmd .CombinedOutput (); err != nil {
786
+ return fmt .Errorf ("exec error: %v, output: %v" , err , string (out ))
774
787
}
775
- case <- timeAfter :
776
- return fmt .Errorf ("timeout waiting for copy blob container %s to %s succeed" , srcContainerName , dstContainerName )
788
+ return nil
777
789
}
790
+ timeoutFunc := func () error {
791
+ _ , percent , _ := d .azcopy .GetAzcopyJob (dstContainerName , authAzcopyEnv )
792
+ return fmt .Errorf ("timeout waiting for copy blob container %s to %s complete, current copy percent: %s%%" , srcPath , dstContainerName , percent )
793
+ }
794
+ copyErr := util .WaitUntilTimeout (time .Duration (d .waitForAzCopyTimeoutMinutes )* time .Minute , execFunc , timeoutFunc )
795
+ if copyErr != nil {
796
+ klog .Warningf ("CopyBlobContainer(%s, %s, %s) failed with error: %v" , srcPath , dstPath , dstContainerName , copyErr )
797
+ } else {
798
+ klog .V (2 ).Infof ("copied blob container %s to %s successfully" , srcPath , dstContainerName )
799
+ }
800
+ return copyErr
778
801
}
779
- }
780
-
781
- // copyVolume copies a volume form volume or snapshot, snapshot is not supported now
782
- func (d * Driver ) copyVolume (req * csi.CreateVolumeRequest , accountSASToken string , authAzcopyEnv []string , dstContainerName , storageEndpointSuffix string ) error {
783
- vs := req .VolumeContentSource
784
- switch vs .Type .(type ) {
785
- case * csi.VolumeContentSource_Snapshot :
786
- return status .Errorf (codes .InvalidArgument , "copy volume from volumeSnapshot is not supported" )
787
- case * csi.VolumeContentSource_Volume :
788
- return d .copyBlobContainer (req , accountSASToken , authAzcopyEnv , dstContainerName , storageEndpointSuffix )
789
- default :
790
- return status .Errorf (codes .InvalidArgument , "%v is not a proper volume source" , vs )
791
- }
802
+ return err
792
803
}
793
804
794
805
// authorizeAzcopyWithIdentity returns auth env for azcopy using cluster identity
0 commit comments