config.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package kubernetes
  2. import (
  3. "path/filepath"
  4. "regexp"
  5. "strings"
  6. "time"
  7. "k8s.io/apimachinery/pkg/api/meta"
  8. "k8s.io/apimachinery/pkg/runtime"
  9. "k8s.io/cli-runtime/pkg/genericclioptions"
  10. "k8s.io/client-go/discovery"
  11. diskcached "k8s.io/client-go/discovery/cached/disk"
  12. "k8s.io/client-go/kubernetes"
  13. "k8s.io/client-go/kubernetes/fake"
  14. "k8s.io/client-go/rest"
  15. "k8s.io/client-go/restmapper"
  16. "k8s.io/client-go/tools/clientcmd"
  17. "k8s.io/client-go/util/homedir"
  18. )
  19. // GetAgentOutOfClusterConfig creates a new Agent using the OutOfClusterConfig
  20. func GetAgentOutOfClusterConfig(conf *OutOfClusterConfig) (*Agent, error) {
  21. restConf, err := conf.ToRESTConfig()
  22. if err != nil {
  23. return nil, err
  24. }
  25. clientset, err := kubernetes.NewForConfig(restConf)
  26. if err != nil {
  27. return nil, err
  28. }
  29. return &Agent{conf, clientset}, nil
  30. }
  31. // GetAgentInClusterConfig uses the service account that kubernetes
  32. // gives to pods to connect
  33. func GetAgentInClusterConfig() (*Agent, error) {
  34. conf, err := rest.InClusterConfig()
  35. if err != nil {
  36. return nil, err
  37. }
  38. restClientGetter := newRESTClientGetterFromInClusterConfig(conf)
  39. clientset, err := kubernetes.NewForConfig(conf)
  40. return &Agent{restClientGetter, clientset}, nil
  41. }
  42. // GetAgentTesting creates a new Agent using an optional existing storage class
  43. func GetAgentTesting(objects ...runtime.Object) *Agent {
  44. return &Agent{&fakeRESTClientGetter{}, fake.NewSimpleClientset(objects...)}
  45. }
  46. // OutOfClusterConfig is the set of parameters required for an out-of-cluster connection.
  47. // This implements RESTClientGetter
  48. type OutOfClusterConfig struct {
  49. KubeConfig []byte
  50. AllowedContexts []string
  51. Context string `json:"context" form:"required"`
  52. }
  53. // ToRESTConfig creates a kubernetes REST client factory -- it simply calls ClientConfig on
  54. // the result of ToRawKubeConfigLoader
  55. func (conf *OutOfClusterConfig) ToRESTConfig() (*rest.Config, error) {
  56. restConf, err := conf.ToRawKubeConfigLoader().ClientConfig()
  57. if err != nil {
  58. return nil, err
  59. }
  60. rest.SetKubernetesDefaults(restConf)
  61. return restConf, nil
  62. }
  63. // ToRawKubeConfigLoader creates a clientcmd.ClientConfig from the raw kubeconfig found in
  64. // the OutOfClusterConfig. It does not implement loading rules or overrides.
  65. func (conf *OutOfClusterConfig) ToRawKubeConfigLoader() clientcmd.ClientConfig {
  66. cmdConf, _ := GetRestrictedClientConfigFromBytes(
  67. conf.KubeConfig,
  68. conf.Context,
  69. conf.AllowedContexts,
  70. )
  71. return cmdConf
  72. }
  73. // ToDiscoveryClient returns a CachedDiscoveryInterface using a computed RESTConfig
  74. // It's required to implement the interface genericclioptions.RESTClientGetter
  75. func (conf *OutOfClusterConfig) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
  76. // From: k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go > func (*configFlags) ToDiscoveryClient()
  77. restConf, err := conf.ToRESTConfig()
  78. if err != nil {
  79. return nil, err
  80. }
  81. restConf.Burst = 100
  82. defaultHTTPCacheDir := filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
  83. // takes the parentDir and the host and comes up with a "usually non-colliding" name for the discoveryCacheDir
  84. parentDir := filepath.Join(homedir.HomeDir(), ".kube", "cache", "discovery")
  85. // strip the optional scheme from host if its there:
  86. schemelessHost := strings.Replace(strings.Replace(restConf.Host, "https://", "", 1), "http://", "", 1)
  87. // now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived
  88. safeHost := regexp.MustCompile(`[^(\w/\.)]`).ReplaceAllString(schemelessHost, "_")
  89. discoveryCacheDir := filepath.Join(parentDir, safeHost)
  90. return diskcached.NewCachedDiscoveryClientForConfig(restConf, discoveryCacheDir, defaultHTTPCacheDir, time.Duration(10*time.Minute))
  91. }
  92. // ToRESTMapper returns a mapper
  93. func (conf *OutOfClusterConfig) ToRESTMapper() (meta.RESTMapper, error) {
  94. // From: k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go > func (*configFlags) ToRESTMapper()
  95. discoveryClient, err := conf.ToDiscoveryClient()
  96. if err != nil {
  97. return nil, err
  98. }
  99. mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
  100. expander := restmapper.NewShortcutExpander(mapper, discoveryClient)
  101. return expander, nil
  102. }
  103. // newRESTClientGetterFromInClusterConfig returns a RESTClientGetter using
  104. // default values set from the *rest.Config
  105. func newRESTClientGetterFromInClusterConfig(conf *rest.Config) genericclioptions.RESTClientGetter {
  106. cfs := genericclioptions.NewConfigFlags(false)
  107. cfs.ClusterName = &conf.ServerName
  108. cfs.Insecure = &conf.Insecure
  109. cfs.APIServer = &conf.Host
  110. cfs.CAFile = &conf.CAFile
  111. cfs.KeyFile = &conf.KeyFile
  112. cfs.CertFile = &conf.CertFile
  113. cfs.BearerToken = &conf.BearerToken
  114. cfs.Timeout = stringptr(conf.Timeout.String())
  115. cfs.Impersonate = &conf.Impersonate.UserName
  116. cfs.ImpersonateGroup = &conf.Impersonate.Groups
  117. cfs.Username = &conf.Username
  118. cfs.Password = &conf.Password
  119. return cfs
  120. }
  121. func stringptr(val string) *string {
  122. return &val
  123. }
  124. type fakeRESTClientGetter struct{}
  125. func (f *fakeRESTClientGetter) ToRESTConfig() (*rest.Config, error) {
  126. return nil, nil
  127. }
  128. func (f *fakeRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
  129. return nil
  130. }
  131. func (f *fakeRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
  132. return nil, nil
  133. }
  134. func (f *fakeRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) {
  135. return nil, nil
  136. }