From 94664bcaf91a7c21ff2166953e8f6907d6942f66 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Sun, 12 Apr 2020 12:59:20 -0700 Subject: [PATCH] kubeconfig pkg for loading/parsing Signed-off-by: Ahmet Alp Balkan --- cmd/kubectx/kubeconfig.go | 31 ++++++++++++++-- cmd/kubectx/kubeconfig/kubeconfig.go | 55 ++++++++++++++++++++++++++++ cmd/kubectx/kubeconfig_raw.go | 1 + cmd/kubectx/list.go | 2 +- 4 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 cmd/kubectx/kubeconfig/kubeconfig.go diff --git a/cmd/kubectx/kubeconfig.go b/cmd/kubectx/kubeconfig.go index ac58bd2..5df8aad 100644 --- a/cmd/kubectx/kubeconfig.go +++ b/cmd/kubectx/kubeconfig.go @@ -6,8 +6,34 @@ import ( "github.com/pkg/errors" "gopkg.in/yaml.v3" + + "github.com/ahmetb/kubectx/cmd/kubectx/kubeconfig" ) +type defaultKubeconfigLoader struct{} + +type kubeconfigFile struct { *os.File } + +func (kf *kubeconfigFile) Reset() error { + if err := kf.Truncate(0);err!= nil { + return errors.Wrap(err, "failed to truncate file") + } + _, err := kf.Seek(0,0) + return errors.Wrap(err, "failed to seek in file") +} + +func (defaultKubeconfigLoader) Load() (kubeconfig.ReadWriteResetCloser, error) { + cfgPath, err := kubeconfigPath() + if err != nil { + return nil, errors.Wrap(err, "cannot determine kubeconfig path") + } + f, err := os.OpenFile(cfgPath, os.O_RDWR, 0) + if err != nil { + return nil, errors.Wrap(err, "failed to open file") + } + return &kubeconfigFile{f}, nil +} + func kubeconfigPath() (string, error) { // KUBECONFIG env var if v := os.Getenv("KUBECONFIG"); v != "" { @@ -40,11 +66,10 @@ func homeDir() string { return home } - // TODO parseKubeconfig doesn't seem necessary when there's a raw version that returns what's needed -func parseKubeconfig(path string) (kubeconfig, error) { +func parseKubeconfig(path string) (kubeconfigContents, error) { // TODO refactor to accept io.Reader instead of file - var v kubeconfig + var v kubeconfigContents f, err := os.Open(path) if err != nil { diff --git a/cmd/kubectx/kubeconfig/kubeconfig.go b/cmd/kubectx/kubeconfig/kubeconfig.go new file mode 100644 index 0000000..89d4d79 --- /dev/null +++ b/cmd/kubectx/kubeconfig/kubeconfig.go @@ -0,0 +1,55 @@ +package kubeconfig + +import ( + "io" + + "github.com/pkg/errors" + "gopkg.in/yaml.v3" +) + +type ReadWriteResetCloser interface{ + io.ReadWriteCloser + + // Reset truncates the file and seeks to the beginning of the file. + Reset() error +} + +type Loader interface { + Load() (ReadWriteResetCloser, error) +} + +type Kubeconfig struct { + loader Loader + + f ReadWriteResetCloser + rootNode *yaml.Node +} + +func (k *Kubeconfig) WithLoader(l Loader) { + k.loader = l +} + +func (k *Kubeconfig) ParseRaw() (*yaml.Node, error) { + f, err := k.loader.Load() + if err != nil { + return nil, errors.Wrap(err, "failed to load kubeconfig") + } + + k.f = f + + var v yaml.Node + if err := yaml.NewDecoder(f).Decode(&v); err != nil { + return nil, errors.Wrap(err, "failed to decode kubeconfig") + } + k.rootNode = v.Content[0] + return k. rootNode, nil +} + +func (k *Kubeconfig) Save() error { + if err := k.f.Reset(); err != nil { + return errors.Wrap(err, "failed to reset file") + } + enc := yaml.NewEncoder(k.f) + enc.SetIndent(2) + return enc.Encode(k.rootNode) +} diff --git a/cmd/kubectx/kubeconfig_raw.go b/cmd/kubectx/kubeconfig_raw.go index ffbc1fa..d38a959 100644 --- a/cmd/kubectx/kubeconfig_raw.go +++ b/cmd/kubectx/kubeconfig_raw.go @@ -9,6 +9,7 @@ import ( ) func parseKubeconfigRaw(r io.Reader) (*yaml.Node, error) { + // TODO DELETE var v yaml.Node if err := yaml.NewDecoder(r).Decode(&v); err != nil { return nil, err diff --git a/cmd/kubectx/list.go b/cmd/kubectx/list.go index 8777831..9be0425 100644 --- a/cmd/kubectx/list.go +++ b/cmd/kubectx/list.go @@ -13,7 +13,7 @@ type context struct { Name string `yaml:"name"` } -type kubeconfig struct { +type kubeconfigContents struct { APIVersion string `yaml:"apiVersion"` CurrentContext string `yaml:"current-context"` Contexts []context `yaml:"contexts"`