diff --git a/cmd/kubevpn/cmds/alias.go b/cmd/kubevpn/cmds/alias.go index 8d39715e..c1b688d8 100644 --- a/cmd/kubevpn/cmds/alias.go +++ b/cmd/kubevpn/cmds/alias.go @@ -61,6 +61,7 @@ func CmdAlias(f cmdutil.Factory) *cobra.Command { If you have following config in your ~/.kubevpn/config.yaml Name: dev + Description: This is dev k8s environment Needs: jumper Flags: - connect @@ -69,11 +70,20 @@ func CmdAlias(f cmdutil.Factory) *cobra.Command { --- Name: jumper + Description: This is jumper k8s environment Flags: - connect - --kubeconfig=~/.kube/jumper_config - --namespace=test - --extra-hosts=xxx.com + + Name: all-in-one + Description: use special flags '--kubeconfig-json', no need to special kubeconfig path + Flags: + - connect + - --kubeconfig-json={"apiVersion":"v1","clusters":[{"cluster":{"certificate-authority-data":"LS0tLS1CRU..."}}]} + - --namespace=test + - --extra-hosts=xxx.com Config file support three field: Name,Needs,Flags @@ -82,6 +92,9 @@ func CmdAlias(f cmdutil.Factory) *cobra.Command { # kubevpn alias jumper, just connect to cluster jumper kubevpn alias jumper + + # support special flags '--kubeconfig-json', it will save kubeconfig into ~/.kubevpn/temp/[ALIAS_NAME] + kubevpn alias all-in-one `)), PreRunE: func(cmd *cobra.Command, args []string) (err error) { if localFile != "" { @@ -100,6 +113,10 @@ func CmdAlias(f cmdutil.Factory) *cobra.Command { return err } for _, conf := range configs { + err = ParseArgs(cmd, &conf) + if err != nil { + return err + } c := exec.Command(name, conf.Flags...) c.Stdout = os.Stdout c.Stdin = os.Stdin diff --git a/cmd/kubevpn/cmds/root.go b/cmd/kubevpn/cmds/root.go index 23427be7..69130afb 100644 --- a/cmd/kubevpn/cmds/root.go +++ b/cmd/kubevpn/cmds/root.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/spf13/cobra" + "github.com/spf13/pflag" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest" @@ -16,6 +17,7 @@ import ( "k8s.io/utils/ptr" "github.com/wencaiwulue/kubevpn/v2/pkg/config" + "github.com/wencaiwulue/kubevpn/v2/pkg/util" ) func NewKubeVPNCommand() *cobra.Command { @@ -97,8 +99,13 @@ func NewKubeVPNCommand() *cobra.Command { return cmd } +func AddKubeconfigJsonFlag(flags *pflag.FlagSet, kubeconfigJson *string) { + flags.StringVar(kubeconfigJson, "kubeconfig-json", ptr.Deref[string](kubeconfigJson, ""), "Json format of kubeconfig to use for CLI requests.") +} + type warp struct { *genericclioptions.ConfigFlags + KubeconfigJson string } func (f *warp) ToRawKubeConfigLoader() clientcmd.ClientConfig { @@ -106,5 +113,11 @@ func (f *warp) ToRawKubeConfigLoader() clientcmd.ClientConfig { home := homedir.HomeDir() f.KubeConfig = ptr.To(strings.Replace(*f.KubeConfig, "~", home, 1)) } + if strings.TrimSpace(f.KubeconfigJson) != "" { + path, err := util.ConvertToTempKubeconfigFile([]byte(f.KubeconfigJson)) + if err == nil { + f.KubeConfig = ptr.To(path) + } + } return f.ConfigFlags.ToRawKubeConfigLoader() } diff --git a/cmd/kubevpn/cmds/status.go b/cmd/kubevpn/cmds/status.go index 88b554b4..4d9a82ad 100644 --- a/cmd/kubevpn/cmds/status.go +++ b/cmd/kubevpn/cmds/status.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "strings" "github.com/liggitt/tabwriter" @@ -233,9 +234,11 @@ func GetConnectionIDByConfig(cmd *cobra.Command, config Config) (string, error) handler.AddExtraRoute(flags, &handler.ExtraRouteInfo{}) configFlags := genericclioptions.NewConfigFlags(true) configFlags.AddFlags(flags) - matchVersionFlags := cmdutil.NewMatchVersionFlags(&warp{ConfigFlags: configFlags}) + var kubeconfigJson string + AddKubeconfigJsonFlag(flags, &kubeconfigJson) + matchVersionFlags := cmdutil.NewMatchVersionFlags(&warp{ConfigFlags: configFlags, KubeconfigJson: kubeconfigJson}) matchVersionFlags.AddFlags(flags) - factory := cmdutil.NewFactory(matchVersionFlags) + f := cmdutil.NewFactory(matchVersionFlags) for _, command := range cmd.Parent().Commands() { command.Flags().VisitAll(func(f *flag.Flag) { @@ -249,7 +252,7 @@ func GetConnectionIDByConfig(cmd *cobra.Command, config Config) (string, error) _ = flags.Set(flag.Name, value) return nil }) - bytes, ns, err := util.ConvertToKubeConfigBytes(factory) + bytes, ns, err := util.ConvertToKubeConfigBytes(f) if err != nil { return "", err } @@ -275,3 +278,56 @@ func GetConnectionIDByConfig(cmd *cobra.Command, config Config) (string, error) } return id, nil } + +func ParseArgs(cmd *cobra.Command, conf *Config) error { + var str string + for i := 0; i < len(conf.Flags); i++ { + kubeconfigJson, err := parseKubeconfigJson(cmd, []string{conf.Flags[i]}) + if err != nil { + return err + } + if kubeconfigJson != "" { + str = kubeconfigJson + conf.Flags = append(conf.Flags[:i], conf.Flags[i+1:]...) + i-- + } + } + + if str == "" { + return nil + } + + file, err := util.ConvertToKubeconfigFile([]byte(str), filepath.Join(config.GetTempPath(), conf.Name)) + if err != nil { + return err + } + conf.Flags = append(conf.Flags, fmt.Sprintf("%s=%s", "--kubeconfig", file)) + return nil +} + +func parseKubeconfigJson(cmd *cobra.Command, args []string) (string, error) { + flags := flag.NewFlagSet("", flag.ContinueOnError) + var sshConf = &pkgssh.SshConfig{} + pkgssh.AddSshFlags(flags, sshConf) + handler.AddExtraRoute(flags, &handler.ExtraRouteInfo{}) + configFlags := genericclioptions.NewConfigFlags(true) + configFlags.AddFlags(flags) + var kubeconfigJson string + AddKubeconfigJsonFlag(flags, &kubeconfigJson) + matchVersionFlags := cmdutil.NewMatchVersionFlags(&warp{ConfigFlags: configFlags}) + matchVersionFlags.AddFlags(flags) + + for _, command := range cmd.Parent().Commands() { + command.Flags().VisitAll(func(f *flag.Flag) { + if flags.Lookup(f.Name) == nil && flags.ShorthandLookup(f.Shorthand) == nil { + flags.AddFlag(f) + } + }) + } + + err := flags.ParseAll(args, func(flag *flag.Flag, value string) error { + _ = flags.Set(flag.Name, value) + return nil + }) + return kubeconfigJson, err +} diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml index a94563eb..69dccde5 100644 --- a/pkg/config/config.yaml +++ b/pkg/config/config.yaml @@ -4,6 +4,7 @@ # Just keep simple Name: dev +Description: This is dev k8s environment, needs jump by qa env Needs: qa Flags: - connect @@ -13,6 +14,7 @@ Flags: --- Name: qa +Description: This is QA k8s environment Flags: - connect - --kubeconfig=~/.kube/jumper_config diff --git a/pkg/util/ns.go b/pkg/util/ns.go index f48dee9b..1f0ef993 100644 --- a/pkg/util/ns.go +++ b/pkg/util/ns.go @@ -152,6 +152,26 @@ func ConvertToTempKubeconfigFile(kubeconfigBytes []byte) (string, error) { return temp.Name(), nil } +func ConvertToKubeconfigFile(kubeconfigBytes []byte, filename string) (string, error) { + f, err := os.Create(filename) + if err != nil { + return "", err + } + _, err = f.Write(kubeconfigBytes) + if err != nil { + return "", err + } + err = f.Chmod(0644) + if err != nil { + return "", err + } + err = f.Close() + if err != nil { + return "", err + } + return f.Name(), nil +} + func containerPathSeparator(pattern string) bool { for i := 0; i < len(pattern); i++ { if os.IsPathSeparator(pattern[i]) {