Port the `needs` fix for `helmfile apply` to `sync`, and make `template` DAG-aware (#940)

This ports the fix for `helfmile apply` to `sync`, so that specifying `--selector` doesn't break `helmfile sync`.

Also make `helmfile template` DAG-aware, so that the manifests are rendered in the order of dependency.

Ref #919
This commit is contained in:
KUOKA Yusuke 2019-11-06 23:16:57 +09:00 committed by GitHub
parent 35adb8ae22
commit ed7a6d9051
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 155 additions and 56 deletions

View File

@ -128,8 +128,8 @@ func (a *App) Diff(c DiffConfigProvider) error {
}
func (a *App) Template(c TemplateConfigProvider) error {
return a.ForEachStateFiltered(func(run *Run) []error {
return run.Template(c)
return a.ForEachState(func(run *Run) (bool, []error) {
return a.template(run, c)
})
}
@ -140,8 +140,8 @@ func (a *App) Lint(c LintConfigProvider) error {
}
func (a *App) Sync(c SyncConfigProvider) error {
return a.ForEachStateFiltered(func(run *Run) []error {
return run.Sync(c)
return a.ForEachState(func(run *Run) (bool, []error) {
return a.sync(run, c)
})
}
@ -901,6 +901,157 @@ Do you really want to delete?
return any, errs
}
func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
st := r.state
helm := r.helm
ctx := r.ctx
affectedReleases := state.AffectedReleases{}
if !c.SkipDeps() {
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
return false, errs
}
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
}
var syncedReleases []state.ReleaseSpec
if len(st.Selectors) > 0 {
var err error
syncedReleases, err = st.GetFilteredReleases()
if err != nil {
return false, []error{err}
}
if len(syncedReleases) == 0 {
return false, nil
}
} else {
syncedReleases = st.Releases
}
releasesToBeSynced := map[string]state.ReleaseSpec{}
for _, r := range syncedReleases {
id := state.ReleaseToID(&r)
releasesToBeSynced[id] = r
}
names := make([]string, len(syncedReleases))
for i, r := range syncedReleases {
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
}
var errs []error
var any bool
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
if len(releasesToBeSynced) > 0 {
synced, syncErrs := withDAG(st, helm, a.Logger, false, a.Wrap(func(subst *state.HelmState, helm helmexec.Interface) []error {
var rs []state.ReleaseSpec
for _, r := range subst.Releases {
if _, ok := releasesToBeSynced[state.ReleaseToID(&r)]; ok {
rs = append(rs, r)
}
}
subst.Releases = rs
opts := &state.SyncOpts{
Set: c.Set(),
}
return subst.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), opts)
}))
any = any || synced
if syncErrs != nil && len(syncErrs) > 0 {
errs = append(errs, syncErrs...)
}
}
affectedReleases.DisplayAffectedReleases(c.Logger())
return any, errs
}
func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
st := r.state
helm := r.helm
ctx := r.ctx
if !c.SkipDeps() {
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
return false, errs
}
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
}
var templatedReleases []state.ReleaseSpec
if len(st.Selectors) > 0 {
var err error
templatedReleases, err = st.GetFilteredReleases()
if err != nil {
return false, []error{err}
}
if len(templatedReleases) == 0 {
return false, nil
}
} else {
templatedReleases = st.Releases
}
releasesToBeTemplated := map[string]state.ReleaseSpec{}
for _, r := range templatedReleases {
id := state.ReleaseToID(&r)
releasesToBeTemplated[id] = r
}
names := make([]string, len(templatedReleases))
for i, r := range templatedReleases {
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
}
var errs []error
var any bool
if len(releasesToBeTemplated) > 0 {
synced, templateErrs := withDAG(st, helm, a.Logger, false, a.Wrap(func(subst *state.HelmState, helm helmexec.Interface) []error {
var rs []state.ReleaseSpec
for _, r := range subst.Releases {
if _, ok := releasesToBeTemplated[state.ReleaseToID(&r)]; ok {
rs = append(rs, r)
}
}
subst.Releases = rs
args := argparser.GetArgs(c.Args(), st)
opts := &state.TemplateOpts{
Set: c.Set(),
}
return subst.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), opts)
}))
any = any || synced
if templateErrs != nil && len(templateErrs) > 0 {
errs = append(errs, templateErrs...)
}
}
return any, errs
}
func fileExistsAt(path string) bool {
fileInfo, err := os.Stat(path)
return err == nil && fileInfo.Mode().IsRegular()

View File

@ -89,58 +89,6 @@ func (r *Run) Diff(c DiffConfigProvider) []error {
return errs
}
func (r *Run) Sync(c SyncConfigProvider) []error {
st := r.state
helm := r.helm
ctx := r.ctx
affectedReleases := state.AffectedReleases{}
if !c.SkipDeps() {
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
return errs
}
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
return errs
}
}
if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
return errs
}
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
opts := &state.SyncOpts{
Set: c.Set(),
}
errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), opts)
affectedReleases.DisplayAffectedReleases(c.Logger())
return errs
}
func (r *Run) Template(c TemplateConfigProvider) []error {
st := r.state
helm := r.helm
ctx := r.ctx
if !c.SkipDeps() {
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
return errs
}
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
return errs
}
}
if errs := st.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
return errs
}
args := argparser.GetArgs(c.Args(), st)
opts := &state.TemplateOpts{
Set: c.Set(),
}
return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), opts)
}
func (r *Run) Test(c TestConfigProvider) []error {
cleanup := c.Cleanup()
timeout := c.Timeout()