Support enforcement that the transitive dependency chain is there.
Signed-off-by: Justin Abrahms <justin@abrah.ms>
This commit is contained in:
parent
75651801a6
commit
4ad9db07cb
|
|
@ -54,6 +54,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command {
|
||||||
f.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")
|
f.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")
|
||||||
f.BoolVar(&applyOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
|
f.BoolVar(&applyOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
|
||||||
f.BoolVar(&applyOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
f.BoolVar(&applyOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
||||||
|
f.BoolVar(&applyOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
|
||||||
f.BoolVar(&applyOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
f.BoolVar(&applyOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
||||||
f.BoolVar(&applyOptions.SkipDiffOnInstall, "skip-diff-on-install", false, "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all")
|
f.BoolVar(&applyOptions.SkipDiffOnInstall, "skip-diff-on-install", false, "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all")
|
||||||
f.BoolVar(&applyOptions.IncludeTests, "include-tests", false, "enable the diffing of the helm test hooks")
|
f.BoolVar(&applyOptions.IncludeTests, "include-tests", false, "enable the diffing of the helm test hooks")
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ func NewDiffCmd(globalCfg *config.GlobalImpl) *cobra.Command {
|
||||||
f.BoolVar(&diffOptions.IncludeTests, "include-tests", false, "enable the diffing of the helm test hooks")
|
f.BoolVar(&diffOptions.IncludeTests, "include-tests", false, "enable the diffing of the helm test hooks")
|
||||||
f.BoolVar(&diffOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
f.BoolVar(&diffOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
||||||
f.BoolVar(&diffOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
f.BoolVar(&diffOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
||||||
|
f.BoolVar(&diffOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
|
||||||
f.BoolVar(&diffOptions.SkipDiffOnInstall, "skip-diff-on-install", false, "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all")
|
f.BoolVar(&diffOptions.SkipDiffOnInstall, "skip-diff-on-install", false, "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all")
|
||||||
f.BoolVar(&diffOptions.ShowSecrets, "show-secrets", false, "do not redact secret values in the output. should be used for debug purpose only")
|
f.BoolVar(&diffOptions.ShowSecrets, "show-secrets", false, "do not redact secret values in the output. should be used for debug purpose only")
|
||||||
f.BoolVar(&diffOptions.NoHooks, "no-hooks", false, "do not diff changes made by hooks.")
|
f.BoolVar(&diffOptions.NoHooks, "no-hooks", false, "do not diff changes made by hooks.")
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command {
|
||||||
f.BoolVar(&syncOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")
|
f.BoolVar(&syncOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")
|
||||||
f.BoolVar(&syncOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
f.BoolVar(&syncOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
||||||
f.BoolVar(&syncOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
f.BoolVar(&syncOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
||||||
|
f.BoolVar(&syncOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
|
||||||
f.BoolVar(&syncOptions.HideNotes, "hide-notes", false, "add --hide-notes flag to helm")
|
f.BoolVar(&syncOptions.HideNotes, "hide-notes", false, "add --hide-notes flag to helm")
|
||||||
f.BoolVar(&syncOptions.TakeOwnership, "take-ownership", false, `add --take-ownership flag to helm`)
|
f.BoolVar(&syncOptions.TakeOwnership, "take-ownership", false, `add --take-ownership flag to helm`)
|
||||||
f.BoolVar(&syncOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`)
|
f.BoolVar(&syncOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command {
|
||||||
f.BoolVar(&templateOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
|
f.BoolVar(&templateOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
|
||||||
f.BoolVar(&templateOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
f.BoolVar(&templateOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
|
||||||
f.BoolVar(&templateOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
f.BoolVar(&templateOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
|
||||||
|
f.BoolVar(&templateOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
|
||||||
f.BoolVar(&templateOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security")
|
f.BoolVar(&templateOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security")
|
||||||
f.BoolVar(&templateOptions.NoHooks, "no-hooks", false, "do not template files made by hooks.")
|
f.BoolVar(&templateOptions.NoHooks, "no-hooks", false, "do not template files made by hooks.")
|
||||||
f.StringVar(&templateOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)
|
f.StringVar(&templateOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)
|
||||||
|
|
|
||||||
|
|
@ -2015,7 +2015,13 @@ func (a *App) withNeeds(r *Run, c DAGConfig, includeDisabled bool, f func(*state
|
||||||
includeNeeds = true
|
includeNeeds = true
|
||||||
}
|
}
|
||||||
|
|
||||||
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: includeNeeds, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(), SkipNeeds: c.SkipNeeds()})
|
batches, err := st.PlanReleases(state.PlanOptions{
|
||||||
|
Reverse: false,
|
||||||
|
SelectedReleases: selectedReleases,
|
||||||
|
IncludeNeeds: includeNeeds,
|
||||||
|
IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(),
|
||||||
|
SkipNeeds: c.SkipNeeds(),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -2041,6 +2047,15 @@ func (a *App) withNeeds(r *Run, c DAGConfig, includeDisabled bool, f func(*state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.EnforceNeedsAreInstalled() {
|
||||||
|
for _, r := range toRender {
|
||||||
|
visited := make(map[string]bool)
|
||||||
|
if depErr := st.HasTransitiveDependencyWithInstalledFalse(r, visited); depErr != nil {
|
||||||
|
return false, []error{fmt.Errorf("Release %s has a transitive dependency %s marked as install=false", depErr.Release.Name, depErr.Dependency.Name)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var rels []state.ReleaseSpec
|
var rels []state.ReleaseSpec
|
||||||
|
|
||||||
if len(toRender) > 0 {
|
if len(toRender) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@ type DAGConfig interface {
|
||||||
SkipNeeds() bool
|
SkipNeeds() bool
|
||||||
IncludeNeeds() bool
|
IncludeNeeds() bool
|
||||||
IncludeTransitiveNeeds() bool
|
IncludeTransitiveNeeds() bool
|
||||||
|
EnforceNeedsAreInstalled() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type WriteValuesConfigProvider interface {
|
type WriteValuesConfigProvider interface {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ type ApplyOptions struct {
|
||||||
IncludeNeeds bool
|
IncludeNeeds bool
|
||||||
// IncludeTransitiveNeeds is true if the transitive needs should be included
|
// IncludeTransitiveNeeds is true if the transitive needs should be included
|
||||||
IncludeTransitiveNeeds bool
|
IncludeTransitiveNeeds bool
|
||||||
|
// EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies
|
||||||
|
EnforceNeedsAreInstalled bool
|
||||||
// SkipDiffOnInstall is true if the diff should be skipped on install
|
// SkipDiffOnInstall is true if the diff should be skipped on install
|
||||||
SkipDiffOnInstall bool
|
SkipDiffOnInstall bool
|
||||||
// DiffArgs is the list of arguments to pass to the helm-diff.
|
// DiffArgs is the list of arguments to pass to the helm-diff.
|
||||||
|
|
@ -139,6 +141,11 @@ func (a *ApplyImpl) IncludeTransitiveNeeds() bool {
|
||||||
return a.ApplyOptions.IncludeTransitiveNeeds
|
return a.ApplyOptions.IncludeTransitiveNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies
|
||||||
|
func (a *ApplyImpl) EnforceNeedsAreInstalled() bool {
|
||||||
|
return a.ApplyOptions.EnforceNeedsAreInstalled
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Remove this function once Helmfile v0.x
|
// TODO: Remove this function once Helmfile v0.x
|
||||||
// RetainValuesFiles returns the retain values files.
|
// RetainValuesFiles returns the retain values files.
|
||||||
func (a *ApplyImpl) RetainValuesFiles() bool {
|
func (a *ApplyImpl) RetainValuesFiles() bool {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ type DiffOptions struct {
|
||||||
IncludeNeeds bool
|
IncludeNeeds bool
|
||||||
// IncludeTransitiveNeeds is the include transitive needs flag
|
// IncludeTransitiveNeeds is the include transitive needs flag
|
||||||
IncludeTransitiveNeeds bool
|
IncludeTransitiveNeeds bool
|
||||||
|
// EnforceNeedsAreInstalled is the enforce needs are installed flag
|
||||||
|
EnforceNeedsAreInstalled bool
|
||||||
// SkipDiffOnInstall is the skip diff on install flag
|
// SkipDiffOnInstall is the skip diff on install flag
|
||||||
SkipDiffOnInstall bool
|
SkipDiffOnInstall bool
|
||||||
// ShowSecrets is the show secrets flag
|
// ShowSecrets is the show secrets flag
|
||||||
|
|
@ -85,6 +87,11 @@ func (t *DiffImpl) IncludeTransitiveNeeds() bool {
|
||||||
return t.DiffOptions.IncludeTransitiveNeeds
|
return t.DiffOptions.IncludeTransitiveNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
|
||||||
|
func (t *DiffImpl) EnforceNeedsAreInstalled() bool {
|
||||||
|
return t.DiffOptions.EnforceNeedsAreInstalled
|
||||||
|
}
|
||||||
|
|
||||||
// Set returns the Set
|
// Set returns the Set
|
||||||
func (t *DiffImpl) Set() []string {
|
func (t *DiffImpl) Set() []string {
|
||||||
return t.DiffOptions.Set
|
return t.DiffOptions.Set
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ type LintOptions struct {
|
||||||
IncludeNeeds bool
|
IncludeNeeds bool
|
||||||
// IncludeTransitiveNeeds is the include transitive needs flag
|
// IncludeTransitiveNeeds is the include transitive needs flag
|
||||||
IncludeTransitiveNeeds bool
|
IncludeTransitiveNeeds bool
|
||||||
|
// EnforceNeedsAreInstalled is the enforce needs are installed flag
|
||||||
|
EnforceNeedsAreInstalled bool
|
||||||
// SkipDeps is the skip deps flag
|
// SkipDeps is the skip deps flag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,3 +76,8 @@ func (l *LintImpl) SkipNeeds() bool {
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
|
||||||
|
func (l *LintImpl) EnforceNeedsAreInstalled() bool {
|
||||||
|
return l.LintOptions.EnforceNeedsAreInstalled
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ type SyncOptions struct {
|
||||||
IncludeNeeds bool
|
IncludeNeeds bool
|
||||||
// IncludeTransitiveNeeds is the include transitive needs flag
|
// IncludeTransitiveNeeds is the include transitive needs flag
|
||||||
IncludeTransitiveNeeds bool
|
IncludeTransitiveNeeds bool
|
||||||
|
// EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies
|
||||||
|
EnforceNeedsAreInstalled bool
|
||||||
// SkipCrds is the skip crds flag
|
// SkipCrds is the skip crds flag
|
||||||
SkipCRDs bool
|
SkipCRDs bool
|
||||||
// Wait is the wait flag
|
// Wait is the wait flag
|
||||||
|
|
@ -160,3 +162,8 @@ func (t *SyncImpl) HideNotes() bool {
|
||||||
func (t *SyncImpl) TakeOwnership() bool {
|
func (t *SyncImpl) TakeOwnership() bool {
|
||||||
return t.SyncOptions.TakeOwnership
|
return t.SyncOptions.TakeOwnership
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
|
||||||
|
func (t *SyncImpl) EnforceNeedsAreInstalled() bool {
|
||||||
|
return t.SyncOptions.EnforceNeedsAreInstalled
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ type TemplateOptions struct {
|
||||||
IncludeNeeds bool
|
IncludeNeeds bool
|
||||||
// IncludeTransitiveNeeds is the include transitive needs flag
|
// IncludeTransitiveNeeds is the include transitive needs flag
|
||||||
IncludeTransitiveNeeds bool
|
IncludeTransitiveNeeds bool
|
||||||
|
// EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies
|
||||||
|
EnforceNeedsAreInstalled bool
|
||||||
// No-Hooks is the no hooks flag
|
// No-Hooks is the no hooks flag
|
||||||
NoHooks bool
|
NoHooks bool
|
||||||
// SkipCleanup is the skip cleanup flag
|
// SkipCleanup is the skip cleanup flag
|
||||||
|
|
@ -158,3 +160,8 @@ func (t *TemplateImpl) KubeVersion() string {
|
||||||
func (t *TemplateImpl) ShowOnly() []string {
|
func (t *TemplateImpl) ShowOnly() []string {
|
||||||
return t.TemplateOptions.ShowOnly
|
return t.TemplateOptions.ShowOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
|
||||||
|
func (t *TemplateImpl) EnforceNeedsAreInstalled() bool {
|
||||||
|
return t.TemplateOptions.EnforceNeedsAreInstalled
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2557,6 +2557,34 @@ func (st *HelmState) UpdateDeps(helm helmexec.Interface, includeTransitiveNeeds
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DependencyError holds information about a release and its dependency that is not installed.
|
||||||
|
type DependencyError struct {
|
||||||
|
Release ReleaseSpec
|
||||||
|
Dependency ReleaseSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasTransitiveDependencyWithInstallFalse checks if a release has a transitive dependency with Install set to false.
|
||||||
|
func (st *HelmState) HasTransitiveDependencyWithInstalledFalse(release ReleaseSpec, visited map[string]bool) *DependencyError {
|
||||||
|
if visited[release.Name] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
visited[release.Name] = true
|
||||||
|
|
||||||
|
for _, dep := range release.Needs {
|
||||||
|
for _, r := range st.Releases {
|
||||||
|
if r.Name == dep {
|
||||||
|
if r.Installed != nil && !*r.Installed {
|
||||||
|
return &DependencyError{Release: release, Dependency: r}
|
||||||
|
}
|
||||||
|
if depErr := st.HasTransitiveDependencyWithInstalledFalse(r, visited); depErr != nil {
|
||||||
|
return depErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// find "Chart.yaml"
|
// find "Chart.yaml"
|
||||||
func findChartDirectory(topLevelDir string) (string, error) {
|
func findChartDirectory(topLevelDir string) (string, error) {
|
||||||
var files []string
|
var files []string
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: v2
|
||||||
|
name: empty
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.16.0"
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
releases:
|
||||||
|
- name: empty1
|
||||||
|
installed: false
|
||||||
|
chart: ./empty
|
||||||
|
- name: empty2
|
||||||
|
chart: ./empty
|
||||||
|
needs:
|
||||||
|
- empty1
|
||||||
Loading…
Reference in New Issue