github.com/codefresh-io/kcfi@v0.0.0-20230301195427-c1578715cc46/cmd/kcfi/upgrade.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"time"
    23  
    24  	"github.com/pkg/errors"
    25  	"github.com/spf13/cobra"
    26  
    27  	"github.com/codefresh-io/kcfi/pkg/helm-internal/completion"
    28  	"helm.sh/helm/v3/cmd/helm/require"
    29  	"helm.sh/helm/v3/pkg/action"
    30  	"helm.sh/helm/v3/pkg/chart/loader"
    31  	"helm.sh/helm/v3/pkg/cli/output"
    32  	"helm.sh/helm/v3/pkg/cli/values"
    33  	"helm.sh/helm/v3/pkg/getter"
    34  	"helm.sh/helm/v3/pkg/storage/driver"
    35  )
    36  
    37  const upgradeDesc = `
    38  This command upgrades a release to a new version of a chart.
    39  
    40  The upgrade arguments must be a release and chart. The chart
    41  argument can be either: a chart reference('example/mariadb'), a path to a chart directory,
    42  a packaged chart, or a fully qualified URL. For chart references, the latest
    43  version will be specified unless the '--version' flag is set.
    44  
    45  To override values in a chart, use either the '--values' flag and pass in a file
    46  or use the '--set' flag and pass configuration from the command line, to force string
    47  values, use '--set-string'. In case a value is large and therefore
    48  you want not to use neither '--values' nor '--set', use '--set-file' to read the
    49  single large value from file.
    50  
    51  You can specify the '--values'/'-f' flag multiple times. The priority will be given to the
    52  last (right-most) file specified. For example, if both myvalues.yaml and override.yaml
    53  contained a key called 'Test', the value set in override.yaml would take precedence:
    54  
    55      $ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis
    56  
    57  You can specify the '--set' flag multiple times. The priority will be given to the
    58  last (right-most) set specified. For example, if both 'bar' and 'newbar' values are
    59  set for a key called 'foo', the 'newbar' value would take precedence:
    60  
    61      $ helm upgrade --set foo=bar --set foo=newbar redis ./redis
    62  `
    63  
    64  func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
    65  	client := action.NewUpgrade(cfg)
    66  	valueOpts := &values.Options{}
    67  	var outfmt output.Format
    68  	var createNamespace bool
    69  
    70  	cmd := &cobra.Command{
    71  		Use:   "upgrade [RELEASE] [CHART]",
    72  		Short: "upgrade a release",
    73  		Long:  upgradeDesc,
    74  		Args:  require.ExactArgs(2),
    75  		RunE: func(cmd *cobra.Command, args []string) error {
    76  			client.Namespace = settings.Namespace()
    77  
    78  			// Fixes #7002 - Support reading values from STDIN for `upgrade` command
    79  			// Must load values AFTER determining if we have to call install so that values loaded from stdin are are not read twice
    80  			if client.Install {
    81  				// If a release does not exist, install it.
    82  				histClient := action.NewHistory(cfg)
    83  				histClient.Max = 1
    84  				if _, err := histClient.Run(args[0]); err == driver.ErrReleaseNotFound {
    85  					// Only print this to stdout for table output
    86  					if outfmt == output.Table {
    87  						fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0])
    88  					}
    89  					instClient := action.NewInstall(cfg)
    90  					instClient.CreateNamespace = createNamespace
    91  					instClient.ChartPathOptions = client.ChartPathOptions
    92  					instClient.DryRun = client.DryRun
    93  					instClient.DisableHooks = client.DisableHooks
    94  					instClient.SkipCRDs = client.SkipCRDs
    95  					instClient.Timeout = client.Timeout
    96  					instClient.Wait = client.Wait
    97  					instClient.Devel = client.Devel
    98  					instClient.Namespace = client.Namespace
    99  					instClient.Atomic = client.Atomic
   100  					instClient.PostRenderer = client.PostRenderer
   101  					instClient.DisableOpenAPIValidation = client.DisableOpenAPIValidation
   102  					instClient.SubNotes = client.SubNotes
   103  
   104  					rel, err := runInstall(args, instClient, valueOpts, out)
   105  					if err != nil {
   106  						return err
   107  					}
   108  					return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
   109  				} else if err != nil {
   110  					return err
   111  				}
   112  			}
   113  
   114  			if client.Version == "" && client.Devel {
   115  				debug("setting version to >0.0.0-0")
   116  				client.Version = ">0.0.0-0"
   117  			}
   118  
   119  			chartPath, err := client.ChartPathOptions.LocateChart(args[1], settings)
   120  			if err != nil {
   121  				return err
   122  			}
   123  
   124  			vals, err := valueOpts.MergeValues(getter.All(settings))
   125  			if err != nil {
   126  				return err
   127  			}
   128  
   129  			// Check chart dependencies to make sure all are present in /charts
   130  			ch, err := loader.Load(chartPath)
   131  			if err != nil {
   132  				return err
   133  			}
   134  			if req := ch.Metadata.Dependencies; req != nil {
   135  				if err := action.CheckDependencies(ch, req); err != nil {
   136  					return err
   137  				}
   138  			}
   139  
   140  			if ch.Metadata.Deprecated {
   141  				fmt.Fprintln(out, "WARNING: This chart is deprecated")
   142  			}
   143  
   144  			rel, err := client.Run(args[0], ch, vals)
   145  			if err != nil {
   146  				return errors.Wrap(err, "UPGRADE FAILED")
   147  			}
   148  
   149  			if outfmt == output.Table {
   150  				fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", args[0])
   151  			}
   152  
   153  			return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
   154  		},
   155  	}
   156  
   157  	// Function providing dynamic auto-completion
   158  	completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) {
   159  		if len(args) == 0 {
   160  			return compListReleases(toComplete, cfg)
   161  		}
   162  		if len(args) == 1 {
   163  			return compListCharts(toComplete, true)
   164  		}
   165  		return nil, completion.BashCompDirectiveNoFileComp
   166  	})
   167  
   168  	f := cmd.Flags()
   169  	f.BoolVar(&createNamespace, "create-namespace", false, "if --install is set, create the release namespace if not present")
   170  	f.BoolVarP(&client.Install, "install", "i", false, "if a release by this name doesn't already exist, run an install")
   171  	f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored")
   172  	f.BoolVar(&client.DryRun, "dry-run", false, "simulate an upgrade")
   173  	f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
   174  	f.MarkDeprecated("recreate-pods", "functionality will no longer be updated. Consult the documentation for other methods to recreate pods")
   175  	f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy")
   176  	f.BoolVar(&client.DisableHooks, "no-hooks", false, "disable pre/post upgrade hooks")
   177  	f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the upgrade process will not validate rendered templates against the Kubernetes OpenAPI Schema")
   178  	f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed when an upgrade is performed with install flag enabled. By default, CRDs are installed if not already present, when an upgrade is performed with install flag enabled")
   179  	f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
   180  	f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
   181  	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")
   182  	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")
   183  	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")
   184  	f.IntVar(&client.MaxHistory, "history-max", 10, "limit the maximum number of revisions saved per release. Use 0 for no limit")
   185  	f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails")
   186  	f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
   187  	f.StringVar(&client.Description, "description", "", "add a custom description")
   188  	addChartPathOptionsFlags(f, &client.ChartPathOptions)
   189  	addValueOptionsFlags(f, valueOpts)
   190  	bindOutputFlag(cmd, &outfmt)
   191  	bindPostRenderFlag(cmd, &client.PostRenderer)
   192  
   193  	return cmd
   194  }