Skip to content

Commit

Permalink
prepare for helm 3
Browse files Browse the repository at this point in the history
  • Loading branch information
Christophe VILA committed Apr 17, 2020
1 parent e564084 commit 7aef962
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 102 deletions.
104 changes: 50 additions & 54 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func (p *sprayCmd) spray() error {
updatedDefaultValues := processIncludeInValuesFile(chart, p.verbose)

// Load default values...
values, err = chartutil.CoalesceValues(chart, &chartHapi.Config{Raw: string(updatedDefaultValues)})
values, err = chartutil.CoalesceValues(chart, &chartHapi.Config{Raw: updatedDefaultValues})
if err != nil {
if p.verbose {
logWithNumberedLines(1, updatedDefaultValues)
Expand All @@ -257,7 +257,7 @@ func (p *sprayCmd) spray() error {
if _, err = tempFile.Write([]byte(updatedDefaultValues)); err != nil {
logErrorAndExit("Error writing updated default values file for umbrella chart into temporary file: %s", err)
}
p.valueFiles = append([]string{tempFile.Name()}, p.valueFiles...)
p.valueFiles = append(p.valueFiles, tempFile.Name())

} else {
values, err = chartutil.CoalesceValues(chart, chart.GetValues())
Expand Down Expand Up @@ -481,26 +481,26 @@ func (p *sprayCmd) spray() error {
shouldWait = true

// Add the "<dependency>.enabled" flags to ensure that only the current chart is to be executed
valuesSet := ""
depValuesSet := ""
for _, dep := range dependencies {
if dep.UsedName == dependency.UsedName {
valuesSet = valuesSet + dep.UsedName + ".enabled=true,"
depValuesSet = depValuesSet + dep.UsedName + ".enabled=true,"
} else {
valuesSet = valuesSet + dep.UsedName + ".enabled=false,"
depValuesSet = depValuesSet + dep.UsedName + ".enabled=false,"
}
}
p.valuesSet = append(p.valuesSet, valuesSet)
var valuesSet []string
valuesSet = append(valuesSet, p.valuesSet...)
valuesSet = append(valuesSet, depValuesSet)

// Upgrade the Deployment
helmstatus := helm.UpgradeWithValues(p.namespace, dependency.CorrespondingReleaseName, p.chartName, p.resetValues, p.reuseValues, p.valueFiles, p.valuesSet, p.valuesSetString, p.valuesSetFile, p.force, p.timeout, p.dryRun, p.debug)
helmstatus := helm.UpgradeWithValues(p.namespace, dependency.CorrespondingReleaseName, p.chartName, p.resetValues, p.reuseValues, p.valueFiles, valuesSet, p.valuesSetString, p.valuesSetFile, p.force, p.timeout, p.dryRun, p.debug)
helmstatusses = append(helmstatusses, helmstatus)

log(3, "release: \"%s\" upgraded", dependency.CorrespondingReleaseName)
if p.verbose {
log(3, "helm status: %s", helmstatus.Status)
}

if p.verbose {
log(3, "helm status: %s", helmstatus.Status)
log(3, "helm resources:")
var scanner = bufio.NewScanner(strings.NewReader(helmstatus.Resources))
for scanner.Scan() {
Expand All @@ -510,64 +510,60 @@ func (p *sprayCmd) spray() error {
}
}

if helmstatus.Status == "" {
log(2, "Warning: no status returned by helm.")
} else if helmstatus.Status != "DEPLOYED" {
if !p.dryRun && helmstatus.Status != "DEPLOYED" {
logErrorAndExit("Error: status returned by helm differs from \"DEPLOYED\". Cannot continue spray processing.")
}
}
}
}

// Wait availability of the just upgraded Releases
if shouldWait {
if shouldWait && !p.dryRun {
log(2, "waiting for Liveness and Readiness...")

if !p.dryRun {
sleep_time := 5
doneDeployments := false
doneStatefulSets := false
doneJobs := false

// Wait for completion of the Deployments/StatefulSets/Jobs
for i := 0; i < p.timeout; {
deployments := getDeployments(helmstatusses)
statefulSets := getStatefulSets(helmstatusses)
jobs := getJobs(helmstatusses)
if len(deployments) > 0 && !doneDeployments {
if p.verbose {
log(3, "waiting for Deployments %v", deployments)
}
doneDeployments, _ = kubectl.AreDeploymentsReady(deployments, p.namespace, p.debug)
} else {
doneDeployments = true
}
if len(statefulSets) > 0 && !doneStatefulSets {
if p.verbose {
log(3, "waiting for StatefulSets %v", statefulSets)
}
doneStatefulSets, _ = kubectl.AreStatefulSetsReady(statefulSets, p.namespace, p.debug)
} else {
doneStatefulSets = true
sleep_time := 5
doneDeployments := false
doneStatefulSets := false
doneJobs := false

// Wait for completion of the Deployments/StatefulSets/Jobs
for i := 0; i < p.timeout; {
deployments := getDeployments(helmstatusses)
statefulSets := getStatefulSets(helmstatusses)
jobs := getJobs(helmstatusses)
if len(deployments) > 0 && !doneDeployments {
if p.verbose {
log(3, "waiting for Deployments %v", deployments)
}
if len(jobs) > 0 && !doneJobs {
if p.verbose {
log(3, "waiting for Jobs %v", jobs)
}
doneJobs, _ = kubectl.AreJobsReady(jobs, p.namespace, p.debug)
} else {
doneJobs = true
doneDeployments, _ = kubectl.AreDeploymentsReady(deployments, p.namespace, p.debug)
} else {
doneDeployments = true
}
if len(statefulSets) > 0 && !doneStatefulSets {
if p.verbose {
log(3, "waiting for StatefulSets %v", statefulSets)
}
if doneDeployments && doneStatefulSets && doneJobs {
break
doneStatefulSets, _ = kubectl.AreStatefulSetsReady(statefulSets, p.namespace, p.debug)
} else {
doneStatefulSets = true
}
if len(jobs) > 0 && !doneJobs {
if p.verbose {
log(3, "waiting for Jobs %v", jobs)
}
time.Sleep(time.Duration(sleep_time) * time.Second)
i = i + sleep_time
doneJobs, _ = kubectl.AreJobsReady(jobs, p.namespace, p.debug)
} else {
doneJobs = true
}

if !doneDeployments || !doneStatefulSets || !doneJobs {
logErrorAndExit("Error: UPGRADE FAILED: timed out waiting for the condition\n==> Error: exit status 1")
if doneDeployments && doneStatefulSets && doneJobs {
break
}
time.Sleep(time.Duration(sleep_time) * time.Second)
i = i + sleep_time
}

if !doneDeployments || !doneStatefulSets || !doneJobs {
logErrorAndExit("Error: UPGRADE FAILED: timed out waiting for the condition\n==> Error: exit status 1")
}
}
}
Expand Down
92 changes: 44 additions & 48 deletions pkg/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,39 @@ limitations under the License.
package helm

import (
"bytes"
"strings"
"strconv"
"bufio"
"io/ioutil"
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"runtime"
"regexp"
"encoding/json"
"runtime"
"strconv"
"strings"
)


// Types returned by some of the functions
type HelmStatus struct {
Namespace string
Status string
Resources string
Deployments []string
Namespace string
Status string
Resources string
Deployments []string
StatefulSets []string
Jobs []string
Jobs []string
}

type HelmRelease struct {
Name string
Revision int
Updated string
Status string
Chart string
AppVersion string
Namespace string
Name string
Revision int
Updated string
Status string
Chart string
AppVersion string
Namespace string
}


// Printing error or outputs
func printError(err error) {
if err != nil {
Expand Down Expand Up @@ -105,78 +103,77 @@ func getStringBetween(value string, a string, b string) string {
return value[posFirstAdjusted:posLastAdjusted]
}

// Parse the "helm status"-like output to extract releant information
// Parse the "helm status"-like output to extract relevant information
// WARNING: this code has been developed and tested with version 'v2.12.2' of Helm
// it may need to be adapted to other versions of Helm.
func parseStatusOutput(outs []byte, helmstatus *HelmStatus) {
var out_str = string(outs)

// Extract the namespace
var namespace = regexp.MustCompile(`NAMESPACE: (.*)`)
var namespace = regexp.MustCompile(`^NAMESPACE: (.*)`)
result := namespace.FindStringSubmatch(out_str)
if len(result) > 0 {
helmstatus.Namespace = string(result[1])
if len(result) > 1 {
helmstatus.Namespace = result[1]
}

// Extract the status
var status = regexp.MustCompile(`STATUS: (.*)`)
var status = regexp.MustCompile(`^STATUS: (.*)`)
result = status.FindStringSubmatch(out_str)
if len(result) > 0 {
helmstatus.Status = string(result[1])
if len(result) > 1 {
helmstatus.Status = result[1]
}

// Extract the resources
helmstatus.Resources = getStringAfterLast (out_str, "RESOURCES:")
helmstatus.Resources = getStringAfterLast(out_str, "RESOURCES:")

// ... and get the Deployments from the resources
var res = getStringBetween (helmstatus.Resources + "==>", "==> v1/Deployment", "==>") + "\n" +
getStringBetween (helmstatus.Resources + "==>", "==> v1beta2/Deployment", "==>") + "\n" +
getStringBetween (helmstatus.Resources + "==>", "==> v1beta1/Deployment", "==>")
var res = getStringBetween(helmstatus.Resources+"==>", "==> v1/Deployment", "==>") + "\n" +
getStringBetween(helmstatus.Resources+"==>", "==> v1beta2/Deployment", "==>") + "\n" +
getStringBetween(helmstatus.Resources+"==>", "==> v1beta1/Deployment", "==>")
var res_as_slice = make([]string, 0)
var scanner = bufio.NewScanner(strings.NewReader(res))
for scanner.Scan() {
if len (scanner.Text()) > 0 {
if len(scanner.Text()) > 0 {
name := strings.Fields(scanner.Text())[0]
res_as_slice = append (res_as_slice, name)
res_as_slice = append(res_as_slice, name)
}
}
if len(res_as_slice) > 0 {
helmstatus.Deployments = res_as_slice[1:]
}

// ... and get the StatefulSets from the resources
res = getStringBetween (helmstatus.Resources + "==>", "==> v1/StatefulSet", "==>") + "\n" +
getStringBetween (helmstatus.Resources + "==>", "==> v1beta2/StatefulSet", "==>") + "\n" +
getStringBetween (helmstatus.Resources + "==>", "==> v1beta1/StatefulSet", "==>")
res = getStringBetween(helmstatus.Resources+"==>", "==> v1/StatefulSet", "==>") + "\n" +
getStringBetween(helmstatus.Resources+"==>", "==> v1beta2/StatefulSet", "==>") + "\n" +
getStringBetween(helmstatus.Resources+"==>", "==> v1beta1/StatefulSet", "==>")

res_as_slice = make([]string, 0)
scanner = bufio.NewScanner(strings.NewReader(res))
for scanner.Scan() {
if len (scanner.Text()) > 0 {
if len(scanner.Text()) > 0 {
name := strings.Fields(scanner.Text())[0]
res_as_slice = append (res_as_slice, name)
res_as_slice = append(res_as_slice, name)
}
}
if len(res_as_slice) > 0 {
helmstatus.StatefulSets = res_as_slice[1:]
}

// ... and get the Jobs from the resources
res = getStringBetween (helmstatus.Resources + "==>", "==> v1/Job", "==>")
res = getStringBetween(helmstatus.Resources+"==>", "==> v1/Job", "==>")
res_as_slice = make([]string, 0)
scanner = bufio.NewScanner(strings.NewReader(res))
for scanner.Scan() {
if len (scanner.Text()) > 0 {
if len(scanner.Text()) > 0 {
name := strings.Fields(scanner.Text())[0]
res_as_slice = append (res_as_slice, name)
res_as_slice = append(res_as_slice, name)
}
}
if len(res_as_slice) > 0 {
helmstatus.Jobs = res_as_slice[1:]
}
}


// Helm functions calls
// --------------------

Expand All @@ -196,8 +193,8 @@ func Version() {

// List ...
type helmReleasesList struct {
Next string
Releases []HelmRelease
Next string
Releases []HelmRelease
}

func List(namespace string) map[string]HelmRelease {
Expand All @@ -223,7 +220,7 @@ func List(namespace string) map[string]HelmRelease {
// Transform the received json into structs
output := cmdOutput.Bytes()
// In case Spray has been launched in debug mode, then leading messages are polluting the output. Removing them until the starting "{"
outputWithoutLeadingDebugMessages := "{" + getStringAfterFirst (string(output), "{")
outputWithoutLeadingDebugMessages := "{" + getStringAfterFirst(string(output), "{")
var releases helmReleasesList
json.Unmarshal([]byte(outputWithoutLeadingDebugMessages), &releases)

Expand All @@ -241,7 +238,7 @@ func List(namespace string) map[string]HelmRelease {

// ListAll ...
func ListAll() map[string]HelmRelease {
return List ("")
return List("")
}

// Delete chart
Expand Down Expand Up @@ -425,7 +422,6 @@ func Fetch(chart string, version string) string {

output := cmdOutput.Bytes()
var output_str = string(output)
var result = strings.Split (output_str, endOfLine)
var result = strings.Split(output_str, endOfLine)
return result[0]
}

0 comments on commit 7aef962

Please sign in to comment.