mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-21 05:02:31 +00:00
Support for -d (deleting contexts)
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
32d65fc527
commit
5ec2f4f032
85
cmd/kubectx/delete.go
Normal file
85
cmd/kubectx/delete.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// deleteContexts deletes context entries one by one.
|
||||||
|
func deleteContexts(w io.Writer, ctxs []string) error {
|
||||||
|
for _, ctx := range ctxs {
|
||||||
|
// TODO inefficency here. we open/write/close the same file many times.
|
||||||
|
deletedName, wasActiveContext, err := deleteContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error deleting context %q", ctx)
|
||||||
|
}
|
||||||
|
if wasActiveContext {
|
||||||
|
// TODO we don't always run as kubectx (sometimes "kubectl ctx")
|
||||||
|
printWarning("You deleted the current context. use \"kubectx\" to select a different one.")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "deleted context %q\n", deletedName) // TODO write with printSuccess (i.e. green)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteContext deletes a context entry by NAME or current-context
|
||||||
|
// indicated by ".".
|
||||||
|
func deleteContext(name string) (deleteName string, wasActiveContext bool, err error) {
|
||||||
|
f, rootNode, err := openKubeconfig()
|
||||||
|
if err != nil {
|
||||||
|
return "", false, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
cur := getCurrentContext(rootNode)
|
||||||
|
|
||||||
|
// resolve "." to a real name
|
||||||
|
if name == "." {
|
||||||
|
wasActiveContext = true
|
||||||
|
name = cur
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkContextExists(rootNode, name) {
|
||||||
|
return "", false, errors.New("context does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := modifyDocToDeleteContext(rootNode, name); err != nil {
|
||||||
|
return "", false, errors.Wrap(err, "failed to modify yaml doc")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := resetFile(f); err != nil {
|
||||||
|
return "", false, err
|
||||||
|
}
|
||||||
|
return name, wasActiveContext, errors.Wrap(saveKubeconfigRaw(f, rootNode), "failed to save kubeconfig file")
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyDocToDeleteContext(rootNode *yaml.Node, deleteName string) error {
|
||||||
|
if rootNode.Kind != yaml.MappingNode {
|
||||||
|
return errors.New("root node was not a mapping node")
|
||||||
|
}
|
||||||
|
contexts := valueOf(rootNode, "contexts")
|
||||||
|
if contexts == nil {
|
||||||
|
return errors.New("there are no contexts in kubeconfig")
|
||||||
|
}
|
||||||
|
if contexts.Kind != yaml.SequenceNode {
|
||||||
|
return errors.New("'contexts' key is not a sequence")
|
||||||
|
}
|
||||||
|
|
||||||
|
i := -1
|
||||||
|
for j, ctxNode := range contexts.Content {
|
||||||
|
nameNode := valueOf(ctxNode, "name")
|
||||||
|
if nameNode != nil && nameNode.Kind == yaml.ScalarNode && nameNode.Value == deleteName {
|
||||||
|
i = j
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i >= 0 {
|
||||||
|
copy(contexts.Content[i:], contexts.Content[i+1:])
|
||||||
|
contexts.Content[len(contexts.Content)-1] = nil
|
||||||
|
contexts.Content = contexts.Content[:len(contexts.Content)-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -21,6 +21,11 @@ type SwitchOp struct {
|
|||||||
// UnsetOp indicates intention to remove current-context preference.
|
// UnsetOp indicates intention to remove current-context preference.
|
||||||
type UnsetOp struct{}
|
type UnsetOp struct{}
|
||||||
|
|
||||||
|
// DeleteOp indicates intention to delete contexts.
|
||||||
|
type DeleteOp struct {
|
||||||
|
Contexts []string // NAME or '.' to indicate current-context.
|
||||||
|
}
|
||||||
|
|
||||||
// UnknownOp indicates an unsupported flag.
|
// UnknownOp indicates an unsupported flag.
|
||||||
type UnknownOp struct{ Args []string }
|
type UnknownOp struct{ Args []string }
|
||||||
|
|
||||||
@ -31,6 +36,11 @@ func parseArgs(argv []string) Op {
|
|||||||
return ListOp{}
|
return ListOp{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if argv[0] == "-d" {
|
||||||
|
ctxs := argv[1:]
|
||||||
|
return DeleteOp{ctxs}
|
||||||
|
}
|
||||||
|
|
||||||
if len(argv) == 1 {
|
if len(argv) == 1 {
|
||||||
v := argv[0]
|
v := argv[0]
|
||||||
if v == "--help" || v == "-h" {
|
if v == "--help" || v == "-h" {
|
||||||
|
@ -42,6 +42,15 @@ func Test_parseArgs_new(t *testing.T) {
|
|||||||
{name: "switch by swap",
|
{name: "switch by swap",
|
||||||
args: []string{"-"},
|
args: []string{"-"},
|
||||||
want: SwitchOp{Target: "-"}},
|
want: SwitchOp{Target: "-"}},
|
||||||
|
{name: "delete - without contexts",
|
||||||
|
args: []string{"-d"},
|
||||||
|
want: DeleteOp{[]string{}}},
|
||||||
|
{name: "delete - current context",
|
||||||
|
args: []string{"-d", "."},
|
||||||
|
want: DeleteOp{[]string{"."}}},
|
||||||
|
{name: "delete - multiple contexts",
|
||||||
|
args: []string{"-d", ".", "a", "b"},
|
||||||
|
want: DeleteOp{[]string{".", "a", "b"}}},
|
||||||
{name: "unrecognized flag",
|
{name: "unrecognized flag",
|
||||||
args: []string{"-x"},
|
args: []string{"-x"},
|
||||||
want: UnknownOp{Args: []string{"-x"}}},
|
want: UnknownOp{Args: []string{"-x"}}},
|
||||||
|
@ -32,6 +32,11 @@ func main() {
|
|||||||
printError(err.Error())
|
printError(err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
case DeleteOp:
|
||||||
|
if err := deleteContexts(os.Stderr, v.Contexts); err != nil {
|
||||||
|
printError(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
case SwitchOp:
|
case SwitchOp:
|
||||||
var newCtx string
|
var newCtx string
|
||||||
var err error
|
var err error
|
||||||
@ -57,3 +62,7 @@ func main() {
|
|||||||
func printError(format string, args ...interface{}) {
|
func printError(format string, args ...interface{}) {
|
||||||
fmt.Fprintf(os.Stderr, color.RedString("error: ")+format+"\n", args...)
|
fmt.Fprintf(os.Stderr, color.RedString("error: ")+format+"\n", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printWarning(format string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(os.Stderr, color.YellowString("warning: ")+format+"\n", args...)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user