github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/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 cmd 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "log" 24 "os" 25 "os/signal" 26 "syscall" 27 "time" 28 29 "github.com/pkg/errors" 30 "github.com/spf13/cobra" 31 32 "helm.sh/helm/v3/cmd/helm/require" 33 "helm.sh/helm/v3/pkg/action" 34 "helm.sh/helm/v3/pkg/chart/loader" 35 "helm.sh/helm/v3/pkg/cli/output" 36 "helm.sh/helm/v3/pkg/cli/values" 37 "helm.sh/helm/v3/pkg/downloader" 38 "helm.sh/helm/v3/pkg/getter" 39 "helm.sh/helm/v3/pkg/storage/driver" 40 ) 41 42 const upgradeDesc = ` 43 This command upgrades a release to a new version of a chart. 44 45 The upgrade arguments must be a release and chart. The chart 46 argument can be either: a chart reference('example/mariadb'), a path to a chart directory, 47 a packaged chart, or a fully qualified URL. For chart references, the latest 48 version will be specified unless the '--version' flag is set. 49 50 To override values in a chart, use either the '--values' flag and pass in a file 51 or use the '--set' flag and pass configuration from the command line, to force string 52 values, use '--set-string'. You can use '--set-file' to set individual 53 values from a file when the value itself is too long for the command line 54 or is dynamically generated. You can also use '--set-json' to set json values 55 (scalars/objects/arrays) from the command line. 56 57 You can specify the '--values'/'-f' flag multiple times. The priority will be given to the 58 last (right-most) file specified. For example, if both myvalues.yaml and override.yaml 59 contained a key called 'Test', the value set in override.yaml would take precedence: 60 61 $ helm upgrade -f myvalues.yaml -f override.yaml redis ./redis 62 63 You can specify the '--set' flag multiple times. The priority will be given to the 64 last (right-most) set specified. For example, if both 'bar' and 'newbar' values are 65 set for a key called 'foo', the 'newbar' value would take precedence: 66 67 $ helm upgrade --set foo=bar --set foo=newbar redis ./redis 68 ` 69 70 func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { 71 client := action.NewUpgrade(cfg) 72 valueOpts := &values.Options{} 73 var outfmt output.Format 74 var createNamespace bool 75 76 cmd := &cobra.Command{ 77 Use: "upgrade [RELEASE] [CHART]", 78 Short: "upgrade a release", 79 Long: upgradeDesc, 80 Args: require.ExactArgs(2), 81 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 82 if len(args) == 0 { 83 return compListReleases(toComplete, args, cfg) 84 } 85 if len(args) == 1 { 86 return compListCharts(toComplete, true) 87 } 88 return nil, cobra.ShellCompDirectiveNoFileComp 89 }, 90 RunE: func(cmd *cobra.Command, args []string) error { 91 client.Namespace = settings.Namespace() 92 93 registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify) 94 if err != nil { 95 return fmt.Errorf("missing registry client: %w", err) 96 } 97 client.SetRegistryClient(registryClient) 98 99 // Fixes #7002 - Support reading values from STDIN for `upgrade` command 100 // Must load values AFTER determining if we have to call install so that values loaded from stdin are are not read twice 101 if client.Install { 102 // If a release does not exist, install it. 103 histClient := action.NewHistory(cfg) 104 histClient.Max = 1 105 if _, err := histClient.Run(args[0]); err == driver.ErrReleaseNotFound { 106 // Only print this to stdout for table output 107 if outfmt == output.Table { 108 fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0]) 109 } 110 instClient := action.NewInstall(cfg) 111 instClient.CreateNamespace = createNamespace 112 instClient.ChartPathOptions = client.ChartPathOptions 113 instClient.Force = client.Force 114 instClient.DryRun = client.DryRun 115 instClient.DisableHooks = client.DisableHooks 116 instClient.SkipCRDs = client.SkipCRDs 117 instClient.Timeout = client.Timeout 118 instClient.Wait = client.Wait 119 instClient.WaitForJobs = client.WaitForJobs 120 instClient.Devel = client.Devel 121 instClient.Namespace = client.Namespace 122 instClient.Atomic = client.Atomic 123 instClient.PostRenderer = client.PostRenderer 124 instClient.DisableOpenAPIValidation = client.DisableOpenAPIValidation 125 instClient.SubNotes = client.SubNotes 126 instClient.Description = client.Description 127 instClient.DependencyUpdate = client.DependencyUpdate 128 instClient.EnableDNS = client.EnableDNS 129 130 rel, err := runInstall(args, instClient, valueOpts, out) 131 if err != nil { 132 return err 133 } 134 return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false}) 135 } else if err != nil { 136 return err 137 } 138 } 139 140 if client.Version == "" && client.Devel { 141 debug("setting version to >0.0.0-0") 142 client.Version = ">0.0.0-0" 143 } 144 145 chartPath, err := client.ChartPathOptions.LocateChart(args[1], settings) 146 if err != nil { 147 return err 148 } 149 150 p := getter.All(settings) 151 vals, err := valueOpts.MergeValues(p) 152 if err != nil { 153 return err 154 } 155 156 // Check chart dependencies to make sure all are present in /charts 157 ch, err := loader.Load(chartPath) 158 if err != nil { 159 return err 160 } 161 if req := ch.Metadata.Dependencies; req != nil { 162 if err := action.CheckDependencies(ch, req); err != nil { 163 err = errors.Wrap(err, "An error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies") 164 if client.DependencyUpdate { 165 man := &downloader.Manager{ 166 Out: out, 167 ChartPath: chartPath, 168 Keyring: client.ChartPathOptions.Keyring, 169 SkipUpdate: false, 170 Getters: p, 171 RepositoryConfig: settings.RepositoryConfig, 172 RepositoryCache: settings.RepositoryCache, 173 Debug: settings.Debug, 174 } 175 if err := man.Update(); err != nil { 176 return err 177 } 178 // Reload the chart with the updated Chart.lock file. 179 if ch, err = loader.Load(chartPath); err != nil { 180 return errors.Wrap(err, "failed reloading chart after repo update") 181 } 182 } else { 183 return err 184 } 185 } 186 } 187 188 if ch.Metadata.Deprecated { 189 warning("This chart is deprecated") 190 } 191 192 // Create context and prepare the handle of SIGTERM 193 ctx := context.Background() 194 ctx, cancel := context.WithCancel(ctx) 195 196 // Set up channel on which to send signal notifications. 197 // We must use a buffered channel or risk missing the signal 198 // if we're not ready to receive when the signal is sent. 199 cSignal := make(chan os.Signal, 2) 200 signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM) 201 go func() { 202 <-cSignal 203 fmt.Fprintf(out, "Release %s has been cancelled.\n", args[0]) 204 cancel() 205 }() 206 207 rel, err := client.RunWithContext(ctx, args[0], ch, vals) 208 if err != nil { 209 return errors.Wrap(err, "UPGRADE FAILED") 210 } 211 212 if outfmt == output.Table { 213 fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", args[0]) 214 } 215 216 return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false}) 217 }, 218 } 219 220 f := cmd.Flags() 221 f.BoolVar(&createNamespace, "create-namespace", false, "if --install is set, create the release namespace if not present") 222 f.BoolVarP(&client.Install, "install", "i", false, "if a release by this name doesn't already exist, run an install") 223 f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") 224 f.BoolVar(&client.DryRun, "dry-run", false, "simulate an upgrade") 225 f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") 226 f.MarkDeprecated("recreate-pods", "functionality will no longer be updated. Consult the documentation for other methods to recreate pods") 227 f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy") 228 f.BoolVar(&client.DisableHooks, "no-hooks", false, "disable pre/post upgrade hooks") 229 f.BoolVar(&client.DisableOpenAPIValidation, "disable-openapi-validation", false, "if set, the upgrade process will not validate rendered templates against the Kubernetes OpenAPI Schema") 230 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") 231 f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") 232 f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") 233 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") 234 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") 235 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") 236 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") 237 f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit") 238 f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails") 239 f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") 240 f.StringVar(&client.Description, "description", "", "add a custom description") 241 f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "update dependencies if they are missing before installing the chart") 242 f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates") 243 addChartPathOptionsFlags(f, &client.ChartPathOptions) 244 addValueOptionsFlags(f, valueOpts) 245 bindOutputFlag(cmd, &outfmt) 246 bindPostRenderFlag(cmd, &client.PostRenderer) 247 248 err := cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 249 if len(args) != 2 { 250 return nil, cobra.ShellCompDirectiveNoFileComp 251 } 252 return compVersionFlag(args[1], toComplete) 253 }) 254 255 if err != nil { 256 log.Fatal(err) 257 } 258 259 return cmd 260 }