Skip to content

Commit 2036d65

Browse files
authored
Merge pull request #2653 from kubernetes-sigs/nfs-restore-clone
feat: support nfs volume clone and snapshot restore
2 parents 762805c + 4d0d832 commit 2036d65

File tree

4 files changed

+43
-65
lines changed

4 files changed

+43
-65
lines changed

pkg/azurefile/azurefile.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,9 +1115,6 @@ func (d *Driver) ResizeFileShare(ctx context.Context, subsID, resourceGroup, acc
11151115

11161116
// copyFileShare copies a fileshare, if dstAccountName is empty, then copy in the same account
11171117
func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest, dstAccountName string, dstAccountSasToken string, authAzcopyEnv []string, secretNamespace string, shareOptions *ShareOptions, accountOptions *storage.AccountOptions, storageEndpointSuffix string) error {
1118-
if shareOptions.Protocol == armstorage.EnabledProtocolsNFS {
1119-
return fmt.Errorf("protocol nfs is not supported for volume cloning")
1120-
}
11211118
var sourceVolumeID string
11221119
if req.GetVolumeContentSource() != nil && req.GetVolumeContentSource().GetVolume() != nil {
11231120
sourceVolumeID = req.GetVolumeContentSource().GetVolume().GetVolumeId()
@@ -1149,7 +1146,7 @@ func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest
11491146
srcPath := fmt.Sprintf("https://%s.file.%s/%s%s", srcAccountName, storageEndpointSuffix, srcFileShareName, srcAccountSasToken)
11501147
dstPath := fmt.Sprintf("https://%s.file.%s/%s%s", dstAccountName, storageEndpointSuffix, dstFileShareName, dstAccountSasToken)
11511148

1152-
return d.copyFileShareByAzcopy(ctx, srcFileShareName, dstFileShareName, srcPath, dstPath, "", srcAccountName, dstAccountName, srcAccountSasToken, authAzcopyEnv, accountOptions)
1149+
return d.copyFileShareByAzcopy(ctx, srcFileShareName, dstFileShareName, srcPath, dstPath, "", srcAccountName, dstAccountName, srcAccountSasToken, authAzcopyEnv, shareOptions, accountOptions)
11531150
}
11541151

11551152
// 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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,9 +1128,6 @@ func (d *Driver) ListSnapshots(_ context.Context, _ *csi.ListSnapshotsRequest) (
11281128

11291129
// restoreSnapshot restores from a snapshot
11301130
func (d *Driver) restoreSnapshot(ctx context.Context, req *csi.CreateVolumeRequest, dstAccountName, dstAccountSasToken string, authAzcopyEnv []string, secretNamespace string, shareOptions *ShareOptions, accountOptions *storage.AccountOptions, storageEndpointSuffix string) error {
1131-
if shareOptions.Protocol == armstorage.EnabledProtocolsNFS {
1132-
return fmt.Errorf("protocol nfs is not supported for snapshot restore")
1133-
}
11341131
var sourceSnapshotID string
11351132
if req.GetVolumeContentSource() != nil && req.GetVolumeContentSource().GetSnapshot() != nil {
11361133
sourceSnapshotID = req.GetVolumeContentSource().GetSnapshot().GetSnapshotId()
@@ -1171,10 +1168,10 @@ func (d *Driver) restoreSnapshot(ctx context.Context, req *csi.CreateVolumeReque
11711168
dstPath := fmt.Sprintf("https://%s.file.%s/%s%s", dstAccountName, storageEndpointSuffix, dstFileShareName, dstAccountSasToken)
11721169

11731170
srcFileShareSnapshotName := fmt.Sprintf("%s(snapshot: %s)", srcFileShareName, snapshot)
1174-
return d.copyFileShareByAzcopy(ctx, srcFileShareSnapshotName, dstFileShareName, srcPath, dstPath, snapshot, srcAccountName, dstAccountName, srcAccountSasToken, authAzcopyEnv, accountOptions)
1171+
return d.copyFileShareByAzcopy(ctx, srcFileShareSnapshotName, dstFileShareName, srcPath, dstPath, snapshot, srcAccountName, dstAccountName, srcAccountSasToken, authAzcopyEnv, shareOptions, accountOptions)
11751172
}
11761173

1177-
func (d *Driver) copyFileShareByAzcopy(ctx context.Context, srcFileShareName, dstFileShareName, srcPath, dstPath, snapshot, srcAccountName, dstAccountName, accountSASToken string, authAzcopyEnv []string, accountOptions *storage.AccountOptions) error {
1174+
func (d *Driver) copyFileShareByAzcopy(ctx context.Context, srcFileShareName, dstFileShareName, srcPath, dstPath, snapshot, srcAccountName, dstAccountName, accountSASToken string, authAzcopyEnv []string, shareOptions *ShareOptions, accountOptions *storage.AccountOptions) error {
11781175
azcopyCopyOptions := azcopyCloneVolumeOptions
11791176
srcPathAuth := srcPath
11801177
if snapshot != "" {
@@ -1186,6 +1183,10 @@ func (d *Driver) copyFileShareByAzcopy(ctx context.Context, srcFileShareName, ds
11861183
}
11871184
}
11881185

1186+
if shareOptions.Protocol == armstorage.EnabledProtocolsNFS {
1187+
azcopyCopyOptions = append(azcopyCopyOptions, "--from-to=FileNFSFileNFS")
1188+
}
1189+
11891190
jobState, percent, err := d.azcopy.GetAzcopyJob(dstFileShareName, authAzcopyEnv)
11901191
klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err)
11911192

pkg/azurefile/controllerserver_test.go

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,33 +1430,6 @@ var _ = ginkgo.Describe("TestCopyVolume", func() {
14301430
ginkgo.AfterEach(func() {
14311431
ctrl.Finish()
14321432
})
1433-
ginkgo.When("restore volume from volumeSnapshot nfs is not supported", func() {
1434-
ginkgo.It("should fail", func(ctx context.Context) {
1435-
allParam := map[string]string{}
1436-
1437-
volumeSnapshotSource := &csi.VolumeContentSource_SnapshotSource{
1438-
SnapshotId: "unit-test",
1439-
}
1440-
volumeContentSourceSnapshotSource := &csi.VolumeContentSource_Snapshot{
1441-
Snapshot: volumeSnapshotSource,
1442-
}
1443-
volumecontensource := csi.VolumeContentSource{
1444-
Type: volumeContentSourceSnapshotSource,
1445-
}
1446-
1447-
req := &csi.CreateVolumeRequest{
1448-
Name: "random-vol-name-valid-request",
1449-
VolumeCapabilities: stdVolCap,
1450-
CapacityRange: lessThanPremCapRange,
1451-
Parameters: allParam,
1452-
VolumeContentSource: &volumecontensource,
1453-
}
1454-
1455-
expectedErr := fmt.Errorf("protocol nfs is not supported for snapshot restore")
1456-
err := d.copyVolume(ctx, req, "", "", []string{}, "", &ShareOptions{Protocol: armstorage.EnabledProtocolsNFS}, nil, "core.windows.net")
1457-
gomega.Expect(err).To(gomega.Equal(expectedErr))
1458-
})
1459-
})
14601433
ginkgo.When("restore volume from volumeSnapshot not found", func() {
14611434
ginkgo.It("should fail", func(ctx context.Context) {
14621435
allParam := map[string]string{}
@@ -1511,33 +1484,6 @@ var _ = ginkgo.Describe("TestCopyVolume", func() {
15111484
gomega.Expect(err).To(gomega.Equal(expectedErr))
15121485
})
15131486
})
1514-
ginkgo.When("copy volume nfs is not supported", func() {
1515-
ginkgo.It("should fail", func(ctx context.Context) {
1516-
allParam := map[string]string{}
1517-
1518-
volumeSource := &csi.VolumeContentSource_VolumeSource{
1519-
VolumeId: "unit-test",
1520-
}
1521-
volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{
1522-
Volume: volumeSource,
1523-
}
1524-
volumecontensource := csi.VolumeContentSource{
1525-
Type: volumeContentSourceVolumeSource,
1526-
}
1527-
1528-
req := &csi.CreateVolumeRequest{
1529-
Name: "random-vol-name-valid-request",
1530-
VolumeCapabilities: stdVolCap,
1531-
CapacityRange: lessThanPremCapRange,
1532-
Parameters: allParam,
1533-
VolumeContentSource: &volumecontensource,
1534-
}
1535-
1536-
expectedErr := fmt.Errorf("protocol nfs is not supported for volume cloning")
1537-
err := d.copyVolume(ctx, req, "", "", []string{}, "", &ShareOptions{Protocol: armstorage.EnabledProtocolsNFS}, nil, "core.windows.net")
1538-
gomega.Expect(err).To(gomega.Equal(expectedErr))
1539-
})
1540-
})
15411487
ginkgo.When("copy volume from volume not found", func() {
15421488
ginkgo.It("should fail", func(ctx context.Context) {
15431489
allParam := map[string]string{}

test/e2e/dynamic_provisioning_test.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,39 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
101101
test.Run(ctx, cs, snapshotrcs, ns)
102102
})
103103

104+
ginkgo.It("should create a pod, write and read to it, take a nfs volume snapshot, and create another pod from the snapshot [file.csi.azure.com]", func(ctx ginkgo.SpecContext) {
105+
skipIfUsingInTreeVolumePlugin()
106+
skipIfTestingInWindowsCluster()
107+
108+
pod := testsuites.PodDetails{
109+
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
110+
Volumes: []testsuites.VolumeDetails{
111+
{
112+
ClaimSize: "100Gi",
113+
VolumeMount: testsuites.VolumeMountDetails{
114+
NameGenerate: "test-volume-",
115+
MountPathGenerate: "/mnt/test-",
116+
},
117+
},
118+
},
119+
}
120+
podWithSnapshot := testsuites.PodDetails{
121+
Cmd: "grep 'hello world' /mnt/test-1/data",
122+
}
123+
test := testsuites.DynamicallyProvisionedVolumeSnapshotTest{
124+
CSIDriver: testDriver,
125+
Pod: pod,
126+
ShouldOverwrite: false,
127+
ShouldRestore: true,
128+
PodWithSnapshot: podWithSnapshot,
129+
StorageClassParameters: map[string]string{
130+
"skuName": "Premium_LRS",
131+
"protocol": "nfs",
132+
},
133+
}
134+
test.Run(ctx, cs, snapshotrcs, ns)
135+
})
136+
104137
ginkgo.It("should create a pod, write to its pv, take a volume snapshot, overwrite data in original pv, create another pod from the snapshot, use another storage class, and read unaltered original data from original pv[file.csi.azure.com]", func(ctx ginkgo.SpecContext) {
105138
skipIfUsingInTreeVolumePlugin()
106139
skipIfTestingInWindowsCluster()
@@ -1740,7 +1773,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
17401773
test.Run(ctx, cs, ns)
17411774
})
17421775

1743-
ginkgo.It("should clone a large size volume from an existing volume [file.csi.azure.com]", func(ctx ginkgo.SpecContext) {
1776+
ginkgo.It("should clone a large size volume from an existing nfs volume [file.csi.azure.com]", func(ctx ginkgo.SpecContext) {
17441777
skipIfTestingInWindowsCluster()
17451778
skipIfTestingInMigrationCluster()
17461779
skipIfUsingInTreeVolumePlugin()
@@ -1765,7 +1798,8 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
17651798
Pod: pod,
17661799
PodWithClonedVolume: podWithClonedVolume,
17671800
StorageClassParameters: map[string]string{
1768-
"skuName": "Standard_LRS",
1801+
"skuName": "Premium_LRS",
1802+
"protocol": "nfs",
17691803
},
17701804
}
17711805
test.Run(ctx, cs, ns)

0 commit comments

Comments
 (0)