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:
@@ -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"
|
||||
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 {
|
||||
|
||||
@@ -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,6 +42,41 @@ func runKubectl(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
config, err := loadConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
@@ -47,19 +87,27 @@ func runKubectl(ctx *cli.Context) error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user