github.com/oam-dev/kubevela@v1.9.11/pkg/utils/util/factory.go (about)

     1  /*
     2  Copyright 2021 The KubeVela 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 util
    18  
    19  import (
    20  	"os"
    21  	"path/filepath"
    22  	"regexp"
    23  	"strings"
    24  	"time"
    25  
    26  	"k8s.io/apimachinery/pkg/api/meta"
    27  	"k8s.io/cli-runtime/pkg/genericclioptions"
    28  	"k8s.io/client-go/discovery"
    29  	diskcached "k8s.io/client-go/discovery/cached/disk"
    30  	"k8s.io/client-go/rest"
    31  	"k8s.io/client-go/restmapper"
    32  	"k8s.io/client-go/tools/clientcmd"
    33  	"k8s.io/client-go/util/homedir"
    34  	ctrl "sigs.k8s.io/controller-runtime"
    35  
    36  	"github.com/oam-dev/kubevela/version"
    37  )
    38  
    39  var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
    40  
    41  var _ genericclioptions.RESTClientGetter = &restConfigGetter{}
    42  
    43  // NewRestConfigGetter create config for helm client.
    44  // The helm client never thought it could be used inside a cluster so it
    45  // took a dependency on the kube cli, we have to create a cli client getter from the rest.Config
    46  func NewRestConfigGetter(namespace string) genericclioptions.RESTClientGetter {
    47  	return &restConfigGetter{
    48  		config:    ctrl.GetConfigOrDie(),
    49  		namespace: namespace,
    50  	}
    51  }
    52  
    53  // NewRestConfigGetterByConfig new rest config getter
    54  func NewRestConfigGetterByConfig(config *rest.Config, namespace string) genericclioptions.RESTClientGetter {
    55  	return &restConfigGetter{
    56  		config:    config,
    57  		namespace: namespace,
    58  	}
    59  }
    60  
    61  type restConfigGetter struct {
    62  	config    *rest.Config
    63  	namespace string
    64  }
    65  
    66  func (r *restConfigGetter) ToRESTConfig() (*rest.Config, error) {
    67  	return r.config, nil
    68  }
    69  
    70  // ToDiscoveryClient implements RESTClientGetter.
    71  // Expects the AddFlags method to have been called.
    72  // Returns a CachedDiscoveryInterface using a computed RESTConfig.
    73  func (r *restConfigGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
    74  	config, err := r.ToRESTConfig()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// The more groups you have, the more discovery requests you need to make.
    80  	// given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests
    81  	// double it just so we don't end up here again for a while.  This config is only used for discovery.
    82  	config.Burst = 100
    83  
    84  	// retrieve a user-provided value for the "cache-dir"
    85  	// defaulting to ~/.kube/http-cache if no user-value is given.
    86  	httpCacheDir := defaultCacheDir
    87  
    88  	discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(homedir.HomeDir(), ".kube", "cache", "discovery"), config.Host)
    89  	return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, 10*time.Minute)
    90  }
    91  
    92  // ToRESTMapper returns a mapper.
    93  func (r *restConfigGetter) ToRESTMapper() (meta.RESTMapper, error) {
    94  	discoveryClient, err := r.ToDiscoveryClient()
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
   100  	expander := restmapper.NewShortcutExpander(mapper, discoveryClient)
   101  	return expander, nil
   102  }
   103  
   104  func (r *restConfigGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
   105  	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
   106  	// use the standard defaults for this client command
   107  	// DEPRECATED: remove and replace with something more accurate
   108  	loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
   109  
   110  	overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
   111  
   112  	// bind auth info flag values to overrides
   113  	if r.config.CertFile != "" {
   114  		overrides.AuthInfo.ClientCertificate = r.config.CertFile
   115  	}
   116  	if r.config.KeyFile != "" {
   117  		overrides.AuthInfo.ClientKey = r.config.KeyFile
   118  	}
   119  	if r.config.BearerToken != "" {
   120  		overrides.AuthInfo.Token = r.config.BearerToken
   121  	}
   122  
   123  	overrides.AuthInfo.Impersonate = r.config.Impersonate.UserName
   124  	overrides.AuthInfo.ImpersonateGroups = r.config.Impersonate.Groups
   125  	overrides.AuthInfo.ImpersonateUserExtra = r.config.Impersonate.Extra
   126  
   127  	if r.config.Username != "" {
   128  		overrides.AuthInfo.Username = r.config.Username
   129  	}
   130  	if r.config.Password != "" {
   131  		overrides.AuthInfo.Password = r.config.Password
   132  	}
   133  
   134  	// bind cluster flags
   135  	if r.config.Host != "" {
   136  		overrides.ClusterInfo.Server = r.config.Host
   137  	}
   138  	if r.config.CAFile != "" {
   139  		overrides.ClusterInfo.CertificateAuthority = r.config.CAFile
   140  	}
   141  	overrides.ClusterInfo.InsecureSkipTLSVerify = r.config.Insecure
   142  
   143  	if r.config.Timeout != 0 {
   144  		overrides.Timeout = r.config.Timeout.String()
   145  	}
   146  	// set namespace
   147  	overrides.Context.Namespace = r.namespace
   148  
   149  	var clientConfig clientcmd.ClientConfig
   150  
   151  	// we only have an interactive prompt when a password is allowed
   152  	if r.config.Password == "" {
   153  		clientConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
   154  	} else {
   155  		clientConfig = clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)
   156  	}
   157  
   158  	return clientConfig
   159  }
   160  
   161  // overlyCautiousIllegalFileCharacters matches characters that *might* not be supported.  Windows is really restrictive, so this is really restrictive
   162  var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/\.)]`)
   163  
   164  // computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name.
   165  func computeDiscoverCacheDir(parentDir, host string) string {
   166  	// strip the optional scheme from host if its there:
   167  	schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1)
   168  	// now do a simple collapse of non-AZ09 characters.  Collisions are possible but unlikely.  Even if we do collide the problem is short lived
   169  	safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_")
   170  	return filepath.Join(parentDir, safeHost)
   171  }
   172  
   173  // GenerateLeaderElectionID returns the Leader Election ID.
   174  func GenerateLeaderElectionID(name string, versionedDeploy bool) string {
   175  	if versionedDeploy {
   176  		return name + "-" + strings.ToLower(strings.ReplaceAll(version.VelaVersion, ".", "-"))
   177  	}
   178  	return name
   179  }