summary history files

backend/config/config.go
package config

import (
	"fmt"
	"runtime"
	"strings"
	"time"

	"k8s.io/client-go/kubernetes"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/clientcmd/api"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

type Config struct {
	KubeConfig         string
	KubeConfigs        map[KubeConfigPath]*clientcmdapi.Config
	DefaultKubeContext KubeContextName
	KubeClusters       map[KubeContextName]KubeCluster
	Opts
}

type KubeConfigPath string

type KubeContextName string

func (k KubeContextName) String() string {
	return string(k)
}

type KubeCluster struct {
	KubeContext    *api.Context
	KubeCluster    *api.Cluster
	KubeClientSet  *kubernetes.Clientset
	KubeRestConfig *restclient.Config
}

type Opts struct {
	Debug bool
}

type OptFunc func(*Opts)

func defaultOpts() Opts {
	return Opts{
		Debug: false,
	}
}

func WithDebug(d bool) OptFunc {
	return func(opts *Opts) {
		opts.Debug = d
	}
}

func (c Config) GetContext(name string) (*api.Context, error) {
	kubeContext, ok := c.KubeClusters[KubeContextName(name)]
	if !ok {
		return nil, fmt.Errorf("context does not exist")
	}
	return kubeContext.KubeContext, nil
}

func (c Config) GetClientSet(contextName string) (*kubernetes.Clientset, error) {
	kubeContext, ok := c.KubeClusters[KubeContextName(contextName)]
	if !ok {
		return &kubernetes.Clientset{}, fmt.Errorf("context does not exist")
	}
	return kubeContext.KubeClientSet, nil
}

func (c Config) GetRestConfig(contextName string) (*restclient.Config, error) {
	kubeContext, ok := c.KubeClusters[KubeContextName(contextName)]
	if !ok {
		return &restclient.Config{}, fmt.Errorf("context does not exist")
	}
	return kubeContext.KubeRestConfig, nil
}

func (c Config) getKubeContext(s string) (*api.Context, bool) {
	for _, apiConfig := range c.KubeConfigs {
		for name, context := range apiConfig.Contexts {
			if strings.ToLower(s) == name {
				return context, true
			}
		}
	}
	return nil, false
}

func (c Config) getKubeCluster(s string) (*api.Cluster, bool) {
	for _, apiConfig := range c.KubeConfigs {
		for name, cluster := range apiConfig.Clusters {
			if strings.ToLower(s) == name {
				return cluster, true
			}
		}
	}
	return nil, false
}

func NewConfig(kubeConfig string, opts ...OptFunc) (Config, error) {
	c := Config{
		KubeClusters: map[KubeContextName]KubeCluster{},
	}

	o := defaultOpts()
	for _, fn := range opts {
		fn(&o)
	}
	c.Opts = o

	kubeConfigs := map[KubeConfigPath]*clientcmdapi.Config{}

	// NOTE(rene): on windows path may have : so only support single kubeconfig
	kConfig := make([]string, 0)
	switch runtime.GOOS {
	case "windows":
		kConfig = append(kConfig, kubeConfig)
	default:
		kConfig = strings.Split(kubeConfig, ":")
	}

	for _, i := range kConfig {
		apiConfig, err := clientcmd.LoadFromFile(i)
		if err != nil {
			return c, err
		}
		kubeConfigs[KubeConfigPath(i)] = apiConfig
	}
	c.KubeConfigs = kubeConfigs

	for _, apiConfig := range c.KubeConfigs {
		for name, context := range apiConfig.Contexts {
			cluster, ok := c.getKubeCluster(name)
			if !ok {
				continue
			}

			configOverrides := clientcmd.ConfigOverrides{
				Context: api.Context{
					Cluster:   context.Cluster,
					Namespace: context.Namespace,
					AuthInfo:  context.AuthInfo,
				},
			}

			restConfig, err := clientcmd.NewNonInteractiveClientConfig(*apiConfig, name, &configOverrides, nil).ClientConfig()
			if err != nil {
				return c, err
			}

			restConfig.Timeout = 30 * time.Second

			clientSet, err := kubernetes.NewForConfig(restConfig)
			if err != nil {
				return c, err
			}

			m := KubeCluster{
				KubeContext:    context,
				KubeCluster:    cluster,
				KubeRestConfig: restConfig,
				KubeClientSet:  clientSet,
			}

			c.KubeClusters[KubeContextName(name)] = m
		}
	}

	return c, nil
}