set command line flags

Signed-off-by: Austin Abro <AustinAbro321@gmail.com>
pull/13604/head
Austin Abro 7 months ago
parent bd3b5ee5d0
commit 2b03c527f1
No known key found for this signature in database
GPG Key ID: 92EB5159E403F9D6

@ -32,6 +32,7 @@ import (
"helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v4/pkg/cli/values"
"helm.sh/helm/v4/pkg/helmpath"
"helm.sh/helm/v4/pkg/kube"
"helm.sh/helm/v4/pkg/postrender"
"helm.sh/helm/v4/pkg/repo"
)
@ -51,6 +52,49 @@ func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
f.StringArrayVar(&v.LiteralValues, "set-literal", []string{}, "set a literal STRING value on the command line")
}
func AddWaitFlag(cmd *cobra.Command, wait *kube.WaitStrategy) {
cmd.Flags().Var(
newWaitValue(wait),
"wait",
"if set, will wait until all resources are in the expected state before marking the operation as successful. It will wait for as long as --timeout. Options are (true, false, watcher, and legacy)",
)
// Sets the strategy to use the watcher strategy if `--wait` is used without an argument
cmd.Flags().Lookup("wait").NoOptDefVal = string(kube.StatusWatcherStrategy)
}
type waitValue kube.WaitStrategy
func newWaitValue(ws *kube.WaitStrategy) *waitValue {
return (*waitValue)(ws)
}
func (ws *waitValue) String() string {
if ws == nil {
return ""
}
return string(*ws)
}
func (ws *waitValue) Set(s string) error {
switch s {
case string(kube.StatusWatcherStrategy), string(kube.LegacyWaiterStrategy):
*ws = waitValue(s)
return nil
case "true":
*ws = waitValue(kube.StatusWatcherStrategy)
return nil
case "false":
*ws = ""
return nil
default:
return fmt.Errorf("invalid wait input %q. Valid inputs are true, false, %s, and %s", s, kube.StatusWatcherStrategy, kube.LegacyWaiterStrategy)
}
}
func (ws *waitValue) Type() string {
return "WaitStrategy"
}
func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
f.StringVar(&c.Version, "version", "", "specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used")
f.BoolVar(&c.Verify, "verify", false, "verify the package before using it")

@ -190,8 +190,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install")
f.BoolVar(&client.Replace, "replace", false, "reuse the given name, only if that name is a deleted release which remains in the history. This is unsafe in production")
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&client.WaitForJobs, "wait-for-jobs", false, "if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout")
f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)")
f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release")
@ -209,6 +208,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
f.BoolVar(&client.TakeOwnership, "take-ownership", false, "if set, install will ignore the check for helm annotations and take ownership of the existing resources")
addValueOptionsFlags(f, valueOpts)
addChartPathOptionsFlags(f, &client.ChartPathOptions)
AddWaitFlag(cmd, &client.Wait)
err := cmd.RegisterFlagCompletionFunc("version", func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
requiredArgs := 2

@ -81,10 +81,10 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVar(&client.Force, "force", false, "force resource update through delete/recreate if needed")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during rollback")
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.WaitForJobs, "wait-for-jobs", false, "if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this rollback when rollback fails")
f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit")
AddWaitFlag(cmd, &client.Wait)
return cmd
}

