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