Skip to content

Commit

Permalink
Add kubecm export command (#713)
Browse files Browse the repository at this point in the history
* add export command

* add export doc link
  • Loading branch information
cr7258 committed Jun 25, 2023
1 parent 27ad7f8 commit ef2e212
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func NewBaseCommand() *BaseCommand {
&ClearCommand{}, // clear command
&CreateCommand{}, // create command
&CloudCommand{}, // cloud command
&ExportCommand{}, // export command
)

return baseCmd
Expand Down
113 changes: 113 additions & 0 deletions cmd/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package cmd

import (
"errors"
"fmt"
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

// AddCommand add command struct
type ExportCommand struct {
BaseCommand
}

// Init AddCommand
func (ec *ExportCommand) Init() {
ec.command = &cobra.Command{
Use: "export",
Short: "Export the specified context from the kubeconfig",
Long: "Export the specified context from the kubeconfig",
Aliases: []string{"e"},
RunE: func(cmd *cobra.Command, args []string) error {
return ec.runExport(args)
},
Example: exportExample(),
}
ec.command.Flags().StringP("file", "f", "", "Path to export kubeconfig files")
_ = ec.command.MarkFlagRequired("file")
}

func (ec *ExportCommand) runExport(args []string) error {
config, err := clientcmd.LoadFromFile(cfgFile)
if err != nil {
return err
}
if len(args) == 0 {
confirm, kubeName, err := selectExportContext(config)
if err != nil {
return err
}
if confirm == "True" {
config, err = exportContext([]string{kubeName}, config)
if err != nil {
return err
}
} else {
return errors.New("nothing exported!")
}
} else {
config, err = exportContext(args, config)
if err != nil {
return err
}
}

file, _ := ec.command.Flags().GetString("file")
err = clientcmd.WriteToFile(*config, file)
if err != nil {
return err
}
return nil
}

func exportContext(ctxs []string, config *clientcmdapi.Config) (*clientcmdapi.Config, error) {
var notFinds []string
exportConfig := clientcmdapi.NewConfig()
for _, ctx := range ctxs {
if ec, ok := config.Contexts[ctx]; ok {
exportConfig.AuthInfos[ec.AuthInfo] = config.AuthInfos[ec.AuthInfo]
exportConfig.Clusters[ec.Cluster] = config.Clusters[ec.Cluster]
exportConfig.Contexts[ctx] = config.Contexts[ctx]
exportConfig.CurrentContext = ctx
fmt.Printf("Context Export:「%s」\n", ctx)
} else {
notFinds = append(notFinds, ctx)
fmt.Printf("「%s」do not exit.\n", ctx)
}
}
if len(notFinds) == len(ctxs) {
return nil, errors.New("nothing exported!")
}
return exportConfig, nil
}

func selectExportContext(config *clientcmdapi.Config) (string, string, error) {
var kubeItems []Needle
for key, obj := range config.Contexts {
if key != config.CurrentContext {
kubeItems = append(kubeItems, Needle{Name: key, Cluster: obj.Cluster, User: obj.AuthInfo})
} else {
kubeItems = append([]Needle{{Name: key, Cluster: obj.Cluster, User: obj.AuthInfo, Center: "(*)"}}, kubeItems...)
}
}
// exit option
kubeItems, err := ExitOption(kubeItems)
if err != nil {
return "", "", err
}
num := SelectUI(kubeItems, "Select The Export Kube Context")
kubeName := kubeItems[num].Name
confirm := BoolUI(fmt.Sprintf("Are you sure you want to export「%s」?", kubeName))
return confirm, kubeName, nil
}

func exportExample() string {
return `
# Export context to myconfig.yaml file
kubecm export -f myconfig.yaml my-context1
# Export multiple contexts to myconfig.yaml file
kubecm export -f myconfig.yaml my-context1 my-context2
`
}
87 changes: 87 additions & 0 deletions cmd/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cmd

import (
"fmt"
"testing"

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

var (
exportTestConfig = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"black-user": {Token: "black-token"},
"red-user": {Token: "red-token"},
},
Clusters: map[string]*clientcmdapi.Cluster{
"pig-cluster": {Server: "http://pig.org:8080"},
"cow-cluster": {Server: "http://cow.org:8080"},
},
Contexts: map[string]*clientcmdapi.Context{
"root-context": {AuthInfo: "black-user", Cluster: "pig-cluster", Namespace: "saw-ns"},
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster", Namespace: "hammer-ns"},
},
}
WantExportConfig = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"black-user": {Token: "black-token"},
},
Clusters: map[string]*clientcmdapi.Cluster{
"pig-cluster": {Server: "http://pig.org:8080"},
},
Contexts: map[string]*clientcmdapi.Context{
"root-context": {AuthInfo: "black-user", Cluster: "pig-cluster", Namespace: "saw-ns"},
},
CurrentContext: "root-context",
}
wantMultipleExportConfig = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"black-user": {Token: "black-token"},
"red-user": {Token: "red-token"},
},
Clusters: map[string]*clientcmdapi.Cluster{
"pig-cluster": {Server: "http://pig.org:8080"},
"cow-cluster": {Server: "http://cow.org:8080"},
},
Contexts: map[string]*clientcmdapi.Context{
"root-context": {AuthInfo: "black-user", Cluster: "pig-cluster", Namespace: "saw-ns"},
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster", Namespace: "hammer-ns"},
},
CurrentContext: "federal-context",
}
)

