github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/root.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 // import "helm.sh/helm/v3/cmd/helm" 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "log" 24 "os" 25 "strings" 26 27 "github.com/spf13/cobra" 28 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/client-go/tools/clientcmd" 31 32 "helm.sh/helm/v3/pkg/action" 33 "helm.sh/helm/v3/pkg/registry" 34 "helm.sh/helm/v3/pkg/repo" 35 ) 36 37 var globalUsage = `The Kubernetes package manager 38 39 Common actions for Helm: 40 41 - helm search: search for charts 42 - helm pull: download a chart to your local directory to view 43 - helm install: upload the chart to Kubernetes 44 - helm list: list releases of charts 45 46 Environment variables: 47 48 | Name | Description | 49 |------------------------------------|---------------------------------------------------------------------------------------------------| 50 | $HELM_CACHE_HOME | set an alternative location for storing cached files. | 51 | $HELM_CONFIG_HOME | set an alternative location for storing Helm configuration. | 52 | $HELM_DATA_HOME | set an alternative location for storing Helm data. | 53 | $HELM_DEBUG | indicate whether or not Helm is running in Debug mode | 54 | $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, sql. | 55 | $HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use. | 56 | $HELM_MAX_HISTORY | set the maximum number of helm release history. | 57 | $HELM_NAMESPACE | set the namespace used for the helm operations. | 58 | $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. | 59 | $HELM_PLUGINS | set the path to the plugins directory | 60 | $HELM_REGISTRY_CONFIG | set the path to the registry config file. | 61 | $HELM_REPOSITORY_CACHE | set the path to the repository cache directory | 62 | $HELM_REPOSITORY_CONFIG | set the path to the repositories file. | 63 | $KUBECONFIG | set an alternative Kubernetes configuration file (default "~/.kube/config") | 64 | $HELM_KUBEAPISERVER | set the Kubernetes API Server Endpoint for authentication | 65 | $HELM_KUBECAFILE | set the Kubernetes certificate authority file. | 66 | $HELM_KUBEASGROUPS | set the Groups to use for impersonation using a comma-separated list. | 67 | $HELM_KUBEASUSER | set the Username to impersonate for the operation. | 68 | $HELM_KUBECONTEXT | set the name of the kubeconfig context. | 69 | $HELM_KUBETOKEN | set the Bearer KubeToken used for authentication. | 70 | $HELM_KUBEINSECURE_SKIP_TLS_VERIFY | indicate if the Kubernetes API server's certificate validation should be skipped (insecure) | 71 | $HELM_KUBETLS_SERVER_NAME | set the server name used to validate the Kubernetes API server certificate | 72 | $HELM_BURST_LIMIT | set the default burst limit in the case the server contains many CRDs (default 100, -1 to disable)| 73 74 Helm stores cache, configuration, and data based on the following configuration order: 75 76 - If a HELM_*_HOME environment variable is set, it will be used 77 - Otherwise, on systems supporting the XDG base directory specification, the XDG variables will be used 78 - When no other location is set a default location will be used based on the operating system 79 80 By default, the default directories depend on the Operating System. The defaults are listed below: 81 82 | Operating System | Cache Path | Configuration Path | Data Path | 83 |------------------|---------------------------|--------------------------------|-------------------------| 84 | Linux | $HOME/.cache/helm | $HOME/.config/helm | $HOME/.local/share/helm | 85 | macOS | $HOME/Library/Caches/helm | $HOME/Library/Preferences/helm | $HOME/Library/helm | 86 | Windows | %TEMP%\helm | %APPDATA%\helm | %APPDATA%\helm | 87 ` 88 89 func NewRootCmd(actionConfig *action.Configuration, out io.Writer, args []string) (*cobra.Command, error) { 90 cmd := &cobra.Command{ 91 Use: "helm", 92 Short: "The Helm package manager for Kubernetes.", 93 Long: globalUsage, 94 SilenceUsage: true, 95 } 96 flags := cmd.PersistentFlags() 97 98 settings.AddFlags(flags) 99 addKlogFlags(flags) 100 101 // Setup shell completion for the namespace flag 102 err := cmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 103 if client, err := actionConfig.KubernetesClientSet(); err == nil { 104 // Choose a long enough timeout that the user notices something is not working 105 // but short enough that the user is not made to wait very long 106 to := int64(3) 107 cobra.CompDebugln(fmt.Sprintf("About to call kube client for namespaces with timeout of: %d", to), settings.Debug) 108 109 nsNames := []string{} 110 if namespaces, err := client.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{TimeoutSeconds: &to}); err == nil { 111 for _, ns := range namespaces.Items { 112 nsNames = append(nsNames, ns.Name) 113 } 114 return nsNames, cobra.ShellCompDirectiveNoFileComp 115 } 116 } 117 return nil, cobra.ShellCompDirectiveDefault 118 }) 119 120 if err != nil { 121 log.Fatal(err) 122 } 123 124 // Setup shell completion for the kube-context flag 125 err = cmd.RegisterFlagCompletionFunc("kube-context", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 126 cobra.CompDebugln("About to get the different kube-contexts", settings.Debug) 127 128 loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() 129 if len(settings.KubeConfig) > 0 { 130 loadingRules = &clientcmd.ClientConfigLoadingRules{ExplicitPath: settings.KubeConfig} 131 } 132 if config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 133 loadingRules, 134 &clientcmd.ConfigOverrides{}).RawConfig(); err == nil { 135 comps := []string{} 136 for name, context := range config.Contexts { 137 comps = append(comps, fmt.Sprintf("%s\t%s", name, context.Cluster)) 138 } 139 return comps, cobra.ShellCompDirectiveNoFileComp 140 } 141 return nil, cobra.ShellCompDirectiveNoFileComp 142 }) 143 144 if err != nil { 145 log.Fatal(err) 146 } 147 148 // We can safely ignore any errors that flags.Parse encounters since 149 // those errors will be caught later during the call to cmd.Execution. 150 // This call is required to gather configuration information prior to 151 // execution. 152 flags.ParseErrorsWhitelist.UnknownFlags = true 153 flags.Parse(args) 154 155 registryClient, err := newDefaultRegistryClient() 156 if err != nil { 157 return nil, err 158 } 159 actionConfig.RegistryClient = registryClient 160 161 // Add subcommands 162 cmd.AddCommand( 163 // chart commands 164 newCreateCmd(out), 165 newDependencyCmd(actionConfig, out), 166 newPullCmd(actionConfig, out), 167 newShowCmd(actionConfig, out), 168 newLintCmd(out), 169 newPackageCmd(actionConfig, out), 170 newRepoCmd(out), 171 newSearchCmd(out), 172 newVerifyCmd(out), 173 174 // release commands 175 newGetCmd(actionConfig, out), 176 newHistoryCmd(actionConfig, out), 177 newInstallCmd(actionConfig, out), 178 newListCmd(actionConfig, out), 179 newReleaseTestCmd(actionConfig, out), 180 newRollbackCmd(actionConfig, out), 181 newStatusCmd(actionConfig, out), 182 newTemplateCmd(actionConfig, out), 183 newUninstallCmd(actionConfig, out), 184 newUpgradeCmd(actionConfig, out), 185 186 newCompletionCmd(out), 187 newEnvCmd(out), 188 newPluginCmd(out), 189 newVersionCmd(out), 190 191 // Hidden documentation generator command: 'helm docs' 192 newDocsCmd(out), 193 ) 194 195 cmd.AddCommand( 196 newRegistryCmd(actionConfig, out), 197 newPushCmd(actionConfig, out), 198 ) 199 200 // Find and add plugins 201 loadPlugins(cmd, out) 202 203 // Check permissions on critical files 204 checkPerms() 205 206 // Check for expired repositories 207 checkForExpiredRepos(settings.RepositoryConfig) 208 209 return cmd, nil 210 } 211 212 func checkForExpiredRepos(repofile string) { 213 214 expiredRepos := []struct { 215 name string 216 old string 217 new string 218 }{ 219 { 220 name: "stable", 221 old: "kubernetes-charts.storage.googleapis.com", 222 new: "https://charts.helm.sh/stable", 223 }, 224 { 225 name: "incubator", 226 old: "kubernetes-charts-incubator.storage.googleapis.com", 227 new: "https://charts.helm.sh/incubator", 228 }, 229 } 230 231 // parse repo file. 232 // Ignore the error because it is okay for a repo file to be unparseable at this 233 // stage. Later checks will trap the error and respond accordingly. 234 repoFile, err := repo.LoadFile(repofile) 235 if err != nil { 236 return 237 } 238 239 for _, exp := range expiredRepos { 240 r := repoFile.Get(exp.name) 241 if r == nil { 242 return 243 } 244 245 if url := r.URL; strings.Contains(url, exp.old) { 246 fmt.Fprintf( 247 os.Stderr, 248 "WARNING: %q is deprecated for %q and will be deleted Nov. 13, 2020.\nWARNING: You should switch to %q via:\nWARNING: helm repo add %q %q --force-update\n", 249 exp.old, 250 exp.name, 251 exp.new, 252 exp.name, 253 exp.new, 254 ) 255 } 256 } 257 258 } 259 260 func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) { 261 if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify { 262 registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify) 263 if err != nil { 264 return nil, err 265 } 266 return registryClient, nil 267 } 268 registryClient, err := newDefaultRegistryClient() 269 if err != nil { 270 return nil, err 271 } 272 return registryClient, nil 273 } 274 275 func newDefaultRegistryClient() (*registry.Client, error) { 276 // Create a new registry client 277 registryClient, err := registry.NewClient( 278 registry.ClientOptDebug(settings.Debug), 279 registry.ClientOptEnableCache(true), 280 registry.ClientOptWriter(os.Stderr), 281 registry.ClientOptCredentialsFile(settings.RegistryConfig), 282 ) 283 if err != nil { 284 return nil, err 285 } 286 return registryClient, nil 287 } 288 289 func newRegistryClientWithTLS(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) { 290 // Create a new registry client 291 registryClient, err := registry.NewRegistryClientWithTLS(os.Stderr, certFile, keyFile, caFile, insecureSkipTLSverify, 292 settings.RegistryConfig, settings.Debug, 293 ) 294 if err != nil { 295 return nil, err 296 } 297 return registryClient, nil 298 }