pkg/kubeconfig/kconf.go
package kubeconfig import ( "fmt" "os" "path" "reflect" clientcmdapi "k8s.io/client-go/tools/clientcmd/api") // Configurable can validate and modify its own kubeconfig attributestype Configurable interface { AddContext() bool AddCluster() bool AddUser() bool hasContext() bool hasCluster() bool hasUser() bool rename() string} // KConf is a kubeconfig mixed with some useful functionstype KConf struct { clientcmdapi.Config} // MainConfigPath is the file path to the main configvar MainConfigPath string func init() { MainConfigPath = path.Join(os.Getenv("HOME"), ".kube", "config")} // AddContext attempts to add a Context and return the resulting namefunc (k *KConf) AddContext(name string, context *clientcmdapi.Context) string { // context exists and is identical if _, ok := k.Contexts[name]; ok && k.hasContext(context) { return "" } name, _ = k.rename(name, "context") k.Config.Contexts[name] = context return name} // IsEqualContext checks whether two Contexts are equalfunc IsEqualContext(ctx1, ctx2 *clientcmdapi.Context) bool { if ctx1.Cluster != ctx2.Cluster || ctx1.AuthInfo != ctx2.AuthInfo || !reflect.DeepEqual(ctx1.Extensions, ctx2.Extensions) { return false } return true} // hasContext checks whether the KConf already contains the given Contextfunc (k *KConf) hasContext(context *clientcmdapi.Context) bool { for _, ctx := range k.Contexts { if IsEqualContext(ctx, context) { return true } } return false} // AddCluster attempts to add a Cluster and return the resulting namefunc (k *KConf) AddCluster(name string, cluster *clientcmdapi.Cluster) string { if k.hasCluster(cluster) { return "" } name, _ = k.rename(name, "cluster") k.Config.Clusters[name] = cluster return name} // IsEqualCluster checks whether two Clusters are equalfunc IsEqualCluster(cls1, cls2 *clientcmdapi.Cluster) bool { if cls1.CertificateAuthority != cls2.CertificateAuthority || string(cls1.CertificateAuthorityData) != string(cls2.CertificateAuthorityData) || cls1.Server != cls2.Server || cls1.InsecureSkipTLSVerify != cls2.InsecureSkipTLSVerify || !reflect.DeepEqual(cls1.Extensions, cls2.Extensions) { return false } return true} // hasCluster checks whether the KConf already contains the given Clusterfunc (k *KConf) hasCluster(cluster *clientcmdapi.Cluster) bool { for _, cls := range k.Clusters { if IsEqualCluster(cls, cluster) { return true } } return false} // AddUser attempts to add an AuthInfo and return the resulting namefunc (k *KConf) AddUser(name string, user *clientcmdapi.AuthInfo) string { if k.hasUser(user) { return "" } name, _ = k.rename(name, "user") k.Config.AuthInfos[name] = user return name} // IsEqualUser checks whether two Users are equalfunc IsEqualUser(user1, user2 *clientcmdapi.AuthInfo) bool {Consider simplifying this complex logical expression. if user1.ClientCertificate != user2.ClientCertificate || string(user1.ClientCertificateData) != string(user2.ClientCertificateData) || user1.ClientKey != user2.ClientKey || string(user1.ClientKeyData) != string(user2.ClientKeyData) || user1.Token != user2.Token || user1.TokenFile != user2.TokenFile || user1.Impersonate != user2.Impersonate || user1.ImpersonateUID != user2.ImpersonateUID || !reflect.DeepEqual(user1.ImpersonateGroups, user2.ImpersonateGroups) || user1.Username != user2.Username || user1.Password != user2.Password || !reflect.DeepEqual(user1.AuthProvider, user2.AuthProvider) || !reflect.DeepEqual(user1.Exec, user2.Exec) { return false } return true} // hasUser checks whether the KConf already contains the given AuthInfofunc (k *KConf) hasUser(user *clientcmdapi.AuthInfo) bool { for _, u := range k.AuthInfos { if IsEqualUser(u, user) { return true } } return false} func (k *KConf) rename(name string, objType string) (string, error) { inc := 1 origName := name for { switch objType { case "context": if _, ok := k.Contexts[name]; !ok { return name, nil } case "cluster": if _, ok := k.Clusters[name]; !ok { return name, nil } case "user": if _, ok := k.AuthInfos[name]; !ok { return name, nil } default: return "", fmt.Errorf("unrecognized type '%s'", objType) } name = fmt.Sprintf("%s-%d", origName, inc) inc++ }} // MoveContext renames an existing contextfunc (k *KConf) MoveContext(oldName, newName string) error { ctx, ok := k.Contexts[oldName] if !ok { return fmt.Errorf("no existing context named '%s'", oldName) } if _, ok := k.Contexts[newName]; ok { return fmt.Errorf("context named '%s' already exists", newName) } k.Contexts[newName] = ctx delete(k.Contexts, oldName) return nil} // contextsWithUser returns a slice of context names that use a specific AuthInfofunc (k *KConf) contextsWithUser(name string) []string { contexts := []string{} for ctxName, ctx := range k.Contexts { if ctx.AuthInfo == name { contexts = append(contexts, ctxName) } } return contexts}