...

Source file src/edge-infra.dev/pkg/k8s/kcli/flags.go

Documentation: edge-infra.dev/pkg/k8s/kcli

     1  package kcli
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  
     7  	"k8s.io/apimachinery/pkg/api/meta"
     8  	"k8s.io/client-go/dynamic"
     9  	"k8s.io/client-go/rest"
    10  	"k8s.io/client-go/tools/clientcmd"
    11  	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
    12  	"sigs.k8s.io/controller-runtime/pkg/client"
    13  	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
    14  )
    15  
    16  // KubeConfig contains configuration related to loading and parsing a Kubeconfig
    17  // file for instantiating K8s clients.
    18  // We don't use the built-in clientcmd flag registration utilities because
    19  // we don't want to expose the full sets of flags as K8s does (eg API server URL,
    20  // namespace, etc).
    21  type KubeConfig struct {
    22  	Context string
    23  	Path    string
    24  
    25  	clientCfg clientcmd.ClientConfig
    26  }
    27  
    28  // RegisterFlags binds common flags to an instance of the KubeConfig struct,
    29  // enabling flag reuse for any binary which needs to build a K8s client and wants
    30  // to allow users to override defaults via flags.
    31  func (k *KubeConfig) RegisterFlags(fs *flag.FlagSet) {
    32  	fs.StringVar(&k.Path, "kubeconfig", "", "Path to the kubeconfig file. "+
    33  		"Uses standard config loading rules if one is not provided.")
    34  	fs.StringVar(&k.Context, "context", "", "Name of the kubeconfig context to use. "+
    35  		"Defaults to current context if not provided.")
    36  }
    37  
    38  // SetupClientConfig creates client loading configuration based on the values
    39  // of bound flags, falling back to bog standard defaults if nothing is provided.
    40  func (k *KubeConfig) SetupClientConfig() error {
    41  	cfgOverrides := clientcmd.ConfigOverrides{}
    42  	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
    43  
    44  	if k.Path != "" {
    45  		loadingRules = &clientcmd.ClientConfigLoadingRules{ExplicitPath: k.Path}
    46  	}
    47  
    48  	if k.Context != "" {
    49  		cfgOverrides.CurrentContext = k.Context
    50  	}
    51  
    52  	clientCfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
    53  		loadingRules, &cfgOverrides,
    54  	)
    55  	k.clientCfg = clientCfg
    56  
    57  	return nil
    58  }
    59  
    60  // RESTConfig returns the rest.Config required to create a K8s client.
    61  func (k *KubeConfig) RESTConfig() (*rest.Config, error) {
    62  	if k.clientCfg == nil {
    63  		if err := k.SetupClientConfig(); err != nil {
    64  			return nil, err
    65  		}
    66  	}
    67  
    68  	return k.clientCfg.ClientConfig()
    69  }
    70  
    71  // Mapper instantiates the API resource mapper from the REST config.
    72  func (k *KubeConfig) Mapper() (meta.RESTMapper, error) {
    73  	cfg, err := k.RESTConfig()
    74  	if err != nil {
    75  		return nil, fmt.Errorf("failed to create k8s client configuration: %w", err)
    76  	}
    77  	httpClient, err := rest.HTTPClientFor(cfg)
    78  	if err != nil {
    79  		return nil, fmt.Errorf("failed to create http client for mapper: %w", err)
    80  	}
    81  	return apiutil.NewDynamicRESTMapper(cfg, httpClient)
    82  }
    83  
    84  // RawConfig returns the raw client configuration file (aka kubeconfig),
    85  // which can be used to check contexts, cluster names, etc.
    86  func (k *KubeConfig) RawConfig() (clientcmdapi.Config, error) {
    87  	if k.clientCfg == nil {
    88  		if err := k.SetupClientConfig(); err != nil {
    89  			return clientcmdapi.Config{}, err
    90  		}
    91  	}
    92  
    93  	return k.clientCfg.RawConfig()
    94  }
    95  
    96  // Client creates a K8s client from the parsed KubeConfig. This is a helper
    97  // function for binaries binding kubeconfig flags using this library.
    98  func (k *KubeConfig) Client(opts client.Options) (client.Client, error) {
    99  	cfg, err := k.RESTConfig()
   100  	if err != nil {
   101  		return nil, fmt.Errorf("failed to create k8s client configuration: %w", err)
   102  	}
   103  	kclient, err := client.New(cfg, opts)
   104  	if err != nil {
   105  		return nil, fmt.Errorf("failed to create k8s client: %w", err)
   106  	}
   107  	return kclient, nil
   108  }
   109  
   110  // DynamicClient creates a dynamic client from the parsed KubeConfig.
   111  func (k *KubeConfig) DynamicClient() (dynamic.Interface, error) {
   112  	cfg, err := k.RESTConfig()
   113  	if err != nil {
   114  		return nil, fmt.Errorf("failed to create k8s client configuration: %w", err)
   115  	}
   116  	return dynamic.NewForConfig(cfg)
   117  }
   118  

View as plain text