1
0
mirror of https://github.com/rancher/cli.git synced 2026-02-05 09:48:36 +01:00

Cache kubeconfig used for kubectl commands

This commit is contained in:
rmweir
2020-11-13 19:42:47 -07:00
parent 85998abbe8
commit bfe0ed5d0f
4 changed files with 113 additions and 9 deletions

View File

@@ -34,11 +34,13 @@ import (
managementClient "github.com/rancher/types/client/management/v3"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"k8s.io/client-go/tools/clientcmd/api"
)
const (
letters = "abcdefghijklmnopqrstuvwxyz0123456789"
cfgFile = "cli2.json"
letters = "abcdefghijklmnopqrstuvwxyz0123456789"
cfgFile = "cli2.json"
kubeConfigKeyFormat = "%s-%s"
)
var (
@@ -143,6 +145,31 @@ func listRoleTemplateBindings(ctx *cli.Context, b []RoleTemplateBinding) error {
return writer.Err()
}
func getKubeConfigForUser(ctx *cli.Context, user string) (*api.Config, error) {
cf, err := loadConfig(ctx)
if err != nil {
return nil, err
}
focusedServer := cf.FocusedServer()
kubeConfig, _ := focusedServer.KubeConfigs[fmt.Sprintf(kubeConfigKeyFormat, user, focusedServer.FocusedCluster())]
return kubeConfig, nil
}
func setKubeConfigForUser(ctx *cli.Context, user string, kubeConfig *api.Config) error {
cf, err := loadConfig(ctx)
if err != nil {
return err
}
if cf.FocusedServer().KubeConfigs == nil {
cf.FocusedServer().KubeConfigs = make(map[string]*api.Config)
}
focusedServer := cf.FocusedServer()
focusedServer.KubeConfigs[fmt.Sprintf(kubeConfigKeyFormat, user, focusedServer.FocusedCluster())] = kubeConfig
return cf.Write()
}
func usersToNameMapping(u []managementClient.User) map[string]string {
userMapping := make(map[string]string)
for _, user := range u {

View File

@@ -5,8 +5,13 @@ import (
"io/ioutil"
"os"
"os/exec"
"strings"
"github.com/rancher/norman/clientbase"
client "github.com/rancher/types/client/management/v3"
"github.com/urfave/cli"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"
)
func KubectlCommand() cli.Command {
@@ -37,29 +42,72 @@ func runKubectl(ctx *cli.Context) error {
return err
}
cluster, err := getClusterByID(c, c.UserConfig.FocusedCluster())
config, err := loadConfig(ctx)
if err != nil {
return err
}
config, err := c.ManagementClient.Cluster.ActionGenerateKubeconfig(cluster)
currentRancherServer := config.FocusedServer()
if currentRancherServer == nil {
return fmt.Errorf("no focused server")
}
currentToken := currentRancherServer.AccessKey
t, err := c.ManagementClient.Token.ByID(currentToken)
if err != nil {
return err
}
currentUser := t.UserID
kubeConfig, err := getKubeConfigForUser(ctx, currentUser)
if err != nil {
return err
}
var isTokenValid bool
if kubeConfig != nil {
tokenID, err := extractKubeconfigTokenID(*kubeConfig)
if err != nil {
return err
}
isTokenValid, err = validateToken(tokenID, c.ManagementClient.Token)
if err != nil {
return err
}
}
if kubeConfig == nil || !isTokenValid {
cluster, err := getClusterByID(c, c.UserConfig.FocusedCluster())
if err != nil {
return err
}
config, err := c.ManagementClient.Cluster.ActionGenerateKubeconfig(cluster)
if err != nil {
return err
}
kubeConfigBytes := []byte(config.Config)
kubeConfig, err = clientcmd.Load(kubeConfigBytes)
if err != nil {
return err
}
if err := setKubeConfigForUser(ctx, currentUser, kubeConfig); err != nil {
return err
}
}
tmpfile, err := ioutil.TempFile("", "rancher-")
if err != nil {
return err
}
defer os.Remove(tmpfile.Name())
_, err = tmpfile.Write([]byte(config.Config))
if err != nil {
if err := clientcmd.WriteToFile(*kubeConfig, tmpfile.Name()); err != nil {
return err
}
err = tmpfile.Close()
if err != nil {
if err := tmpfile.Close(); err != nil {
return err
}
@@ -74,3 +122,29 @@ func runKubectl(ctx *cli.Context) error {
}
return nil
}
func extractKubeconfigTokenID(kubeconfig api.Config) (string, error) {
if len(kubeconfig.AuthInfos) != 1 {
return "", fmt.Errorf("invalid kubeconfig, expected to contain exactly 1 user")
}
var parts []string
for _, val := range kubeconfig.AuthInfos {
parts = strings.Split(val.Token, ":")
if len(parts) != 2 {
return "", fmt.Errorf("failed to parse kubeconfig token")
}
}
return parts[0], nil
}
func validateToken(tokenID string, tokenClient client.TokenOperations) (bool, error) {
token, err := tokenClient.ByID(tokenID)
if err != nil {
if !clientbase.IsNotFound(err) {
return false, err
}
return false, nil
}
return !token.Expired, nil
}

View File

@@ -8,6 +8,7 @@ import (
"strings"
"github.com/sirupsen/logrus"
"k8s.io/client-go/tools/clientcmd/api"
)
// Config holds the main config for the user
@@ -28,6 +29,7 @@ type ServerConfig struct {
Project string `json:"project"`
CACerts string `json:"cacert"`
KubeCredentials map[string]*ExecCredential `json:"kubeCredentials"`
KubeConfigs map[string]*api.Config `json:"kubeConfigs"`
}
func (c Config) Write() error {

1
go.mod
View File

@@ -24,4 +24,5 @@ require (
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
gopkg.in/yaml.v2 v2.2.8
k8s.io/client-go v12.0.0+incompatible
)