Skip to content

Commit b85243a

Browse files
authored
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
1 parent 53c3fe9 commit b85243a

File tree

5 files changed

+33
-108
lines changed

5 files changed

+33
-108
lines changed

pkg/app/app.go

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ func (a *App) Diff(c DiffConfigProvider) error {
216216

217217
func (a *App) Template(c TemplateConfigProvider) error {
218218
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
219-
prepErr := run.withPreparedCharts(true, c.SkipDeps(), "template", func() {
219+
// `helm template` in helm v2 does not support local chart.
220+
// So, we set forceDownload=true for helm v2 only
221+
prepErr := run.withPreparedCharts(!run.helm.IsHelm3(), c.SkipDeps(), "template", func() {
220222
ok, errs = a.template(run, c)
221223
})
222224

@@ -230,6 +232,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
230232

231233
func (a *App) Lint(c LintConfigProvider) error {
232234
return a.ForEachState(func(run *Run) (_ bool, errs []error) {
235+
// `helm lint` on helm v2 and v3 does not support remote charts, that we need to set `forceDownload=true` here
233236
prepErr := run.withPreparedCharts(true, c.SkipDeps(), "lint", func() {
234237
errs = run.Lint(c)
235238
})
@@ -970,15 +973,6 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
970973
// on running various helm commands on unnecessary releases
971974
st.Releases = toApply
972975

973-
if !c.SkipDeps() {
974-
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
975-
return false, false, errs
976-
}
977-
}
978-
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
979-
return false, false, errs
980-
}
981-
982976
// helm must be 2.11+ and helm-diff should be provided `--detailed-exitcode` in order for `helmfile apply` to work properly
983977
detailedExitCode := true
984978

@@ -1157,15 +1151,6 @@ func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
11571151
// on running various helm commands on unnecessary releases
11581152
st.Releases = toSync
11591153

1160-
if !c.SkipDeps() {
1161-
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
1162-
return false, errs
1163-
}
1164-
}
1165-
if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
1166-
return false, errs
1167-
}
1168-
11691154
toDelete, err := st.DetectReleasesToBeDeletedForSync(helm, toSync)
11701155
if err != nil {
11711156
return false, []error{err}
@@ -1279,15 +1264,6 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
12791264
// on running various helm commands on unnecessary releases
12801265
st.Releases = toRender
12811266

1282-
if !c.SkipDeps() {
1283-
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
1284-
return false, errs
1285-
}
1286-
}
1287-
if errs := st.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
1288-
return false, errs
1289-
}
1290-
12911267
releasesToRender := map[string]state.ReleaseSpec{}
12921268
for _, r := range toRender {
12931269
id := state.ReleaseToID(&r)

pkg/app/run.go

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (r *Run) withPreparedCharts(forceDownload, skipRepos bool, helmfileCommand
5959
return err
6060
}
6161

62-
releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, 2, helmfileCommand, forceDownload)
62+
releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, 2, helmfileCommand, forceDownload, skipRepos)
6363

6464
if len(errs) > 0 {
6565
return fmt.Errorf("%v", errs)
@@ -114,7 +114,6 @@ func (r *Run) Status(c StatusesConfigProvider) []error {
114114

115115
func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error) {
116116
st := r.state
117-
helm := r.helm
118117

119118
allReleases := st.GetReleasesWithOverrides()
120119

@@ -131,15 +130,6 @@ func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error)
131130
// on running various helm commands on unnecessary releases
132131
st.Releases = toDiff
133132

134-
if !c.SkipDeps() {
135-
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
136-
return nil, false, false, errs
137-
}
138-
}
139-
if errs := st.PrepareReleases(helm, "diff"); errs != nil && len(errs) > 0 {
140-
return nil, false, false, errs
141-
}
142-
143133
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
144134

145135
opts := &state.DiffOpts{
@@ -188,14 +178,6 @@ func (r *Run) Lint(c LintConfigProvider) []error {
188178
values := c.Values()
189179
args := argparser.GetArgs(c.Args(), st)
190180
workers := c.Concurrency()
191-
if !c.SkipDeps() {
192-
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
193-
return errs
194-
}
195-
}
196-
if errs := st.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 {
197-
return errs
198-
}
199181
opts := &state.LintOpts{
200182
Set: c.Set(),
201183
}

pkg/state/chart_dependency.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ func updateDependencies(st *HelmState, shell helmexec.DependencyUpdater, unresol
254254

255255
_, err := depMan.Update(shell, wd, unresolved)
256256
if err != nil {
257-
return nil, fmt.Errorf("unable to resolve %d deps: %v", len(unresolved.deps), err)
257+
return nil, fmt.Errorf("unable to update %d deps: %v", len(unresolved.deps), err)
258258
}
259259

260260
return resolveDependencies(st, depMan, unresolved)

pkg/state/state.go

Lines changed: 26 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -805,12 +805,13 @@ func releasesNeedCharts(releases []ReleaseSpec) []ReleaseSpec {
805805
// (2) temporary local chart generated from kustomization or manifests
806806
// (3) remote chart
807807
//
808-
// When running `helmfile lint` or `helmfile template`, PrepareCharts will download and untar charts for linting and templating.
808+
// When running `helmfile template` on helm v2, or `helmfile lint` on both helm v2 and v3,
809+
// PrepareCharts will download and untar charts for linting and templating.
809810
//
810811
// Otheriwse, if a chart is not a helm chart, it will call "chartify" to turn it into a chart.
811812
//
812813
// If exists, it will also patch resources by json patches, strategic-merge patches, and injectors.
813-
func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, forceDownload bool) (map[string]string, []error) {
814+
func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, forceDownload, skipDeps bool) (map[string]string, []error) {
814815
releases := releasesNeedCharts(st.Releases)
815816

816817
temp := make(map[string]string, len(releases))
@@ -831,6 +832,12 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
831832
helm3 = helm.IsHelm3()
832833
}
833834

835+
updated, err := st.ResolveDeps()
836+
if err != nil {
837+
return nil, []error{err}
838+
}
839+
*st = *updated
840+
834841
st.scatterGather(
835842
concurrency,
836843
len(releases),
@@ -842,6 +849,16 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
842849
},
843850
func(workerIndex int) {
844851
for release := range jobQueue {
852+
// Call user-defined `prepare` hooks to create/modify local charts to be used by
853+
// the later process.
854+
//
855+
// If it wasn't called here, Helmfile can end up an issue like
856+
// https://github.com/roboll/helmfile/issues/1328
857+
if _, err := st.triggerPrepareEvent(release, helmfileCommand); err != nil {
858+
results <- &downloadResults{err: err}
859+
return
860+
}
861+
845862
var chartPath string
846863

847864
chartification, clean, err := st.PrepareChartify(helm, release, workerIndex)
@@ -869,6 +886,13 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
869886
chartPath = release.Chart
870887
} else if pathExists(normalizeChart(st.basePath, release.Chart)) {
871888
chartPath = normalizeChart(st.basePath, release.Chart)
889+
890+
if !skipDeps {
891+
if err := helm.BuildDeps(release.Name, chartPath); err != nil {
892+
results <- &downloadResults{err: err}
893+
return
894+
}
895+
}
872896
} else {
873897
fetchFlags := []string{}
874898

@@ -1540,35 +1564,6 @@ func (st *HelmState) FilterReleases() error {
15401564
return nil
15411565
}
15421566

1543-
func (st *HelmState) PrepareReleases(helm helmexec.Interface, helmfileCommand string) []error {
1544-
errs := []error{}
1545-
1546-
for i := range st.Releases {
1547-
release := st.Releases[i]
1548-
1549-
if release.Installed != nil && !*release.Installed {
1550-
continue
1551-
}
1552-
1553-
if _, err := st.triggerPrepareEvent(&release, helmfileCommand); err != nil {
1554-
errs = append(errs, newReleaseFailedError(&release, err))
1555-
continue
1556-
}
1557-
}
1558-
if len(errs) != 0 {
1559-
return errs
1560-
}
1561-
1562-
updated, err := st.ResolveDeps()
1563-
if err != nil {
1564-
return []error{err}
1565-
}
1566-
1567-
*st = *updated
1568-
1569-
return nil
1570-
}
1571-
15721567
func (st *HelmState) TriggerGlobalPrepareEvent(helmfileCommand string) (bool, error) {
15731568
return st.triggerGlobalReleaseEvent("prepare", nil, helmfileCommand)
15741569
}
@@ -1660,34 +1655,6 @@ func (st *HelmState) UpdateDeps(helm helmexec.Interface) []error {
16601655
return nil
16611656
}
16621657

1663-
// BuildDeps wrapper for building dependencies on the releases
1664-
func (st *HelmState) BuildDeps(helm helmexec.Interface) []error {
1665-
errs := []error{}
1666-
1667-
releases := releasesNeedCharts(st.Releases)
1668-
1669-
for _, release := range releases {
1670-
if len(release.Chart) == 0 {
1671-
errs = append(errs, errors.New("chart is required for: "+release.Name))
1672-
continue
1673-
}
1674-
1675-
if release.Installed != nil && !*release.Installed {
1676-
continue
1677-
}
1678-
1679-
if isLocalChart(release.Chart) {
1680-
if err := helm.BuildDeps(release.Name, normalizeChart(st.basePath, release.Chart)); err != nil {
1681-
errs = append(errs, err)
1682-
}
1683-
}
1684-
}
1685-
if len(errs) != 0 {
1686-
return errs
1687-
}
1688-
return nil
1689-
}
1690-
16911658
func pathExists(chart string) bool {
16921659
_, err := os.Stat(chart)
16931660
return err == nil

pkg/testhelper/testfs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (f *TestFs) ReadFile(filename string) ([]byte, error) {
7070
str, ok = f.files[filepath.Join(f.Cwd, filename)]
7171
}
7272
if !ok {
73-
return []byte(nil), fmt.Errorf("no registered file found: %s", filename)
73+
return []byte(nil), os.ErrNotExist
7474
}
7575

7676
f.fileReaderCalls += 1

0 commit comments

Comments
 (0)