Skip to content

Commit

Permalink
some new future (#16)
Browse files Browse the repository at this point in the history
* add clear cmd & fix issue#11 #15 & add utest

* update docs

* fix for golang-ci

* fix golang style

* fix utest
  • Loading branch information
sunny0826 authored Dec 11, 2020
1 parent 0986831 commit 76677be
Show file tree
Hide file tree
Showing 21 changed files with 519 additions and 24 deletions.
1 change: 1 addition & 0 deletions cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func formatNewConfig(file string) (*clientcmdapi.Config, string, error) {
return nil, "", errors.New("Only support add 1 context. You can use `merge` cmd")
}
name, err := formatAndCheckName(file)
config = CheckValidContext(config)
if err != nil {
return nil, "", err
}
Expand Down
75 changes: 75 additions & 0 deletions cmd/clear.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cmd

import (
"fmt"
"os"
"reflect"

"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
)

// ClearCommand clean command struct
type ClearCommand struct {
BaseCommand
}

// Init AliasCommand
func (cl *ClearCommand) Init() {
cl.command = &cobra.Command{
Use: "clear",
Short: "Clear lapsed context, cluster and user",
Long: "Clear lapsed context, cluster and user",
RunE: func(cmd *cobra.Command, args []string) error {
return cl.runClear(cmd, args)
},
Example: clearExample(),
}
cl.command.DisableFlagsInUseLine = true
}

func (cl *ClearCommand) runClear(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
if ok, err := clearContext(cfgFile); ok {
printString(os.Stdout, fmt.Sprintf("There is nothing to clean in 「%s」\n", cfgFile))
return nil
} else if err != nil {
return err
}
} else {
for _, file := range args {
if ok, err := clearContext(file); ok {
printString(os.Stdout, fmt.Sprintf("There is nothing to clean in 「%s」\n", file))
} else if err != nil {
return err
}
}
}
return nil
}

func clearContext(file string) (bool, error) {
config, err := clientcmd.LoadFromFile(file)
if err != nil {
return false, err
}
outConfig := config.DeepCopy()
outConfig = CheckValidContext(outConfig)
if reflect.DeepEqual(config, outConfig) {
return true, nil
}
err = UpdateConfigFile(file, outConfig)
if err != nil {
return false, err
}
return false, nil
}

func clearExample() string {
return fmt.Sprintf(`
# Clear lapsed context, cluster and user (default is %s)
kubecm clear
# Customised clear lapsed files
kubecm clear config.yaml test.yaml
`, cfgFile)
}
44 changes: 44 additions & 0 deletions cmd/clear_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cmd

