fix(kubectl): parse yaml instead of csv

closes #1439
This commit is contained in:
Jan De Dobbeleer 2021-12-17 20:54:43 +01:00 committed by Jan De Dobbeleer
parent e887f4ecea
commit 9edd53e679
3 changed files with 53 additions and 52 deletions

View file

@ -2,7 +2,6 @@ package main
import (
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
)
@ -14,23 +13,23 @@ type kubectl struct {
props properties
env environmentInfo
Context string
KubeConfigContext
}
type KubeConfigContext struct {
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
Namespace string `yaml:"namespace"`
KubeContext
}
type KubeConfig struct {
CurrentContext string `yaml:"current-context"`
Contexts []struct {
Context KubeConfigContext `yaml:"context"`
Name string `yaml:"name"`
Context *KubeContext `yaml:"context"`
Name string `yaml:"name"`
} `yaml:"contexts"`
}
type KubeContext struct {
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
Namespace string `yaml:"namespace"`
}
func (k *kubectl) string() string {
segmentTemplate := k.props.getString(SegmentTemplate, "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}")
template := &textTemplate{
@ -65,7 +64,7 @@ func (k *kubectl) doParseKubeConfig() bool {
if len(kubeconfigs) == 0 {
kubeconfigs = []string{filepath.Join(k.env.homeDir(), ".kube/config")}
}
contexts := make(map[string]KubeConfigContext)
contexts := make(map[string]*KubeContext)
k.Context = ""
for _, kubeconfig := range kubeconfigs {
if len(kubeconfig) == 0 {
@ -91,10 +90,13 @@ func (k *kubectl) doParseKubeConfig() bool {
}
context, exists := contexts[k.Context]
if exists {
k.KubeConfigContext = context
return true
if !exists {
continue
}
if context != nil {
k.KubeContext = *context
}
return true
}
displayError := k.props.getBool(DisplayError, false)
@ -110,7 +112,7 @@ func (k *kubectl) doCallKubectl() bool {
if !k.env.hasCommand(cmd) {
return false
}
result, err := k.env.runCommand(cmd, "config", "view", "--minify", "--output", "jsonpath={..current-context},{..namespace},{..context.user},{..context.cluster}")
result, err := k.env.runCommand(cmd, "config", "view", "--output", "yaml", "--minify")
displayError := k.props.getBool(DisplayError, false)
if err != nil && displayError {
k.setError("KUBECTL ERR")
@ -120,15 +122,16 @@ func (k *kubectl) doCallKubectl() bool {
return false
}
values := strings.Split(result, ",")
if len(values) < 4 {
var config KubeConfig
err = yaml.Unmarshal([]byte(result), &config)
if err != nil {
return false
}
k.Context = values[0]
k.Namespace = values[1]
k.User = values[2]
k.Cluster = values[3]
return len(k.Context) > 0
k.Context = config.CurrentContext
if len(config.Contexts) > 0 {
k.KubeContext = *config.Contexts[0].Context
}
return true
}
func (k *kubectl) setError(message string) {

View file

@ -1,6 +1,8 @@
package main
import (
"fmt"
"io/ioutil"
"path/filepath"
"testing"
@ -29,16 +31,16 @@ func TestKubectlSegment(t *testing.T) {
ExpectedString string
Files map[string]string
}{
{Case: "disabled", Template: standardTemplate, KubectlExists: false, Context: "aaa", Namespace: "bbb", ExpectedString: "", ExpectedEnabled: false},
{
Case: "not enough arguments",
Template: standardTemplate,
KubectlExists: true,
Context: "aaa",
Namespace: "bbb",
ExpectedString: "",
ExpectedEnabled: false,
Case: "kubeconfig incomplete",
Template: testKubectlAllInfoTemplate,
ParseKubeConfig: true,
Kubeconfig: "currentcontextmarker" + lsep + "contextdefinitionincomplete",
Files: testKubeConfigFiles,
ExpectedString: "ctx :: :: :: ",
ExpectedEnabled: true,
},
{Case: "disabled", Template: standardTemplate, KubectlExists: false, Context: "aaa", Namespace: "bbb", ExpectedEnabled: false},
{
Case: "all information",
Template: testKubectlAllInfoTemplate,
@ -50,7 +52,7 @@ func TestKubectlSegment(t *testing.T) {
ExpectedString: "aaa :: bbb :: ccc :: ddd",
ExpectedEnabled: true,
},
{Case: "no namespace", Template: standardTemplate, KubectlExists: true, Context: "aaa", Namespace: "", ExpectedString: "", ExpectedEnabled: false},
{Case: "no namespace", Template: standardTemplate, KubectlExists: true, Context: "aaa", ExpectedString: "aaa", ExpectedEnabled: true},
{
Case: "kubectl error",
Template: standardTemplate,
@ -100,30 +102,16 @@ func TestKubectlSegment(t *testing.T) {
ExpectedString: "KUBECONFIG ERR :: KUBECONFIG ERR :: KUBECONFIG ERR :: KUBECONFIG ERR",
ExpectedEnabled: true,
},
{
Case: "kubeconfig incomplete",
Template: testKubectlAllInfoTemplate,
ParseKubeConfig: true,
Kubeconfig: "currentcontextmarker" + lsep + "contextdefinitionincomplete",
Files: testKubeConfigFiles,
ExpectedString: "ctx :: :: :: ",
ExpectedEnabled: true,
},
}
for _, tc := range cases {
env := new(MockedEnvironment)
env.On("hasCommand", "kubectl").Return(tc.KubectlExists)
addCommaAndvalue := func(s string) string {
if s == "" {
return ""
}
return "," + s
var kubeconfig string
content, err := ioutil.ReadFile("./test/kubectl.yml")
if err == nil {
kubeconfig = fmt.Sprintf(string(content), tc.Cluster, tc.User, tc.Namespace, tc.Context)
}
kubectlOut := tc.Context
kubectlOut += addCommaAndvalue(tc.Namespace)
kubectlOut += addCommaAndvalue(tc.User)
kubectlOut += addCommaAndvalue(tc.Cluster)
var kubectlErr error
if tc.KubectlErr {
kubectlErr = &commandError{
@ -131,9 +119,7 @@ func TestKubectlSegment(t *testing.T) {
exitCode: 1,
}
}
env.On("runCommand", "kubectl",
[]string{"config", "view", "--minify", "--output", "jsonpath={..current-context},{..namespace},{..context.user},{..context.cluster}"}).Return(kubectlOut, kubectlErr)
env.On("runCommand", "kubectl", []string{"config", "view", "--output", "yaml", "--minify"}).Return(kubeconfig, kubectlErr)
env.On("getenv", "KUBECONFIG").Return(tc.Kubeconfig)
for path, content := range tc.Files {
env.On("getFileContent", path).Return(content)

12
src/test/kubectl.yml Normal file
View file

@ -0,0 +1,12 @@
apiVersion: v1
clusters: null
contexts:
- context:
cluster: '%s'
user: '%s'
namespace: '%s'
name: jan
current-context: '%s'
kind: Config
preferences: {}
users: null