mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-07-06 12:06:13 +00:00
feat(kubens): added force flag to switch namespaces even if it doesn'… (#416)
* feat(kubens): added force flag to switch namespaces even if it doesn't exist * Merged lines * fixed README.md and flags.go * updated flags.go, flags_test.go
This commit is contained in:
parent
4997a261dc
commit
b5daf2cef7
@ -46,6 +46,15 @@ Active namespace is "kube-system".
|
||||
$ kubens -
|
||||
Context "test" set.
|
||||
Active namespace is "default".
|
||||
|
||||
# change the active namespace even if it doesn't exist
|
||||
$ kubens not-found-namespace --force
|
||||
Context "test" set.
|
||||
Active namespace is "not-found-namespace".
|
||||
---
|
||||
$ kubens not-found-namespace -f
|
||||
Context "test" set.
|
||||
Active namespace is "not-found-namespace".
|
||||
```
|
||||
|
||||
If you have [`fzf`](https://github.com/junegunn/fzf) installed, you can also
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/cmdutil"
|
||||
@ -33,28 +34,51 @@ func (op UnsupportedOp) Run(_, _ io.Writer) error {
|
||||
// parseArgs looks at flags (excl. executable name, i.e. argv[0])
|
||||
// and decides which operation should be taken.
|
||||
func parseArgs(argv []string) Op {
|
||||
if len(argv) == 0 {
|
||||
n := len(argv)
|
||||
|
||||
if n == 0 {
|
||||
if cmdutil.IsInteractiveMode(os.Stdout) {
|
||||
return InteractiveSwitchOp{SelfCmd: os.Args[0]}
|
||||
}
|
||||
return ListOp{}
|
||||
}
|
||||
|
||||
if len(argv) == 1 {
|
||||
if n == 1 {
|
||||
v := argv[0]
|
||||
if v == "--help" || v == "-h" {
|
||||
switch v {
|
||||
case "--help", "-h":
|
||||
return HelpOp{}
|
||||
}
|
||||
if v == "--version" || v == "-V" {
|
||||
case "--version", "-V":
|
||||
return VersionOp{}
|
||||
}
|
||||
if v == "--current" || v == "-c" {
|
||||
case "--current", "-c":
|
||||
return CurrentOp{}
|
||||
default:
|
||||
return getSwitchOp(v, false)
|
||||
}
|
||||
if strings.HasPrefix(v, "-") && v != "-" {
|
||||
return UnsupportedOp{Err: fmt.Errorf("unsupported option '%s'", v)}
|
||||
} else if n == 2 {
|
||||
// {namespace} -f|--force
|
||||
name := argv[0]
|
||||
force := slices.Contains([]string{"-f", "--force"}, argv[1])
|
||||
|
||||
if !force {
|
||||
if !slices.Contains([]string{"-f", "--force"}, argv[0]) {
|
||||
return UnsupportedOp{Err: fmt.Errorf("unsupported arguments %q", argv)}
|
||||
}
|
||||
|
||||
// -f|--force {namespace}
|
||||
force = true
|
||||
name = argv[1]
|
||||
}
|
||||
return SwitchOp{Target: argv[0]}
|
||||
|
||||
return getSwitchOp(name, force)
|
||||
}
|
||||
|
||||
return UnsupportedOp{Err: fmt.Errorf("too many arguments")}
|
||||
}
|
||||
|
||||
func getSwitchOp(v string, force bool) Op {
|
||||
if strings.HasPrefix(v, "-") && v != "-" {
|
||||
return UnsupportedOp{Err: fmt.Errorf("unsupported option %q", v)}
|
||||
}
|
||||
return SwitchOp{Target: v, Force: force}
|
||||
}
|
||||
|
@ -48,12 +48,30 @@ func Test_parseArgs_new(t *testing.T) {
|
||||
{name: "switch by name",
|
||||
args: []string{"foo"},
|
||||
want: SwitchOp{Target: "foo"}},
|
||||
{name: "switch by name force short flag",
|
||||
args: []string{"foo", "-f"},
|
||||
want: SwitchOp{Target: "foo", Force: true}},
|
||||
{name: "switch by name force long flag",
|
||||
args: []string{"foo", "--force"},
|
||||
want: SwitchOp{Target: "foo", Force: true}},
|
||||
{name: "switch by name force short flag before name",
|
||||
args: []string{"-f", "foo"},
|
||||
want: SwitchOp{Target: "foo", Force: true}},
|
||||
{name: "switch by name force long flag before name",
|
||||
args: []string{"--force", "foo"},
|
||||
want: SwitchOp{Target: "foo", Force: true}},
|
||||
{name: "switch by name unknown arguments",
|
||||
args: []string{"foo", "-x"},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("unsupported arguments %q", []string{"foo", "-x"})}},
|
||||
{name: "switch by name unknown arguments",
|
||||
args: []string{"-x", "foo"},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("unsupported arguments %q", []string{"-x", "foo"})}},
|
||||
{name: "switch by swap",
|
||||
args: []string{"-"},
|
||||
want: SwitchOp{Target: "-"}},
|
||||
{name: "unrecognized flag",
|
||||
args: []string{"-x"},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("unsupported option '-x'")}},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("unsupported option %q", "-x")}},
|
||||
{name: "too many args",
|
||||
args: []string{"a", "b", "c"},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("too many arguments")}},
|
||||
|
@ -65,7 +65,7 @@ func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error {
|
||||
if choice == "" {
|
||||
return errors.New("you did not choose any of the options")
|
||||
}
|
||||
name, err := switchNamespace(kc, choice)
|
||||
name, err := switchNamespace(kc, choice, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to switch namespace")
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ func printUsage(out io.Writer) error {
|
||||
help := `USAGE:
|
||||
%PROG% : list the namespaces in the current context
|
||||
%PROG% <NAME> : change the active namespace of current context
|
||||
%PROG% <NAME> --force/-f : force change the active namespace of current context (even if it doesn't exist)
|
||||
%PROG% - : switch to the previous namespace in this context
|
||||
%PROG% -c, --current : show the current namespace
|
||||
%PROG% -h,--help : show this message
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
|
||||
type SwitchOp struct {
|
||||
Target string // '-' for back and forth, or NAME
|
||||
Force bool // force switch even if the namespace doesn't exist
|
||||
}
|
||||
|
||||
func (s SwitchOp) Run(_, stderr io.Writer) error {
|
||||
@ -38,7 +39,7 @@ func (s SwitchOp) Run(_, stderr io.Writer) error {
|
||||
return errors.Wrap(err, "kubeconfig error")
|
||||
}
|
||||
|
||||
toNS, err := switchNamespace(kc, s.Target)
|
||||
toNS, err := switchNamespace(kc, s.Target, s.Force)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -46,7 +47,7 @@ func (s SwitchOp) Run(_, stderr io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func switchNamespace(kc *kubeconfig.Kubeconfig, ns string) (string, error) {
|
||||
func switchNamespace(kc *kubeconfig.Kubeconfig, ns string, force bool) (string, error) {
|
||||
ctx := kc.GetCurrentContext()
|
||||
if ctx == "" {
|
||||
return "", errors.New("current-context is not set")
|
||||
@ -69,12 +70,14 @@ func switchNamespace(kc *kubeconfig.Kubeconfig, ns string) (string, error) {
|
||||
ns = prev
|
||||
}
|
||||
|
||||
ok, err := namespaceExists(kc, ns)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to query if namespace exists (is cluster accessible?)")
|
||||
}
|
||||
if !ok {
|
||||
return "", errors.Errorf("no namespace exists with name \"%s\"", ns)
|
||||
if !force {
|
||||
ok, err := namespaceExists(kc, ns)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to query if namespace exists (is cluster accessible?)")
|
||||
}
|
||||
if !ok {
|
||||
return "", errors.Errorf("no namespace exists with name \"%s\"", ns)
|
||||
}
|
||||
}
|
||||
|
||||
if err := kc.SetNamespace(ctx, ns); err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user