Fix various issues in chart preparation (#1400)
In #1172, we accidentally changed the meaning of prepare hook that is intended to be called BEFORE the pathExists check. It broke the scenario where one used a prepare hook for generating the local chart dynamically. This fixes Helmfile not to fetch local chart generated by prepare hook. In addition to that, this patch results in the following fixes: - Fix an issue that `helmfile template` without `--skip-deps` fails while trying to run `helm dep build` on `helm fetch`ed chart, when the remote chart has outdated dependencies in the Chart.lock file. It should be up to the chart maintainer to update Chart.lock and the user should not be blocked due to that. So, after this patch `helm dep build` is run only on the local chart, not on fetched remote chart. - Skip fetching chart on `helmfile template` when using Helm v3. `helm template` in helm v3 does support rendering remote charts so we do not need to fetch beforehand. Fixes #1328 May relate to #1341
This commit is contained in:
parent
53c3fe9f37
commit
b85243a6b4
|
|
@ -216,7 +216,9 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
|||
|
||||
func (a *App) Template(c TemplateConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
prepErr := run.withPreparedCharts(true, c.SkipDeps(), "template", func() {
|
||||
// `helm template` in helm v2 does not support local chart.
|
||||
// So, we set forceDownload=true for helm v2 only
|
||||
prepErr := run.withPreparedCharts(!run.helm.IsHelm3(), c.SkipDeps(), "template", func() {
|
||||
ok, errs = a.template(run, c)
|
||||
})
|
||||
|
||||
|
|
@ -230,6 +232,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
|
|||
|
||||
func (a *App) Lint(c LintConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||
// `helm lint` on helm v2 and v3 does not support remote charts, that we need to set `forceDownload=true` here
|
||||
prepErr := run.withPreparedCharts(true, c.SkipDeps(), "lint", func() {
|
||||
errs = run.Lint(c)
|
||||
})
|
||||
|
|
@ -970,15 +973,6 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
|||
// on running various helm commands on unnecessary releases
|
||||
st.Releases = toApply
|
||||
|
||||
if !c.SkipDeps() {
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return false, false, errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
|
||||
return false, false, errs
|
||||
}
|
||||
|
||||
// helm must be 2.11+ and helm-diff should be provided `--detailed-exitcode` in order for `helmfile apply` to work properly
|
||||
detailedExitCode := true
|
||||
|
||||
|
|
@ -1157,15 +1151,6 @@ func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
|
|||
// on running various helm commands on unnecessary releases
|
||||
st.Releases = toSync
|
||||
|
||||
if !c.SkipDeps() {
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return false, errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
|
||||
return false, errs
|
||||
}
|
||||
|
||||
toDelete, err := st.DetectReleasesToBeDeletedForSync(helm, toSync)
|
||||
if err != nil {
|
||||
return false, []error{err}
|
||||
|
|
@ -1279,15 +1264,6 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
|
|||
// on running various helm commands on unnecessary releases
|
||||
st.Releases = toRender
|
||||
|
||||
if !c.SkipDeps() {
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return false, errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
|
||||
return false, errs
|
||||
}
|
||||
|
||||
releasesToRender := map[string]state.ReleaseSpec{}
|
||||
for _, r := range toRender {
|
||||
id := state.ReleaseToID(&r)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func (r *Run) withPreparedCharts(forceDownload, skipRepos bool, helmfileCommand
|
|||
return err
|
||||
}
|
||||
|
||||
releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, 2, helmfileCommand, forceDownload)
|
||||
releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, 2, helmfileCommand, forceDownload, skipRepos)
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%v", errs)
|
||||
|
|
@ -114,7 +114,6 @@ func (r *Run) Status(c StatusesConfigProvider) []error {
|
|||
|
||||
func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error) {
|
||||
st := r.state
|
||||
helm := r.helm
|
||||
|
||||
allReleases := st.GetReleasesWithOverrides()
|
||||
|
||||
|
|
@ -131,15 +130,6 @@ func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error)
|
|||
// on running various helm commands on unnecessary releases
|
||||
st.Releases = toDiff
|
||||
|
||||
if !c.SkipDeps() {
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return nil, false, false, errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "diff"); errs != nil && len(errs) > 0 {
|
||||
return nil, false, false, errs
|
||||
}
|
||||
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
opts := &state.DiffOpts{
|
||||
|
|
@ -188,14 +178,6 @@ func (r *Run) Lint(c LintConfigProvider) []error {
|
|||
values := c.Values()
|
||||
args := argparser.GetArgs(c.Args(), st)
|
||||
workers := c.Concurrency()
|
||||
if !c.SkipDeps() {
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
opts := &state.LintOpts{
|
||||
Set: c.Set(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ func updateDependencies(st *HelmState, shell helmexec.DependencyUpdater, unresol
|
|||
|
||||
_, err := depMan.Update(shell, wd, unresolved)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to resolve %d deps: %v", len(unresolved.deps), err)
|
||||
return nil, fmt.Errorf("unable to update %d deps: %v", len(unresolved.deps), err)
|
||||
}
|
||||
|
||||
return resolveDependencies(st, depMan, unresolved)
|
||||
|
|
|
|||
|
|
@ -805,12 +805,13 @@ func releasesNeedCharts(releases []ReleaseSpec) []ReleaseSpec {
|
|||
// (2) temporary local chart generated from kustomization or manifests
|
||||
// (3) remote chart
|
||||
//
|
||||
// When running `helmfile lint` or `helmfile template`, PrepareCharts will download and untar charts for linting and templating.
|
||||
// When running `helmfile template` on helm v2, or `helmfile lint` on both helm v2 and v3,
|
||||
// PrepareCharts will download and untar charts for linting and templating.
|
||||
//
|
||||
// Otheriwse, if a chart is not a helm chart, it will call "chartify" to turn it into a chart.
|
||||
//
|
||||
// If exists, it will also patch resources by json patches, strategic-merge patches, and injectors.
|
||||
func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, forceDownload bool) (map[string]string, []error) {
|
||||
func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, forceDownload, skipDeps bool) (map[string]string, []error) {
|
||||
releases := releasesNeedCharts(st.Releases)
|
||||
|
||||
temp := make(map[string]string, len(releases))
|
||||
|
|
@ -831,6 +832,12 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
|
|||
helm3 = helm.IsHelm3()
|
||||
}
|
||||
|
||||
updated, err := st.ResolveDeps()
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
*st = *updated
|
||||
|
||||
st.scatterGather(
|
||||
concurrency,
|
||||
len(releases),
|
||||
|
|
@ -842,6 +849,16 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
|
|||
},
|
||||
func(workerIndex int) {
|
||||
for release := range jobQueue {
|
||||
// Call user-defined `prepare` hooks to create/modify local charts to be used by
|
||||
// the later process.
|
||||
//
|
||||
// If it wasn't called here, Helmfile can end up an issue like
|
||||
// https://github.com/roboll/helmfile/issues/1328
|
||||
if _, err := st.triggerPrepareEvent(release, helmfileCommand); err != nil {
|
||||
results <- &downloadResults{err: err}
|
||||
return
|
||||
}
|
||||
|
||||
var chartPath string
|
||||
|
||||
chartification, clean, err := st.PrepareChartify(helm, release, workerIndex)
|
||||
|
|
@ -869,6 +886,13 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
|
|||
chartPath = release.Chart
|
||||
} else if pathExists(normalizeChart(st.basePath, release.Chart)) {
|
||||
chartPath = normalizeChart(st.basePath, release.Chart)
|
||||
|
||||
if !skipDeps {
|
||||
if err := helm.BuildDeps(release.Name, chartPath); err != nil {
|
||||
results <- &downloadResults{err: err}
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fetchFlags := []string{}
|
||||
|
||||
|
|
@ -1540,35 +1564,6 @@ func (st *HelmState) FilterReleases() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *HelmState) PrepareReleases(helm helmexec.Interface, helmfileCommand string) []error {
|
||||
errs := []error{}
|
||||
|
||||
for i := range st.Releases {
|
||||
release := st.Releases[i]
|
||||
|
||||
if release.Installed != nil && !*release.Installed {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := st.triggerPrepareEvent(&release, helmfileCommand); err != nil {
|
||||
errs = append(errs, newReleaseFailedError(&release, err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
updated, err := st.ResolveDeps()
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
*st = *updated
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *HelmState) TriggerGlobalPrepareEvent(helmfileCommand string) (bool, error) {
|
||||
return st.triggerGlobalReleaseEvent("prepare", nil, helmfileCommand)
|
||||
}
|
||||
|
|
@ -1660,34 +1655,6 @@ func (st *HelmState) UpdateDeps(helm helmexec.Interface) []error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// BuildDeps wrapper for building dependencies on the releases
|
||||
func (st *HelmState) BuildDeps(helm helmexec.Interface) []error {
|
||||
errs := []error{}
|
||||
|
||||
releases := releasesNeedCharts(st.Releases)
|
||||
|
||||
for _, release := range releases {
|
||||
if len(release.Chart) == 0 {
|
||||
errs = append(errs, errors.New("chart is required for: "+release.Name))
|
||||
continue
|
||||
}
|
||||
|
||||
if release.Installed != nil && !*release.Installed {
|
||||
continue
|
||||
}
|
||||
|
||||
if isLocalChart(release.Chart) {
|
||||
if err := helm.BuildDeps(release.Name, normalizeChart(st.basePath, release.Chart)); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
return errs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pathExists(chart string) bool {
|
||||
_, err := os.Stat(chart)
|
||||
return err == nil
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func (f *TestFs) ReadFile(filename string) ([]byte, error) {
|
|||
str, ok = f.files[filepath.Join(f.Cwd, filename)]
|
||||
}
|
||||
if !ok {
|
||||
return []byte(nil), fmt.Errorf("no registered file found: %s", filename)
|
||||
return []byte(nil), os.ErrNotExist
|
||||
}
|
||||
|
||||
f.fileReaderCalls += 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue