@@ -16,6 +16,7 @@ package gcecloudprovider
16
16
17
17
import (
18
18
"fmt"
19
+ "strconv"
19
20
"strings"
20
21
21
22
csi "github.com/container-storage-interface/spec/lib/go/csi/v0"
@@ -24,16 +25,26 @@ import (
24
25
computebeta "google.golang.org/api/compute/v0.beta"
25
26
compute "google.golang.org/api/compute/v1"
26
27
"google.golang.org/api/googleapi"
28
+ "google.golang.org/grpc/codes"
29
+ "google.golang.org/grpc/status"
27
30
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
28
31
"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
29
32
)
30
33
34
+ const (
35
+ DiskSizeGb = 10
36
+ Timestamp = "2018-09-05T15:17:08.270-07:00"
37
+ BasePath = "https://www.googleapis.com/compute/v1/projects/"
38
+ snapshotURITemplateGlobal = "%s/global/snapshots/%s" //{gce.projectID}/global/snapshots/{snapshot.Name}"
39
+ )
40
+
31
41
type FakeCloudProvider struct {
32
42
project string
33
43
zone string
34
44
35
45
disks map [string ]* CloudDisk
36
46
instances map [string ]* compute.Instance
47
+ snapshots map [string ]* compute.Snapshot
37
48
}
38
49
39
50
var _ GCECompute = & FakeCloudProvider {}
@@ -44,6 +55,7 @@ func FakeCreateCloudProvider(project, zone string) (*FakeCloudProvider, error) {
44
55
zone : zone ,
45
56
disks : map [string ]* CloudDisk {},
46
57
instances : map [string ]* compute.Instance {},
58
+ snapshots : map [string ]* compute.Snapshot {},
47
59
}, nil
48
60
49
61
}
@@ -52,6 +64,66 @@ func (cloud *FakeCloudProvider) ListZones(ctx context.Context, region string) ([
52
64
return []string {cloud .zone , "country-region-fakesecondzone" }, nil
53
65
}
54
66
67
+ func (cloud * FakeCloudProvider ) ListSnapshots (ctx context.Context , filter string , maxEntries int64 , pageToken string ) ([]* compute.Snapshot , string , error ) {
68
+ var sourceDisk string
69
+ snapshots := []* compute.Snapshot {}
70
+ if len (filter ) > 0 {
71
+ filterSplits := strings .Fields (filter )
72
+ if len (filterSplits ) != 3 || filterSplits [0 ] != "sourceDisk" {
73
+ return nil , "" , invalidError ()
74
+ }
75
+ sourceDisk = filterSplits [2 ]
76
+ }
77
+ for _ , snapshot := range cloud .snapshots {
78
+ if len (sourceDisk ) > 0 {
79
+ if snapshot .SourceDisk == sourceDisk {
80
+ continue
81
+ }
82
+ }
83
+ snapshots = append (snapshots , snapshot )
84
+ }
85
+
86
+ var (
87
+ ulenSnapshots = len (snapshots )
88
+ startingToken int
89
+ )
90
+
91
+ if len (pageToken ) > 0 {
92
+ i , err := strconv .ParseUint (pageToken , 10 , 32 )
93
+ if err != nil {
94
+ return nil , "" , invalidError ()
95
+ }
96
+ startingToken = int (i )
97
+ }
98
+
99
+ if startingToken > ulenSnapshots {
100
+ return nil , "" , invalidError ()
101
+ }
102
+
103
+ // Discern the number of remaining entries.
104
+ rem := ulenSnapshots - startingToken
105
+
106
+ // If maxEntries is 0 or greater than the number of remaining entries then
107
+ // set maxEntries to the number of remaining entries.
108
+ max := int (maxEntries )
109
+ if max == 0 || max > rem {
110
+ max = rem
111
+ }
112
+
113
+ results := []* compute.Snapshot {}
114
+ j := startingToken
115
+ for i := 0 ; i < max ; i ++ {
116
+ results = append (results , snapshots [j ])
117
+ j ++
118
+ }
119
+
120
+ var nextToken string
121
+ if j < ulenSnapshots {
122
+ nextToken = fmt .Sprintf ("%d" , j )
123
+ }
124
+ return results , nextToken , nil
125
+ }
126
+
55
127
// Disk Methods
56
128
func (cloud * FakeCloudProvider ) GetDisk (ctx context.Context , volKey * meta.Key ) (* CloudDisk , error ) {
57
129
disk , ok := cloud .disks [volKey .Name ]
@@ -128,7 +200,7 @@ func (cloud *FakeCloudProvider) DeleteDisk(ctx context.Context, volKey *meta.Key
128
200
}
129
201
130
202
func (cloud * FakeCloudProvider ) AttachDisk (ctx context.Context , disk * CloudDisk , volKey * meta.Key , readWrite , diskType , instanceZone , instanceName string ) error {
131
- source := cloud .GetDiskSourceURI (disk , volKey )
203
+ source := cloud .GetDiskSourceURI (volKey )
132
204
133
205
attachedDiskV1 := & compute.AttachedDisk {
134
206
DeviceName : disk .GetName (),
@@ -162,10 +234,6 @@ func (cloud *FakeCloudProvider) DetachDisk(ctx context.Context, volKey *meta.Key
162
234
return nil
163
235
}
164
236
165
- func (cloud * FakeCloudProvider ) GetDiskSourceURI (disk * CloudDisk , volKey * meta.Key ) string {
166
- return ""
167
- }
168
-
169
237
func (cloud * FakeCloudProvider ) GetDiskTypeURI (volKey * meta.Key , diskType string ) string {
170
238
switch volKey .Type () {
171
239
case meta .Zonal :
@@ -208,6 +276,105 @@ func (cloud *FakeCloudProvider) GetInstanceOrError(ctx context.Context, instance
208
276
return instance , nil
209
277
}
210
278
279
+ // Snapshot Methods
280
+ func (cloud * FakeCloudProvider ) GetSnapshot (ctx context.Context , snapshotName string ) (* compute.Snapshot , error ) {
281
+ snapshot , ok := cloud .snapshots [snapshotName ]
282
+ if ! ok {
283
+ return nil , notFoundError ()
284
+ }
285
+ snapshot .Status = "READY"
286
+ return snapshot , nil
287
+ }
288
+
289
+ func (cloud * FakeCloudProvider ) CreateSnapshot (ctx context.Context , volKey * meta.Key , snapshotName string ) (* compute.Snapshot , error ) {
290
+ if snapshot , ok := cloud .snapshots [snapshotName ]; ok {
291
+ return snapshot , nil
292
+ }
293
+
294
+ var snapshotToCreate * compute.Snapshot
295
+ switch volKey .Type () {
296
+ case meta .Zonal :
297
+ snapshotToCreateGA := & compute.Snapshot {
298
+ Name : snapshotName ,
299
+ DiskSizeGb : int64 (DiskSizeGb ),
300
+ CreationTimestamp : Timestamp ,
301
+ Status : "UPLOADING" ,
302
+ SelfLink : cloud .getGlobalSnapshotURI (snapshotName ),
303
+ SourceDisk : cloud .getZonalDiskSourceURI (volKey .Name , volKey .Zone ),
304
+ }
305
+ snapshotToCreate = snapshotToCreateGA
306
+ case meta .Regional :
307
+ snapshotToCreateBeta := & compute.Snapshot {
308
+ Name : volKey .Name ,
309
+ DiskSizeGb : int64 (DiskSizeGb ),
310
+ CreationTimestamp : Timestamp ,
311
+ Status : "UPLOADING" ,
312
+ SelfLink : cloud .getGlobalSnapshotURI (snapshotName ),
313
+ SourceDisk : cloud .getRegionalDiskSourceURI (volKey .Name , volKey .Region ),
314
+ }
315
+ snapshotToCreate = snapshotToCreateBeta
316
+ default :
317
+ return nil , fmt .Errorf ("could not create snapshot, disk key was neither zonal nor regional, instead got: %v" , volKey .String ())
318
+ }
319
+
320
+ cloud .snapshots [snapshotName ] = snapshotToCreate
321
+ return snapshotToCreate , nil
322
+ }
323
+
324
+ // Snapshot Methods
325
+ func (cloud * FakeCloudProvider ) DeleteSnapshot (ctx context.Context , snapshotName string ) error {
326
+ delete (cloud .snapshots , snapshotName )
327
+ return nil
328
+ }
329
+
330
+ func (cloud * FakeCloudProvider ) ValidateExistingSnapshot (resp * compute.Snapshot , volKey * meta.Key ) error {
331
+ if resp == nil {
332
+ return fmt .Errorf ("disk does not exist" )
333
+ }
334
+
335
+ diskSource := cloud .GetDiskSourceURI (volKey )
336
+ if resp .SourceDisk != diskSource {
337
+ return status .Error (codes .AlreadyExists , fmt .Sprintf ("snapshot already exists with same name but with a different disk source %s, expected disk source %s" , diskSource , resp .SourceDisk ))
338
+ }
339
+ // Snapshot exists with matching source disk.
340
+ glog .V (4 ).Infof ("Compatible snapshot already exists. Reusing existing." )
341
+ return nil
342
+ }
343
+
344
+ func (cloud * FakeCloudProvider ) GetDiskSourceURI (volKey * meta.Key ) string {
345
+ switch volKey .Type () {
346
+ case Zonal :
347
+ return cloud .getZonalDiskSourceURI (volKey .Name , volKey .Zone )
348
+ case Regional :
349
+ return cloud .getRegionalDiskSourceURI (volKey .Name , volKey .Region )
350
+ default :
351
+ return ""
352
+ }
353
+ }
354
+
355
+ func (cloud * FakeCloudProvider ) getZonalDiskSourceURI (diskName , zone string ) string {
356
+ return BasePath + fmt .Sprintf (
357
+ diskSourceURITemplateSingleZone ,
358
+ cloud .project ,
359
+ zone ,
360
+ diskName )
361
+ }
362
+
363
+ func (cloud * FakeCloudProvider ) getRegionalDiskSourceURI (diskName , region string ) string {
364
+ return BasePath + fmt .Sprintf (
365
+ diskSourceURITemplateRegional ,
366
+ cloud .project ,
367
+ region ,
368
+ diskName )
369
+ }
370
+
371
+ func (cloud * FakeCloudProvider ) getGlobalSnapshotURI (snapshotName string ) string {
372
+ return BasePath + fmt .Sprintf (
373
+ snapshotURITemplateGlobal ,
374
+ cloud .project ,
375
+ snapshotName )
376
+ }
377
+
211
378
func notFoundError () * googleapi.Error {
212
379
return & googleapi.Error {
213
380
Errors : []googleapi.ErrorItem {
@@ -217,3 +384,13 @@ func notFoundError() *googleapi.Error {
217
384
},
218
385
}
219
386
}
387
+
388
+ func invalidError () * googleapi.Error {
389
+ return & googleapi.Error {
390
+ Errors : []googleapi.ErrorItem {
391
+ {
392
+ Reason : "invalid" ,
393
+ },
394
+ },
395
+ }
396
+ }
0 commit comments