feat: Automatically enable Helm v3 mode

Runs `helm version` in helmexec.New, and exposes a method on Interface to allow other packages to use the detected version. Preserves compatibility with previous HELMFILE_HELM3 mechanism.

Resolves #923
This commit is contained in:
Andrew Drake 2019-11-13 20:34:17 -05:00 committed by Andrew Drake
parent 43f1188325
commit c099f69d94
6 changed files with 42 additions and 20 deletions

View File

@ -1994,6 +1994,9 @@ func (helm *mockHelmExec) Fetch(chart string, flags ...string) error {
func (helm *mockHelmExec) Lint(name, chart string, flags ...string) error {
return nil
}
func (helm *mockHelmExec) IsHelm3() bool {
return false
}
func TestTemplate_SingleStateFile(t *testing.T) {
files := map[string]string{

View File

@ -157,6 +157,10 @@ func (helm *Helm) TemplateRelease(name, chart string, flags ...string) error {
return nil
}
func (helm *Helm) IsHelm3() bool {
return false
}
func (helm *Helm) sync(m *sync.Mutex, f func()) {
if m != nil {
m.Lock()

View File

@ -20,6 +20,7 @@ type decryptedSecret struct {
type execer struct {
helmBinary string
isHelm3 bool
runner Runner
logger *zap.SugaredLogger
kubeContext string
@ -45,15 +46,31 @@ func NewLogger(writer io.Writer, logLevel string) *zap.SugaredLogger {
return zap.New(core).Sugar()
}
func detectHelm3(helmBinary string, logger *zap.SugaredLogger, runner Runner) bool {
// Support explicit opt-in via environment variable
if os.Getenv("HELMFILE_HELM3") != "" {
return true
}
// Autodetect from `helm verison`
bytes, err := runner.Execute(helmBinary, []string{"version", "--client", "--short"}, nil)
if err != nil {
panic(err)
}
return strings.HasPrefix(string(bytes), "v3.")
}
// New for running helm commands
func New(helmBinary string, logger *zap.SugaredLogger, kubeContext string, runner Runner) *execer {
return &execer{
helmBinary: helmBinary,
isHelm3: detectHelm3(helmBinary, logger, runner),
logger: logger,
kubeContext: kubeContext,
runner: runner,
decryptedSecrets: make(map[string]*decryptedSecret),
}
}
func (helm *execer) SetExtraArgs(args ...string) {
@ -126,7 +143,7 @@ func (helm *execer) List(context HelmContext, filter string, flags ...string) (s
preArgs := context.GetTillerlessArgs(helm.helmBinary)
env := context.getTillerlessEnv()
var args []string
if helm.isHelm3() {
if helm.IsHelm3() {
args = []string{"list", "--filter", filter}
} else {
args = []string{"list", filter}
@ -139,7 +156,7 @@ func (helm *execer) List(context HelmContext, filter string, flags ...string) (s
// of the release to exist.
//
// This fixes it by removing the header from the v3 output, so that the output is formatted the same as that of v2.
if helm.isHelm3() {
if helm.IsHelm3() {
lines := strings.Split(string(out), "\n")
lines = lines[1:]
out = []byte(strings.Join(lines, "\n"))
@ -219,7 +236,7 @@ func (helm *execer) DecryptSecret(context HelmContext, name string, flags ...str
func (helm *execer) TemplateRelease(name string, chart string, flags ...string) error {
helm.logger.Infof("Templating release=%v, chart=%v", name, chart)
var args []string
if helm.isHelm3() {
if helm.IsHelm3() {
args = []string{"template", name, chart}
} else {
args = []string{"template", chart, "--name", name}
@ -286,7 +303,7 @@ func (helm *execer) TestRelease(context HelmContext, name string, flags ...strin
preArgs := context.GetTillerlessArgs(helm.helmBinary)
env := context.getTillerlessEnv()
var args []string
if helm.isHelm3() {
if helm.IsHelm3() {
args = []string{"test", "run", name}
} else {
args = []string{"test", name}
@ -323,6 +340,6 @@ func (helm *execer) write(out []byte) {
}
}
func (helm *execer) isHelm3() bool {
return os.Getenv("HELMFILE_HELM3") != ""
func (helm *execer) IsHelm3() bool {
return helm.isHelm3
}

View File

@ -19,8 +19,10 @@ type Interface interface {
TestRelease(context HelmContext, name string, flags ...string) error
List(context HelmContext, filter string, flags ...string) (string, error)
DecryptSecret(context HelmContext, name string, flags ...string) (string, error)
IsHelm3() bool
}
type DependencyUpdater interface {
UpdateDeps(chart string) error
IsHelm3() bool
}

View File

@ -280,7 +280,7 @@ func (m *chartDependencyManager) lockFileName() string {
}
func (m *chartDependencyManager) Update(shell helmexec.DependencyUpdater, wd string, unresolved *UnresolvedDependencies) (*ResolvedDependencies, error) {
if isHelm3() {
if shell.IsHelm3() {
return m.updateHelm3(shell, wd, unresolved)
}
return m.updateHelm2(shell, wd, unresolved)
@ -330,7 +330,7 @@ func (m *chartDependencyManager) doUpdate(chartLockFile string, unresolved *Unre
return nil, err
}
if isHelm3() && originalLockFileContent != nil {
if shell.IsHelm3() && originalLockFileContent != nil {
if err := m.writeBytes(filepath.Join(wd, chartLockFile), originalLockFileContent); err != nil {
return nil, err
}
@ -357,7 +357,7 @@ func (m *chartDependencyManager) doUpdate(chartLockFile string, unresolved *Unre
})
// Don't update lock file if no dependency updated.
if !isHelm3() && originalLockFileContent != nil {
if !shell.IsHelm3() && originalLockFileContent != nil {
originalLockedReqs := &ChartLockedRequirements{}
if err := yaml.Unmarshal(originalLockFileContent, originalLockedReqs); err != nil {
return nil, err

View File

@ -477,7 +477,7 @@ func (st *HelmState) DeleteReleasesForSync(affectedReleases *AffectedReleases, h
relErr = newReleaseError(release, err)
} else {
var args []string
if isHelm3() {
if helm.IsHelm3() {
args = []string{}
if release.Namespace != "" {
args = append(args, "--namespace", release.Namespace)
@ -577,7 +577,7 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
relErr = newReleaseError(release, err)
} else if installed {
var args []string
if isHelm3() {
if helm.IsHelm3() {
args = []string{}
} else {
args = []string{"--purge"}
@ -646,7 +646,7 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
func (st *HelmState) listReleases(context helmexec.HelmContext, helm helmexec.Interface, release *ReleaseSpec) (string, error) {
flags := st.connectionFlags(release)
if isHelm3() && release.Namespace != "" {
if helm.IsHelm3() && release.Namespace != "" {
flags = append(flags, "--namespace", release.Namespace)
}
return helm.List(context, "^"+release.Name+"$", flags...)
@ -1161,11 +1161,11 @@ func (st *HelmState) DeleteReleases(affectedReleases *AffectedReleases, helm hel
st.ApplyOverrides(&release)
flags := []string{}
if purge && !isHelm3() {
if purge && !helm.IsHelm3() {
flags = append(flags, "--purge")
}
flags = st.appendConnectionFlags(flags, &release)
if isHelm3() && release.Namespace != "" {
if helm.IsHelm3() && release.Namespace != "" {
flags = append(flags, "--namespace", release.Namespace)
}
context := st.createHelmContext(&release, workerIndex)
@ -1192,7 +1192,7 @@ func (st *HelmState) TestReleases(helm helmexec.Interface, cleanup bool, timeout
flags = append(flags, "--cleanup")
}
duration := strconv.Itoa(timeout)
if isHelm3() {
if helm.IsHelm3() {
duration += "s"
}
flags = append(flags, "--timeout", duration)
@ -1202,10 +1202,6 @@ func (st *HelmState) TestReleases(helm helmexec.Interface, cleanup bool, timeout
})
}
func isHelm3() bool {
return os.Getenv("HELMFILE_HELM3") != ""
}
// Clean will remove any generated secrets
func (st *HelmState) Clean() []error {
errs := []error{}
@ -1532,7 +1528,7 @@ func (st *HelmState) flagsForUpgrade(helm helmexec.Interface, release *ReleaseSp
}
if timeout != 0 {
duration := strconv.Itoa(timeout)
if isHelm3() {
if helm.IsHelm3() {
duration += "s"
}
flags = append(flags, "--timeout", duration)