Skip to content

Commit 6d4d537

Browse files
authored
Merge pull request #2033 from umagnus/release-1.29-diff-copyvolume
[release-1.29] fix: set the correct destination account name for copy volume if storageAccount is specified in storage class
2 parents 1c37e98 + aa21767 commit 6d4d537

7 files changed

+237
-93
lines changed

pkg/azurefile/azurefile.go

+23-56
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import (
2222
"encoding/binary"
2323
"fmt"
2424
"net/url"
25-
"os"
26-
"os/exec"
2725
"strconv"
2826
"strings"
2927
"sync"
@@ -187,8 +185,6 @@ const (
187185
SnapshotID = "snapshot_id"
188186

189187
FSGroupChangeNone = "None"
190-
191-
waitForAzCopyInterval = 2 * time.Second
192188
)
193189

194190
var (
@@ -993,72 +989,43 @@ func (d *Driver) ResizeFileShare(ctx context.Context, subsID, resourceGroup, acc
993989
})
994990
}
995991

996-
// copyFileShare copies a fileshare in the same storage account
997-
func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest, accountSASToken string, authAzcopyEnv []string, secretName, secretNamespace string, secrets map[string]string, shareOptions *fileclient.ShareOptions, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
992+
// copyFileShare copies a fileshare, if dstAccountName is empty, then copy in the same account
993+
func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest, dstAccountName string, dstAccountSasToken string, authAzcopyEnv []string, secretName, secretNamespace string, secrets map[string]string, shareOptions *fileclient.ShareOptions, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
998994
if shareOptions.Protocol == storage.EnabledProtocolsNFS {
999995
return fmt.Errorf("protocol nfs is not supported for volume cloning")
1000996
}
1001997
var sourceVolumeID string
1002998
if req.GetVolumeContentSource() != nil && req.GetVolumeContentSource().GetVolume() != nil {
1003999
sourceVolumeID = req.GetVolumeContentSource().GetVolume().GetVolumeId()
10041000
}
1005-
resourceGroupName, accountName, srcFileShareName, _, _, _, err := GetFileShareInfo(sourceVolumeID) //nolint:dogsled
1001+
srcResourceGroupName, srcAccountName, srcFileShareName, _, _, srcSubscriptionID, err := GetFileShareInfo(sourceVolumeID) //nolint:dogsled
10061002
if err != nil {
10071003
return status.Error(codes.NotFound, err.Error())
10081004
}
1005+
if dstAccountName == "" {
1006+
dstAccountName = srcAccountName
1007+
}
10091008
dstFileShareName := shareOptions.Name
1010-
if srcFileShareName == "" || dstFileShareName == "" {
1011-
return fmt.Errorf("srcFileShareName(%s) or dstFileShareName(%s) is empty", srcFileShareName, dstFileShareName)
1009+
if srcAccountName == "" || srcFileShareName == "" || dstFileShareName == "" {
1010+
return fmt.Errorf("one or more of srcAccountName(%s), srcFileShareName(%s), dstFileShareName(%s) are empty", srcAccountName, srcFileShareName, dstFileShareName)
1011+
}
1012+
srcAccountSasToken := dstAccountSasToken
1013+
if srcAccountName != dstAccountName && dstAccountSasToken != "" {
1014+
srcAccountOptions := &azure.AccountOptions{
1015+
Name: srcAccountName,
1016+
ResourceGroup: srcResourceGroupName,
1017+
SubscriptionID: srcSubscriptionID,
1018+
GetLatestAccountKey: accountOptions.GetLatestAccountKey,
1019+
}
1020+
if srcAccountSasToken, _, err = d.getAzcopyAuth(ctx, srcAccountName, "", storageEndpointSuffix, srcAccountOptions, nil, "", secretNamespace, true); err != nil {
1021+
return err
1022+
}
10121023
}
10131024

1014-
timeAfter := time.After(time.Duration(d.waitForAzCopyTimeoutMinutes) * time.Minute)
1015-
timeTick := time.Tick(waitForAzCopyInterval)
1016-
srcPath := fmt.Sprintf("https://%s.file.%s/%s%s", accountName, storageEndpointSuffix, srcFileShareName, accountSASToken)
1017-
dstPath := fmt.Sprintf("https://%s.file.%s/%s%s", accountName, storageEndpointSuffix, dstFileShareName, accountSASToken)
1025+
srcPath := fmt.Sprintf("https://%s.file.%s/%s%s", srcAccountName, storageEndpointSuffix, srcFileShareName, srcAccountSasToken)
1026+
dstPath := fmt.Sprintf("https://%s.file.%s/%s%s", dstAccountName, storageEndpointSuffix, dstFileShareName, dstAccountSasToken)
10181027

1019-
jobState, percent, err := d.azcopy.GetAzcopyJob(dstFileShareName, authAzcopyEnv)
1020-
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
1021-
if jobState == fileutil.AzcopyJobError || jobState == fileutil.AzcopyJobCompleted {
1022-
return err
1023-
}
1024-
klog.V(2).Infof("begin to copy fileshare %s to %s", srcFileShareName, dstFileShareName)
1025-
for {
1026-
select {
1027-
case <-timeTick:
1028-
jobState, percent, err := d.azcopy.GetAzcopyJob(dstFileShareName, authAzcopyEnv)
1029-
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
1030-
switch jobState {
1031-
case fileutil.AzcopyJobError, fileutil.AzcopyJobCompleted:
1032-
return err
1033-
case fileutil.AzcopyJobNotFound:
1034-
klog.V(2).Infof("copy fileshare %s to %s", srcFileShareName, dstFileShareName)
1035-
cmd := exec.Command("azcopy", "copy", srcPath, dstPath)
1036-
cmd.Args = append(cmd.Args, defaultAzcopyCopyOptions...)
1037-
if len(authAzcopyEnv) > 0 {
1038-
cmd.Env = append(os.Environ(), authAzcopyEnv...)
1039-
}
1040-
out, copyErr := cmd.CombinedOutput()
1041-
if accountSASToken == "" && strings.Contains(string(out), authorizationPermissionMismatch) && copyErr != nil {
1042-
klog.Warningf("azcopy list failed with AuthorizationPermissionMismatch error, should assign \"Storage File Data SMB Share Elevated Contributor\" role to controller identity, fall back to use sas token, original output: %v", string(out))
1043-
var sasToken string
1044-
if sasToken, _, err = d.getAzcopyAuth(ctx, accountName, "", storageEndpointSuffix, accountOptions, secrets, secretName, secretNamespace, true); err != nil {
1045-
return err
1046-
}
1047-
cmd := exec.Command("azcopy", "copy", srcPath+sasToken, dstPath+sasToken)
1048-
cmd.Args = append(cmd.Args, defaultAzcopyCopyOptions...)
1049-
out, copyErr = cmd.CombinedOutput()
1050-
}
1051-
if copyErr != nil {
1052-
klog.Warningf("CopyFileShare(%s, %s, %s) failed with error(%v): %v", resourceGroupName, accountName, dstFileShareName, copyErr, string(out))
1053-
} else {
1054-
klog.V(2).Infof("copied fileshare %s to %s successfully", srcFileShareName, dstFileShareName)
1055-
}
1056-
return copyErr
1057-
}
1058-
case <-timeAfter:
1059-
return fmt.Errorf("timeout waiting for copy fileshare %s to %s succeed", srcFileShareName, dstFileShareName)
1060-
}
1061-
}
1028+
return d.copyFileShareByAzcopy(ctx, srcFileShareName, dstFileShareName, srcPath, dstPath, srcAccountName, dstAccountName, srcResourceGroupName, srcAccountSasToken, authAzcopyEnv, secretName, secretNamespace, secrets, accountOptions, storageEndpointSuffix)
10621029
}
10631030

10641031
// GetTotalAccountQuota returns the total quota in GB of all file shares in the storage account and the number of file shares

pkg/azurefile/controllerserver.go

+74-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"context"
2121
"fmt"
2222
"net/url"
23+
"os"
24+
"os/exec"
2325
"strconv"
2426
"strings"
2527
"time"
@@ -595,7 +597,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
595597
if err != nil {
596598
return nil, status.Errorf(codes.Internal, "failed to getAzcopyAuth on account(%s) rg(%s), error: %v", accountOptions.Name, accountOptions.ResourceGroup, err)
597599
}
598-
if err := d.copyVolume(ctx, req, accountSASToken, authAzcopyEnv, secretName, secretNamespace, secret, shareOptions, accountOptions, storageEndpointSuffix); err != nil {
600+
if err := d.copyVolume(ctx, req, accountName, accountSASToken, authAzcopyEnv, secretName, secretNamespace, secret, shareOptions, accountOptions, storageEndpointSuffix); err != nil {
599601
return nil, err
600602
}
601603
// storeAccountKey is not needed here since copy volume is only using SAS token
@@ -746,13 +748,13 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
746748
}
747749

748750
// copyVolume copy an azure file
749-
func (d *Driver) copyVolume(ctx context.Context, req *csi.CreateVolumeRequest, accountSASToken string, authAzcopyEnv []string, secretName, secretNamespace string, secrets map[string]string, shareOptions *fileclient.ShareOptions, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
751+
func (d *Driver) copyVolume(ctx context.Context, req *csi.CreateVolumeRequest, accountName string, accountSASToken string, authAzcopyEnv []string, secretName, secretNamespace string, secrets map[string]string, shareOptions *fileclient.ShareOptions, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
750752
vs := req.VolumeContentSource
751753
switch vs.Type.(type) {
752754
case *csi.VolumeContentSource_Snapshot:
753755
return status.Errorf(codes.InvalidArgument, "copy volume from volumeSnapshot is not supported")
754756
case *csi.VolumeContentSource_Volume:
755-
return d.copyFileShare(ctx, req, accountSASToken, authAzcopyEnv, secretName, secretNamespace, secrets, shareOptions, accountOptions, storageEndpointSuffix)
757+
return d.copyFileShare(ctx, req, accountName, accountSASToken, authAzcopyEnv, secretName, secretNamespace, secrets, shareOptions, accountOptions, storageEndpointSuffix)
756758
default:
757759
return status.Errorf(codes.InvalidArgument, "%v is not a proper volume source", vs)
758760
}
@@ -1000,6 +1002,75 @@ func (d *Driver) ListSnapshots(_ context.Context, _ *csi.ListSnapshotsRequest) (
10001002
return nil, status.Error(codes.Unimplemented, "")
10011003
}
10021004

1005+
func (d *Driver) copyFileShareByAzcopy(ctx context.Context, srcFileShareName, dstFileShareName, srcPath, dstPath, srcAccountName, dstAccountName, srcResourceGroupName, accountSASToken string, authAzcopyEnv []string, secretName, secretNamespace string, secrets map[string]string, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
1006+
azcopyCopyOptions := defaultAzcopyCopyOptions
1007+
jobState, percent, err := d.azcopy.GetAzcopyJob(dstFileShareName, authAzcopyEnv)
1008+
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
1009+
switch jobState {
1010+
case volumehelper.AzcopyJobError, volumehelper.AzcopyJobCompleted:
1011+
return err
1012+
case volumehelper.AzcopyJobRunning:
1013+
return fmt.Errorf("wait for the existing AzCopy job to complete, current copy percentage is %s%%", percent)
1014+
case volumehelper.AzcopyJobNotFound:
1015+
klog.V(2).Infof("copy fileshare %s:%s to %s:%s", srcAccountName, srcFileShareName, dstAccountName, dstFileShareName)
1016+
execFuncWithAuth := func() error {
1017+
if out, err := d.execAzcopyCopy(srcPath, dstPath, azcopyCopyOptions, authAzcopyEnv); err != nil {
1018+
return fmt.Errorf("exec error: %v, output: %v", err, string(out))
1019+
}
1020+
return nil
1021+
}
1022+
timeoutFunc := func() error {
1023+
_, percent, _ := d.azcopy.GetAzcopyJob(dstFileShareName, authAzcopyEnv)
1024+
return fmt.Errorf("timeout waiting for copy fileshare %s:%s to %s:%s complete, current copy percent: %s%%", srcAccountName, srcFileShareName, dstAccountName, dstFileShareName, percent)
1025+
}
1026+
copyErr := volumehelper.WaitUntilTimeout(time.Duration(d.waitForAzCopyTimeoutMinutes)*time.Minute, execFuncWithAuth, timeoutFunc)
1027+
if accountSASToken == "" && copyErr != nil && strings.Contains(copyErr.Error(), authorizationPermissionMismatch) {
1028+
klog.Warningf("azcopy list failed with AuthorizationPermissionMismatch error, should assign \"Storage File Data Privileged Contributor\" role to controller identity, fall back to use sas token, original error: %v", copyErr)
1029+
var srcSasToken, dstSasToken string
1030+
srcAccountOptions := &azure.AccountOptions{
1031+
Name: srcAccountName,
1032+
ResourceGroup: srcResourceGroupName,
1033+
SubscriptionID: accountOptions.SubscriptionID,
1034+
GetLatestAccountKey: accountOptions.GetLatestAccountKey,
1035+
}
1036+
if srcSasToken, _, err = d.getAzcopyAuth(ctx, srcAccountName, "", storageEndpointSuffix, srcAccountOptions, nil, "", secretNamespace, true); err != nil {
1037+
return err
1038+
}
1039+
if srcAccountName == dstAccountName {
1040+
dstSasToken = srcSasToken
1041+
} else {
1042+
if dstSasToken, _, err = d.getAzcopyAuth(ctx, dstAccountName, "", storageEndpointSuffix, accountOptions, secrets, secretName, secretNamespace, true); err != nil {
1043+
return err
1044+
}
1045+
}
1046+
execFuncWithSasToken := func() error {
1047+
if out, err := d.execAzcopyCopy(srcPath+srcSasToken, dstPath+dstSasToken, azcopyCopyOptions, []string{}); err != nil {
1048+
return fmt.Errorf("exec error: %v, output: %v", err, string(out))
1049+
}
1050+
return nil
1051+
}
1052+
copyErr = volumehelper.WaitUntilTimeout(time.Duration(d.waitForAzCopyTimeoutMinutes)*time.Minute, execFuncWithSasToken, timeoutFunc)
1053+
}
1054+
if copyErr != nil {
1055+
klog.Warningf("CopyFileShare(%s, %s, %s) failed with error: %v", accountOptions.ResourceGroup, dstAccountName, dstFileShareName, copyErr)
1056+
} else {
1057+
klog.V(2).Infof("copied fileshare %s to %s successfully", srcFileShareName, dstFileShareName)
1058+
}
1059+
return copyErr
1060+
}
1061+
return err
1062+
}
1063+
1064+
// execAzcopyCopy exec azcopy copy command
1065+
func (d *Driver) execAzcopyCopy(srcPath, dstPath string, azcopyCopyOptions, authAzcopyEnv []string) ([]byte, error) {
1066+
cmd := exec.Command("azcopy", "copy", srcPath, dstPath)
1067+
cmd.Args = append(cmd.Args, azcopyCopyOptions...)
1068+
if len(authAzcopyEnv) > 0 {
1069+
cmd.Env = append(os.Environ(), authAzcopyEnv...)
1070+
}
1071+
return cmd.CombinedOutput()
1072+
}
1073+
10031074
// ControllerExpandVolume controller expand volume
10041075
func (d *Driver) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
10051076
volumeID := req.GetVolumeId()

pkg/azurefile/controllerserver_test.go

+13-28
Original file line numberDiff line numberDiff line change
@@ -1744,7 +1744,7 @@ func TestCopyVolume(t *testing.T) {
17441744
ctx := context.Background()
17451745

17461746
expectedErr := status.Errorf(codes.InvalidArgument, "copy volume from volumeSnapshot is not supported")
1747-
err := d.copyVolume(ctx, req, "", []string{}, "", "", secret, nil, nil, "core.windows.net")
1747+
err := d.copyVolume(ctx, req, "", "", []string{}, "", "", secret, nil, nil, "core.windows.net")
17481748
if !reflect.DeepEqual(err, expectedErr) {
17491749
t.Errorf("Unexpected error: %v", err)
17501750
}
@@ -1779,7 +1779,7 @@ func TestCopyVolume(t *testing.T) {
17791779
ctx := context.Background()
17801780

17811781
expectedErr := fmt.Errorf("protocol nfs is not supported for volume cloning")
1782-
err := d.copyVolume(ctx, req, "", []string{}, "", "", secret, &fileclient.ShareOptions{Protocol: storage.EnabledProtocolsNFS}, nil, "core.windows.net")
1782+
err := d.copyVolume(ctx, req, "", "", []string{}, "", "", secret, &fileclient.ShareOptions{Protocol: storage.EnabledProtocolsNFS}, nil, "core.windows.net")
17831783
if !reflect.DeepEqual(err, expectedErr) {
17841784
t.Errorf("Unexpected error: %v", err)
17851785
}
@@ -1814,7 +1814,7 @@ func TestCopyVolume(t *testing.T) {
18141814
ctx := context.Background()
18151815

18161816
expectedErr := status.Errorf(codes.NotFound, "error parsing volume id: \"unit-test\", should at least contain two #")
1817-
err := d.copyVolume(ctx, req, "", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
1817+
err := d.copyVolume(ctx, req, "", "", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
18181818
if !reflect.DeepEqual(err, expectedErr) {
18191819
t.Errorf("Unexpected error: %v", err)
18201820
}
@@ -1848,8 +1848,8 @@ func TestCopyVolume(t *testing.T) {
18481848
d := NewFakeDriver()
18491849
ctx := context.Background()
18501850

1851-
expectedErr := fmt.Errorf("srcFileShareName() or dstFileShareName(dstFileshare) is empty")
1852-
err := d.copyVolume(ctx, req, "", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
1851+
expectedErr := fmt.Errorf("one or more of srcAccountName(unit-test), srcFileShareName(), dstFileShareName(dstFileshare) are empty")
1852+
err := d.copyVolume(ctx, req, "", "", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
18531853
if !reflect.DeepEqual(err, expectedErr) {
18541854
t.Errorf("Unexpected error: %v", err)
18551855
}
@@ -1883,8 +1883,8 @@ func TestCopyVolume(t *testing.T) {
18831883
d := NewFakeDriver()
18841884
ctx := context.Background()
18851885

1886-
expectedErr := fmt.Errorf("srcFileShareName(fileshare) or dstFileShareName() is empty")
1887-
err := d.copyVolume(ctx, req, "", []string{}, "", "", secret, &fileclient.ShareOptions{}, nil, "core.windows.net")
1886+
expectedErr := fmt.Errorf("one or more of srcAccountName(f5713de20cde511e8ba4900), srcFileShareName(fileshare), dstFileShareName() are empty")
1887+
err := d.copyVolume(ctx, req, "", "", []string{}, "", "", secret, &fileclient.ShareOptions{}, nil, "core.windows.net")
18881888
if !reflect.DeepEqual(err, expectedErr) {
18891889
t.Errorf("Unexpected error: %v", err)
18901890
}
@@ -1916,27 +1916,15 @@ func TestCopyVolume(t *testing.T) {
19161916
secret := map[string]string{}
19171917
ctx := context.Background()
19181918

1919-
ctrl := gomock.NewController(t)
1920-
defer ctrl.Finish()
1921-
1922-
m := util.NewMockEXEC(ctrl)
1923-
listStr := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false"
1924-
m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3"), gomock.Any()).Return(listStr, nil)
1925-
// if test.enableShow {
1926-
// m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstContainer -B 3")).Return(test.showStr, test.showErr)
1927-
// }
1928-
1929-
d.azcopy.ExecCmd = m
1930-
1931-
var expectedErr error
1932-
err := d.copyVolume(ctx, req, "sastoken", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
1919+
expectedErr := fmt.Errorf("one or more of srcAccountName(f5713de20cde511e8ba4900), srcFileShareName(fileshare), dstFileShareName() are empty")
1920+
err := d.copyVolume(ctx, req, "", "", []string{}, "", "", secret, &fileclient.ShareOptions{}, nil, "core.windows.net")
19331921
if !reflect.DeepEqual(err, expectedErr) {
19341922
t.Errorf("Unexpected error: %v", err)
19351923
}
19361924
},
19371925
},
19381926
{
1939-
name: "azcopy job is first in progress and then be completed",
1927+
name: "azcopy job is in progress",
19401928
testFunc: func(t *testing.T) {
19411929
d := NewFakeDriver()
19421930
mp := map[string]string{}
@@ -1965,16 +1953,13 @@ func TestCopyVolume(t *testing.T) {
19651953

19661954
m := util.NewMockEXEC(ctrl)
19671955
listStr1 := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false"
1968-
listStr2 := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false"
1969-
o1 := m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3"), gomock.Any()).Return(listStr1, nil).Times(1)
1956+
m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3"), gomock.Any()).Return(listStr1, nil).Times(1)
19701957
m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstFileshare -B 3"), gomock.Any()).Return("Percent Complete (approx): 50.0", nil)
1971-
o2 := m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstFileshare -B 3"), gomock.Any()).Return(listStr2, nil)
1972-
gomock.InOrder(o1, o2)
19731958

19741959
d.azcopy.ExecCmd = m
19751960

1976-
var expectedErr error
1977-
err := d.copyVolume(ctx, req, "sastoken", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
1961+
expectedErr := fmt.Errorf("wait for the existing AzCopy job to complete, current copy percentage is 50.0%%")
1962+
err := d.copyVolume(ctx, req, "", "sastoken", []string{}, "", "", secret, &fileclient.ShareOptions{Name: "dstFileshare"}, nil, "core.windows.net")
19781963
if !reflect.DeepEqual(err, expectedErr) {
19791964
t.Errorf("Unexpected error: %v", err)
19801965
}

0 commit comments

Comments
 (0)