github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/context/kubernetes/load.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"github.com/docker/cli/cli/command"
     8  	"github.com/docker/cli/cli/context"
     9  	"github.com/docker/cli/cli/context/store"
    10  	api "github.com/docker/compose-on-kubernetes/api"
    11  	"github.com/docker/docker/pkg/homedir"
    12  	"github.com/pkg/errors"
    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  	AuthProvider     *clientcmdapi.AuthProviderConfig `json:",omitempty"`
    23  	Exec             *clientcmdapi.ExecConfig         `json:",omitempty"`
    24  	UsernamePassword *UsernamePassword                `json:"usernamePassword,omitempty"`
    25  }
    26  
    27  // UsernamePassword contains username/password auth info
    28  type UsernamePassword struct {
    29  	Username string `json:"username,omitempty"`
    30  	Password string `json:"password,omitempty"`
    31  }
    32  
    33  var _ command.EndpointDefaultResolver = &EndpointMeta{}
    34  
    35  // Endpoint is a typed wrapper around a context-store generic endpoint describing
    36  // a Kubernetes endpoint, with TLS data
    37  type Endpoint struct {
    38  	EndpointMeta
    39  	TLSData *context.TLSData
    40  }
    41  
    42  func init() {
    43  	command.RegisterDefaultStoreEndpoints(
    44  		store.EndpointTypeGetter(KubernetesEndpoint, func() interface{} { return &EndpointMeta{} }),
    45  	)
    46  }
    47  
    48  // WithTLSData loads TLS materials for the endpoint
    49  func (c *EndpointMeta) WithTLSData(s store.Reader, contextName string) (Endpoint, error) {
    50  	tlsData, err := context.LoadTLSData(s, contextName, KubernetesEndpoint)
    51  	if err != nil {
    52  		return Endpoint{}, err
    53  	}
    54  	return Endpoint{
    55  		EndpointMeta: *c,
    56  		TLSData:      tlsData,
    57  	}, nil
    58  }
    59  
    60  // KubernetesConfig creates the kubernetes client config from the endpoint
    61  func (c *Endpoint) KubernetesConfig() clientcmd.ClientConfig {
    62  	cfg := clientcmdapi.NewConfig()
    63  	cluster := clientcmdapi.NewCluster()
    64  	cluster.Server = c.Host
    65  	cluster.InsecureSkipTLSVerify = c.SkipTLSVerify
    66  	authInfo := clientcmdapi.NewAuthInfo()
    67  	if c.TLSData != nil {
    68  		cluster.CertificateAuthorityData = c.TLSData.CA
    69  		authInfo.ClientCertificateData = c.TLSData.Cert
    70  		authInfo.ClientKeyData = c.TLSData.Key
    71  	}
    72  	if c.UsernamePassword != nil {
    73  		authInfo.Username = c.UsernamePassword.Username
    74  		authInfo.Password = c.UsernamePassword.Password
    75  	}
    76  	authInfo.AuthProvider = c.AuthProvider
    77  	authInfo.Exec = c.Exec
    78  	cfg.Clusters["cluster"] = cluster
    79  	cfg.AuthInfos["authInfo"] = authInfo
    80  	ctx := clientcmdapi.NewContext()
    81  	ctx.AuthInfo = "authInfo"
    82  	ctx.Cluster = "cluster"
    83  	ctx.Namespace = c.DefaultNamespace
    84  	cfg.Contexts["context"] = ctx
    85  	cfg.CurrentContext = "context"
    86  	return clientcmd.NewDefaultClientConfig(*cfg, &clientcmd.ConfigOverrides{})
    87  }
    88  
    89  // ResolveDefault returns endpoint metadata for the default Kubernetes
    90  // endpoint, which is derived from the env-based kubeconfig.
    91  func (c *EndpointMeta) ResolveDefault(stackOrchestrator command.Orchestrator) (interface{}, *store.EndpointTLSData, error) {
    92  	kubeconfig := os.Getenv("KUBECONFIG")
    93  	if kubeconfig == "" {
    94  		kubeconfig = filepath.Join(homedir.Get(), ".kube/config")
    95  	}
    96  	kubeEP, err := FromKubeConfig(kubeconfig, "", "")
    97  	if err != nil {
    98  		if stackOrchestrator == command.OrchestratorKubernetes || stackOrchestrator == command.OrchestratorAll {
    99  			return nil, nil, errors.Wrapf(err, "default orchestrator is %s but unable to resolve kubernetes endpoint", stackOrchestrator)
   100  		}
   101  
   102  		// We deliberately quash the error here, returning nil
   103  		// for the first argument is sufficient to indicate we weren't able to
   104  		// provide a default
   105  		return nil, nil, nil
   106  	}
   107  
   108  	var tls *store.EndpointTLSData
   109  	if kubeEP.TLSData != nil {
   110  		tls = kubeEP.TLSData.ToStoreTLSData()
   111  	}
   112  	return kubeEP.EndpointMeta, tls, nil
   113  }
   114  
   115  // EndpointFromContext extracts kubernetes endpoint info from current context
   116  func EndpointFromContext(metadata store.Metadata) *EndpointMeta {
   117  	ep, ok := metadata.Endpoints[KubernetesEndpoint]
   118  	if !ok {
   119  		return nil
   120  	}
   121  	typed, ok := ep.(EndpointMeta)
   122  	if !ok {
   123  		return nil
   124  	}
   125  	return &typed
   126  }
   127  
   128  // ConfigFromContext resolves a kubernetes client config for the specified context.
   129  // If kubeconfigOverride is specified, use this config file instead of the context defaults.ConfigFromContext
   130  // if command.ContextDockerHost is specified as the context name, fallsback to the default user's kubeconfig file
   131  func ConfigFromContext(name string, s store.Reader) (clientcmd.ClientConfig, error) {
   132  	ctxMeta, err := s.GetMetadata(name)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	epMeta := EndpointFromContext(ctxMeta)
   137  	if epMeta != nil {
   138  		ep, err := epMeta.WithTLSData(s, name)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  		return ep.KubernetesConfig(), nil
   143  	}
   144  	// context has no kubernetes endpoint
   145  	return api.NewKubernetesConfig(""), nil
   146  }