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  }