mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-25 15:02:21 +00:00
Implement switch via editing yaml in-place
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
04e963c02c
commit
a9476f3215
@ -20,15 +20,25 @@ func main() {
|
|||||||
case ListOp:
|
case ListOp:
|
||||||
printListContexts(os.Stdout)
|
printListContexts(os.Stdout)
|
||||||
case SwitchOp:
|
case SwitchOp:
|
||||||
// TODO implement
|
if v.Target == "-" {
|
||||||
|
// TODO implement swap
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
newCtx, err := switchContext(v.Target)
|
||||||
|
if err != nil {
|
||||||
|
printError("faield to switch context: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "Switched to context %q.\n", newCtx)
|
||||||
case UnknownOp:
|
case UnknownOp:
|
||||||
fmt.Printf("%s unsupported operation: %s\n",
|
printError("unsupported operation: %s", strings.Join(v.Args, " "))
|
||||||
color.RedString("error:"),
|
|
||||||
strings.Join(v.Args, " "))
|
|
||||||
printHelp(os.Stdout)
|
printHelp(os.Stdout)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("internal error: operation type %T not handled", op)
|
fmt.Printf("internal error: operation type %T not handled", op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printError(format string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(os.Stderr, color.RedString("error: "+format+"\n"), args...)
|
||||||
|
}
|
||||||
|
103
cmd/kubectx/switch.go
Normal file
103
cmd/kubectx/switch.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// switchContext switches to specified context name.
|
||||||
|
func switchContext(name string) (string, error) {
|
||||||
|
cfgPath, err := kubeconfigPath()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "cannot determine kubeconfig path")
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(cfgPath, os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to open file")
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
kc, err := parseKubeconfigRaw(f)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "yaml parse error")
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := getCurrentContext(kc)
|
||||||
|
fmt.Printf("current-context=%s\n", cur)
|
||||||
|
|
||||||
|
if err := modifyCurrentContext(kc, name); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Truncate(0); err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to truncate")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := f.Seek(0, 0); err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to seek")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := saveKubeconfigRaw(f, kc); err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to save kubeconfig")
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// getCurrentContext returns "current-context" value in given
|
||||||
|
// kubeconfig object Node, or returns "" if not found.
|
||||||
|
func getCurrentContext(rootNode *yaml.Node) string {
|
||||||
|
if rootNode.Kind != yaml.MappingNode {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for i, ch := range rootNode.Content {
|
||||||
|
if i%2 == 0 && ch.Value == "current-context" {
|
||||||
|
return rootNode.Content[i+1].Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyCurrentContext(rootNode *yaml.Node, name string) error {
|
||||||
|
if rootNode.Kind != yaml.MappingNode {
|
||||||
|
return errors.New("document is not a map")
|
||||||
|
}
|
||||||
|
|
||||||
|
// find current-context field => modify value (next children)
|
||||||
|
for i, ch := range rootNode.Content {
|
||||||
|
if i%2 == 0 && ch.Value == "current-context" {
|
||||||
|
rootNode.Content[i+1].Value = name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if current-context ==> create new field
|
||||||
|
keyNode := &yaml.Node{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: "current-context",
|
||||||
|
Tag: "!!str"}
|
||||||
|
valueNode := &yaml.Node{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: name,
|
||||||
|
Tag: "!!str"}
|
||||||
|
rootNode.Content = append(rootNode.Content, keyNode, valueNode)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseKubeconfigRaw(r io.Reader) (*yaml.Node, error) {
|
||||||
|
var v yaml.Node
|
||||||
|
if err := yaml.NewDecoder(r).Decode(&v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v.Content[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveKubeconfigRaw(w io.Writer, rootNode *yaml.Node) error {
|
||||||
|
enc := yaml.NewEncoder(w)
|
||||||
|
enc.SetIndent(2)
|
||||||
|
return enc.Encode(rootNode)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user