func Test_exportContext(t *testing.T) {
type args struct {
ctxs []string
config *clientcmdapi.Config
}
tests := []struct {
name string
args args
wantErr bool
}{
{"export", args{[]string{"root-context"}, &exportTestConfig}, false},
{"export-not-exist", args{[]string{"a"}, &exportTestConfig}, true},
{"multiple-export", args{[]string{"root-context", "federal-context"}, &exportTestConfig}, false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exportedConfig, err := exportContext(tt.args.ctxs, tt.args.config)
if (err != nil) != tt.wantErr {
t.Errorf("exportContext() error = %v, wantErr %v", err, tt.wantErr)
} else {
switch tt.name {
case "export":
checkConfig(&WantExportConfig, exportedConfig, t)
case "multiple-export":
checkConfig(&wantMultipleExportConfig, exportedConfig, t)
}
if err != nil {
fmt.Println(err)
}
}
})
}
}
3 changes: 2 additions & 1 deletion docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
* [kubecm namespace](/en-us/cli/kubecm_namespace.md)
* [kubecm rename](/en-us/cli/kubecm_rename.md)
* [kubecm switch](/en-us/cli/kubecm_switch.md)
* [kubecm version](/en-us/cli/kubecm_version.md)
* [kubecm version](/en-us/cli/kubecm_version.md)
* [kubecm export](/en-us/cli/kubecm_export.md)
1 change: 1 addition & 0 deletions docs/en-us/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
* [switch](/en-us/cli/kubecm_switch.md)
* [clear](/en-us/cli/kubecm_clear.md)
* [version](/en-us/cli/kubecm_version.md)
* [export](/en-us/cli/kubecm_export.md)
* [Contribute](/en-us/contribute.md)
40 changes: 40 additions & 0 deletions docs/en-us/cli/kubecm_export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## kubecm export

Export the specified context from the kubeconfig

### Synopsis

Export the specified context from the kubeconfig

```
kubecm export [flags]
```

### Examples

```
# Export context to myconfig.yaml file
kubecm export -f myconfig.yaml my-context1
# Export multiple contexts to myconfig.yaml file
kubecm export -f myconfig.yaml my-context1 my-context2
```

### Options

```
-f, --file string Path to export kubeconfig files
-h, --help help for export
```

### Options inherited from parent commands

```
--config string path of kubeconfig (default "/Users/guoxudong/.kube/config")
-m, --mac-notify enable to display Mac notification banner
--ui-size int number of list items to show in menu at once (default 4)
```

### SEE ALSO

* [kubecm](kubecm.md) - KubeConfig Manager.

1 change: 1 addition & 0 deletions docs/zh-cn/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
* [switch](/zh-cn/cli/kubecm_switch.md)
* [clear](/en-us/cli/kubecm_clear.md)
* [version](/zh-cn/cli/kubecm_version.md)
* [export](/zh-cn/cli/kubecm_export.md)
* [贡献](/zh-cn/contribute.md)
35 changes: 35 additions & 0 deletions docs/zh-cn/cli/kubecm_export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## kubecm export

导出指定 context

### 简介

导出指定 context

```
kubecm export [flags]
```

### 示例

```
# Export context to myconfig.yaml file
kubecm export -f myconfig.yaml my-context1
# Export multiple contexts to myconfig.yaml file
kubecm export -f myconfig.yaml my-context1 my-context2
```

### 选项

```
-f, --file string Path to export kubeconfig files
-h, --help help for export
```

### 全局选项

```
--config string path of kubeconfig (default "/Users/guoxudong/.kube/config")
-m, --mac-notify enable to display Mac notification banner
--ui-size int number of list items to show in menu at once (default 4)
```

0 comments on commit ef2e212

Please sign in to comment.