@@ -20,9 +20,9 @@ import (
2020 "fmt"
2121 "math"
2222 "os"
23+ "path/filepath"
2324 "sort"
2425 "strconv"
25- "strings"
2626
2727 "github.com/golang/protobuf/ptypes"
2828
@@ -33,14 +33,11 @@ import (
3333 "google.golang.org/grpc/status"
3434
3535 "github.com/container-storage-interface/spec/lib/go/csi"
36- "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
3736 utilexec "k8s.io/utils/exec"
3837)
3938
4039const (
4140 deviceID = "deviceID"
42- provisionRoot = "/csi-data-dir"
43- snapshotRoot = "/csi-data-dir"
4441 maxStorageCapacity = tib
4542)
4643
@@ -138,114 +135,46 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
138135 },
139136 }, nil
140137 }
141- return nil , status .Error (codes .AlreadyExists , fmt . Sprintf ( "Volume with the same name: %s but with different size already exist" , req .GetName () ))
138+ return nil , status .Errorf (codes .AlreadyExists , "Volume with the same name: %s but with different size already exist" , req .GetName ())
142139 }
143140
144141 volumeID := uuid .NewUUID ().String ()
145142 path := getVolumePath (volumeID )
146143
147- if requestedAccessType == blockAccess {
148- executor := utilexec .New ()
149- size := fmt .Sprintf ("%dM" , capacity / mib )
150- // Create a block file.
151- out , err := executor .Command ("fallocate" , "-l" , size , path ).CombinedOutput ()
152- if err != nil {
153- glog .V (3 ).Infof ("failed to create block device: %v" , string (out ))
154- return nil , err
155- }
156-
157- // Associate block file with the loop device.
158- volPathHandler := volumepathhandler.VolumePathHandler {}
159- _ , err = volPathHandler .AttachFileDevice (path )
160- if err != nil {
161- glog .Errorf ("failed to attach device: %v" , err )
162- // Remove the block file because it'll no longer be used again.
163- if err2 := os .Remove (path ); err != nil {
164- glog .Errorf ("failed to cleanup block file %s: %v" , path , err2 )
165- }
166- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to attach device: %v" , err ))
167- }
168- }
169-
170144 vol , err := createHostpathVolume (volumeID , req .GetName (), capacity , requestedAccessType , false /* ephemeral */ )
171145 if err != nil {
172- return nil , status .Error (codes .Internal , fmt . Sprintf ( "failed to create volume: %s " , err ) )
146+ return nil , status .Errorf (codes .Internal , "failed to create volume %v : %v " , volumeID , err )
173147 }
174148 glog .V (4 ).Infof ("created volume %s at path %s" , vol .VolID , vol .VolPath )
175149
176150 if req .GetVolumeContentSource () != nil {
177151 contentSource := req .GetVolumeContentSource ()
178- if contentSource .GetSnapshot () != nil {
179- snapshotId := contentSource .GetSnapshot ().GetSnapshotId ()
180- snapshot , ok := hostPathVolumeSnapshots [snapshotId ]
181- if ! ok {
182- deleteHostpathVolume (volumeID )
183- return nil , status .Errorf (codes .NotFound , "cannot find snapshot %v" , snapshotId )
184- }
185- if snapshot .ReadyToUse != true {
186- deleteHostpathVolume (volumeID )
187- return nil , status .Errorf (codes .Internal , "Snapshot %v is not yet ready to use." , snapshotId )
188- }
189- snapshotPath := snapshot .Path
190- args := []string {"zxvf" , snapshotPath , "-C" , path }
191- executor := utilexec .New ()
192- out , err := executor .Command ("tar" , args ... ).CombinedOutput ()
193- if err != nil {
194- deleteHostpathVolume (volumeID )
195- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed pre-populate data for volume: %v: %s" , err , out ))
196- }
152+ if snapshot := contentSource .GetSnapshot (); snapshot != nil {
153+ err = loadFromSnapshot (snapshot .GetSnapshotId (), path )
197154 }
198155 if srcVolume := contentSource .GetVolume (); srcVolume != nil {
199- srcVolumeID := srcVolume .GetVolumeId ()
200- hostPathVolume , ok := hostPathVolumes [srcVolumeID ]
201- if ! ok {
202- deleteHostpathVolume (volumeID )
203- return nil , status .Error (codes .NotFound , "source volumeID does not exist, are source/destination in the same storage class?" )
204- }
205- srcPath := hostPathVolume .VolPath
206- isEmpty , err := hostPathIsEmpty (srcPath )
207- if err != nil {
208- deleteHostpathVolume (volumeID )
209- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed verification check of source hostpath volume: %s: %v" , srcVolumeID , err ))
210- }
211-
212- // If the source hostpath volume is empty it's a noop and we just move along, otherwise the cp call will fail with a a file stat error DNE
213- if ! isEmpty {
214- args := []string {"-a" , srcPath + "/*" , path + "/" }
215- executor := utilexec .New ()
216- out , err := executor .Command ("cp" , args ... ).CombinedOutput ()
217- if err != nil {
218- deleteHostpathVolume (volumeID )
219- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed pre-populate data (clone) for volume: %s: %s" , volumeID , out ))
220- }
156+ err = loadFromVolume (srcVolume .GetVolumeId (), path )
157+ }
158+ if err != nil {
159+ if delErr := deleteHostpathVolume (volumeID ); delErr != nil {
160+ glog .V (2 ).Infof ("deleting hostpath volume %v failed: %v" , volumeID , delErr )
221161 }
162+ return nil , err
222163 }
164+ glog .V (4 ).Infof ("successfully populated volume %s" , vol .VolID )
223165 }
224166
225- createVolumeResponse := & csi.CreateVolumeResponse {}
226- if req .GetVolumeContentSource () != nil {
227- createVolumeResponse = & csi.CreateVolumeResponse {
228- Volume : & csi.Volume {
229- VolumeId : volumeID ,
230- CapacityBytes : req .GetCapacityRange ().GetRequiredBytes (),
231- VolumeContext : req .GetParameters (),
232- ContentSource : req .GetVolumeContentSource (),
233- },
234- }
235- } else {
236- createVolumeResponse = & csi.CreateVolumeResponse {
237- Volume : & csi.Volume {
238- VolumeId : volumeID ,
239- CapacityBytes : req .GetCapacityRange ().GetRequiredBytes (),
240- VolumeContext : req .GetParameters (),
241- },
242- }
243- }
244- return createVolumeResponse , nil
167+ return & csi.CreateVolumeResponse {
168+ Volume : & csi.Volume {
169+ VolumeId : volumeID ,
170+ CapacityBytes : req .GetCapacityRange ().GetRequiredBytes (),
171+ VolumeContext : req .GetParameters (),
172+ ContentSource : req .GetVolumeContentSource (),
173+ },
174+ }, nil
245175}
246176
247177func (cs * controllerServer ) DeleteVolume (ctx context.Context , req * csi.DeleteVolumeRequest ) (* csi.DeleteVolumeResponse , error ) {
248-
249178 // Check arguments
250179 if len (req .GetVolumeId ()) == 0 {
251180 return nil , status .Error (codes .InvalidArgument , "Volume ID missing in request" )
@@ -256,36 +185,12 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
256185 return nil , err
257186 }
258187
259- vol , err := getVolumeByID (req .GetVolumeId ())
260- if err != nil {
261- // Return OK if the volume is not found.
262- return & csi.DeleteVolumeResponse {}, nil
263- }
264- glog .V (4 ).Infof ("deleting volume %s" , vol .VolID )
265-
266- if vol .VolAccessType == blockAccess {
267-
268- volPathHandler := volumepathhandler.VolumePathHandler {}
269- // Get the associated loop device.
270- device , err := volPathHandler .GetLoopDevice (getVolumePath (vol .VolID ))
271- if err != nil {
272- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to get the loop device: %v" , err ))
273- }
274-
275- if device != "" {
276- // Remove any associated loop device.
277- glog .V (4 ).Infof ("deleting loop device %s" , device )
278- if err := volPathHandler .RemoveLoopDevice (device ); err != nil {
279- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to remove loop device: %v" , err ))
280- }
281- }
282- }
283-
284- if err := deleteHostpathVolume (vol .VolID ); err != nil && ! os .IsNotExist (err ) {
285- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to delete volume: %s" , err ))
188+ volId := req .GetVolumeId ()
189+ if err := deleteHostpathVolume (volId ); err != nil {
190+ return nil , status .Errorf (codes .Internal , "failed to delete volume %v: %v" , volId , err )
286191 }
287192
288- glog .V (4 ).Infof ("volume deleted ok: %s " , vol . VolID )
193+ glog .V (4 ).Infof ("volume %v successfully deleted " , volId )
289194
290195 return & csi.DeleteVolumeResponse {}, nil
291196}
@@ -344,6 +249,11 @@ func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolume
344249 return nil , status .Error (codes .Unimplemented , "" )
345250}
346251
252+ // getSnapshotPath returns the full path to where the snapshot is stored
253+ func getSnapshotPath (snapshotId string ) string {
254+ return filepath .Join (dataRoot , fmt .Sprintf ("%s.tgz" , snapshotId ))
255+ }
256+
347257// CreateSnapshot uses tar command to create snapshot for hostpath volume. The tar command can quickly create
348258// archives of entire directories. The host image must have "tar" binaries in /bin, /usr/sbin, or /usr/bin.
349259func (cs * controllerServer ) CreateSnapshot (ctx context.Context , req * csi.CreateSnapshotRequest ) (* csi.CreateSnapshotResponse , error ) {
@@ -377,7 +287,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
377287 },
378288 }, nil
379289 }
380- return nil , status .Error (codes .AlreadyExists , fmt . Sprintf ( "snapshot with the same name: %s but with different SourceVolumeId already exist" , req .GetName () ))
290+ return nil , status .Errorf (codes .AlreadyExists , "snapshot with the same name: %s but with different SourceVolumeId already exist" , req .GetName ())
381291 }
382292
383293 volumeID := req .GetSourceVolumeId ()
@@ -389,8 +299,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
389299 snapshotID := uuid .NewUUID ().String ()
390300 creationTime := ptypes .TimestampNow ()
391301 volPath := hostPathVolume .VolPath
392- filePath := []string {snapshotRoot , "/" , snapshotID , ".tgz" }
393- file := strings .Join (filePath , "" )
302+ file := getSnapshotPath (snapshotID )
394303 args := []string {}
395304 if hostPathVolume .VolAccessType == blockAccess {
396305 glog .V (4 ).Infof ("Creating snapshot of Raw Block Mode Volume" )
@@ -402,7 +311,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
402311 executor := utilexec .New ()
403312 out , err := executor .Command ("tar" , args ... ).CombinedOutput ()
404313 if err != nil {
405- return nil , status .Error (codes .Internal , fmt . Sprintf ( "failed create snapshot: %v: %s" , err , out ) )
314+ return nil , status .Errorf (codes .Internal , "failed create snapshot: %v: %s" , err , out )
406315 }
407316
408317 glog .V (4 ).Infof ("create volume snapshot %s" , file )
@@ -439,9 +348,8 @@ func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS
439348 return nil , err
440349 }
441350 snapshotID := req .GetSnapshotId ()
442- glog .V (4 ).Infof ("deleting volume %s" , snapshotID )
443- pathSlice := []string {snapshotRoot , "/" , snapshotID , ".tgz" }
444- path := strings .Join (pathSlice , "" )
351+ glog .V (4 ).Infof ("deleting snapshot %s" , snapshotID )
352+ path := getSnapshotPath (snapshotID )
445353 os .RemoveAll (path )
446354 delete (hostPathVolumeSnapshots , snapshotID )
447355 return & csi.DeleteSnapshotResponse {}, nil
@@ -579,7 +487,7 @@ func (cs *controllerServer) validateControllerServiceRequest(c csi.ControllerSer
579487 return nil
580488 }
581489 }
582- return status .Error (codes .InvalidArgument , fmt . Sprintf ( " %s" , c ) )
490+ return status .Errorf (codes .InvalidArgument , "unsupported capability %s" , c )
583491}
584492
585493func getControllerServiceCapabilities (cl []csi.ControllerServiceCapability_RPC_Type ) []* csi.ControllerServiceCapability {
0 commit comments