Skip to content

Commit

Permalink
feat: Merge multiple docs inside a single helmfile.yaml (roboll#270)
Browse files Browse the repository at this point in the history
Resolves roboll#254
  • Loading branch information
mumoshu authored Sep 19, 2018
1 parent 1ade353 commit 9808849
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 5 deletions.
72 changes: 72 additions & 0 deletions docs/writing-helmfile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# The Helmfile Best Practices Guide

This guide covers the Helmfile’s considered patterns for writing advanced helmfiles. It focuses on how helmfile should be structured and executed.

## Layering

You may occasionally end up with many helmfiles that shares common parts like which repositories to use, and whichi release to be bundled by default.

Use Layering to extract te common parts into a dedicated *library helmfile*s, so that each helmfile becomes DRY.

Let's assume that your `helmfile.yaml` looks like:

```
{ readFile "commons.yaml" }}
---
{{ readFile "environments.yaml" }}
---
releases:
- name: myapp
chart: mychart
```

Whereas `commons.yaml` contained a monitoring agent:

```yaml
releases:
- name: metricbaet
chart: stable/metricbeat
```
And `environments.yaml` contained well-known environments:

```yaml
environments:
development:
production:
```

At run time, template expressions in your `helmfile.yaml` are executed:

```yaml
releases:
- name: metricbaet
chart: stable/metricbeat
---
environments:
development:
production:
---
releases:
- name: myapp
chart: mychart
```

Resulting YAML documents are merged in the order of occurrence,
so that your `helmfile.yaml` becomes:

```yaml
environments:
development:
production:
releases:
- name: metricbaet
chart: stable/metricbeat
- name: myapp
chart: mychart
```

Great!

Now, repeat the above steps for each your `helmfile.yaml`, so that all your helmfiles becomes DRY.
28 changes: 23 additions & 5 deletions state/create.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package state

import (
"bytes"
"fmt"
"github.com/imdario/mergo"
"github.com/roboll/helmfile/environment"
"github.com/roboll/helmfile/helmexec"
"github.com/roboll/helmfile/valuesfile"
"go.uber.org/zap"
"gopkg.in/yaml.v2"
"io"
"io/ioutil"
"os"
"path/filepath"
Expand Down Expand Up @@ -64,16 +66,32 @@ func (c *creator) CreateFromYaml(content []byte, file string, env string) (*Helm
if err != nil {
return nil, &StateLoadError{fmt.Sprintf("failed to read %s", file), err}
}
state.FilePath = file
state.basePath = basePath

unmarshal := yaml.UnmarshalStrict
decoder := yaml.NewDecoder(bytes.NewReader(content))
if !c.Strict {
unmarshal = yaml.Unmarshal
decoder.SetStrict(false)
} else {
decoder.SetStrict(true)
}
if err := unmarshal(content, &state); err != nil {
return nil, &StateLoadError{fmt.Sprintf("failed to read %s", file), err}
i := 0
for {
i++

var intermediate HelmState

err := decoder.Decode(&intermediate)
if err == io.EOF {
break
} else if err != nil {
return nil, &StateLoadError{fmt.Sprintf("failed to read %s: reading document at index %d", file, i), err}
}

if err := mergo.Merge(&state, &intermediate, mergo.WithAppendSlice); err != nil {
return nil, &StateLoadError{fmt.Sprintf("failed to read %s: merging document at index %d", file, i), err}
}
}
state.FilePath = file

if len(state.DeprecatedReleases) > 0 {
if len(state.Releases) > 0 {
Expand Down

0 comments on commit 9808849

Please sign in to comment.