@@ -14,9 +14,11 @@ import (
14
14
"os/exec"
15
15
"path"
16
16
"path/filepath"
17
+ "strconv"
17
18
"strings"
18
19
"time"
19
20
21
+ "github.com/blang/semver"
20
22
"github.com/golang/protobuf/ptypes/empty"
21
23
apiv1 "k8s.io/api/core/v1"
22
24
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -277,24 +279,26 @@ func executeK8s(q *integrationplugin.DeployQuery) error {
277
279
}
278
280
279
281
func executeHelm (q * integrationplugin.DeployQuery ) error {
280
- releaseName := q .GetOptions ()["cds.integration.release_name" ]
281
- namespace := q .GetOptions ()["cds.integration.namespace" ]
282
- helmChart := q .GetOptions ()["cds.integration.helm_chart" ]
283
- helmValues := q .GetOptions ()["cds.integration.helm_values" ]
284
- timeoutStr := q .GetOptions ()["cds.integration.timeout" ]
285
282
project := q .GetOptions ()["cds.project" ]
286
283
workflow := q .GetOptions ()["cds.workflow" ]
287
- application := q .GetOptions ()["cds.application" ]
288
- if namespace == "" {
289
- namespace = "default"
284
+ helmVersion := q .GetOptions ()["cds.integration.helm_version" ]
285
+
286
+ if helmVersion == "" {
287
+ helmVersion = "2.12.2"
290
288
}
291
- if releaseName != "" {
292
- application = releaseName
289
+
290
+ version , err := semver .Parse (helmVersion )
291
+ if err != nil {
292
+ return fmt .Errorf ("Invalid Helm Version %s - err: %v" , helmVersion , err )
293
+ }
294
+ supportedVersion := ">=2.0.0 <4.0.0"
295
+ expectedRange , err := semver .ParseRange (supportedVersion )
296
+ if err != nil {
297
+ return fmt .Errorf ("Fail to parse semver range : %v" , err )
293
298
}
294
299
295
- helmFound := false
296
- if _ , err := exec .LookPath ("helm" ); err == nil {
297
- helmFound = true
300
+ if ! expectedRange (version ) {
301
+ return fmt .Errorf ("Unsupported helm version, should be : %s" , supportedVersion )
298
302
}
299
303
300
304
cwd , err := os .Getwd ()
@@ -303,12 +307,38 @@ func executeHelm(q *integrationplugin.DeployQuery) error {
303
307
}
304
308
305
309
binaryName := "helm"
310
+ kubeCfg := "KUBECONFIG=" + path .Join (cwd , ".kube/config" )
311
+
312
+ helmFound := false
313
+ if _ , err := exec .LookPath ("helm" ); err == nil {
314
+ helmFound = true
315
+ }
316
+
317
+ if helmFound {
318
+ out , err := exec .Command (binaryName , "version" , "--client" , "--short" ).Output ()
319
+ if err != nil {
320
+ return fmt .Errorf ("Cannot check helm version : %v" , err )
321
+ }
322
+ installedHelm := strings .TrimPrefix (string (out ), "Client: " )
323
+ installedVersion , err := semver .ParseTolerant (installedHelm )
324
+ if err != nil {
325
+ return fmt .Errorf ("Invalid installed Helm Version %s - err: %v" , installedHelm , err )
326
+ }
327
+
328
+ if ! version .Equals (installedVersion ) {
329
+ fmt .Println ("Helm in path is not at correct version, need installation" )
330
+ fmt .Printf ("Path version : %s\n " , installedVersion .String ())
331
+ fmt .Printf ("Target version : %s\n " , version .String ())
332
+ helmFound = false
333
+ }
334
+ }
335
+
306
336
if ! helmFound {
307
- fmt .Println ("Download helm in progress..." )
337
+ fmt .Printf ("Download helm %s in progress...\n " , version . String () )
308
338
netClient := & http.Client {
309
339
Timeout : time .Second * 600 ,
310
340
}
311
- response , err := netClient .Get ("https://storage.googleapis.com/kubernetes- helm/helm-v2.12.2-" + sdk .GOOS + "-" + sdk .GOARCH + ".tar.gz" )
341
+ response , err := netClient .Get (fmt . Sprintf ( "https://get.helm.sh/ helm-v%s-%s-%s.tar.gz" , version . String (), sdk .GOOS , sdk .GOARCH ) )
312
342
if err != nil {
313
343
return fmt .Errorf ("Cannot download helm : %v" , err )
314
344
}
@@ -334,14 +364,43 @@ func executeHelm(q *integrationplugin.DeployQuery) error {
334
364
binaryName = path .Join ("." , binaryName , sdk .GOOS + "-" + sdk .GOARCH , "helm" )
335
365
}
336
366
367
+ switch version .Major {
368
+ case 2 :
369
+ return executeHelmV2 (binaryName , kubeCfg , q )
370
+ case 3 :
371
+ return executeHelmV3 (binaryName , kubeCfg , q )
372
+ }
373
+
374
+ return fmt .Errorf ("Unsupported helm version" )
375
+ }
376
+
377
+ func executeHelmV2 (binaryName , kubeCfg string , q * integrationplugin.DeployQuery ) error {
378
+ releaseName := q .GetOptions ()["cds.integration.release_name" ]
379
+ namespace := q .GetOptions ()["cds.integration.namespace" ]
380
+ helmChart := q .GetOptions ()["cds.integration.helm_chart" ]
381
+ helmValues := q .GetOptions ()["cds.integration.helm_values" ]
382
+ timeoutStr := q .GetOptions ()["cds.integration.timeout" ]
383
+ application := q .GetOptions ()["cds.application" ]
384
+
385
+ if namespace == "" {
386
+ namespace = "default"
387
+ }
388
+ if releaseName != "" {
389
+ application = releaseName
390
+ }
391
+
392
+ if d , err := time .ParseDuration (timeoutStr ); err == nil {
393
+ timeoutStr = strconv .Itoa (int (d .Seconds ()))
394
+ fmt .Println ("timeout is a duration, converting timeout in seconds to " + timeoutStr )
395
+ }
396
+
337
397
cmdInit := exec .Command (binaryName , "init" , "--client-only" )
338
398
cmdInit .Env = os .Environ ()
339
399
cmdInit .Stderr = os .Stderr
340
400
cmdInit .Stdout = os .Stdout
341
401
if err := cmdInit .Run (); err != nil {
342
402
return fmt .Errorf ("Cannot execute helm init : %v" , err )
343
403
}
344
- kubeCfg := "KUBECONFIG=" + path .Join (cwd , ".kube/config" )
345
404
346
405
if _ , err := os .Stat (helmChart ); err == nil {
347
406
fmt .Println ("Helm dependency update" )
@@ -402,6 +461,93 @@ func executeHelm(q *integrationplugin.DeployQuery) error {
402
461
return nil
403
462
}
404
463
464
+ func executeHelmV3 (binaryName , kubeCfg string , q * integrationplugin.DeployQuery ) error {
465
+ releaseName := q .GetOptions ()["cds.integration.release_name" ]
466
+ namespace := q .GetOptions ()["cds.integration.namespace" ]
467
+ helmChart := q .GetOptions ()["cds.integration.helm_chart" ]
468
+ helmValues := q .GetOptions ()["cds.integration.helm_values" ]
469
+ timeoutStr := q .GetOptions ()["cds.integration.timeout" ]
470
+ application := q .GetOptions ()["cds.application" ]
471
+
472
+ if namespace == "" {
473
+ namespace = "default"
474
+ }
475
+ if releaseName != "" {
476
+ application = releaseName
477
+ }
478
+ if _ , err := time .ParseDuration (timeoutStr ); err != nil {
479
+ timeoutStr = timeoutStr + "s"
480
+ fmt .Println ("timeout is not a duration, setting timeout to " + timeoutStr )
481
+ }
482
+
483
+ cmdRepoAdd := exec .Command (binaryName , "repo" , "add" , "stable" , "https://kubernetes-charts.storage.googleapis.com/" )
484
+ cmdRepoAdd .Env = os .Environ ()
485
+ cmdRepoAdd .Stderr = os .Stderr
486
+ cmdRepoAdd .Stdout = os .Stdout
487
+ if err := cmdRepoAdd .Run (); err != nil {
488
+ return fmt .Errorf ("Cannot execute helm repo add stable : %v" , err )
489
+ }
490
+
491
+ if _ , err := os .Stat (helmChart ); err == nil {
492
+ fmt .Println ("Helm dependency update" )
493
+ cmdDependency := exec .Command (binaryName , "dependency" , "update" , helmChart )
494
+ cmdDependency .Env = os .Environ ()
495
+ cmdDependency .Env = append (cmdDependency .Env , kubeCfg )
496
+ cmdDependency .Stderr = os .Stderr
497
+ cmdDependency .Stdout = os .Stdout
498
+ if errCmd := cmdDependency .Run (); errCmd != nil {
499
+ return fmt .Errorf ("Cannot execute helm dependency update : %v" , errCmd )
500
+ }
501
+ }
502
+
503
+ cmdGet := exec .Command (binaryName , "get" , "all" , "--namespace=" + namespace , application )
504
+ cmdGet .Env = os .Environ ()
505
+ cmdGet .Env = append (cmdGet .Env , kubeCfg )
506
+ errCmd := cmdGet .Run ()
507
+
508
+ var args []string
509
+ if errCmd != nil { // Install
510
+ fmt .Printf ("Install helm release '%s' with chart '%s'...\n " , application , helmChart )
511
+ args = []string {"install" , "--debug" , "--timeout=" + timeoutStr , "--wait=true" , "--namespace=" + namespace }
512
+ if helmValues != "" {
513
+ args = append (args , "-f" , helmValues )
514
+ }
515
+
516
+ helmChartArgs := strings .Split (helmChart , " " )
517
+ if len (helmChartArgs ) > 1 {
518
+ args = append (args , "--repo=" + helmChartArgs [0 ], helmChartArgs [1 ])
519
+ args = append (args , application , helmChartArgs [1 ])
520
+ } else {
521
+ args = append (args , application , helmChart )
522
+ }
523
+ } else {
524
+ fmt .Printf ("Update helm release '%s' with chart '%s'...\n " , application , helmChart )
525
+ args = []string {"upgrade" , "--timeout=" + timeoutStr , "--wait=true" , "--namespace=" + namespace }
526
+ if helmValues != "" {
527
+ args = append (args , "-f" , helmValues )
528
+ }
529
+
530
+ helmChartArgs := strings .Split (helmChart , " " )
531
+ if len (helmChartArgs ) > 1 {
532
+ args = append (args , "--repo=" + helmChartArgs [0 ], application , helmChartArgs [1 ])
533
+ } else {
534
+ args = append (args , application , helmChart )
535
+ }
536
+ }
537
+
538
+ fmt .Printf ("Execute: helm %s\n " , strings .Join (args , " " ))
539
+ cmd := exec .Command (binaryName , args ... )
540
+ cmd .Env = os .Environ ()
541
+ cmd .Env = append (cmd .Env , kubeCfg )
542
+ cmd .Stderr = os .Stderr
543
+ cmd .Stdout = os .Stdout
544
+ if err := cmd .Run (); err != nil {
545
+ return fmt .Errorf ("Cannot execute helm install/update : %v" , err )
546
+ }
547
+
548
+ return nil
549
+ }
550
+
405
551
func writeHelmBinary (pathname string , gzipStream io.Reader ) error {
406
552
uncompressedStream , err := gzip .NewReader (gzipStream )
407
553
if err != nil {
0 commit comments