github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/driver/kubernetes/context/load.go (about) 1 package context 2 3 import ( 4 "net/url" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "github.com/docker/cli/cli/command" 10 "github.com/docker/cli/cli/context" 11 "github.com/docker/cli/cli/context/store" 12 "github.com/docker/docker/pkg/homedir" 13 "k8s.io/client-go/tools/clientcmd" 14 clientcmdapi "k8s.io/client-go/tools/clientcmd/api" 15 ) 16 17 // EndpointMeta is a typed wrapper around a context-store generic endpoint describing 18 // a Kubernetes endpoint, without TLS data 19 type EndpointMeta struct { 20 context.EndpointMetaBase 21 DefaultNamespace string `json:",omitempty"` 22 ProxyURL string `json:",omitempty"` 23 AuthProvider *clientcmdapi.AuthProviderConfig `json:",omitempty"` 24 Exec *clientcmdapi.ExecConfig `json:",omitempty"` 25 UsernamePassword *UsernamePassword `json:"usernamePassword,omitempty"` 26 Token string `json:"token,omitempty"` 27 } 28 29 // UsernamePassword contains username/password auth info 30 type UsernamePassword struct { 31 Username string `json:"username,omitempty"` 32 Password string `json:"password,omitempty"` 33 } 34 35 var _ command.EndpointDefaultResolver = &EndpointMeta{} 36 37 // Endpoint is a typed wrapper around a context-store generic endpoint describing 38 // a Kubernetes endpoint, with TLS data 39 type Endpoint struct { 40 EndpointMeta 41 TLSData *context.TLSData 42 } 43 44 func init() { 45 command.RegisterDefaultStoreEndpoints( 46 store.EndpointTypeGetter(KubernetesEndpoint, func() interface{} { return &EndpointMeta{} }), 47 ) 48 } 49 50 // WithTLSData loads TLS materials for the endpoint 51 func (c *EndpointMeta) WithTLSData(s store.Reader, contextName string) (Endpoint, error) { 52 tlsData, err := context.LoadTLSData(s, contextName, KubernetesEndpoint) 53 if err != nil { 54 return Endpoint{}, err 55 } 56 return Endpoint{ 57 EndpointMeta: *c, 58 TLSData: tlsData, 59 }, nil 60 } 61 62 // KubernetesConfig creates the kubernetes client config from the endpoint 63 func (c *Endpoint) KubernetesConfig() clientcmd.ClientConfig { 64 cfg := clientcmdapi.NewConfig() 65 cluster := clientcmdapi.NewCluster() 66 cluster.Server = c.Host 67 if c.ProxyURL != "" { 68 cluster.ProxyURL = c.ProxyURL 69 } 70 cluster.InsecureSkipTLSVerify = c.SkipTLSVerify 71 authInfo := clientcmdapi.NewAuthInfo() 72 if c.TLSData != nil { 73 cluster.CertificateAuthorityData = c.TLSData.CA 74 authInfo.ClientCertificateData = c.TLSData.Cert 75 authInfo.ClientKeyData = c.TLSData.Key 76 } 77 if c.UsernamePassword != nil { 78 authInfo.Username = c.UsernamePassword.Username 79 authInfo.Password = c.UsernamePassword.Password 80 } 81 if c.Token != "" { 82 authInfo.Token = c.Token 83 } 84 authInfo.AuthProvider = c.AuthProvider 85 authInfo.Exec = c.Exec 86 cfg.Clusters["cluster"] = cluster 87 cfg.AuthInfos["authInfo"] = authInfo 88 ctx := clientcmdapi.NewContext() 89 ctx.AuthInfo = "authInfo" 90 ctx.Cluster = "cluster" 91 ctx.Namespace = c.DefaultNamespace 92 cfg.Contexts["context"] = ctx 93 cfg.CurrentContext = "context" 94 return clientcmd.NewDefaultClientConfig(*cfg, &clientcmd.ConfigOverrides{}) 95 } 96 97 // ResolveDefault returns endpoint metadata for the default Kubernetes 98 // endpoint, which is derived from the env-based kubeconfig. 99 func (c *EndpointMeta) ResolveDefault() (interface{}, *store.EndpointTLSData, error) { 100 kubeconfig := os.Getenv("KUBECONFIG") 101 if kubeconfig == "" { 102 kubeconfig = filepath.Join(homedir.Get(), ".kube/config") 103 } 104 kubeEP, err := FromKubeConfig(kubeconfig, "", "") 105 if err != nil { 106 // We deliberately quash the error here, returning nil 107 // for the first argument is sufficient to indicate we weren't able to 108 // provide a default 109 return nil, nil, nil 110 } 111 var tls *store.EndpointTLSData 112 if kubeEP.TLSData != nil { 113 tls = kubeEP.TLSData.ToStoreTLSData() 114 } 115 return kubeEP.EndpointMeta, tls, nil 116 } 117 118 // EndpointFromContext extracts kubernetes endpoint info from current context 119 func EndpointFromContext(metadata store.Metadata) *EndpointMeta { 120 ep, ok := metadata.Endpoints[KubernetesEndpoint] 121 if !ok { 122 return nil 123 } 124 typed, ok := ep.(EndpointMeta) 125 if !ok { 126 return nil 127 } 128 return &typed 129 } 130 131 // ConfigFromContext resolves a kubernetes client config for the specified context. 132 // If kubeconfigOverride is specified, use this config file instead of the context defaults.ConfigFromContext 133 // if command.ContextDockerHost is specified as the context name, fallsback to the default user's kubeconfig file 134 func ConfigFromContext(name string, s store.Reader) (clientcmd.ClientConfig, error) { 135 ctxMeta, err := s.GetMetadata(name) 136 if err != nil { 137 return nil, err 138 } 139 epMeta := EndpointFromContext(ctxMeta) 140 if epMeta != nil { 141 ep, err := epMeta.WithTLSData(s, name) 142 if err != nil { 143 return nil, err 144 } 145 return ep.KubernetesConfig(), nil 146 } 147 // context has no kubernetes endpoint 148 return NewKubernetesConfig(""), nil 149 } 150 151 // NewKubernetesConfig resolves the path to the desired Kubernetes configuration 152 // file based on the KUBECONFIG environment variable and command line flags. 153 func NewKubernetesConfig(configPath string) clientcmd.ClientConfig { 154 kubeConfig := configPath 155 if kubeConfig == "" { 156 if config := os.Getenv("KUBECONFIG"); config != "" { 157 kubeConfig = config 158 } else { 159 kubeConfig = filepath.Join(homedir.Get(), ".kube/config") 160 } 161 } 162 return clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 163 &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeConfig}, 164 &clientcmd.ConfigOverrides{}) 165 } 166 167 // ConfigFromEndpoint loads kubernetes config from endpoint 168 func ConfigFromEndpoint(endpointName string, s store.Reader) (clientcmd.ClientConfig, error) { 169 if strings.HasPrefix(endpointName, "kubernetes://") { 170 u, _ := url.Parse(endpointName) 171 if kubeconfig := u.Query().Get("kubeconfig"); kubeconfig != "" { 172 _ = os.Setenv(clientcmd.RecommendedConfigPathEnvVar, kubeconfig) 173 } 174 rules := clientcmd.NewDefaultClientConfigLoadingRules() 175 apiConfig, err := rules.Load() 176 if err != nil { 177 return nil, err 178 } 179 return clientcmd.NewDefaultClientConfig(*apiConfig, &clientcmd.ConfigOverrides{}), nil 180 } 181 return ConfigFromContext(endpointName, s) 182 }