github.com/valdemarpavesi/helm@v2.9.1+incompatible/cmd/helm/upgrade.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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  	"strings"
    23  
    24  	"github.com/spf13/cobra"
    25  
    26  	"k8s.io/helm/pkg/chartutil"
    27  	"k8s.io/helm/pkg/helm"
    28  	"k8s.io/helm/pkg/storage/driver"
    29  )
    30  
    31  const upgradeDesc = `
    32  This command upgrades a release to a new version of a chart.
    33  
    34  The upgrade arguments must be a release and chart. The chart
    35  argument can be either: a chart reference('stable/mariadb'), a path to a chart directory,
    36  a packaged chart, or a fully qualified URL. For chart references, the latest
    37  version will be specified unless the '--version' flag is set.
    38  
    39  To override values in a chart, use either the '--values' flag and pass in a file
    40  or use the '--set' flag and pass configuration from the command line, to force string
    41  values, use '--set-string'.
    42  
    43  You can specify the '--values'/'-f' flag multiple times. The priority will be given to the
    44  last (right-most) file specified. For example, if both myvalues.yaml and override.yaml
    45  contained a key called 'Test', the value set in override.yaml would take precedence:
    46  
    47  	$ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis
    48  
    49  You can specify the '--set' flag multiple times. The priority will be given to the
    50  last (right-most) set specified. For example, if both 'bar' and 'newbar' values are
    51  set for a key called 'foo', the 'newbar' value would take precedence:
    52  
    53  	$ helm upgrade --set foo=bar --set foo=newbar redis ./redis
    54  `
    55  
    56  type upgradeCmd struct {
    57  	release      string
    58  	chart        string
    59  	out          io.Writer
    60  	client       helm.Interface
    61  	dryRun       bool
    62  	recreate     bool
    63  	force        bool
    64  	disableHooks bool
    65  	valueFiles   valueFiles
    66  	values       []string
    67  	stringValues []string
    68  	verify       bool
    69  	keyring      string
    70  	install      bool
    71  	namespace    string
    72  	version      string
    73  	timeout      int64
    74  	resetValues  bool
    75  	reuseValues  bool
    76  	wait         bool
    77  	repoURL      string
    78  	username     string
    79  	password     string
    80  	devel        bool
    81  
    82  	certFile string
    83  	keyFile  string
    84  	caFile   string
    85  }
    86  
    87  func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
    88  
    89  	upgrade := &upgradeCmd{
    90  		out:    out,
    91  		client: client,
    92  	}
    93  
    94  	cmd := &cobra.Command{
    95  		Use:     "upgrade [RELEASE] [CHART]",
    96  		Short:   "upgrade a release",
    97  		Long:    upgradeDesc,
    98  		PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
    99  		RunE: func(cmd *cobra.Command, args []string) error {
   100  			if err := checkArgsLength(len(args), "release name", "chart path"); err != nil {
   101  				return err
   102  			}
   103  
   104  			if upgrade.version == "" && upgrade.devel {
   105  				debug("setting version to >0.0.0-0")
   106  				upgrade.version = ">0.0.0-0"
   107  			}
   108  
   109  			upgrade.release = args[0]
   110  			upgrade.chart = args[1]
   111  			upgrade.client = ensureHelmClient(upgrade.client)
   112  
   113  			return upgrade.run()
   114  		},
   115  	}
   116  
   117  	f := cmd.Flags()
   118  	f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file or a URL(can specify multiple)")
   119  	f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade")
   120  	f.BoolVar(&upgrade.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
   121  	f.BoolVar(&upgrade.force, "force", false, "force resource update through delete/recreate if needed")
   122  	f.StringArrayVar(&upgrade.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
   123  	f.StringArrayVar(&upgrade.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
   124  	f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks")
   125  	f.BoolVar(&upgrade.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks")
   126  	f.BoolVar(&upgrade.verify, "verify", false, "verify the provenance of the chart before upgrading")
   127  	f.StringVar(&upgrade.keyring, "keyring", defaultKeyring(), "path to the keyring that contains public signing keys")
   128  	f.BoolVarP(&upgrade.install, "install", "i", false, "if a release by this name doesn't already exist, run an install")
   129  	f.StringVar(&upgrade.namespace, "namespace", "", "namespace to install the release into (only used if --install is set). Defaults to the current kube config namespace")
   130  	f.StringVar(&upgrade.version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used")
   131  	f.Int64Var(&upgrade.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
   132  	f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
   133  	f.BoolVar(&upgrade.reuseValues, "reuse-values", false, "when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.")
   134  	f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
   135  	f.StringVar(&upgrade.repoURL, "repo", "", "chart repository url where to locate the requested chart")
   136  	f.StringVar(&upgrade.username, "username", "", "chart repository username where to locate the requested chart")
   137  	f.StringVar(&upgrade.password, "password", "", "chart repository password where to locate the requested chart")
   138  	f.StringVar(&upgrade.certFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
   139  	f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
   140  	f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
   141  	f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
   142  
   143  	f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
   144  
   145  	return cmd
   146  }
   147  
   148  func (u *upgradeCmd) run() error {
   149  	chartPath, err := locateChartPath(u.repoURL, u.username, u.password, u.chart, u.version, u.verify, u.keyring, u.certFile, u.keyFile, u.caFile)
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	if u.install {
   155  		// If a release does not exist, install it. If another error occurs during
   156  		// the check, ignore the error and continue with the upgrade.
   157  		//
   158  		// The returned error is a grpc.rpcError that wraps the message from the original error.
   159  		// So we're stuck doing string matching against the wrapped error, which is nested somewhere
   160  		// inside of the grpc.rpcError message.
   161  		releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1))
   162  
   163  		if err == nil {
   164  			if u.namespace == "" {
   165  				u.namespace = defaultNamespace()
   166  			}
   167  			previousReleaseNamespace := releaseHistory.Releases[0].Namespace
   168  			if previousReleaseNamespace != u.namespace {
   169  				fmt.Fprintf(u.out,
   170  					"WARNING: Namespace %q doesn't match with previous. Release will be deployed to %s\n",
   171  					u.namespace, previousReleaseNamespace,
   172  				)
   173  			}
   174  		}
   175  
   176  		if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound(u.release).Error()) {
   177  			fmt.Fprintf(u.out, "Release %q does not exist. Installing it now.\n", u.release)
   178  			ic := &installCmd{
   179  				chartPath:    chartPath,
   180  				client:       u.client,
   181  				out:          u.out,
   182  				name:         u.release,
   183  				valueFiles:   u.valueFiles,
   184  				dryRun:       u.dryRun,
   185  				verify:       u.verify,
   186  				disableHooks: u.disableHooks,
   187  				keyring:      u.keyring,
   188  				values:       u.values,
   189  				stringValues: u.stringValues,
   190  				namespace:    u.namespace,
   191  				timeout:      u.timeout,
   192  				wait:         u.wait,
   193  			}
   194  			return ic.run()
   195  		}
   196  	}
   197  
   198  	rawVals, err := vals(u.valueFiles, u.values, u.stringValues)
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	// Check chart requirements to make sure all dependencies are present in /charts
   204  	if ch, err := chartutil.Load(chartPath); err == nil {
   205  		if req, err := chartutil.LoadRequirements(ch); err == nil {
   206  			if err := checkDependencies(ch, req); err != nil {
   207  				return err
   208  			}
   209  		} else if err != chartutil.ErrRequirementsNotFound {
   210  			return fmt.Errorf("cannot load requirements: %v", err)
   211  		}
   212  	} else {
   213  		return prettyError(err)
   214  	}
   215  
   216  	resp, err := u.client.UpdateRelease(
   217  		u.release,
   218  		chartPath,
   219  		helm.UpdateValueOverrides(rawVals),
   220  		helm.UpgradeDryRun(u.dryRun),
   221  		helm.UpgradeRecreate(u.recreate),
   222  		helm.UpgradeForce(u.force),
   223  		helm.UpgradeDisableHooks(u.disableHooks),
   224  		helm.UpgradeTimeout(u.timeout),
   225  		helm.ResetValues(u.resetValues),
   226  		helm.ReuseValues(u.reuseValues),
   227  		helm.UpgradeWait(u.wait))
   228  	if err != nil {
   229  		return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err))
   230  	}
   231  
   232  	if settings.Debug {
   233  		printRelease(u.out, resp.Release)
   234  	}
   235  
   236  	fmt.Fprintf(u.out, "Release %q has been upgraded. Happy Helming!\n", u.release)
   237  
   238  	// Print the status like status command does
   239  	status, err := u.client.ReleaseStatus(u.release)
   240  	if err != nil {
   241  		return prettyError(err)
   242  	}
   243  	PrintStatus(u.out, status)
   244  
   245  	return nil
   246  }