@@ -17,6 +17,7 @@ package main
17
17
import (
18
18
"flag"
19
19
"fmt"
20
+ "io/ioutil"
20
21
"os"
21
22
"os/exec"
22
23
"path/filepath"
@@ -36,11 +37,12 @@ var (
36
37
teardownDriver = flag .Bool ("teardown-driver" , true , "teardown the driver after the e2e test" )
37
38
bringupCluster = flag .Bool ("bringup-cluster" , true , "build kubernetes and bringup a cluster" )
38
39
gceZone = flag .String ("gce-zone" , "" , "zone that the gce k8s cluster is created/found in" )
39
- kubeVersion = flag .String ("kube-version" , "master" , "version of Kubernetes to download and use" )
40
+ kubeVersion = flag .String ("kube-version" , "" , "version of Kubernetes to download and use for the cluster" )
41
+ testVersion = flag .String ("test-version" , "" , "version of Kubernetes to download and use for tests" )
40
42
kubeFeatureGates = flag .String ("kube-feature-gates" , "" , "feature gates to set on new kubernetes cluster" )
41
43
localK8sDir = flag .String ("local-k8s-dir" , "" , "local kubernetes/kubernetes directory to run e2e tests from" )
42
- deploymentStrat = flag .String ("deployment-strategy" , "gce " , "choose between deploying on gce or gke" )
43
- gkeClusterVer = flag .String ("gke-cluster-version" , "latest " , "version of Kubernetes master and node for gke" )
44
+ deploymentStrat = flag .String ("deployment-strategy" , "" , "choose between deploying on gce or gke" )
45
+ gkeClusterVer = flag .String ("gke-cluster-version" , "" , "version of Kubernetes master and node for gke" )
44
46
45
47
// Test infrastructure flags
46
48
boskosResourceType = flag .String ("boskos-resource-type" , "gce-project" , "name of the boskos resource type to reserve" )
@@ -67,43 +69,57 @@ const (
67
69
func init () {
68
70
flag .Set ("logtostderr" , "true" )
69
71
}
70
- func main () {
71
- flag .Parse ()
72
72
73
- if len (* stagingImage ) == 0 && ! * inProw {
74
- klog .Fatalf ("staging-image is a required flag, please specify the name of image to stage to" )
73
+ func ensureVariable (v * string , set bool , msgOnError string ) {
74
+ if set && len (* v ) == 0 {
75
+ klog .Fatal (msgOnError )
76
+ } else if ! set && len (* v ) != 0 {
77
+ klog .Fatal (msgOnError )
75
78
}
79
+ }
76
80
77
- if len (* saFile ) == 0 {
78
- klog .Fatalf ("service-account-file is a required flag" )
81
+ func ensureFlag (v * bool , setTo bool , msgOnError string ) {
82
+ if * v != setTo {
83
+ klog .Fatal (msgOnError )
79
84
}
85
+ }
80
86
81
- if len (* deployOverlayName ) == 0 {
82
- klog .Fatalf ("deploy-overlay-name is a required flag" )
83
- }
84
87
85
- if len (* storageClassFile ) == 0 && ! * migrationTest {
86
- klog .Fatalf ("One of storageclass-file and migration-test must be set" )
87
- }
88
+ func main () {
89
+ flag .Parse ()
88
90
89
- if len ( * storageClassFile ) != 0 && * migrationTest {
90
- klog . Fatalf ( "storage-class-file and migration-test cannot both be set " )
91
+ if ! * inProw {
92
+ ensureVariable ( stagingImage , true , "staging-image is a required flag, please specify the name of image to stage to " )
91
93
}
92
94
93
- if ! * bringupCluster && len (* kubeFeatureGates ) > 0 {
94
- klog .Fatalf ("kube-feature-gates set but not bringing up new cluster" )
95
+ ensureVariable (saFile , true , "service-account-file is a required flag" )
96
+ ensureVariable (deployOverlayName , true , "deploy-overlay-name is a required flag" )
97
+ ensureVariable (testFocus , true , "test-focus is a required flag" )
98
+ ensureVariable (gceZone , true , "gce-zone is a required flag" )
99
+
100
+ if * migrationTest {
101
+ ensureVariable (storageClassFile , false , "storage-class-file and migration-test cannot both be set" )
102
+ } else {
103
+ ensureVariable (storageClassFile , true , "One of storageclass-file and migration-test must be set" )
95
104
}
96
105
97
- if len ( * testFocus ) == 0 {
98
- klog . Fatalf ( "test-focus is a required flag " )
106
+ if ! * bringupCluster {
107
+ ensureVariable ( kubeFeatureGates , false , "kube-feature-gates set but not bringing up new cluster " )
99
108
}
100
109
101
- if len (* gceZone ) == 0 {
102
- klog .Fatalf ("gce-zone is a required flag" )
110
+ if * deploymentStrat == "gke" {
111
+ ensureFlag (migrationTest , false , "Cannot set deployment strategy to 'gke' for migration tests." )
112
+ ensureVariable (kubeVersion , false , "Cannot set kube-version when using deployment strategy 'gke'. Use gke-cluster-version." )
113
+ ensureVariable (gkeClusterVer , true , "Must set gke-cluster-version when using deployment strategy 'gke'." )
114
+ ensureVariable (kubeFeatureGates , false , "Cannot set feature gates when using deployment strategy 'gke'." )
115
+ if len (* localK8sDir ) == 0 {
116
+ ensureVariable (testVersion , true , "Must set either test-version or local k8s dir when using deployment strategy 'gke'." )
117
+ }
103
118
}
104
119
105
- if * deploymentStrat == "gke" && * migrationTest {
106
- klog .Fatalf ("Cannot set deployment strategy to 'gke' for migration tests." )
120
+ if len (* localK8sDir ) != 0 {
121
+ ensureVariable (kubeVersion , false , "Cannot set a kube version when using a local k8s dir." )
122
+ ensureVariable (testVersion , false , "Cannot set a test version when using a local k8s dir." )
107
123
}
108
124
109
125
err := handle ()
@@ -122,10 +138,10 @@ func handle() error {
122
138
if ! ok {
123
139
return fmt .Errorf ("Could not find env variable GOPATH" )
124
140
}
141
+
125
142
pkgDir := filepath .Join (goPath , "src" , "sigs.k8s.io" , "gcp-compute-persistent-disk-csi-driver" )
126
- k8sIoDir := filepath .Join (pkgDir , "test" , "k8s-integration" , "src" , "k8s.io" )
127
- k8sDir := filepath .Join (k8sIoDir , "kubernetes" )
128
143
144
+ // If running in Prow, then acquire and set up a project through Boskos
129
145
if * inProw {
130
146
project , _ := testutils .SetupProwConfig (* boskosResourceType )
131
147
@@ -157,69 +173,134 @@ func handle() error {
157
173
}
158
174
}
159
175
176
+ // Create temporary directories for kubernetes builds
177
+ k8sParentDir := getTempDir ()
178
+ k8sDir := filepath .Join (k8sParentDir , "kubernetes" )
179
+ testParentDir := getTempDir ()
180
+ testDir := filepath .Join (testParentDir , "kubernetes" )
181
+ defer removeTempDir (k8sParentDir )
182
+ defer removeTempDir (testParentDir )
183
+
184
+ numTasks := 4
185
+ errChan := make (chan error , numTasks )
186
+ k8sDependencyChan := make (chan bool , 1 )
187
+
188
+ // If kube version is set, then download and build Kubernetes for cluster creation
189
+ // Otherwise, either GKE or a prebuild local K8s dir is being used
190
+ if len (* kubeVersion ) != 0 {
191
+ go func () {
192
+ err := downloadKubernetesSource (pkgDir , k8sParentDir , * kubeVersion )
193
+ if err != nil {
194
+ errChan <- fmt .Errorf ("failed to download Kubernetes source: %v" , err )
195
+ k8sDependencyChan <- false
196
+ return
197
+ }
198
+ err = buildKubernetes (k8sDir )
199
+ if err != nil {
200
+ errChan <- fmt .Errorf ("failed to build Kubernetes: %v" , err )
201
+ k8sDependencyChan <- false
202
+ return
203
+ }
204
+ k8sDependencyChan <- true
205
+ errChan <- nil
206
+ }()
207
+ } else {
208
+ errChan <- nil
209
+ k8sDir = * localK8sDir
210
+ k8sDependencyChan <- true
211
+ }
212
+
213
+ // If test version is set, then download and build Kubernetes to run K8s tests
214
+ // Otherwise, either kube version is set (which implies GCE) or a local K8s dir is being used
215
+ if len (* testVersion ) != 0 && * testVersion != * kubeVersion {
216
+ go func () {
217
+ // TODO: Build only the tests
218
+ err := downloadKubernetesSource (pkgDir , testParentDir , * testVersion )
219
+ if err != nil {
220
+ errChan <- fmt .Errorf ("failed to download Kubernetes source: %v" , err )
221
+ return
222
+ }
223
+ err = buildKubernetes (testDir )
224
+ if err != nil {
225
+ errChan <- fmt .Errorf ("failed to build Kubernetes: %v" , err )
226
+ return
227
+ }
228
+ errChan <- nil
229
+ }()
230
+ } else {
231
+ testDir = k8sDir
232
+ errChan <- nil
233
+ }
234
+
235
+ // Build and push the driver, if required. Defer the driver image deletion.
160
236
if * doDriverBuild {
161
- err := pushImage (pkgDir , * stagingImage , stagingVersion )
162
- if err != nil {
163
- return fmt .Errorf ("failed pushing image: %v" , err )
164
- }
165
- defer func () {
237
+ go func () {
238
+ errChan <- pushImage (pkgDir , * stagingImage , stagingVersion )
239
+ }()
240
+ defer func (){
166
241
if * teardownCluster {
167
- err = deleteImage (* stagingImage , stagingVersion )
242
+ err : = deleteImage (* stagingImage , stagingVersion )
168
243
if err != nil {
169
244
klog .Errorf ("failed to delete image: %v" , err )
170
245
}
171
246
}
172
247
}()
248
+ } else {
249
+ errChan <- nil
173
250
}
174
251
175
252
if * bringupCluster {
176
- err := downloadKubernetesSource (pkgDir , k8sIoDir , * kubeVersion )
177
- if err != nil {
178
- return fmt .Errorf ("failed to download Kubernetes source: %v" , err )
179
- }
180
-
181
- err = buildKubernetes (k8sDir )
182
- if err != nil {
183
- return fmt .Errorf ("failed to build Kubernetes: %v" , err )
184
- }
185
-
186
- kshPath := filepath .Join (k8sDir , "cluster" , "kubectl.sh" )
187
- _ , err = os .Stat (kshPath )
188
- if err == nil {
189
- // Set kubectl to the one bundled in the k8s tar for versioning
190
- err = os .Setenv ("GCE_PD_KUBECTL" , kshPath )
191
- if err != nil {
192
- return fmt .Errorf ("failed to set cluster specific kubectl: %v" , err )
253
+ go func (){
254
+ if ! (<- k8sDependencyChan ){
255
+ errChan <- nil
256
+ return
193
257
}
194
- } else {
195
- klog .Errorf ("could not find cluster kubectl at %s, falling back to default kubectl" , kshPath )
196
- }
197
258
198
- if len (* kubeFeatureGates ) != 0 {
199
- err = os .Setenv ("KUBE_FEATURE_GATES" , * kubeFeatureGates )
200
- if err != nil {
201
- return fmt .Errorf ("failed to set kubernetes feature gates: %v" , err )
202
- }
203
- klog .V (4 ).Infof ("Set Kubernetes feature gates: %v" , * kubeFeatureGates )
204
- }
259
+ switch * deploymentStrat {
260
+ case "gce" :
261
+ kshPath := filepath .Join (k8sDir , "cluster" , "kubectl.sh" )
262
+ _ , err := os .Stat (kshPath )
263
+ if err == nil {
264
+ // Set kubectl to the one bundled in the k8s tar for versioning
265
+ err = os .Setenv ("GCE_PD_KUBECTL" , kshPath )
266
+ if err != nil {
267
+ errChan <- fmt .Errorf ("failed to set cluster specific kubectl: %v" , err )
268
+ return
269
+ }
270
+ } else {
271
+ klog .Errorf ("could not find cluster kubectl at %s, falling back to default kubectl" , kshPath )
272
+ }
205
273
206
- switch * deploymentStrat {
207
- case "gce" :
208
- err = clusterUpGCE (k8sDir , * gceZone )
209
- if err != nil {
210
- return fmt .Errorf ("failed to cluster up: %v" , err )
211
- }
212
- case "gke" :
213
- err = clusterUpGKE (* gceZone )
214
- if err != nil {
215
- return fmt .Errorf ("failed to cluster up: %v" , err )
216
- }
217
- default :
218
- return fmt .Errorf ("deployment-strategy must be set to 'gce' or 'gke', but is: %s" , * deploymentStrat )
219
- }
274
+ if len (* kubeFeatureGates ) != 0 {
275
+ err = os .Setenv ("KUBE_FEATURE_GATES" , * kubeFeatureGates )
276
+ if err != nil {
277
+ errChan <- fmt .Errorf ("failed to set kubernetes feature gates: %v" , err )
278
+ return
279
+ }
280
+ klog .V (4 ).Infof ("Set Kubernetes feature gates: %v" , * kubeFeatureGates )
281
+ }
220
282
283
+ err = clusterUpGCE (k8sDir , * gceZone )
284
+ if err != nil {
285
+ errChan <- fmt .Errorf ("failed to cluster up: %v" , err )
286
+ return
287
+ }
288
+ case "gke" :
289
+ err := clusterUpGKE (* gceZone )
290
+ if err != nil {
291
+ errChan <- fmt .Errorf ("failed to cluster up: %v" , err )
292
+ return
293
+ }
294
+ default :
295
+ errChan <- fmt .Errorf ("deployment-strategy must be set to 'gce' or 'gke', but is: %s" , * deploymentStrat )
296
+ }
297
+ errChan <- nil
298
+ }()
299
+ } else {
300
+ errChan <- nil
221
301
}
222
302
303
+ // Defer the tear down of the cluster through GKE or GCE
223
304
if * teardownCluster {
224
305
defer func () {
225
306
switch * deploymentStrat {
@@ -239,7 +320,21 @@ func handle() error {
239
320
}()
240
321
}
241
322
242
- err := installDriver (goPath , pkgDir , k8sDir , * stagingImage , stagingVersion , * deployOverlayName , * doDriverBuild )
323
+ // Block until all background operations are complete
324
+ var firstErr error = nil
325
+ for i := 0 ; i < 4 ; i ++ {
326
+ if err := <- errChan ; err != nil {
327
+ if firstErr == nil {
328
+ firstErr = err
329
+ }
330
+ }
331
+ }
332
+ if firstErr != nil {
333
+ return firstErr
334
+ }
335
+
336
+ // Install the driver and defer its teardown
337
+ err := installDriver (goPath , pkgDir , * stagingImage , stagingVersion , * deployOverlayName , * doDriverBuild )
243
338
if * teardownDriver {
244
339
defer func () {
245
340
// TODO (#140): collect driver logs
@@ -252,14 +347,11 @@ func handle() error {
252
347
return fmt .Errorf ("failed to install CSI Driver: %v" , err )
253
348
}
254
349
255
- if len (* localK8sDir ) != 0 {
256
- k8sDir = * localK8sDir
257
- }
258
-
350
+ // Run the tests using the testDir kubernetes
259
351
if len (* storageClassFile ) != 0 {
260
- err = runCSITests (pkgDir , k8sDir , * testFocus , * storageClassFile , * gceZone )
352
+ err = runCSITests (pkgDir , testDir , * testFocus , * storageClassFile , * gceZone )
261
353
} else if * migrationTest {
262
- err = runMigrationTests (pkgDir , k8sDir , * testFocus , * gceZone )
354
+ err = runMigrationTests (pkgDir , testDir , * testFocus , * gceZone )
263
355
} else {
264
356
return fmt .Errorf ("Did not run either CSI or Migration test" )
265
357
}
@@ -331,6 +423,7 @@ func runTestsWithConfig(pkgDir, k8sDir, gceZone, testFocus, testConfigArg string
331
423
return nil
332
424
}
333
425
426
+
334
427
func runCommand (action string , cmd * exec.Cmd ) error {
335
428
cmd .Stdout = os .Stdout
336
429
cmd .Stdin = os .Stdin
@@ -420,7 +513,7 @@ func getOverlayDir(pkgDir, deployOverlayName string) string {
420
513
return filepath .Join (pkgDir , "deploy" , "kubernetes" , "overlays" , deployOverlayName )
421
514
}
422
515
423
- func installDriver (goPath , pkgDir , k8sDir , stagingImage , stagingVersion , deployOverlayName string , doDriverBuild bool ) error {
516
+ func installDriver (goPath , pkgDir , stagingImage , stagingVersion , deployOverlayName string , doDriverBuild bool ) error {
424
517
if doDriverBuild {
425
518
// Install kustomize
426
519
out , err := exec .Command (filepath .Join (pkgDir , "deploy" , "kubernetes" , "install-kustomize.sh" )).CombinedOutput ()
@@ -449,10 +542,8 @@ func installDriver(goPath, pkgDir, k8sDir, stagingImage, stagingVersion, deployO
449
542
}
450
543
451
544
// setup service account file for secret creation
452
- tmpSaFile := fmt .Sprintf ("/tmp/%s/cloud-sa.json" , string (uuid .NewUUID ()))
453
-
454
- os .MkdirAll (filepath .Dir (tmpSaFile ), 0750 )
455
- defer os .Remove (filepath .Dir (tmpSaFile ))
545
+ tmpSaFile := filepath .Join (getTempDir (), "cloud-sa.json" )
546
+ defer removeTempDir (filepath .Dir (tmpSaFile ))
456
547
457
548
// Need to copy it to name the file "cloud-sa.json"
458
549
out , err := exec .Command ("cp" , * saFile , tmpSaFile ).CombinedOutput ()
@@ -602,3 +693,18 @@ func deleteImage(stagingImage, stagingVersion string) error {
602
693
}
603
694
return nil
604
695
}
696
+
697
+ func getTempDir () string {
698
+ dir , err := ioutil .TempDir ("" , "" )
699
+ if err != nil {
700
+ klog .Fatalf ("Error creating temp dir: %v" , err )
701
+ }
702
+ return dir
703
+ }
704
+
705
+ func removeTempDir (dir string ) {
706
+ err := os .RemoveAll (dir )
707
+ if err != nil {
708
+ klog .Fatalf ("Error removing temp dir: %v" , err )
709
+ }
710
+ }
0 commit comments