mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-19 12:12:33 +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.
|
||||
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.
|
||||
type UnknownOp struct{ Args []string }
|
||||
|
||||
@ -31,6 +36,11 @@ func parseArgs(argv []string) Op {
|
||||
return ListOp{}
|
||||
}
|
||||
|
||||
if argv[0] == "-d" {
|
||||
ctxs := argv[1:]
|
||||
return DeleteOp{ctxs}
|
||||
}
|
||||
|
||||
if len(argv) == 1 {
|
||||
v := argv[0]
|
||||
if v == "--help" || v == "-h" {
|
||||
|
@ -42,6 +42,15 @@ func Test_parseArgs_new(t *testing.T) {
|
||||
{name: "switch by swap",
|
||||
args: []string{"-"},
|
||||
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",
|
||||
args: []string{"-x"},
|
||||
want: UnknownOp{Args: []string{"-x"}}},
|
||||
|
@ -32,6 +32,11 @@ func main() {
|
||||
printError(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
case DeleteOp:
|
||||
if err := deleteContexts(os.Stderr, v.Contexts); err != nil {
|
||||
printError(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
case SwitchOp:
|
||||
var newCtx string
|
||||
var err error
|
||||
@ -57,3 +62,7 @@ func main() {
|
||||
func printError(format string, args ...interface{}) {
|
||||
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