github.com/canthefason/helm@v2.2.1-0.20170221172616-16b043b8d505+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 "io/ioutil" 23 "strings" 24 25 "github.com/ghodss/yaml" 26 "github.com/spf13/cobra" 27 28 "k8s.io/helm/cmd/helm/strvals" 29 "k8s.io/helm/pkg/chartutil" 30 "k8s.io/helm/pkg/helm" 31 "k8s.io/helm/pkg/storage/driver" 32 ) 33 34 const upgradeDesc = ` 35 This command upgrades a release to a new version of a chart. 36 37 The upgrade arguments must be a release and chart. The chart 38 argument can be either: a chart reference('stable/mariadb'), a path to a chart directory, 39 a packaged chart, or a fully qualified URL. For chart references, the latest 40 version will be specified unless the '--version' flag is set. 41 42 To override values in a chart, use either the '--values' flag and pass in a file 43 or use the '--set' flag and pass configuration from the command line. 44 45 You can specify the '--values'/'-f' flag multiple times. The priority will be given to the 46 last (right-most) file specified. For example, if both myvalues.yaml and override.yaml 47 contained a key called 'Test', the value set in override.yaml would take precedence: 48 49 $ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis 50 51 You can specify the '--set' flag multiple times. The priority will be given to the 52 last (right-most) set specified. For example, if both 'bar' and 'newbar' values are 53 set for a key called 'foo', the 'newbar' value would take precedence: 54 55 $ helm upgrade --set foo=bar --set foo=newbar redis ./redis 56 ` 57 58 type upgradeCmd struct { 59 release string 60 chart string 61 out io.Writer 62 client helm.Interface 63 dryRun bool 64 recreate bool 65 disableHooks bool 66 valueFiles valueFiles 67 values []string 68 verify bool 69 keyring string 70 install bool 71 namespace string 72 version string 73 timeout int64 74 resetValues bool 75 wait bool 76 } 77 78 func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { 79 80 upgrade := &upgradeCmd{ 81 out: out, 82 client: client, 83 } 84 85 cmd := &cobra.Command{ 86 Use: "upgrade [RELEASE] [CHART]", 87 Short: "upgrade a release", 88 Long: upgradeDesc, 89 PersistentPreRunE: setupConnection, 90 RunE: func(cmd *cobra.Command, args []string) error { 91 if err := checkArgsLength(len(args), "release name", "chart path"); err != nil { 92 return err 93 } 94 95 upgrade.release = args[0] 96 upgrade.chart = args[1] 97 upgrade.client = ensureHelmClient(upgrade.client) 98 99 return upgrade.run() 100 }, 101 } 102 103 f := cmd.Flags() 104 f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") 105 f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade") 106 f.BoolVar(&upgrade.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") 107 f.StringArrayVar(&upgrade.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") 108 f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks") 109 f.BoolVar(&upgrade.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks") 110 f.BoolVar(&upgrade.verify, "verify", false, "verify the provenance of the chart before upgrading") 111 f.StringVar(&upgrade.keyring, "keyring", defaultKeyring(), "path to the keyring that contains public singing keys") 112 f.BoolVarP(&upgrade.install, "install", "i", false, "if a release by this name doesn't already exist, run an install") 113 f.StringVar(&upgrade.namespace, "namespace", "default", "namespace to install the release into (only used if --install is set)") 114 f.StringVar(&upgrade.version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used") 115 f.Int64Var(&upgrade.timeout, "timeout", 300, "time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)") 116 f.BoolVar(&upgrade.resetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") 117 f.BoolVar(&upgrade.wait, "wait", false, "if set, will wait until all Pods, PVCs, and Services are in a ready state before marking the release as successful. It will wait for as long as --timeout") 118 119 f.MarkDeprecated("disable-hooks", "use --no-hooks instead") 120 121 return cmd 122 } 123 124 func (u *upgradeCmd) run() error { 125 chartPath, err := locateChartPath(u.chart, u.version, u.verify, u.keyring) 126 if err != nil { 127 return err 128 } 129 130 if u.install { 131 // If a release does not exist, install it. If another error occurs during 132 // the check, ignore the error and continue with the upgrade. 133 // 134 // The returned error is a grpc.rpcError that wraps the message from the original error. 135 // So we're stuck doing string matching against the wrapped error, which is nested somewhere 136 // inside of the grpc.rpcError message. 137 _, err := u.client.ReleaseContent(u.release, helm.ContentReleaseVersion(1)) 138 if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound.Error()) { 139 fmt.Fprintf(u.out, "Release %q does not exist. Installing it now.\n", u.release) 140 ic := &installCmd{ 141 chartPath: chartPath, 142 client: u.client, 143 out: u.out, 144 name: u.release, 145 valueFiles: u.valueFiles, 146 dryRun: u.dryRun, 147 verify: u.verify, 148 disableHooks: u.disableHooks, 149 keyring: u.keyring, 150 values: u.values, 151 namespace: u.namespace, 152 timeout: u.timeout, 153 wait: u.wait, 154 } 155 return ic.run() 156 } 157 } 158 159 rawVals, err := u.vals() 160 if err != nil { 161 return err 162 } 163 164 // Check chart requirements to make sure all dependencies are present in /charts 165 if ch, err := chartutil.Load(chartPath); err == nil { 166 if req, err := chartutil.LoadRequirements(ch); err == nil { 167 checkDependencies(ch, req, u.out) 168 } 169 } 170 171 resp, err := u.client.UpdateRelease( 172 u.release, 173 chartPath, 174 helm.UpdateValueOverrides(rawVals), 175 helm.UpgradeDryRun(u.dryRun), 176 helm.UpgradeRecreate(u.recreate), 177 helm.UpgradeDisableHooks(u.disableHooks), 178 helm.UpgradeTimeout(u.timeout), 179 helm.ResetValues(u.resetValues), 180 helm.UpgradeWait(u.wait)) 181 if err != nil { 182 return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) 183 } 184 185 if flagDebug { 186 printRelease(u.out, resp.Release) 187 } 188 189 fmt.Fprintf(u.out, "Release %q has been upgraded. Happy Helming!\n", u.release) 190 191 // Print the status like status command does 192 status, err := u.client.ReleaseStatus(u.release) 193 if err != nil { 194 return prettyError(err) 195 } 196 PrintStatus(u.out, status) 197 198 return nil 199 } 200 201 func (u *upgradeCmd) vals() ([]byte, error) { 202 base := map[string]interface{}{} 203 204 // User specified a values files via -f/--values 205 for _, filePath := range u.valueFiles { 206 currentMap := map[string]interface{}{} 207 bytes, err := ioutil.ReadFile(filePath) 208 if err != nil { 209 return []byte{}, err 210 } 211 212 if err := yaml.Unmarshal(bytes, ¤tMap); err != nil { 213 return []byte{}, fmt.Errorf("failed to parse %s: %s", filePath, err) 214 } 215 // Merge with the previous map 216 base = mergeValues(base, currentMap) 217 } 218 219 // User specified a value via --set 220 for _, value := range u.values { 221 if err := strvals.ParseInto(value, base); err != nil { 222 return []byte{}, fmt.Errorf("failed parsing --set data: %s", err) 223 } 224 } 225 226 return yaml.Marshal(base) 227 }