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