@@ -20,9 +20,9 @@ import (
20
20
"fmt"
21
21
"math"
22
22
"os"
23
+ "path/filepath"
23
24
"sort"
24
25
"strconv"
25
- "strings"
26
26
27
27
"github.com/golang/protobuf/ptypes"
28
28
@@ -33,14 +33,11 @@ import (
33
33
"google.golang.org/grpc/status"
34
34
35
35
"github.com/container-storage-interface/spec/lib/go/csi"
36
- "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
37
36
utilexec "k8s.io/utils/exec"
38
37
)
39
38
40
39
const (
41
40
deviceID = "deviceID"
42
- provisionRoot = "/csi-data-dir"
43
- snapshotRoot = "/csi-data-dir"
44
41
maxStorageCapacity = tib
45
42
)
46
43
@@ -138,114 +135,46 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
138
135
},
139
136
}, nil
140
137
}
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 ())
142
139
}
143
140
144
141
volumeID := uuid .NewUUID ().String ()
145
142
path := getVolumePath (volumeID )
146
143
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
-
170
144
vol , err := createHostpathVolume (volumeID , req .GetName (), capacity , requestedAccessType , false /* ephemeral */ )
171
145
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 )
173
147
}
174
148
glog .V (4 ).Infof ("created volume %s at path %s" , vol .VolID , vol .VolPath )
175
149
176
150
if req .GetVolumeContentSource () != nil {
177
151
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 )
197
154
}
198
155
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 )
221
161
}
162
+ return nil , err
222
163
}
164
+ glog .V (4 ).Infof ("successfully populated volume %s" , vol .VolID )
223
165
}
224
166
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
245
175
}
246
176
247
177
func (cs * controllerServer ) DeleteVolume (ctx context.Context , req * csi.DeleteVolumeRequest ) (* csi.DeleteVolumeResponse , error ) {
248
-
249
178
// Check arguments
250
179
if len (req .GetVolumeId ()) == 0 {
251
180
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
256
185
return nil , err
257
186
}
258
187
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 )
286
191
}
287
192
288
- glog .V (4 ).Infof ("volume deleted ok: %s " , vol . VolID )
193
+ glog .V (4 ).Infof ("volume %v successfully deleted " , volId )
289
194
290
195
return & csi.DeleteVolumeResponse {}, nil
291
196
}
@@ -344,6 +249,11 @@ func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolume
344
249
return nil , status .Error (codes .Unimplemented , "" )
345
250
}
346
251
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
+
347
257
// CreateSnapshot uses tar command to create snapshot for hostpath volume. The tar command can quickly create
348
258
// archives of entire directories. The host image must have "tar" binaries in /bin, /usr/sbin, or /usr/bin.
349
259
func (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
377
287
},
378
288
}, nil
379
289
}
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 ())
381
291
}
382
292
383
293
volumeID := req .GetSourceVolumeId ()
@@ -389,8 +299,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
389
299
snapshotID := uuid .NewUUID ().String ()
390
300
creationTime := ptypes .TimestampNow ()
391
301
volPath := hostPathVolume .VolPath
392
- filePath := []string {snapshotRoot , "/" , snapshotID , ".tgz" }
393
- file := strings .Join (filePath , "" )
302
+ file := getSnapshotPath (snapshotID )
394
303
args := []string {}
395
304
if hostPathVolume .VolAccessType == blockAccess {
396
305
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
402
311
executor := utilexec .New ()
403
312
out , err := executor .Command ("tar" , args ... ).CombinedOutput ()
404
313
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 )
406
315
}
407
316
408
317
glog .V (4 ).Infof ("create volume snapshot %s" , file )
@@ -439,9 +348,8 @@ func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS
439
348
return nil , err
440
349
}
441
350
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 )
445
353
os .RemoveAll (path )
446
354
delete (hostPathVolumeSnapshots , snapshotID )
447
355
return & csi.DeleteSnapshotResponse {}, nil
@@ -579,7 +487,7 @@ func (cs *controllerServer) validateControllerServiceRequest(c csi.ControllerSer
579
487
return nil
580
488
}
581
489
}
582
- return status .Error (codes .InvalidArgument , fmt . Sprintf ( " %s" , c ) )
490
+ return status .Errorf (codes .InvalidArgument , "unsupported capability %s" , c )
583
491
}
584
492
585
493
func getControllerServiceCapabilities (cl []csi.ControllerServiceCapability_RPC_Type ) []* csi.ControllerServiceCapability {
0 commit comments