import (
"io/ioutil"
"os"
"testing"

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

func Test_clearContext(t *testing.T) {
trueFile, _ := ioutil.TempFile("", "")
falseFile, _ := ioutil.TempFile("", "")
defer os.Remove(trueFile.Name())
defer os.Remove(falseFile.Name())
_ = clientcmd.WriteToFile(appendMergeConfig, trueFile.Name())
_ = clientcmd.WriteToFile(wrongRootConfig, falseFile.Name())

type args struct {
file string
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
// TODO: Add test cases.
{"true", args{file: trueFile.Name()}, true, false},
{"false", args{file: falseFile.Name()}, false, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := clearContext(tt.args.file)
if (err != nil) != tt.wantErr {
t.Errorf("clearContext() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("clearContext() got = %v, want %v", got, tt.want)
}
})
}
}
1 change: 1 addition & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func NewBaseCommand() *BaseCommand {
&NamespaceCommand{}, // namespace command
&ListCommand{}, // list command
&AliasCommand{}, // alias command
&ClearCommand{}, // clear command
)

return baseCmd
Expand Down
45 changes: 41 additions & 4 deletions cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package cmd

import (
"log"
"fmt"
"strings"

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

"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
)

// ListCommand list cmd struct
Expand All @@ -27,23 +31,56 @@ func (lc *ListCommand) Init() {
}

func (lc *ListCommand) runList(command *cobra.Command, args []string) error {
err := Formatable()
config, err := clientcmd.LoadFromFile(cfgFile)
if err != nil {
return err
}
err = ClusterStatus()
config = CheckValidContext(config)
outConfig, err := filterArgs(args, config)
if err != nil {
log.Fatalf("Cluster check failure!\n%v", err)
return err
}
err = PrintTable(outConfig)
if err != nil {
return err
}
err = ClusterStatus()
if err != nil {
return fmt.Errorf("Cluster check failure!\n%v", err)
}
return nil
}

func filterArgs(args []string, config *clientcmdapi.Config) (*clientcmdapi.Config, error) {
if len(args) == 0 {
return config, nil
}
contextList := make(map[string]string)
for key := range config.Contexts {
for _, search := range args {
if strings.Contains(key, search) {
contextList[key] = search
}
}
}
for key := range config.Contexts {
if _, ok := contextList[key]; !ok {
delete(config.Contexts, key)
}
}
if len(config.Contexts) == 0 {
return nil, fmt.Errorf("there is no matching context for %v", args)
}
return config, nil
}

func listExample() string {
return `
# List all the contexts in your kubeconfig file
kubecm ls
# Aliases
kubecm l
# Filter out keywords(Multi-keyword support)
kubecm ls kind k3s
`
}
72 changes: 72 additions & 0 deletions cmd/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package cmd

import (
"reflect"
"testing"

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

var (
noRootMergeConfig = 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{
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster", Namespace: "hammer-ns"},
},
}
noFederalMergeConfig = 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"},
},
}
)

func NewAllConfig() *clientcmdapi.Config {
return appendMergeConfig.DeepCopy()
}

func Test_filterArgs(t *testing.T) {

type args struct {
args []string
config *clientcmdapi.Config
}
tests := []struct {
name string
args args
want *clientcmdapi.Config
wantErr bool
}{
// TODO: Add test cases.
{"noFederal", args{[]string{"root"}, NewAllConfig()}, &noFederalMergeConfig, false},
{"noRoot", args{[]string{"federal"}, NewAllConfig()}, &noRootMergeConfig, false},
{"all-context", args{[]string{"root", "federal"}, NewAllConfig()}, &appendMergeConfig, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := filterArgs(tt.args.args, tt.args.config)
if (err != nil) != tt.wantErr {
t.Errorf("filterArgs() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("filterArgs() got = %v, want %v", got, tt.want)
}
})
}
}
53 changes: 49 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ limitations under the License.
*/

import (
"bytes"
"flag"
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strings"

"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -73,10 +79,49 @@ func (cli *Cli) Run() error {
}
return cli.rootCmd.Execute()
}

func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
u, err := user.Current()
if nil == err {
return u.HomeDir
}
// cross compile support
if "windows" == runtime.GOOS {
return homeWindows()
}
// Unix-like system, so just assume Unix
return homeUnix()
}

func homeUnix() string {
if home := os.Getenv("HOME"); home != "" {
return home
}
var stdout bytes.Buffer
cmd := exec.Command("sh", "-c", "eval echo ~$USER")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return ""
}
result := strings.TrimSpace(stdout.String())
if result == "" {
fmt.Println("blank output when reading home directory")
os.Exit(0)
}
return os.Getenv("USERPROFILE") // windows

return result
}

func homeWindows() string {
drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
home = os.Getenv("USERPROFILE")
}
if home == "" {
fmt.Println("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
os.Exit(0)
}

return home
}
4 changes: 0 additions & 4 deletions cmd/switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ func (sc *SwitchCommand) runSwitch(command *cobra.Command, args []string) error
return err
}
sc.command.Printf("Switched to context 「%s」\n", config.CurrentContext)
//err = Formatable()
//if err != nil {
// return err
//}
return nil
}

Expand Down
Loading

0 comments on commit 76677be

Please sign in to comment.