Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,6 @@ import (
func main() {
rootCommand := switcher.NewCommandStartSwitcher()

// if first argument is not found, assume it is a context name
// hence call default subcommand
if len(os.Args) > 1 {
cmd, _, err := rootCommand.Find(os.Args[1:])
if err != nil || cmd == nil {
args := append([]string{"set-context"}, os.Args[1:]...)
rootCommand.SetArgs(args)
}

// cobra somehow does not recognize - as a valid command
if os.Args[1] == "-" {
args := append([]string{"set-previous-context"}, os.Args[1:]...)
rootCommand.SetArgs(args)
}

if os.Args[1] == "." {
args := append([]string{"set-last-context"}, os.Args[1:]...)
rootCommand.SetArgs(args)
}
}

if err := rootCommand.Execute(); err != nil {
fmt.Print(err)
os.Exit(1)
Expand Down
72 changes: 72 additions & 0 deletions cmd/switcher/alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package switcher

import (
"fmt"
"os"
"strings"

"github.com/danielfoehrkn/kubeswitch/pkg/subcommands/alias"
"github.com/spf13/cobra"
)

var (
aliasContextCmd = &cobra.Command{
Use: "alias",
Short: "Create an alias for a context. Use ALIAS=CONTEXT_NAME",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 || !strings.Contains(args[0], "=") || len(strings.Split(args[0], "=")) != 2 {
return fmt.Errorf("please provide the alias in the form ALIAS=CONTEXT_NAME")
}

arguments := strings.Split(args[0], "=")
ctxName, err := resolveContextName(arguments[1])
if err != nil {
return err
}

stores, config, err := initialize()
if err != nil {
return err
}

return alias.Alias(arguments[0], ctxName, stores, config, stateDirectory, noIndex)
},
SilenceErrors: true,
}

aliasLsCmd = &cobra.Command{
Use: "ls",
Short: "List all existing aliases",
RunE: func(cmd *cobra.Command, args []string) error {
return alias.ListAliases(stateDirectory)
},
}

aliasRmCmd = &cobra.Command{
Use: "rm",
Short: "Remove an existing alias",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return fmt.Errorf("please provide the alias to remove as the first argument")
}

return alias.RemoveAlias(args[0], stateDirectory)
},
SilenceErrors: true,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to implement ValidArgs function for autocompletion

}
)

func init() {
aliasRmCmd.Flags().StringVar(
&stateDirectory,
"state-directory",
os.ExpandEnv("$HOME/.kube/switch-state"),
"path to the state directory.")

aliasContextCmd.AddCommand(aliasLsCmd)
aliasContextCmd.AddCommand(aliasRmCmd)

setFlagsForContextCommands(aliasContextCmd)

rootCommand.AddCommand(aliasContextCmd)
}
25 changes: 25 additions & 0 deletions cmd/switcher/clean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package switcher

import (
"github.com/danielfoehrkn/kubeswitch/pkg/subcommands/clean"
"github.com/spf13/cobra"
)

var (
cleanCmd = &cobra.Command{
Use: "clean",
Short: "Cleans all temporary and cached kubeconfig files",
Long: `Cleans the temporary kubeconfig files created in the directory $HOME/.kube/switch_tmp and flushes every cache`,
RunE: func(cmd *cobra.Command, args []string) error {
stores, _, err := initialize()
if err != nil {
return err
}
return clean.Clean(stores)
},
}
)

func init() {
rootCommand.AddCommand(cleanCmd)
}
42 changes: 42 additions & 0 deletions cmd/switcher/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package switcher

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var (
setName string

completionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish]",
Short: "generate completion script",
Long: "load the completion script for switch into the current shell",
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish"},
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
root := cmd.Root()
if setName != "" {
root.Use = setName
}
switch args[0] {
case "bash":
return root.GenBashCompletion(os.Stdout)
case "zsh":
return root.GenZshCompletion(os.Stdout)
case "fish":
return root.GenFishCompletion(os.Stdout, true)
}
return fmt.Errorf("unsupported shell type: %s", args[0])
},
}
)

func init() {
completionCmd.Flags().StringVarP(&setName, "cmd", "c", "", "generate completion for the specified command")

rootCommand.AddCommand(completionCmd)
}
206 changes: 206 additions & 0 deletions cmd/switcher/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package switcher

import (
"fmt"
"os"

delete_context "github.com/danielfoehrkn/kubeswitch/pkg/subcommands/delete-context"
"github.com/danielfoehrkn/kubeswitch/pkg/subcommands/history"
"github.com/danielfoehrkn/kubeswitch/pkg/subcommands/hooks"
list_contexts "github.com/danielfoehrkn/kubeswitch/pkg/subcommands/list-contexts"
set_context "github.com/danielfoehrkn/kubeswitch/pkg/subcommands/set-context"
unset_context "github.com/danielfoehrkn/kubeswitch/pkg/subcommands/unset-context"
"github.com/danielfoehrkn/kubeswitch/pkg/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var (
previousContextCmd = &cobra.Command{
Use: "set-previous-context",
Short: "Switch to the previous context from the history",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
stores, config, err := initialize()
if err != nil {
return err
}

kc, err := history.SetPreviousContext(stores, config, stateDirectory, noIndex)
reportNewContext(kc)
return err
},
}

