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

add the valueFiles value to the FluxHelmRelease #1468

Merged
merged 4 commits into from
Oct 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions apis/helm.integrations.flux.weave.works/v1alpha2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v1alpha2

import (
"github.com/ghodss/yaml"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/helm/pkg/chartutil"
)
Expand All @@ -22,9 +23,10 @@ type FluxHelmRelease struct {
// FluxHelmReleaseSpec is the spec for a FluxHelmRelease resource
// FluxHelmReleaseSpec
type FluxHelmReleaseSpec struct {
ChartGitPath string `json:"chartGitPath"`
ReleaseName string `json:"releaseName,omitempty"`
FluxHelmValues `json:",inline"`
ChartGitPath string `json:"chartGitPath"`
ReleaseName string `json:"releaseName,omitempty"`
ValueFileSecrets []v1.LocalObjectReference `json:"valueFileSecrets,omitempty"`
FluxHelmValues `json:",inline"`
}

type FluxHelmReleaseStatus struct {
Expand Down
7 changes: 7 additions & 0 deletions chart/flux/templates/helm-operator-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,12 @@ spec:
type: string
values:
type: object
valueFileSecrets:
type: array
items:
type: object
properties:
name:
type: string
{{- end -}}
{{- end -}}
7 changes: 7 additions & 0 deletions deploy-helm/flux-helm-release-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ spec:
type: string
values:
type: object
valueFileSecrets:
type: array
items:
type: object
properties:
name:
type: string
8 changes: 4 additions & 4 deletions integrations/helm/chartsync/chartsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (chs *ChartChangeSync) applyChartChanges(prevRef, head string) error {
rlsName := release.GetReleaseName(fhr)
opts := release.InstallOptions{DryRun: false}
chs.mu.RLock()
if _, err = chs.release.Install(chs.clone.Dir(), rlsName, fhr, release.UpgradeAction, opts); err != nil {
if _, err = chs.release.Install(chs.clone.Dir(), rlsName, fhr, release.UpgradeAction, opts, &chs.kubeClient); err != nil {
// NB in this step, failure to release is considered non-fatal, i.e,. we move on to the next rather than giving up entirely.
chs.logger.Log("warning", "failure to release chart with changes in git", "error", err, "chart", chartPath, "release", rlsName)
}
Expand Down Expand Up @@ -250,7 +250,7 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr ifv1.FluxHelmRelease) {

opts := release.InstallOptions{DryRun: false}
if rel == nil {
_, err := chs.release.Install(chs.clone.Dir(), releaseName, fhr, release.InstallAction, opts)
_, err := chs.release.Install(chs.clone.Dir(), releaseName, fhr, release.InstallAction, opts, &chs.kubeClient)
if err != nil {
chs.logger.Log("warning", "Failed to install chart", "namespace", fhr.Namespace, "name", fhr.Name, "error", err)
}
Expand All @@ -263,7 +263,7 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr ifv1.FluxHelmRelease) {
return
}
if changed {
_, err := chs.release.Install(chs.clone.Dir(), releaseName, fhr, release.UpgradeAction, opts)
_, err := chs.release.Install(chs.clone.Dir(), releaseName, fhr, release.UpgradeAction, opts, &chs.kubeClient)
if err != nil {
chs.logger.Log("warning", "Failed to upgrade chart", "namespace", fhr.Namespace, "name", fhr.Name, "error", err)
}
Expand Down Expand Up @@ -391,7 +391,7 @@ func (chs *ChartChangeSync) shouldUpgrade(chartsRepo string, currRel *hapi_relea
// Get the desired release state
opts := release.InstallOptions{DryRun: true}
tempRelName := currRel.GetName() + "-temp"
desRel, err := chs.release.Install(chartsRepo, tempRelName, fhr, release.InstallAction, opts)
desRel, err := chs.release.Install(chartsRepo, tempRelName, fhr, release.InstallAction, opts, &chs.kubeClient)
if err != nil {
return false, err
}
Expand Down
58 changes: 56 additions & 2 deletions integrations/helm/release/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import (
"path/filepath"
"time"

"github.com/ghodss/yaml"
"github.com/go-kit/kit/log"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/helm/pkg/chartutil"
k8shelm "k8s.io/helm/pkg/helm"
hapi_release "k8s.io/helm/pkg/proto/hapi/release"

Expand Down Expand Up @@ -132,7 +136,7 @@ func (r *Release) canDelete(name string) (bool, error) {
// charts, and the FluxHelmRelease specifying the release. Depending
// on the release type, this is either a new release, or an upgrade of
// an existing one.
func (r *Release) Install(repoDir, releaseName string, fhr ifv1.FluxHelmRelease, action Action, opts InstallOptions) (*hapi_release.Release, error) {
func (r *Release) Install(repoDir, releaseName string, fhr ifv1.FluxHelmRelease, action Action, opts InstallOptions, kubeClient *kubernetes.Clientset) (*hapi_release.Release, error) {
r.logger.Log("info", fmt.Sprintf("releaseName= %s, action=%s, install options: %+v", releaseName, action, opts))

chartPath := fhr.Spec.ChartGitPath
Expand All @@ -155,7 +159,29 @@ func (r *Release) Install(repoDir, releaseName string, fhr ifv1.FluxHelmRelease,
}
}

strVals, err := fhr.Spec.Values.YAML()
// Read values from given valueFile paths (configmaps, etc.)
mergedValues := chartutil.Values{}
for _, valueFileSecret := range fhr.Spec.ValueFileSecrets {
// Read the contents of the secret
secret, err := kubeClient.CoreV1().Secrets(namespace).Get(valueFileSecret.Name, v1.GetOptions{})
if err != nil {
r.logger.Log("error", fmt.Sprintf("Cannot get secret %s for Chart release [%s]: %#v", valueFileSecret.Name, releaseName, err))
return nil, err
}

// Load values.yaml file and merge
var values chartutil.Values
err = yaml.Unmarshal(secret.Data["values.yaml"], &values)
if err != nil {
r.logger.Log("error", fmt.Sprintf("Cannot yaml.Unmashal values.yaml in secret %s for Chart release [%s]: %#v", valueFileSecret.Name, releaseName, err))
return nil, err
}
mergedValues = mergeValues(mergedValues, values)
}
// Merge in values after valueFiles
mergedValues = mergeValues(mergedValues, fhr.Spec.Values)

strVals, err := mergedValues.YAML()
if err != nil {
r.logger.Log("error", fmt.Sprintf("Problem with supplied customizations for Chart release [%s]: %#v", releaseName, err))
return nil, err
Expand Down Expand Up @@ -293,3 +319,31 @@ func (r *Release) annotateResources(release *hapi_release.Release, fhr ifv1.Flux
func fhrResourceID(fhr ifv1.FluxHelmRelease) flux.ResourceID {
return flux.MakeResourceID(fhr.Namespace, "FluxHelmRelease", fhr.Name)
}

// Merges source and destination `chartutils.Values`, preferring values from the source Values
// This is slightly adapted from https://github.com/helm/helm/blob/master/cmd/helm/install.go#L329
func mergeValues(dest, src chartutil.Values) chartutil.Values {
Smirl marked this conversation as resolved.
Show resolved Hide resolved
for k, v := range src {
// If the key doesn't exist already, then just set the key to that value
if _, exists := dest[k]; !exists {
dest[k] = v
continue
}
nextMap, ok := v.(map[string]interface{})
// If it isn't another map, overwrite the value
if !ok {
dest[k] = v
continue
}
// Edge case: If the key exists in the destination, but isn't a map
destMap, isMap := dest[k].(map[string]interface{})
// If the source map has a map for this key, prefer it
if !isMap {
dest[k] = v
continue
}
// If we got to this point, it is a map in both, so merge them
dest[k] = mergeValues(destMap, nextMap)
}
return dest
}
80 changes: 63 additions & 17 deletions site/helm-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,40 +37,86 @@ Flux-Helm Integration implementation consists of two parts:
kind: FluxHelmRelease
metadata:
name: mongodb
namespace: myNamespace
namespace: myNamespace
spec:
chartGitPath: mongodb
releaseName: mongo-database
values:
valueFileSecrets:
- name: "my-secret-1"
- name: "my-secret-2"
values
image: bitnami/mongodb:3.7.1-r1
```

## Required fields

- name
- namespace
- chartGitPath ... path (from repo root) to a Chart subdirectory
- `.metadata.name`
- `.metadata.namespace`
- `.spec.chartGitPath` - path (relative to `--git-charts-path`) to a Chart subdirectory

## Optional fields

- image
- resources -> requests -> memory (nested)
- releaseName:
- `.spec.values` - Any values which are passed to tiller in a similar
manner to the `--set` flag in the helm CLI. They can be any value
like that in a chart's `values.yaml`. For example:
```yaml
values:
foo: value1
bar:
baz: value2
oof:
- item1
- item2
```

- `.spec.valueFileSecrets` - Value files read in a similar way to the
`-f/--values` flag in the helm CLI. This field is an array of
`LocalObjectReference` which reference secrets.

- A `LocalObjectReference` is an object with a `name` parameter (see
example below).
- The secrets must contain a file called `values.yaml`.
- The secrets must be in the same namespace as the FluxHelmRelease.
- These values always have a lower priority that those passed
via the `.spec.values` parameter.
- If multiple secret names are passed the last in the list have higher
priority.

This is useful if you want to have cluster defaults such as the
`region`, `clustername`, `environment`, a local docker registry URL,
etc. or if you want to have secret values not checked into git.

For example:
```yaml
valueFileSecrets:
- name: "my-secret-1"
- name: "my-secret-2"
```
Where `my-secret-1` _could_ look something like:
```yaml
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: cluster-bootstrap
namespace: dev
data:
values.yaml: <base64 encoded values.yaml>
```
The contents of values.yaml _could_ look something like:
```yaml
clusterName: "my-cluster"
dockerRegistry: "registry.local"
mySecretValue: "foo"
```

- `.spec.releaseName`:
- if a release already exists and Flux should start managing it, then
releasename must be provided
- if releasename is not provided, Flux will construct a release name
based on the namespace and the Custom Resource name (ie
$namespace-$CR_name)

```yaml
- values:
foo: value1
bar:
baz: value2
oof:
- item1
- item2
```
- `automated` annotations define which images Flux will automatically
deploy on a cluster. You can use glob, semver or regex expressions.
Here's an example for a single image:
Expand Down