mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-25 15:02:21 +00:00
Add support for -u/--unset
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
94e8d3b4c7
commit
c5f17b83e7
@ -18,6 +18,9 @@ type SwitchOp struct {
|
|||||||
Target string // '-' for back and forth, or NAME
|
Target string // '-' for back and forth, or NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnsetOp indicates intention to remove current-context preference.
|
||||||
|
type UnsetOp struct{}
|
||||||
|
|
||||||
// UnknownOp indicates an unsupported flag.
|
// UnknownOp indicates an unsupported flag.
|
||||||
type UnknownOp struct{ Args []string }
|
type UnknownOp struct{ Args []string }
|
||||||
|
|
||||||
@ -36,6 +39,9 @@ func parseArgs(argv []string) Op {
|
|||||||
if v == "--current" || v == "-c" {
|
if v == "--current" || v == "-c" {
|
||||||
return CurrentOp{}
|
return CurrentOp{}
|
||||||
}
|
}
|
||||||
|
if v == "--unset" || v == "-u" {
|
||||||
|
return UnsetOp{}
|
||||||
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(v, "-") && v != "-" {
|
if strings.HasPrefix(v, "-") && v != "-" {
|
||||||
return UnknownOp{argv}
|
return UnknownOp{argv}
|
||||||
|
@ -30,6 +30,12 @@ func Test_parseArgs_new(t *testing.T) {
|
|||||||
{name: "current long form",
|
{name: "current long form",
|
||||||
args: []string{"--current"},
|
args: []string{"--current"},
|
||||||
want: CurrentOp{}},
|
want: CurrentOp{}},
|
||||||
|
{name: "unset shorthand",
|
||||||
|
args: []string{"-u"},
|
||||||
|
want: UnsetOp{}},
|
||||||
|
{name: "unset long form",
|
||||||
|
args: []string{"--unset"},
|
||||||
|
want: UnsetOp{}},
|
||||||
{name: "switch by name",
|
{name: "switch by name",
|
||||||
args: []string{"foo"},
|
args: []string{"foo"},
|
||||||
want: SwitchOp{Target: "foo"}},
|
want: SwitchOp{Target: "foo"}},
|
||||||
|
52
cmd/kubectx/kubeconfig_raw.go
Normal file
52
cmd/kubectx/kubeconfig_raw.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func openKubeconfig() (f *os.File, rootNode *yaml.Node, err error) {
|
||||||
|
cfgPath, err := kubeconfigPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "cannot determine kubeconfig path")
|
||||||
|
}
|
||||||
|
f, err = os.OpenFile(cfgPath, os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "failed to open file")
|
||||||
|
}
|
||||||
|
|
||||||
|
kc, err := parseKubeconfigRaw(f)
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
return nil, nil, errors.Wrap(err, "yaml parse error")
|
||||||
|
}
|
||||||
|
return f, kc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// resetFile deletes contents of a file and sets the seek
|
||||||
|
// position to 0.
|
||||||
|
func resetFile(f *os.File) error {
|
||||||
|
if err := f.Truncate(0); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to truncate")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := f.Seek(0, 0)
|
||||||
|
return errors.Wrap(err, "failed to seek")
|
||||||
|
}
|
@ -22,6 +22,11 @@ func main() {
|
|||||||
printError(err.Error())
|
printError(err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
case UnsetOp:
|
||||||
|
if err := unsetContext(); err != nil {
|
||||||
|
printError(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
case ListOp:
|
case ListOp:
|
||||||
if err := printListContexts(os.Stdout); err != nil {
|
if err := printListContexts(os.Stdout); err != nil {
|
||||||
printError(err.Error())
|
printError(err.Error())
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@ -15,21 +12,12 @@ func switchContext(name string) (string, error) {
|
|||||||
return "", errors.Wrap(err, "failed to determine state file")
|
return "", errors.Wrap(err, "failed to determine state file")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgPath, err := kubeconfigPath()
|
f, kc, err := openKubeconfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "cannot determine kubeconfig path")
|
return "", err
|
||||||
}
|
|
||||||
f, err := os.OpenFile(cfgPath, os.O_RDWR, 0)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "failed to open file")
|
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
kc, err := parseKubeconfigRaw(f)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "yaml parse error")
|
|
||||||
}
|
|
||||||
|
|
||||||
prev := getCurrentContext(kc)
|
prev := getCurrentContext(kc)
|
||||||
|
|
||||||
// TODO: add a check to ensure user can't switch to non-existing context.
|
// TODO: add a check to ensure user can't switch to non-existing context.
|
||||||
@ -41,12 +29,8 @@ func switchContext(name string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.Truncate(0); err != nil {
|
if err := resetFile(f); err != nil {
|
||||||
return "", errors.Wrap(err, "failed to truncate")
|
return "", err
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := f.Seek(0, 0); err != nil {
|
|
||||||
return "", errors.Wrap(err, "failed to seek")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := saveKubeconfigRaw(f, kc); err != nil {
|
if err := saveKubeconfigRaw(f, kc); err != nil {
|
||||||
@ -153,17 +137,3 @@ func modifyCurrentContext(rootNode *yaml.Node, name string) error {
|
|||||||
rootNode.Content = append(rootNode.Content, keyNode, valueNode)
|
rootNode.Content = append(rootNode.Content, keyNode, valueNode)
|
||||||
return nil
|
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)
|
|
||||||
}
|
|
||||||
|
34
cmd/kubectx/unset.go
Normal file
34
cmd/kubectx/unset.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func unsetContext() error {
|
||||||
|
f, rootNode, err := openKubeconfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if err := modifyDocToUnsetContext(rootNode); err != nil {
|
||||||
|
return errors.Wrap(err, "error while modifying current-context")
|
||||||
|
}
|
||||||
|
if err := resetFile(f); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := saveKubeconfigRaw(f, rootNode); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to save kubeconfig file after modification")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyDocToUnsetContext(rootNode *yaml.Node) error {
|
||||||
|
if rootNode.Kind != yaml.MappingNode {
|
||||||
|
return errors.New("kubeconfig file is not a map document")
|
||||||
|
}
|
||||||
|
curCtxValNode := valueOf(rootNode, "current-context")
|
||||||
|
curCtxValNode.Value = ""
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user