mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-07-19 09:39:36 +00:00
Add filtering contexts
This commit is contained in:
parent
561793c356
commit
c44c9306fd
@ -40,6 +40,16 @@ func parseArgs(argv []string) Op {
|
|||||||
return ListOp{}
|
return ListOp{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if argv[0] == "--list" || argv[0] == "-l" {
|
||||||
|
if len(argv) == 1 {
|
||||||
|
return ListOp{}
|
||||||
|
}
|
||||||
|
if filters, ok := parseFilterSyntax(argv[1:]); ok {
|
||||||
|
return ListOp{Filters: filters}
|
||||||
|
}
|
||||||
|
return UnsupportedOp{Err: fmt.Errorf("'-l' filters must use A=B format")}
|
||||||
|
}
|
||||||
|
|
||||||
if argv[0] == "-d" {
|
if argv[0] == "-d" {
|
||||||
if len(argv) == 1 {
|
if len(argv) == 1 {
|
||||||
if cmdutil.IsInteractiveMode(os.Stdout) {
|
if cmdutil.IsInteractiveMode(os.Stdout) {
|
||||||
|
@ -39,6 +39,21 @@ func Test_parseArgs_new(t *testing.T) {
|
|||||||
{name: "help long form",
|
{name: "help long form",
|
||||||
args: []string{"--help"},
|
args: []string{"--help"},
|
||||||
want: HelpOp{}},
|
want: HelpOp{}},
|
||||||
|
{name: "list shorthand",
|
||||||
|
args: []string{"-l"},
|
||||||
|
want: ListOp{}},
|
||||||
|
{name: "list long form",
|
||||||
|
args: []string{"--list"},
|
||||||
|
want: ListOp{}},
|
||||||
|
{name: "list long form filters",
|
||||||
|
args: []string{"--list", "cluster=cl"},
|
||||||
|
want: ListOp{Filters: map[string]string{"cluster": "cl"}}},
|
||||||
|
{name: "list long form filters - wrong syntax",
|
||||||
|
args: []string{"--list", "cluster-cl"},
|
||||||
|
want: UnsupportedOp{fmt.Errorf("'-l' filters must use A=B format")}},
|
||||||
|
{name: "current long form",
|
||||||
|
args: []string{"--current"},
|
||||||
|
want: CurrentOp{}},
|
||||||
{name: "current shorthand",
|
{name: "current shorthand",
|
||||||
args: []string{"-c"},
|
args: []string{"-c"},
|
||||||
want: CurrentOp{}},
|
want: CurrentOp{}},
|
||||||
|
@ -88,7 +88,7 @@ func (op InteractiveDeleteOp) Run(_, stderr io.Writer) error {
|
|||||||
}
|
}
|
||||||
kc.Close()
|
kc.Close()
|
||||||
|
|
||||||
if len(kc.ContextNames()) == 0 {
|
if len(kc.ContextNames(nil)) == 0 {
|
||||||
return errors.New("no contexts found in config")
|
return errors.New("no contexts found in config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"facette.io/natsort"
|
"facette.io/natsort"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -27,9 +28,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ListOp describes listing contexts.
|
// ListOp describes listing contexts.
|
||||||
type ListOp struct{}
|
type ListOp struct {
|
||||||
|
Filters map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
func (_ ListOp) Run(stdout, stderr io.Writer) error {
|
// parseFilterSyntax parses multiple A=B form into a map[A]=B and returns
|
||||||
|
// whether it is parsed correctly.
|
||||||
|
func parseFilterSyntax(v []string) (map[string]string, bool) {
|
||||||
|
m := make(map[string]string)
|
||||||
|
for _, vv := range v {
|
||||||
|
s := strings.Split(vv, "=")
|
||||||
|
if len(s) != 2 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
key, value := s[0], s[1]
|
||||||
|
if key == "" || value == "" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
m[key] = value
|
||||||
|
}
|
||||||
|
return m, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op ListOp) Run(stdout, stderr io.Writer) error {
|
||||||
kc := new(kubeconfig.Kubeconfig).WithLoader(kubeconfig.DefaultLoader)
|
kc := new(kubeconfig.Kubeconfig).WithLoader(kubeconfig.DefaultLoader)
|
||||||
defer kc.Close()
|
defer kc.Close()
|
||||||
if err := kc.Parse(); err != nil {
|
if err := kc.Parse(); err != nil {
|
||||||
@ -40,7 +61,7 @@ func (_ ListOp) Run(stdout, stderr io.Writer) error {
|
|||||||
return errors.Wrap(err, "kubeconfig error")
|
return errors.Wrap(err, "kubeconfig error")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxs := kc.ContextNames()
|
ctxs := kc.ContextNames(op.Filters)
|
||||||
natsort.Sort(ctxs)
|
natsort.Sort(ctxs)
|
||||||
|
|
||||||
cur := kc.GetCurrentContext()
|
cur := kc.GetCurrentContext()
|
||||||
|
@ -44,7 +44,7 @@ func (k *Kubeconfig) contextNode(name string) (*yaml.Node, error) {
|
|||||||
return nil, errors.Errorf("context with name \"%s\" not found", name)
|
return nil, errors.Errorf("context with name \"%s\" not found", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *Kubeconfig) ContextNames() []string {
|
func (k *Kubeconfig) ContextNames(filters map[string]string) []string {
|
||||||
contexts := valueOf(k.rootNode, "contexts")
|
contexts := valueOf(k.rootNode, "contexts")
|
||||||
if contexts == nil {
|
if contexts == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -54,8 +54,19 @@ func (k *Kubeconfig) ContextNames() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ctxNames []string
|
var ctxNames []string
|
||||||
|
ctxLoop:
|
||||||
for _, ctx := range contexts.Content {
|
for _, ctx := range contexts.Content {
|
||||||
nameVal := valueOf(ctx, "name")
|
nameVal := valueOf(ctx, "name")
|
||||||
|
for k, v := range filters {
|
||||||
|
ctxVal := valueOf(ctx, "context")
|
||||||
|
if ctxVal == nil {
|
||||||
|
continue ctxLoop
|
||||||
|
}
|
||||||
|
vVal := valueOf(ctxVal, k)
|
||||||
|
if vVal == nil || vVal.Value != v {
|
||||||
|
continue ctxLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
if nameVal != nil {
|
if nameVal != nil {
|
||||||
ctxNames = append(ctxNames, nameVal.Value)
|
ctxNames = append(ctxNames, nameVal.Value)
|
||||||
}
|
}
|
||||||
@ -64,7 +75,7 @@ func (k *Kubeconfig) ContextNames() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *Kubeconfig) ContextExists(name string) bool {
|
func (k *Kubeconfig) ContextExists(name string) bool {
|
||||||
ctxNames := k.ContextNames()
|
ctxNames := k.ContextNames(nil)
|
||||||
for _, v := range ctxNames {
|
for _, v := range ctxNames {
|
||||||
if v == name {
|
if v == name {
|
||||||
return true
|
return true
|
||||||
|
@ -33,20 +33,39 @@ func TestKubeconfig_ContextNames(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := kc.ContextNames()
|
ctx := kc.ContextNames(nil)
|
||||||
expected := []string{"abc", "def", "ghi"}
|
expected := []string{"abc", "def", "ghi"}
|
||||||
if diff := cmp.Diff(expected, ctx); diff != "" {
|
if diff := cmp.Diff(expected, ctx); diff != "" {
|
||||||
t.Fatalf("%s", diff)
|
t.Fatalf("%s", diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKubeconfig_ContextNames_Filtered(t *testing.T) {
|
||||||
|
tl := WithMockKubeconfigLoader(
|
||||||
|
testutil.KC().WithCtxs(
|
||||||
|
testutil.Ctx("abc").Ns("ns1"),
|
||||||
|
testutil.Ctx("def"),
|
||||||
|
testutil.Ctx("ghi").Ns("ns2"),
|
||||||
|
).Set("field1", map[string]string{"bar": "zoo"}).ToYAML(t))
|
||||||
|
kc := new(Kubeconfig).WithLoader(tl)
|
||||||
|
if err := kc.Parse(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := kc.ContextNames(map[string]string{"namespace": "ns2"})
|
||||||
|
expected := []string{"ghi"}
|
||||||
|
if diff := cmp.Diff(expected, ctx); diff != "" {
|
||||||
|
t.Fatalf("%s", diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestKubeconfig_ContextNames_noContextsEntry(t *testing.T) {
|
func TestKubeconfig_ContextNames_noContextsEntry(t *testing.T) {
|
||||||
tl := WithMockKubeconfigLoader(`a: b`)
|
tl := WithMockKubeconfigLoader(`a: b`)
|
||||||
kc := new(Kubeconfig).WithLoader(tl)
|
kc := new(Kubeconfig).WithLoader(tl)
|
||||||
if err := kc.Parse(); err != nil {
|
if err := kc.Parse(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
ctx := kc.ContextNames()
|
ctx := kc.ContextNames(nil)
|
||||||
var expected []string = nil
|
var expected []string = nil
|
||||||
if diff := cmp.Diff(expected, ctx); diff != "" {
|
if diff := cmp.Diff(expected, ctx); diff != "" {
|
||||||
t.Fatalf("%s", diff)
|
t.Fatalf("%s", diff)
|
||||||
@ -59,7 +78,7 @@ func TestKubeconfig_ContextNames_nonArrayContextsEntry(t *testing.T) {
|
|||||||
if err := kc.Parse(); err != nil {
|
if err := kc.Parse(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
ctx := kc.ContextNames()
|
ctx := kc.ContextNames(nil)
|
||||||
var expected []string = nil
|
var expected []string = nil
|
||||||
if diff := cmp.Diff(expected, ctx); diff != "" {
|
if diff := cmp.Diff(expected, ctx); diff != "" {
|
||||||
t.Fatalf("%s", diff)
|
t.Fatalf("%s", diff)
|
||||||
|
Loading…
Reference in New Issue
Block a user