feat: `helmfile template --skip-cleanup` (#1570)
* feat: `helmfile template --skip-cleanup` Resolves #1517
This commit is contained in:
parent
5a15b65b94
commit
88884b68dc
4
main.go
4
main.go
|
|
@ -256,6 +256,10 @@ func main() {
|
||||||
Name: "skip-deps",
|
Name: "skip-deps",
|
||||||
Usage: "skip running `helm repo update` and `helm dependency build`",
|
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 {
|
Action: action(func(run *app.App, c configImpl) error {
|
||||||
return run.Template(c)
|
return run.Template(c)
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,9 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Template(c TemplateConfigProvider) error {
|
func (a *App) Template(c TemplateConfigProvider) error {
|
||||||
|
|
||||||
|
opts := []LoadOption{SetRetainValuesFiles(c.SkipCleanup())}
|
||||||
|
|
||||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||||
// `helm template` in helm v2 does not support local chart.
|
// `helm template` in helm v2 does not support local chart.
|
||||||
// So, we set forceDownload=true for helm v2 only
|
// So, we set forceDownload=true for helm v2 only
|
||||||
|
|
@ -233,7 +236,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
})
|
}, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) WriteValues(c WriteValuesConfigProvider) error {
|
func (a *App) WriteValues(c WriteValuesConfigProvider) error {
|
||||||
|
|
@ -1437,6 +1440,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
|
||||||
Set: c.Set(),
|
Set: c.Set(),
|
||||||
IncludeCRDs: c.IncludeCRDs(),
|
IncludeCRDs: c.IncludeCRDs(),
|
||||||
OutputDirTemplate: c.OutputDirTemplate(),
|
OutputDirTemplate: c.OutputDirTemplate(),
|
||||||
|
SkipCleanup: c.SkipCleanup(),
|
||||||
}
|
}
|
||||||
return subst.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts)
|
return subst.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts)
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -2241,6 +2241,7 @@ type configImpl struct {
|
||||||
set []string
|
set []string
|
||||||
output string
|
output string
|
||||||
includeCRDs bool
|
includeCRDs bool
|
||||||
|
skipCleanup bool
|
||||||
skipDeps bool
|
skipDeps bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2264,6 +2265,10 @@ func (c configImpl) Validate() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c configImpl) SkipCleanup() bool {
|
||||||
|
return c.skipCleanup
|
||||||
|
}
|
||||||
|
|
||||||
func (c configImpl) SkipDeps() bool {
|
func (c configImpl) SkipDeps() bool {
|
||||||
return c.skipDeps
|
return c.skipDeps
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ type TemplateConfigProvider interface {
|
||||||
OutputDirTemplate() string
|
OutputDirTemplate() string
|
||||||
Validate() bool
|
Validate() bool
|
||||||
SkipDeps() bool
|
SkipDeps() bool
|
||||||
|
SkipCleanup() bool
|
||||||
OutputDir() string
|
OutputDir() string
|
||||||
IncludeCRDs() bool
|
IncludeCRDs() bool
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ type execer struct {
|
||||||
extra []string
|
extra []string
|
||||||
decryptedSecretMutex sync.Mutex
|
decryptedSecretMutex sync.Mutex
|
||||||
decryptedSecrets map[string]*decryptedSecret
|
decryptedSecrets map[string]*decryptedSecret
|
||||||
|
writeTempFile func([]byte) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogger(writer io.Writer, logLevel string) *zap.SugaredLogger {
|
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()
|
defer secret.mutex.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tempFile := helm.writeTempFile
|
||||||
|
|
||||||
|
if tempFile == nil {
|
||||||
|
tempFile = func(content []byte) (string, error) {
|
||||||
tmpFile, err := ioutil.TempFile("", "secret")
|
tmpFile, err := ioutil.TempFile("", "secret")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
_, err = tmpFile.Write(secret.bytes)
|
|
||||||
|
_, err = tmpFile.Write(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmpFile.Name(), err
|
return tmpFile.Name(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpFileName, err := tempFile(secret.bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
helm.logger.Debugf("Decrypted %s into %s", absPath, tmpFileName)
|
||||||
|
|
||||||
|
return tmpFileName, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (helm *execer) TemplateRelease(name string, chart string, flags ...string) error {
|
func (helm *execer) TemplateRelease(name string, chart string, flags ...string) error {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package helmexec
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -257,6 +258,12 @@ func Test_DecryptSecret(t *testing.T) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
logger := NewLogger(&buffer, "debug")
|
logger := NewLogger(&buffer, "debug")
|
||||||
helm := MockExecer(logger, "dev")
|
helm := MockExecer(logger, "dev")
|
||||||
|
|
||||||
|
tmpFilePath := "path/to/temp/file"
|
||||||
|
helm.writeTempFile = func(content []byte) (string, error) {
|
||||||
|
return tmpFilePath, nil
|
||||||
|
}
|
||||||
|
|
||||||
helm.DecryptSecret(HelmContext{}, "secretName")
|
helm.DecryptSecret(HelmContext{}, "secretName")
|
||||||
cwd, err := filepath.Abs(".")
|
cwd, err := filepath.Abs(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -270,9 +277,10 @@ Decrypting secret %s/secretName
|
||||||
exec: helm --kube-context dev secrets dec %s/secretName
|
exec: helm --kube-context dev secrets dec %s/secretName
|
||||||
Preparing to decrypt secret %s/secretName
|
Preparing to decrypt secret %s/secretName
|
||||||
Found secret in cache %s/secretName
|
Found secret in cache %s/secretName
|
||||||
`, cwd, cwd, cwd, cwd, cwd)
|
Decrypted %s/secretName into path/to/temp/file
|
||||||
if buffer.String() != expected {
|
`, cwd, cwd, cwd, cwd, cwd, cwd)
|
||||||
t.Errorf("helmexec.DecryptSecret()\nactual = %v\nexpect = %v", buffer.String(), expected)
|
if d := cmp.Diff(expected, buffer.String()); d != "" {
|
||||||
|
t.Errorf("helmexec.DecryptSecret(): want (-), got (+):\n%s", d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -670,6 +670,10 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
|
||||||
preps, prepErrs := st.prepareSyncReleases(helm, additionalValues, workerLimit, opts)
|
preps, prepErrs := st.prepareSyncReleases(helm, additionalValues, workerLimit, opts)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if opts.SkipCleanup {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range preps {
|
for _, p := range preps {
|
||||||
st.removeFiles(p.files)
|
st.removeFiles(p.files)
|
||||||
}
|
}
|
||||||
|
|
@ -1125,6 +1129,7 @@ func (st *HelmState) runHelmDepBuilds(helm helmexec.Interface, concurrency int,
|
||||||
|
|
||||||
type TemplateOpts struct {
|
type TemplateOpts struct {
|
||||||
Set []string
|
Set []string
|
||||||
|
SkipCleanup bool
|
||||||
OutputDirTemplate string
|
OutputDirTemplate string
|
||||||
IncludeCRDs bool
|
IncludeCRDs bool
|
||||||
}
|
}
|
||||||
|
|
@ -1136,7 +1141,9 @@ func (o *TemplateOpts) Apply(opts *TemplateOpts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TemplateReleases wrapper for executing helm template on the releases
|
// 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{}
|
opts := &TemplateOpts{}
|
||||||
for _, o := range opt {
|
for _, o := range opt {
|
||||||
o.Apply(opts)
|
o.Apply(opts)
|
||||||
|
|
@ -1156,6 +1163,10 @@ func (st *HelmState) TemplateReleases(helm helmexec.Interface, outputDir string,
|
||||||
flags, files, err := st.flagsForTemplate(helm, release, 0)
|
flags, files, err := st.flagsForTemplate(helm, release, 0)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if opts.SkipCleanup {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
st.removeFiles(files)
|
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)
|
preps, prepErrs := st.prepareDiffReleases(helm, additionalValues, workerLimit, detailedExitCode, includeTests, suppressSecrets, opts)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if opts.SkipCleanup {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range preps {
|
for _, p := range preps {
|
||||||
st.removeFiles(p.files)
|
st.removeFiles(p.files)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue