Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Return Values as part of the helm.Chart object so that chart comparison
Browse files Browse the repository at this point in the history
done during dry-run will take into account the charts base values which
ultimately results in ensure we perform a release when a charts base
values change.
  • Loading branch information
stefansedich authored and hiddeco committed Jan 8, 2020
1 parent 448897b commit 0f03935
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 35 deletions.
11 changes: 5 additions & 6 deletions pkg/apis/helm.fluxcd.io/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import (
"github.com/fluxcd/flux/pkg/resource"
"github.com/ghodss/yaml"

"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"k8s.io/helm/pkg/chartutil"

"github.com/fluxcd/helm-operator/pkg/helm/v2"
"github.com/fluxcd/helm-operator/pkg/helm"
v2 "github.com/fluxcd/helm-operator/pkg/helm/v2"
)

// +genclient
Expand Down Expand Up @@ -280,7 +279,7 @@ const (
// FluxHelmValues embeds chartutil.Values so we can implement deepcopy on map[string]interface{}
// +k8s:deepcopy-gen=false
type HelmValues struct {
chartutil.Values `json:"values,omitempty"`
helm.Values `json:"values,omitempty"`
}

// DeepCopyInto implements deepcopy-gen method for use in generated code
Expand All @@ -293,7 +292,7 @@ func (in *HelmValues) DeepCopyInto(out *HelmValues) {
if err != nil {
return
}
var values chartutil.Values
var values helm.Values
err = yaml.Unmarshal(b, &values)
if err != nil {
return
Expand Down
1 change: 1 addition & 0 deletions pkg/helm/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Chart struct {
Name string
Version string
AppVersion string
Values Values
Files []*File
Templates []*File
Dependencies []*Chart
Expand Down
2 changes: 2 additions & 0 deletions pkg/helm/v2/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ func chartToGenericChart(c *chart.Chart) *helm.Chart {
if c == nil || c.Metadata == nil {
return nil
}

return &helm.Chart{
Name: c.Metadata.Name,
Version: c.Metadata.Version,
AppVersion: c.Metadata.AppVersion,
Values: valuesToGenericValues(c.Values),
Files: filesToGenericFiles(c.Files),
Templates: templatesToGenericFiles(c.Templates),
Dependencies: dependenciesToGenericDependencies(c.Dependencies),
Expand Down
1 change: 1 addition & 0 deletions pkg/helm/v3/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func chartToGenericChart(c *chart.Chart) *helm.Chart {
Name: c.Name(),
Version: formatVersion(c),
AppVersion: c.AppVersion(),
Values: c.Values,
Files: filesToGenericFiles(c.Files),
Templates: filesToGenericFiles(c.Templates),
Dependencies: dependenciesToGenericDependencies(c.Dependencies()),
Expand Down
29 changes: 29 additions & 0 deletions pkg/helm/values.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package helm

import (
"crypto/sha256"
"encoding/hex"

"github.com/ghodss/yaml"
)

// Values represents a collection of (Helm) values.
// We define our own type to avoid working with two `chartutil`
// versions.
type Values map[string]interface{}

// YAML encodes the values into YAML bytes.
func (v Values) YAML() ([]byte, error) {
b, err := yaml.Marshal(v)
return b, err
}

// Checksum calculates and returns the SHA256 checksum of the YAML
// encoded values.
func (v Values) Checksum() string {
b, _ := v.YAML()

hasher := sha256.New()
hasher.Write(b)
return hex.EncodeToString(hasher.Sum(nil))
}
2 changes: 1 addition & 1 deletion pkg/release/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func (r *Release) Uninstall(client helm.Client, hr *v1.HelmRelease) {
// before running the dry-run release to determine if any undefined
// mutations have occurred.
func shouldSync(logger log.Logger, client helm.Client, hr *v1.HelmRelease, curRel *helm.Release,
chartPath string, values values, logDiffs bool) (bool, error) {
chartPath string, values helm.Values, logDiffs bool) (bool, error) {

if curRel == nil {
logger.Log("info", "no existing release", "action", "install")
Expand Down
33 changes: 5 additions & 28 deletions pkg/release/values.go
Original file line number Diff line number Diff line change
@@ -1,53 +1,30 @@
package release

import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path/filepath"

v1 "github.com/fluxcd/helm-operator/pkg/apis/helm.fluxcd.io/v1"
"github.com/fluxcd/helm-operator/pkg/helm"
"github.com/ghodss/yaml"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"

"github.com/fluxcd/helm-operator/pkg/apis/helm.fluxcd.io/v1"
)

// values represents a collection of (Helm) values.
// We define our own type to avoid working with two `chartutil`
// versions.
type values map[string]interface{}

// YAML encodes the values into YAML bytes.
func (v values) YAML() ([]byte, error) {
b, err := yaml.Marshal(v)
return b, err
}

// Checksum calculates and returns the SHA256 checksum of the YAML
// encoded values.
func (v values) Checksum() string {
b, _ := v.YAML()

hasher := sha256.New()
hasher.Write(b)
return hex.EncodeToString(hasher.Sum(nil))
}

// values attempts to compose the final values for the given
// `HelmRelease`. It returns the values as bytes and a checksum,
// or an error in case anything went wrong.
func composeValues(coreV1Client corev1.CoreV1Interface, hr *v1.HelmRelease, chartPath string) (values, error) {
result := values{}
func composeValues(coreV1Client corev1.CoreV1Interface, hr *v1.HelmRelease, chartPath string) (helm.Values, error) {
result := helm.Values{}
ns := hr.Namespace

for _, v := range hr.GetValuesFromSources() {
var valueFile values
var valueFile helm.Values

switch {
case v.ConfigMapKeyRef != nil:
Expand Down
28 changes: 28 additions & 0 deletions test/e2e/15_upgrade.bats
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ function setup() {
poll_until_equals 'podinfo-git HelmRelease revision matches' "$head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.revision}'"
}

@test "Git values.yaml change causes upgrade" {
# Apply the HelmRelease fixtures
kubectl apply -f "$FIXTURES_DIR/releases/git.yaml" >&3

# Wait for it to be deployed
poll_until_equals 'podinfo-git HelmRelease' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o 'custom-columns=status:status.releaseStatus' --no-headers"

# Clone the charts repository
local clone_dir
clone_dir="$(mktemp -d)"
defer rm -rf "'$clone_dir'"
git clone -b master ssh://git@localhost/git-server/repos/cluster.git "$clone_dir"
cd "$clone_dir"

# Make a values.yaml mutation in Git
sed -i 's%replicaCount: 1%replicaCount: 2%' charts/podinfo/values.yaml
git add charts/podinfo/values.yaml
git -c 'user.email=foo@bar.com' -c 'user.name=Foo' commit -m "Change replicaCount to 2"

# Record new HEAD and push change
head_hash=$(git rev-list -n 1 HEAD)
git push >&3

# Assert change is rolled out
poll_until_equals 'podinfo-git HelmRelease chart update' "successfully cloned chart revision: $head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.conditions[?(@.type==\"ChartFetched\")].message}'"
poll_until_equals 'podinfo-git HelmRelease revision matches' "$head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.revision}'"
}

function teardown() {
run_deferred

Expand Down

0 comments on commit 0f03935

Please sign in to comment.