@ -278,7 +278,6 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
f.BoolVar(&client.ReuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored")
f.BoolVar(&client.ResetThenReuseValues, "reset-then-reuse-values", false, "when upgrading, reset the values to the ones built into the chart, apply the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' or '--reuse-values' is specified, this is ignored")
f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.WaitForJobs, "wait-for-jobs", false, "if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.Atomic, "atomic", false, "if set, upgrade process rolls back changes made in case of failed upgrade. The --wait flag will be set automatically if --atomic is used")
f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit")
@ -295,6 +294,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
addValueOptionsFlags(f, valueOpts)
bindOutputFlag(cmd, &outfmt)
bindPostRenderFlag(cmd, &client.PostRenderer)
AddWaitFlag(cmd, &client.Wait)
err := cmd.RegisterFlagCompletionFunc("version", func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 2 {

@ -371,7 +371,7 @@ func (cfg *Configuration) recordRelease(r *release.Release) {
// Init initializes the action configuration
func (cfg *Configuration) Init(getter genericclioptions.RESTClientGetter, namespace, helmDriver string, log DebugLog) error {
kc, err := kube.New(getter, kube.StatusWaiterStrategy)
kc, err := kube.New(getter, kube.StatusWatcherStrategy)
if err != nil {
return err
}

@ -79,7 +79,7 @@ type Install struct {
HideSecret bool
DisableHooks bool
Replace bool
Wait bool
Wait kube.WaitStrategy
WaitForJobs bool
Devel bool
DependencyUpdate bool
@ -157,6 +157,10 @@ func (i *Install) GetRegistryClient() *registry.Client {
return i.ChartPathOptions.registryClient
}
func (i *Install) shouldWait() bool {
return i.Wait != ""
}
func (i *Install) installCRDs(crds []chart.CRD) error {
// We do these one file at a time in the order they were read.
totalItems := []*resource.Info{}
@ -289,7 +293,11 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
// Make sure if Atomic is set, that wait is set as well. This makes it so
// the user doesn't have to specify both
i.Wait = i.Wait || i.Atomic
if !i.shouldWait() {
if i.Atomic {
i.Wait = "watcher"
}
}
caps, err := i.cfg.getCapabilities()
if err != nil {
@ -465,7 +473,7 @@ func (i *Install) performInstall(rel *release.Release, toBeAdopted kube.Resource
return rel, err
}
if i.Wait {
if i.shouldWait() {
if i.WaitForJobs {
err = i.cfg.KubeClient.WaitWithJobs(resources, i.Timeout)
} else {

@ -34,6 +34,7 @@ import (
"helm.sh/helm/v4/internal/test"
"helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v4/pkg/kube"
kubefake "helm.sh/helm/v4/pkg/kube/fake"
"helm.sh/helm/v4/pkg/release"
"helm.sh/helm/v4/pkg/storage/driver"
@ -407,7 +408,7 @@ func TestInstallRelease_Wait(t *testing.T) {
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
instAction.cfg.KubeClient = failer
instAction.Wait = true
instAction.Wait = kube.StatusWatcherStrategy
vals := map[string]interface{}{}
goroutines := runtime.NumGoroutine()
@ -426,7 +427,7 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) {
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitDuration = 10 * time.Second
instAction.cfg.KubeClient = failer
instAction.Wait = true
instAction.Wait = kube.StatusWatcherStrategy
vals := map[string]interface{}{}
ctx, cancel := context.WithCancel(context.Background())
@ -449,7 +450,7 @@ func TestInstallRelease_WaitForJobs(t *testing.T) {
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
instAction.cfg.KubeClient = failer
instAction.Wait = true
instAction.Wait = kube.StatusWatcherStrategy
instAction.WaitForJobs = true
vals := map[string]interface{}{}

@ -25,6 +25,7 @@ import (
"github.com/pkg/errors"
"helm.sh/helm/v4/pkg/chartutil"
"helm.sh/helm/v4/pkg/kube"
"helm.sh/helm/v4/pkg/release"
helmtime "helm.sh/helm/v4/pkg/time"
)
@ -37,7 +38,7 @@ type Rollback struct {
Version int
Timeout time.Duration
Wait bool
Wait kube.WaitStrategy
WaitForJobs bool
DisableHooks bool
DryRun bool
@ -89,6 +90,10 @@ func (r *Rollback) Run(name string) error {
return nil
}
func (r *Rollback) shouldWait() bool {
return !(r.Wait == "")
}
// prepareRollback finds the previous release and prepares a new release object with
// the previous release's configuration
func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Release, error) {
@ -223,7 +228,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
}
}
if r.Wait {
if r.shouldWait() {
if r.WaitForJobs {
if err := r.cfg.KubeClient.WaitWithJobs(target, r.Timeout); err != nil {
targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error()))

@ -64,8 +64,8 @@ type Upgrade struct {
SkipCRDs bool
// Timeout is the timeout for this operation
Timeout time.Duration
// Wait determines whether the wait operation should be performed after the upgrade is requested.
Wait bool
// Wait determines whether the wait operation should be performed and what type of wait.
Wait kube.WaitStrategy
// WaitForJobs determines whether the wait operation for the Jobs should be performed after the upgrade is requested.
WaitForJobs bool
// DisableHooks disables hook processing if set to true.
@ -155,7 +155,11 @@ func (u *Upgrade) RunWithContext(ctx context.Context, name string, chart *chart.
// Make sure if Atomic is set, that wait is set as well. This makes it so
// the user doesn't have to specify both
u.Wait = u.Wait || u.Atomic
if !u.shouldWait() {
if u.Atomic {
u.Wait = kube.StatusWatcherStrategy
}
}
if err := chartutil.ValidateReleaseName(name); err != nil {
return nil, errors.Errorf("release name is invalid: %s", name)
@ -186,6 +190,10 @@ func (u *Upgrade) RunWithContext(ctx context.Context, name string, chart *chart.
return res, nil
}
func (u *Upgrade) shouldWait() bool {
return u.Wait != ""
}
// isDryRun returns true if Upgrade is set to run as a DryRun
func (u *Upgrade) isDryRun() bool {
if u.DryRun || u.DryRunOption == "client" || u.DryRunOption == "server" || u.DryRunOption == "true" {
@ -443,7 +451,7 @@ func (u *Upgrade) releasingUpgrade(c chan<- resultMessage, upgradedRelease *rele
}
}
if u.Wait {
if u.shouldWait() {
u.cfg.Log(
"waiting for release %s resources (created: %d updated: %d deleted: %d)",
upgradedRelease.Name, len(results.Created), len(results.Updated), len(results.Deleted))
@ -526,7 +534,9 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
rollin := NewRollback(u.cfg)
rollin.Version = filteredHistory[0].Version
rollin.Wait = true
if !u.shouldWait() {
rollin.Wait = kube.StatusWatcherStrategy
}
rollin.WaitForJobs = u.WaitForJobs
rollin.DisableHooks = u.DisableHooks
rollin.Recreate = u.Recreate

@ -24,6 +24,7 @@ import (
"time"
"helm.sh/helm/v4/pkg/chart"
"helm.sh/helm/v4/pkg/kube"
"helm.sh/helm/v4/pkg/storage/driver"
"github.com/stretchr/testify/assert"
@ -52,7 +53,7 @@ func TestUpgradeRelease_Success(t *testing.T) {
rel.Info.Status = release.StatusDeployed
req.NoError(upAction.cfg.Releases.Create(rel))
upAction.Wait = true
upAction.Wait = kube.StatusWatcherStrategy
vals := map[string]interface{}{}
ctx, done := context.WithCancel(context.Background())
@ -82,7 +83,7 @@ func TestUpgradeRelease_Wait(t *testing.T) {
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
upAction.cfg.KubeClient = failer
upAction.Wait = true
upAction.Wait = kube.StatusWatcherStrategy
vals := map[string]interface{}{}
res, err := upAction.Run(rel.Name, buildChart(), vals)
@ -104,7 +105,7 @@ func TestUpgradeRelease_WaitForJobs(t *testing.T) {
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
upAction.cfg.KubeClient = failer
upAction.Wait = true
upAction.Wait = kube.StatusWatcherStrategy
upAction.WaitForJobs = true
vals := map[string]interface{}{}
@ -128,7 +129,7 @@ func TestUpgradeRelease_CleanupOnFail(t *testing.T) {
failer.WaitError = fmt.Errorf("I timed out")
failer.DeleteError = fmt.Errorf("I tried to delete nil")
upAction.cfg.KubeClient = failer
upAction.Wait = true
upAction.Wait = kube.StatusWatcherStrategy
upAction.CleanupOnFail = true
vals := map[string]interface{}{}
@ -395,7 +396,7 @@ func TestUpgradeRelease_Interrupted_Wait(t *testing.T) {
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitDuration = 10 * time.Second
upAction.cfg.KubeClient = failer
upAction.Wait = true
upAction.Wait = kube.StatusWatcherStrategy
vals := map[string]interface{}{}
ctx := context.Background()

@ -80,11 +80,11 @@ type Client struct {
Waiter
}
type WaitStrategy int
type WaitStrategy string
const (
StatusWaiterStrategy WaitStrategy = iota
LegacyWaiterStrategy
StatusWatcherStrategy WaitStrategy = "watcher"
LegacyWaiterStrategy WaitStrategy = "legacy"
)
func init() {
@ -106,7 +106,7 @@ func (c *Client) newWaiter(strategy WaitStrategy) (Waiter, error) {
return nil, err
}
return &HelmWaiter{kubeClient: kc, log: c.Log}, nil
case StatusWaiterStrategy:
case StatusWatcherStrategy:
cfg, err := c.Factory.ToRESTConfig()
if err != nil {
return nil, err

@ -659,7 +659,7 @@ func TestWaitDelete(t *testing.T) {
func TestReal(t *testing.T) {
t.Skip("This is a live test, comment this line to run")
c, err := New(nil, StatusWaiterStrategy)
c, err := New(nil, StatusWatcherStrategy)
if err != nil {
t.Fatal(err)
}
@ -672,7 +672,7 @@ func TestReal(t *testing.T) {
}
testSvcEndpointManifest := testServiceManifest + "\n---\n" + testEndpointManifest
c, err = New(nil, StatusWaiterStrategy)
c, err = New(nil, StatusWatcherStrategy)
if err != nil {
t.Fatal(err)
}

Loading…
Cancel
Save