...

Source file src/helm.sh/helm/v3/pkg/cli/environment.go

Documentation: helm.sh/helm/v3/pkg/cli

     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  /*
    18  Package cli describes the operating environment for the Helm CLI.
    19  
    20  Helm's environment encapsulates all of the service dependencies Helm has.
    21  These dependencies are expressed as interfaces so that alternate implementations
    22  (mocks, etc.) can be easily generated.
    23  */
    24  package cli
    25  
    26  import (
    27  	"fmt"
    28  	"net/http"
    29  	"os"
    30  	"strconv"
    31  	"strings"
    32  
    33  	"github.com/spf13/pflag"
    34  	"k8s.io/cli-runtime/pkg/genericclioptions"
    35  	"k8s.io/client-go/rest"
    36  
    37  	"helm.sh/helm/v3/internal/version"
    38  	"helm.sh/helm/v3/pkg/helmpath"
    39  )
    40  
    41  // defaultMaxHistory sets the maximum number of releases to 0: unlimited
    42  const defaultMaxHistory = 10
    43  
    44  // defaultBurstLimit sets the default client-side throttling limit
    45  const defaultBurstLimit = 100
    46  
    47  // defaultQPS sets the default QPS value to 0 to use library defaults unless specified
    48  const defaultQPS = float32(0)
    49  
    50  // EnvSettings describes all of the environment settings.
    51  type EnvSettings struct {
    52  	namespace string
    53  	config    *genericclioptions.ConfigFlags
    54  
    55  	// KubeConfig is the path to the kubeconfig file
    56  	KubeConfig string
    57  	// KubeContext is the name of the kubeconfig context.
    58  	KubeContext string
    59  	// Bearer KubeToken used for authentication
    60  	KubeToken string
    61  	// Username to impersonate for the operation
    62  	KubeAsUser string
    63  	// Groups to impersonate for the operation, multiple groups parsed from a comma delimited list
    64  	KubeAsGroups []string
    65  	// Kubernetes API Server Endpoint for authentication
    66  	KubeAPIServer string
    67  	// Custom certificate authority file.
    68  	KubeCaFile string
    69  	// KubeInsecureSkipTLSVerify indicates if server's certificate will not be checked for validity.
    70  	// This makes the HTTPS connections insecure
    71  	KubeInsecureSkipTLSVerify bool
    72  	// KubeTLSServerName overrides the name to use for server certificate validation.
    73  	// If it is not provided, the hostname used to contact the server is used
    74  	KubeTLSServerName string
    75  	// Debug indicates whether or not Helm is running in Debug mode.
    76  	Debug bool
    77  	// RegistryConfig is the path to the registry config file.
    78  	RegistryConfig string
    79  	// RepositoryConfig is the path to the repositories file.
    80  	RepositoryConfig string
    81  	// RepositoryCache is the path to the repository cache directory.
    82  	RepositoryCache string
    83  	// PluginsDirectory is the path to the plugins directory.
    84  	PluginsDirectory string
    85  	// MaxHistory is the max release history maintained.
    86  	MaxHistory int
    87  	// BurstLimit is the default client-side throttling limit.
    88  	BurstLimit int
    89  	// QPS is queries per second which may be used to avoid throttling.
    90  	QPS float32
    91  }
    92  
    93  func New() *EnvSettings {
    94  	env := &EnvSettings{
    95  		namespace:                 os.Getenv("HELM_NAMESPACE"),
    96  		MaxHistory:                envIntOr("HELM_MAX_HISTORY", defaultMaxHistory),
    97  		KubeContext:               os.Getenv("HELM_KUBECONTEXT"),
    98  		KubeToken:                 os.Getenv("HELM_KUBETOKEN"),
    99  		KubeAsUser:                os.Getenv("HELM_KUBEASUSER"),
   100  		KubeAsGroups:              envCSV("HELM_KUBEASGROUPS"),
   101  		KubeAPIServer:             os.Getenv("HELM_KUBEAPISERVER"),
   102  		KubeCaFile:                os.Getenv("HELM_KUBECAFILE"),
   103  		KubeTLSServerName:         os.Getenv("HELM_KUBETLS_SERVER_NAME"),
   104  		KubeInsecureSkipTLSVerify: envBoolOr("HELM_KUBEINSECURE_SKIP_TLS_VERIFY", false),
   105  		PluginsDirectory:          envOr("HELM_PLUGINS", helmpath.DataPath("plugins")),
   106  		RegistryConfig:            envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry/config.json")),
   107  		RepositoryConfig:          envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")),
   108  		RepositoryCache:           envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")),
   109  		BurstLimit:                envIntOr("HELM_BURST_LIMIT", defaultBurstLimit),
   110  		QPS:                       envFloat32Or("HELM_QPS", defaultQPS),
   111  	}
   112  	env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG"))
   113  
   114  	// bind to kubernetes config flags
   115  	env.config = &genericclioptions.ConfigFlags{
   116  		Namespace:        &env.namespace,
   117  		Context:          &env.KubeContext,
   118  		BearerToken:      &env.KubeToken,
   119  		APIServer:        &env.KubeAPIServer,
   120  		CAFile:           &env.KubeCaFile,
   121  		KubeConfig:       &env.KubeConfig,
   122  		Impersonate:      &env.KubeAsUser,
   123  		Insecure:         &env.KubeInsecureSkipTLSVerify,
   124  		TLSServerName:    &env.KubeTLSServerName,
   125  		ImpersonateGroup: &env.KubeAsGroups,
   126  		WrapConfigFn: func(config *rest.Config) *rest.Config {
   127  			config.Burst = env.BurstLimit
   128  			config.QPS = env.QPS
   129  			config.Wrap(func(rt http.RoundTripper) http.RoundTripper {
   130  				return &retryingRoundTripper{wrapped: rt}
   131  			})
   132  			config.UserAgent = version.GetUserAgent()
   133  			return config
   134  		},
   135  	}
   136  	return env
   137  }
   138  
   139  // AddFlags binds flags to the given flagset.
   140  func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
   141  	fs.StringVarP(&s.namespace, "namespace", "n", s.namespace, "namespace scope for this request")
   142  	fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to the kubeconfig file")
   143  	fs.StringVar(&s.KubeContext, "kube-context", s.KubeContext, "name of the kubeconfig context to use")
   144  	fs.StringVar(&s.KubeToken, "kube-token", s.KubeToken, "bearer token used for authentication")
   145  	fs.StringVar(&s.KubeAsUser, "kube-as-user", s.KubeAsUser, "username to impersonate for the operation")
   146  	fs.StringArrayVar(&s.KubeAsGroups, "kube-as-group", s.KubeAsGroups, "group to impersonate for the operation, this flag can be repeated to specify multiple groups.")
   147  	fs.StringVar(&s.KubeAPIServer, "kube-apiserver", s.KubeAPIServer, "the address and the port for the Kubernetes API server")
   148  	fs.StringVar(&s.KubeCaFile, "kube-ca-file", s.KubeCaFile, "the certificate authority file for the Kubernetes API server connection")
   149  	fs.StringVar(&s.KubeTLSServerName, "kube-tls-server-name", s.KubeTLSServerName, "server name to use for Kubernetes API server certificate validation. If it is not provided, the hostname used to contact the server is used")
   150  	fs.BoolVar(&s.KubeInsecureSkipTLSVerify, "kube-insecure-skip-tls-verify", s.KubeInsecureSkipTLSVerify, "if true, the Kubernetes API server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
   151  	fs.BoolVar(&s.Debug, "debug", s.Debug, "enable verbose output")
   152  	fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file")
   153  	fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs")
   154  	fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the file containing cached repository indexes")
   155  	fs.IntVar(&s.BurstLimit, "burst-limit", s.BurstLimit, "client-side default throttling limit")
   156  	fs.Float32Var(&s.QPS, "qps", s.QPS, "queries per second used when communicating with the Kubernetes API, not including bursting")
   157  }
   158  
   159  func envOr(name, def string) string {
   160  	if v, ok := os.LookupEnv(name); ok {
   161  		return v
   162  	}
   163  	return def
   164  }
   165  
   166  func envBoolOr(name string, def bool) bool {
   167  	if name == "" {
   168  		return def
   169  	}
   170  	envVal := envOr(name, strconv.FormatBool(def))
   171  	ret, err := strconv.ParseBool(envVal)
   172  	if err != nil {
   173  		return def
   174  	}
   175  	return ret
   176  }
   177  
   178  func envIntOr(name string, def int) int {
   179  	if name == "" {
   180  		return def
   181  	}
   182  	envVal := envOr(name, strconv.Itoa(def))
   183  	ret, err := strconv.Atoi(envVal)
   184  	if err != nil {
   185  		return def
   186  	}
   187  	return ret
   188  }
   189  
   190  func envFloat32Or(name string, def float32) float32 {
   191  	if name == "" {
   192  		return def
   193  	}
   194  	envVal := envOr(name, strconv.FormatFloat(float64(def), 'f', 2, 32))
   195  	ret, err := strconv.ParseFloat(envVal, 32)
   196  	if err != nil {
   197  		return def
   198  	}
   199  	return float32(ret)
   200  }
   201  
   202  func envCSV(name string) (ls []string) {
   203  	trimmed := strings.Trim(os.Getenv(name), ", ")
   204  	if trimmed != "" {
   205  		ls = strings.Split(trimmed, ",")
   206  	}
   207  	return
   208  }
   209  
   210  func (s *EnvSettings) EnvVars() map[string]string {
   211  	envvars := map[string]string{
   212  		"HELM_BIN":               os.Args[0],
   213  		"HELM_CACHE_HOME":        helmpath.CachePath(""),
   214  		"HELM_CONFIG_HOME":       helmpath.ConfigPath(""),
   215  		"HELM_DATA_HOME":         helmpath.DataPath(""),
   216  		"HELM_DEBUG":             fmt.Sprint(s.Debug),
   217  		"HELM_PLUGINS":           s.PluginsDirectory,
   218  		"HELM_REGISTRY_CONFIG":   s.RegistryConfig,
   219  		"HELM_REPOSITORY_CACHE":  s.RepositoryCache,
   220  		"HELM_REPOSITORY_CONFIG": s.RepositoryConfig,
   221  		"HELM_NAMESPACE":         s.Namespace(),
   222  		"HELM_MAX_HISTORY":       strconv.Itoa(s.MaxHistory),
   223  		"HELM_BURST_LIMIT":       strconv.Itoa(s.BurstLimit),
   224  		"HELM_QPS":               strconv.FormatFloat(float64(s.QPS), 'f', 2, 32),
   225  
   226  		// broken, these are populated from helm flags and not kubeconfig.
   227  		"HELM_KUBECONTEXT":                  s.KubeContext,
   228  		"HELM_KUBETOKEN":                    s.KubeToken,
   229  		"HELM_KUBEASUSER":                   s.KubeAsUser,
   230  		"HELM_KUBEASGROUPS":                 strings.Join(s.KubeAsGroups, ","),
   231  		"HELM_KUBEAPISERVER":                s.KubeAPIServer,
   232  		"HELM_KUBECAFILE":                   s.KubeCaFile,
   233  		"HELM_KUBEINSECURE_SKIP_TLS_VERIFY": strconv.FormatBool(s.KubeInsecureSkipTLSVerify),
   234  		"HELM_KUBETLS_SERVER_NAME":          s.KubeTLSServerName,
   235  	}
   236  	if s.KubeConfig != "" {
   237  		envvars["KUBECONFIG"] = s.KubeConfig
   238  	}
   239  	return envvars
   240  }
   241  
   242  // Namespace gets the namespace from the configuration
   243  func (s *EnvSettings) Namespace() string {
   244  	if ns, _, err := s.config.ToRawKubeConfigLoader().Namespace(); err == nil {
   245  		return ns
   246  	}
   247  	if s.namespace != "" {
   248  		return s.namespace
   249  	}
   250  	return "default"
   251  }
   252  
   253  // SetNamespace sets the namespace in the configuration
   254  func (s *EnvSettings) SetNamespace(namespace string) {
   255  	s.namespace = namespace
   256  }
   257  
   258  // RESTClientGetter gets the kubeconfig from EnvSettings
   259  func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter {
   260  	return s.config
   261  }
   262  

View as plain text