feat: `helmfile template --skip-cleanup` (#1570)

* feat: `helmfile template --skip-cleanup`

Resolves #1517
This commit is contained in:
Yusuke Kuoka 2020-11-06 09:23:49 +09:00 committed by GitHub
parent 5a15b65b94
commit 88884b68dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 64 additions and 10 deletions

View File

@ -256,6 +256,10 @@ func main() {
Name: "skip-deps",
Usage: "skip running `helm repo update` and `helm dependency build`",
},
cli.BoolFlag{
Name: "skip-cleanup",
Usage: "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security",
},
},
Action: action(func(run *app.App, c configImpl) error {
return run.Template(c)

View File

@ -218,6 +218,9 @@ func (a *App) Diff(c DiffConfigProvider) error {
}
func (a *App) Template(c TemplateConfigProvider) error {
opts := []LoadOption{SetRetainValuesFiles(c.SkipCleanup())}
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
// `helm template` in helm v2 does not support local chart.
// So, we set forceDownload=true for helm v2 only
@ -233,7 +236,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
}
return
})
}, opts...)
}
func (a *App) WriteValues(c WriteValuesConfigProvider) error {
@ -1437,6 +1440,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
Set: c.Set(),
IncludeCRDs: c.IncludeCRDs(),
OutputDirTemplate: c.OutputDirTemplate(),
SkipCleanup: c.SkipCleanup(),
}
return subst.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts)
}))

View File

@ -2241,6 +2241,7 @@ type configImpl struct {
set []string
output string
includeCRDs bool
skipCleanup bool
skipDeps bool
}
@ -2264,6 +2265,10 @@ func (c configImpl) Validate() bool {
return true
}
func (c configImpl) SkipCleanup() bool {
return c.skipCleanup
}
func (c configImpl) SkipDeps() bool {
return c.skipDeps
}

View File

@ -134,6 +134,7 @@ type TemplateConfigProvider interface {
OutputDirTemplate() string
Validate() bool
SkipDeps() bool
SkipCleanup() bool
OutputDir() string
IncludeCRDs() bool

View File

@ -29,6 +29,7 @@ type execer struct {
extra []string
decryptedSecretMutex sync.Mutex
decryptedSecrets map[string]*decryptedSecret
writeTempFile func([]byte) (string, error)
}
func NewLogger(writer io.Writer, logLevel string) *zap.SugaredLogger {
@ -278,16 +279,32 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
defer secret.mutex.RUnlock()
}
tmpFile, err := ioutil.TempFile("", "secret")
if err != nil {
return "", err
tempFile := helm.writeTempFile
if tempFile == nil {
tempFile = func(content []byte) (string, error) {
tmpFile, err := ioutil.TempFile("", "secret")
if err != nil {
return "", err
}
_, err = tmpFile.Write(content)
if err != nil {
return "", err
}
return tmpFile.Name(), nil
}
}
_, err = tmpFile.Write(secret.bytes)
tmpFileName, err := tempFile(secret.bytes)
if err != nil {
return "", err
}
return tmpFile.Name(), err
helm.logger.Debugf("Decrypted %s into %s", absPath, tmpFileName)
return tmpFileName, err
}
func (helm *execer) TemplateRelease(name string, chart string, flags ...string) error {

View File

@ -3,6 +3,7 @@ package helmexec
import (
"bytes"
"fmt"
"github.com/google/go-cmp/cmp"
"os"
"path"
"path/filepath"
@ -257,6 +258,12 @@ func Test_DecryptSecret(t *testing.T) {
var buffer bytes.Buffer
logger := NewLogger(&buffer, "debug")
helm := MockExecer(logger, "dev")
tmpFilePath := "path/to/temp/file"
helm.writeTempFile = func(content []byte) (string, error) {
return tmpFilePath, nil
}
helm.DecryptSecret(HelmContext{}, "secretName")
cwd, err := filepath.Abs(".")
if err != nil {
@ -270,9 +277,10 @@ Decrypting secret %s/secretName
exec: helm --kube-context dev secrets dec %s/secretName
Preparing to decrypt secret %s/secretName
Found secret in cache %s/secretName
`, cwd, cwd, cwd, cwd, cwd)
if buffer.String() != expected {
t.Errorf("helmexec.DecryptSecret()\nactual = %v\nexpect = %v", buffer.String(), expected)
Decrypted %s/secretName into path/to/temp/file
`, cwd, cwd, cwd, cwd, cwd, cwd)
if d := cmp.Diff(expected, buffer.String()); d != "" {
t.Errorf("helmexec.DecryptSecret(): want (-), got (+):\n%s", d)
}
}

View File

@ -670,6 +670,10 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
preps, prepErrs := st.prepareSyncReleases(helm, additionalValues, workerLimit, opts)
defer func() {
if opts.SkipCleanup {
return
}
for _, p := range preps {
st.removeFiles(p.files)
}
@ -1125,6 +1129,7 @@ func (st *HelmState) runHelmDepBuilds(helm helmexec.Interface, concurrency int,
type TemplateOpts struct {
Set []string
SkipCleanup bool
OutputDirTemplate string
IncludeCRDs bool
}
@ -1136,7 +1141,9 @@ func (o *TemplateOpts) Apply(opts *TemplateOpts) {
}
// TemplateReleases wrapper for executing helm template on the releases
func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, additionalValues []string, args []string, workerLimit int, validate bool, opt ...TemplateOpt) []error {
func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string, additionalValues []string, args []string, workerLimit int,
validate bool, opt ...TemplateOpt) []error {
opts := &TemplateOpts{}
for _, o := range opt {
o.Apply(opts)
@ -1156,6 +1163,10 @@ func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string,
flags, files, err := st.flagsForTemplate(helm, release, 0)
defer func() {
if opts.SkipCleanup {
return
}
st.removeFiles(files)
}()
@ -1571,6 +1582,10 @@ func (st *HelmState) DiffReleases(helm helmexec.Interface, additionalValues []st
preps, prepErrs := st.prepareDiffReleases(helm, additionalValues, workerLimit, detailedExitCode, includeTests, suppressSecrets, opts)
defer func() {
if opts.SkipCleanup {
return
}
for _, p := range preps {
st.removeFiles(p.files)
}