Files
kubevela/pkg/utils/util/factory.go
Jianbo Sun dd222ac876 refactor cli/dashboard/apiserver to reference folder (#1084)
* refactor cli/dashboard/apiserver to reference folder

* address comments
2021-02-23 13:03:38 +08:00

146 lines
5.1 KiB
Go

package util
import (
"os"
"path/filepath"
"regexp"
"strings"
"time"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/discovery"
diskcached "k8s.io/client-go/discovery/cached/disk"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
ctrl "sigs.k8s.io/controller-runtime"
)
var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
var _ genericclioptions.RESTClientGetter = &restConfigGetter{}
// NewRestConfigGetter create config for helm client.
// The helm client never thought it could be used inside a cluster so it
// took a dependency on the kube cli, we have to create a cli client getter from the rest.Config
func NewRestConfigGetter(namespace string) genericclioptions.RESTClientGetter {
return &restConfigGetter{
config: ctrl.GetConfigOrDie(),
namespace: namespace,
}
}
type restConfigGetter struct {
config *rest.Config
namespace string
}
func (r *restConfigGetter) ToRESTConfig() (*rest.Config, error) {
return r.config, nil
}
// ToDiscoveryClient implements RESTClientGetter.
// Expects the AddFlags method to have been called.
// Returns a CachedDiscoveryInterface using a computed RESTConfig.
func (r *restConfigGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
config, err := r.ToRESTConfig()
if err != nil {
return nil, err
}
// The more groups you have, the more discovery requests you need to make.
// given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests
// double it just so we don't end up here again for a while. This config is only used for discovery.
config.Burst = 100
// retrieve a user-provided value for the "cache-dir"
// defaulting to ~/.kube/http-cache if no user-value is given.
httpCacheDir := defaultCacheDir
discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(homedir.HomeDir(), ".kube", "cache", "discovery"), config.Host)
return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, 10*time.Minute)
}
// ToRESTMapper returns a mapper.
func (r *restConfigGetter) ToRESTMapper() (meta.RESTMapper, error) {
discoveryClient, err := r.ToDiscoveryClient()
if err != nil {
return nil, err
}
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
expander := restmapper.NewShortcutExpander(mapper, discoveryClient)
return expander, nil
}
func (r *restConfigGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
// use the standard defaults for this client command
// DEPRECATED: remove and replace with something more accurate
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
// bind auth info flag values to overrides
if r.config.CertFile != "" {
overrides.AuthInfo.ClientCertificate = r.config.CertFile
}
if r.config.KeyFile != "" {
overrides.AuthInfo.ClientKey = r.config.KeyFile
}
if r.config.BearerToken != "" {
overrides.AuthInfo.Token = r.config.BearerToken
}
overrides.AuthInfo.Impersonate = r.config.Impersonate.UserName
overrides.AuthInfo.ImpersonateGroups = r.config.Impersonate.Groups
overrides.AuthInfo.ImpersonateUserExtra = r.config.Impersonate.Extra
if r.config.Username != "" {
overrides.AuthInfo.Username = r.config.Username
}
if r.config.Password != "" {
overrides.AuthInfo.Password = r.config.Password
}
// bind cluster flags
if r.config.Host != "" {
overrides.ClusterInfo.Server = r.config.Host
}
if r.config.CAFile != "" {
overrides.ClusterInfo.CertificateAuthority = r.config.CAFile
}
overrides.ClusterInfo.InsecureSkipTLSVerify = r.config.Insecure
if r.config.Timeout != 0 {
overrides.Timeout = r.config.Timeout.String()
}
// set namespace
overrides.Context.Namespace = r.namespace
var clientConfig clientcmd.ClientConfig
// we only have an interactive prompt when a password is allowed
if r.config.Password == "" {
clientConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
} else {
clientConfig = clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)
}
return clientConfig
}
// overlyCautiousIllegalFileCharacters matches characters that *might* not be supported. Windows is really restrictive, so this is really restrictive
var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/\.)]`)
// computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name.
func computeDiscoverCacheDir(parentDir, host string) string {
// strip the optional scheme from host if its there:
schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1)
// now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived
safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_")
return filepath.Join(parentDir, safeHost)
}