mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-24 22:42:58 +00:00
Implement facilities to parse kubeconfig file
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
7c2f8ffa75
commit
da08491f0b
@ -1,9 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func kubeconfigPath() (string, error) {
|
func kubeconfigPath() (string, error) {
|
||||||
@ -27,3 +29,15 @@ func kubeconfigPath() (string, error) {
|
|||||||
}
|
}
|
||||||
return filepath.Join(home, ".kube", "config"), nil
|
return filepath.Join(home, ".kube", "config"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseKubeconfig(path string) (kubeconfig, error) {
|
||||||
|
// TODO refactor to accept io.Reader instead of file
|
||||||
|
var v kubeconfig
|
||||||
|
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return v, errors.Wrap(err, "file open error")
|
||||||
|
}
|
||||||
|
err = yaml.NewDecoder(f).Decode(&v)
|
||||||
|
return v, errors.Wrap(err, "yaml parse error")
|
||||||
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_kubeconfigPath_homePath(t *testing.T) {
|
func Test_kubeconfigPath_homePath(t *testing.T) {
|
||||||
@ -72,5 +75,79 @@ func Test_kubeconfigPath_envOvverideDoesNotSupportPathSeparator(t *testing.T) {
|
|||||||
|
|
||||||
_, err := kubeconfigPath()
|
_, err := kubeconfigPath()
|
||||||
if err == nil { t.Fatal("expected error")}
|
if err == nil { t.Fatal("expected error")}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func Test_parseKubeconfig_openError(t *testing.T) {
|
||||||
|
_, err := parseKubeconfig("/non/existing/path")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
msg := err.Error()
|
||||||
|
expected := `file open error`
|
||||||
|
if !strings.Contains(msg, expected) {
|
||||||
|
t.Fatalf("expected=%q, got=%q", expected, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_parseKubeconfig_yamlFormatError(t *testing.T) {
|
||||||
|
file, cleanup := testfile(t, `a: [1,2 `) // supposed to be invalid yaml
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
_, err := parseKubeconfig(file)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error")
|
||||||
|
}
|
||||||
|
expected := "yaml parse error"
|
||||||
|
if got := err.Error(); !strings.Contains(got, expected) {
|
||||||
|
t.Fatalf("expected=%q; got=%q", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_parseKubeconfig(t *testing.T) {
|
||||||
|
file, cleanup := testfile(t,
|
||||||
|
`
|
||||||
|
apiVersion: v1
|
||||||
|
current-context: foo
|
||||||
|
contexts:
|
||||||
|
- name: c3
|
||||||
|
- name: c2
|
||||||
|
- name: c1`)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
got, err := parseKubeconfig(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := kubeconfig{
|
||||||
|
APIVersion: "v1",
|
||||||
|
CurrentContext: "foo",
|
||||||
|
Contexts: []context{
|
||||||
|
{Name:"c3"},{Name:"c2"},{Name:"c1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := cmp.Diff(expected, got)
|
||||||
|
if diff != "" {
|
||||||
|
t.Fatalf("got wrong object:\n%s", diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testfile(t *testing.T, contents string) (path string, cleanup func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
f, err := ioutil.TempFile(os.TempDir(), "test-file")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create test file: %v", err)
|
||||||
|
}
|
||||||
|
path = f.Name()
|
||||||
|
if _, err := f.Write([]byte(contents)); err != nil {
|
||||||
|
t.Fatalf("failed to write to test file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, func() {
|
||||||
|
f.Close()
|
||||||
|
os.Remove(path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,36 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type context struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type kubeconfig struct {
|
||||||
|
APIVersion string `yaml:"apiVersion"`
|
||||||
|
CurrentContext string `yaml:"current-context"`
|
||||||
|
Contexts []context `yaml:"contexts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func printListContexts(out io.Writer) error {
|
||||||
|
cfgPath, err := kubeconfigPath()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to determine kubeconfig path")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := parseKubeconfig(cfgPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to read kubeconfig file")
|
||||||
|
}
|
||||||
|
_ = cfg
|
||||||
|
|
||||||
|
// print each context
|
||||||
|
// - natural sort
|
||||||
|
// - highlight current context
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -13,12 +13,12 @@ func main() {
|
|||||||
var op Op
|
var op Op
|
||||||
op = parseArgs(os.Args[1:])
|
op = parseArgs(os.Args[1:])
|
||||||
|
|
||||||
|
// TODO consider addin Run() operation to each operation type
|
||||||
switch v := op.(type) {
|
switch v := op.(type) {
|
||||||
case HelpOp:
|
case HelpOp:
|
||||||
printHelp(os.Stdout)
|
printHelp(os.Stdout)
|
||||||
case ListOp:
|
case ListOp:
|
||||||
// TODO implement
|
printListContexts(os.Stdout)
|
||||||
panic("not implemented")
|
|
||||||
case SwitchOp:
|
case SwitchOp:
|
||||||
// TODO implement
|
// TODO implement
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
|
2
go.mod
2
go.mod
@ -5,4 +5,6 @@ go 1.14
|
|||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/google/go-cmp v0.4.0
|
github.com/google/go-cmp v0.4.0
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||||
)
|
)
|
||||||
|
5
go.sum
5
go.sum
@ -7,7 +7,12 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
|||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
Loading…
Reference in New Issue
Block a user