@@ -19,6 +19,7 @@ package nfs
19
19
import (
20
20
"fmt"
21
21
"os"
22
+ "os/exec"
22
23
"path/filepath"
23
24
"regexp"
24
25
"strconv"
@@ -143,12 +144,19 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
143
144
}
144
145
}
145
146
147
+ if req .GetVolumeContentSource () != nil {
148
+ if err := cs .copyVolume (ctx , req , nfsVol ); err != nil {
149
+ return nil , err
150
+ }
151
+ }
152
+
146
153
setKeyValueInMap (parameters , paramSubDir , nfsVol .subDir )
147
154
return & csi.CreateVolumeResponse {
148
155
Volume : & csi.Volume {
149
156
VolumeId : nfsVol .id ,
150
157
CapacityBytes : 0 , // by setting it to zero, Provisioner will use PVC requested size as PV size
151
158
VolumeContext : parameters ,
159
+ ContentSource : req .GetVolumeContentSource (),
152
160
},
153
161
}, nil
154
162
}
@@ -307,6 +315,52 @@ func (cs *ControllerServer) internalUnmount(ctx context.Context, vol *nfsVolume)
307
315
return err
308
316
}
309
317
318
+ func (cs * ControllerServer ) copyFromVolume (ctx context.Context , req * csi.CreateVolumeRequest , dstVol * nfsVolume ) error {
319
+ srcVol , err := getNfsVolFromID (req .GetVolumeContentSource ().GetVolume ().GetVolumeId ())
320
+ if err != nil {
321
+ return err
322
+ }
323
+ srcPath := getInternalVolumePath (cs .Driver .workingMountDir , srcVol )
324
+ dstPath := getInternalVolumePath (cs .Driver .workingMountDir , dstVol )
325
+ klog .V (2 ).Infof ("copy volume from volume %v -> %v" , srcPath , dstPath )
326
+
327
+ var volCap * csi.VolumeCapability
328
+ if len (req .GetVolumeCapabilities ()) > 0 {
329
+ volCap = req .GetVolumeCapabilities ()[0 ]
330
+ }
331
+ if err = cs .internalMount (ctx , srcVol , nil , volCap ); err != nil {
332
+ return status .Errorf (codes .Internal , "failed to mount src nfs server: %v" , err .Error ())
333
+ }
334
+ defer func () {
335
+ if err = cs .internalUnmount (ctx , srcVol ); err != nil {
336
+ klog .Warningf ("failed to unmount nfs server: %v" , err .Error ())
337
+ }
338
+ }()
339
+ if err = cs .internalMount (ctx , dstVol , nil , volCap ); err != nil {
340
+ return status .Errorf (codes .Internal , "failed to mount dst nfs server: %v" , err .Error ())
341
+ }
342
+ defer func () {
343
+ if err = cs .internalUnmount (ctx , dstVol ); err != nil {
344
+ klog .Warningf ("failed to unmount dst nfs server: %v" , err .Error ())
345
+ }
346
+ }()
347
+ out , err := exec .Command ("cp" , "-a" , fmt .Sprintf ("%v%v." , srcPath , filepath .Separator ), dstPath ).CombinedOutput ()
348
+ klog .V (2 ).Infof ("copied %s -> %s output: %v" , srcPath , dstPath , string (out ))
349
+ return err
350
+ }
351
+
352
+ func (cs * ControllerServer ) copyVolume (ctx context.Context , req * csi.CreateVolumeRequest , vol * nfsVolume ) error {
353
+ vs := req .VolumeContentSource
354
+ switch vs .Type .(type ) {
355
+ case * csi.VolumeContentSource_Snapshot :
356
+ return status .Error (codes .Unimplemented , "Currently only volume copy from another volume is supported" )
357
+ case * csi.VolumeContentSource_Volume :
358
+ return cs .copyFromVolume (ctx , req , vol )
359
+ default :
360
+ return status .Errorf (codes .InvalidArgument , "%v not a proper volume source" , vs )
361
+ }
362
+ }
363
+
310
364
// newNFSVolume Convert VolumeCreate parameters to an nfsVolume
311
365
func newNFSVolume (name string , size int64 , params map [string ]string ) (* nfsVolume , error ) {
312
366
var server , baseDir , subDir string
0 commit comments