Skip to content

Commit

Permalink
feat: helmfile template --output-dir-template for customizing outpu…
Browse files Browse the repository at this point in the history
…t dirs (#1357)

This is useful for e.g. removing state file names and their hash values out of output dirs so that it can be used easily in a gitops setup. For example, `--output-dir-template mybasedir/{{.Release.Name}}` produces `mybasedir/RELEASE/CHART/templates/*.yaml` for each release in your helmfile.yaml.
  • Loading branch information
mumoshu authored Jul 16, 2020
1 parent 31d0fce commit df6489a
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 7 deletions.
8 changes: 8 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ func main() {
Name: "output-dir",
Usage: "output directory to pass to helm template (helm template --output-dir)",
},
cli.StringFlag{
Name: "output-dir-template",
Usage: "go text template for generating the output directory. Default: {{ .OutputDir }}/{{ .State.BaseName }}-{{ .State.AbsPathSHA1 }}-{{ .Release.Name}}",
},
cli.IntFlag{
Name: "concurrency",
Value: 0,
Expand Down Expand Up @@ -552,6 +556,10 @@ func (c configImpl) OutputDir() string {
return c.c.String("output-dir")
}

func (c configImpl) OutputDirTemplate() string {
return c.c.String("output-dir-template")
}

func (c configImpl) Validate() bool {
return c.c.Bool("validate")
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,8 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {

args := argparser.GetArgs(c.Args(), st)
opts := &state.TemplateOpts{
Set: c.Set(),
Set: c.Set(),
OutputDirTemplate: c.OutputDirTemplate(),
}
return subst.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts)
}))
Expand Down
4 changes: 4 additions & 0 deletions pkg/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,10 @@ func (c configImpl) OutputDir() string {
return "output/subdir"
}

func (c configImpl) OutputDirTemplate() string {
return ""
}

func (c configImpl) Concurrency() int {
return 1
}
Expand Down
1 change: 1 addition & 0 deletions pkg/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ type TemplateConfigProvider interface {

Values() []string
Set() []string
OutputDirTemplate() string
Validate() bool
SkipDeps() bool
OutputDir() string
Expand Down
54 changes: 48 additions & 6 deletions pkg/state/state.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package state

import (
"bytes"
"crypto/sha1"
"encoding/hex"
"errors"
Expand All @@ -16,6 +17,7 @@ import (
"strconv"
"strings"
"sync"
"text/template"

"github.com/roboll/helmfile/pkg/environment"
"github.com/roboll/helmfile/pkg/event"
Expand Down Expand Up @@ -828,7 +830,8 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
}

type TemplateOpts struct {
Set []string
Set []string
OutputDirTemplate string
}

type TemplateOpt interface{ Apply(*TemplateOpts) }
Expand Down Expand Up @@ -890,8 +893,8 @@ func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string,
}
}

if len(outputDir) > 0 {
releaseOutputDir, err := st.GenerateOutputDir(outputDir, release)
if len(outputDir) > 0 || len(opts.OutputDirTemplate) > 0 {
releaseOutputDir, err := st.GenerateOutputDir(outputDir, release, opts.OutputDirTemplate)
if err != nil {
errs = append(errs, err)
}
Expand Down Expand Up @@ -2193,7 +2196,7 @@ func (hf *SubHelmfileSpec) UnmarshalYAML(unmarshal func(interface{}) error) erro
return nil
}

func (st *HelmState) GenerateOutputDir(outputDir string, release *ReleaseSpec) (string, error) {
func (st *HelmState) GenerateOutputDir(outputDir string, release *ReleaseSpec, outputDirTemplate string) (string, error) {
// get absolute path of state file to generate a hash
// use this hash to write helm output in a specific directory by state file and release name
// ie. in a directory named stateFileName-stateFileHash-releaseName
Expand All @@ -2208,14 +2211,53 @@ func (st *HelmState) GenerateOutputDir(outputDir string, release *ReleaseSpec) (
var stateFileExtension = filepath.Ext(st.FilePath)
var stateFileName = st.FilePath[0 : len(st.FilePath)-len(stateFileExtension)]

sha1sum := hex.EncodeToString(hasher.Sum(nil))[:8]

var sb strings.Builder
sb.WriteString(stateFileName)
sb.WriteString("-")
sb.WriteString(hex.EncodeToString(hasher.Sum(nil))[:8])
sb.WriteString(sha1sum)
sb.WriteString("-")
sb.WriteString(release.Name)

return path.Join(outputDir, sb.String()), nil
if outputDirTemplate == "" {
outputDirTemplate = filepath.Join("{{ .OutputDir }}", "{{ .State.BaseName }}-{{ .State.AbsPathSHA1 }}-{{ .Release.Name}}")
}

t, err := template.New("output-dir").Parse(outputDirTemplate)
if err != nil {
return "", fmt.Errorf("parsing output-dir templmate")
}

buf := &bytes.Buffer{}

type state struct {
BaseName string
Path string
AbsPath string
AbsPathSHA1 string
}

data := struct {
OutputDir string
State state
Release *ReleaseSpec
}{
OutputDir: outputDir,
State: state{
BaseName: stateFileName,
Path: st.FilePath,
AbsPath: stateAbsPath,
AbsPathSHA1: sha1sum,
},
Release: release,
}

if err := t.Execute(buf, data); err != nil {
return "", fmt.Errorf("executing output-dir template: %w", err)
}

return buf.String(), nil
}

func (st *HelmState) ToYaml() (string, error) {
Expand Down

0 comments on commit df6489a

Please sign in to comment.