lastContextCmd = &cobra.Command{
Use: "set-last-context",
Short: "Switch to the last used context from the history",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
stores, config, err := initialize()
if err != nil {
return err
}

kc, err := history.SetLastContext(stores, config, stateDirectory, noIndex)
reportNewContext(kc)
return err
},
}

listContextsCmd = &cobra.Command{
Use: "list-contexts",
Short: "List all available contexts without fuzzy search",
Aliases: []string{"ls"},
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
lc, err := listContexts("")
if err != nil {
return err
}
for _, c := range lc {
fmt.Println(c)
}
return nil
},
}

setContextCmd = &cobra.Command{
Use: "set-context",
Short: "Switch to context name provided as first argument",
Long: `Switch to context name provided as first argument. KubeContext name has to exist in any of the found Kubeconfig files.`,
Args: cobra.ExactArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
log := logrus.New().WithField("hook", "")
return hooks.Hooks(log, configPath, stateDirectory, "", false)
},
RunE: func(cmd *cobra.Command, args []string) error {
stores, config, err := initialize()
if err != nil {
return err
}

kc, err := set_context.SetContext(args[0], stores, config, stateDirectory, noIndex, true)
reportNewContext(kc)
return err
},
SilenceUsage: true,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to implement ValidArgs function for autocompletion

}

deleteContextCmd = &cobra.Command{
Use: "delete-context",
Short: "Delete context name provided as first argument",
Long: `Delete context name provided as first argument. KubeContext name has to exist in the current Kubeconfig file.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctxName, err := resolveContextName(args[0])
fmt.Println("delete-context", ctxName, args, err)
if err != nil {
return err
}
return delete_context.DeleteContext(ctxName)
},
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to implement ValidArgs function for autocompletion

}

unsetContextCmd = &cobra.Command{
Use: "unset-context",
Short: "Unset current-context",
Long: `Unset current-context in the current Kubeconfig file.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return unset_context.UnsetCurrentContext()
},
}

currentContextCmd = &cobra.Command{
Use: "current-context",
Short: "Show current-context",
Long: `Show current-context in the current Kubeconfig file.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx, err := util.GetCurrentContext()
if err != nil {
return err
}
fmt.Println(ctx)
return nil
},
}
)

func init() {
rootCommand.AddCommand(currentContextCmd)
rootCommand.AddCommand(deleteContextCmd)
rootCommand.AddCommand(setContextCmd)
rootCommand.AddCommand(listContextsCmd)
rootCommand.AddCommand(unsetContextCmd)
rootCommand.AddCommand(previousContextCmd)
rootCommand.AddCommand(lastContextCmd)

setFlagsForContextCommands(setContextCmd)
setFlagsForContextCommands(listContextsCmd)
// need to add flags as the namespace history allows switching to any {context: namespace} combination
setFlagsForContextCommands(previousContextCmd)
setFlagsForContextCommands(lastContextCmd)
}

func listContexts(prefix string) ([]string, error) {
stores, config, err := initialize()
if err != nil {
return nil, err
}

lc, err := list_contexts.ListContexts(stores, config, stateDirectory, noIndex, prefix)
if err != nil {
return nil, err
}
return lc, nil
}

func resolveContextName(contextName string) (string, error) {
if contextName == "." {
c, err := util.GetCurrentContext()
if err != nil {
return "", err
}
contextName = c
}
return contextName, nil
}

func setFlagsForContextCommands(command *cobra.Command) {
setCommonFlags(command)
command.Flags().StringVar(
&storageBackend,
"store",
"filesystem",
"the backing store to be searched for kubeconfig files. Can be either \"filesystem\" or \"vault\"")
command.Flags().StringVar(
&kubeconfigName,
"kubeconfig-name",
defaultKubeconfigName,
"only shows kubeconfig files with this name. Accepts wilcard arguments '*' and '?'. Defaults to 'config'.")
command.Flags().StringVar(
&vaultAPIAddressFromFlag,
"vault-api-address",
"",
"the API address of the Vault store. Overrides the default \"vaultAPIAddress\" field in the SwitchConfig. This flag is overridden by the environment variable \"VAULT_ADDR\".")
command.Flags().StringVar(
&configPath,
"config-path",
os.ExpandEnv("$HOME/.kube/switch-config.yaml"),
"path on the local filesystem to the configuration file.")
// not used for setContext command. Makes call in switch.sh script easier (no need to exclude flag from call)
command.Flags().BoolVar(
&showPreview,
"show-preview",
true,
"show preview of the selected kubeconfig. Possibly makes sense to disable when using vault as the kubeconfig store to prevent excessive requests against the API.")
}

func reportNewContext(ctxName *string) {
if ctxName == nil {
return
}
fmt.Printf("switched to context \"%s\".\n", *ctxName)
}
Loading