2020-10-15 10:48:41 -07:00
|
|
|
package main
|
|
|
|
|
2021-02-10 18:23:00 -08:00
|
|
|
import (
|
2021-11-21 07:02:51 -08:00
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"gopkg.in/yaml.v3"
|
2021-02-10 18:23:00 -08:00
|
|
|
)
|
|
|
|
|
2021-11-21 07:02:51 -08:00
|
|
|
// Whether to use kubectl or read kubeconfig ourselves
|
|
|
|
const ParseKubeConfig Property = "parse_kubeconfig"
|
|
|
|
|
2020-10-15 10:48:41 -07:00
|
|
|
type kubectl struct {
|
2022-01-01 11:08:08 -08:00
|
|
|
props Properties
|
2021-11-21 07:02:51 -08:00
|
|
|
env environmentInfo
|
|
|
|
Context string
|
2021-12-17 11:54:43 -08:00
|
|
|
KubeContext
|
2021-11-21 07:02:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
type KubeConfig struct {
|
|
|
|
CurrentContext string `yaml:"current-context"`
|
|
|
|
Contexts []struct {
|
2021-12-17 11:54:43 -08:00
|
|
|
Context *KubeContext `yaml:"context"`
|
|
|
|
Name string `yaml:"name"`
|
2021-11-21 07:02:51 -08:00
|
|
|
} `yaml:"contexts"`
|
2020-10-15 10:48:41 -07:00
|
|
|
}
|
|
|
|
|
2021-12-17 11:54:43 -08:00
|
|
|
type KubeContext struct {
|
|
|
|
Cluster string `yaml:"cluster"`
|
|
|
|
User string `yaml:"user"`
|
|
|
|
Namespace string `yaml:"namespace"`
|
|
|
|
}
|
|
|
|
|
2020-10-15 10:48:41 -07:00
|
|
|
func (k *kubectl) string() string {
|
2021-02-10 18:23:00 -08:00
|
|
|
segmentTemplate := k.props.getString(SegmentTemplate, "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}")
|
|
|
|
template := &textTemplate{
|
|
|
|
Template: segmentTemplate,
|
|
|
|
Context: k,
|
2021-05-26 12:12:58 -07:00
|
|
|
Env: k.env,
|
2021-02-10 18:23:00 -08:00
|
|
|
}
|
2021-04-11 06:24:03 -07:00
|
|
|
text, err := template.render()
|
|
|
|
if err != nil {
|
|
|
|
return err.Error()
|
|
|
|
}
|
|
|
|
return text
|
2020-10-15 10:48:41 -07:00
|
|
|
}
|
|
|
|
|
2022-01-01 11:08:08 -08:00
|
|
|
func (k *kubectl) init(props Properties, env environmentInfo) {
|
2020-10-15 10:48:41 -07:00
|
|
|
k.props = props
|
|
|
|
k.env = env
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k *kubectl) enabled() bool {
|
2021-11-21 07:02:51 -08:00
|
|
|
parseKubeConfig := k.props.getBool(ParseKubeConfig, false)
|
|
|
|
if parseKubeConfig {
|
|
|
|
return k.doParseKubeConfig()
|
|
|
|
}
|
|
|
|
return k.doCallKubectl()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k *kubectl) doParseKubeConfig() bool {
|
|
|
|
// Follow kubectl search rules (see https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable)
|
|
|
|
// TL;DR: KUBECONFIG can contain a list of files. If it's empty ~/.kube/config is used. First file in list wins when merging keys.
|
|
|
|
kubeconfigs := filepath.SplitList(k.env.getenv("KUBECONFIG"))
|
|
|
|
if len(kubeconfigs) == 0 {
|
|
|
|
kubeconfigs = []string{filepath.Join(k.env.homeDir(), ".kube/config")}
|
|
|
|
}
|
2021-12-17 11:54:43 -08:00
|
|
|
contexts := make(map[string]*KubeContext)
|
2021-11-21 07:02:51 -08:00
|
|
|
k.Context = ""
|
|
|
|
for _, kubeconfig := range kubeconfigs {
|
|
|
|
if len(kubeconfig) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
content := k.env.getFileContent(kubeconfig)
|
|
|
|
|
|
|
|
var config KubeConfig
|
|
|
|
err := yaml.Unmarshal([]byte(content), &config)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, context := range config.Contexts {
|
|
|
|
if _, exists := contexts[context.Name]; !exists {
|
|
|
|
contexts[context.Name] = context.Context
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(k.Context) == 0 {
|
|
|
|
k.Context = config.CurrentContext
|
|
|
|
}
|
|
|
|
|
|
|
|
context, exists := contexts[k.Context]
|
2021-12-17 11:54:43 -08:00
|
|
|
if !exists {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if context != nil {
|
|
|
|
k.KubeContext = *context
|
2021-11-21 07:02:51 -08:00
|
|
|
}
|
2021-12-17 11:54:43 -08:00
|
|
|
return true
|
2021-11-21 07:02:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
displayError := k.props.getBool(DisplayError, false)
|
|
|
|
if !displayError {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
k.setError("KUBECONFIG ERR")
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k *kubectl) doCallKubectl() bool {
|
2021-01-05 04:05:37 -08:00
|
|
|
cmd := "kubectl"
|
|
|
|
if !k.env.hasCommand(cmd) {
|
2020-10-15 10:48:41 -07:00
|
|
|
return false
|
|
|
|
}
|
2021-12-17 11:54:43 -08:00
|
|
|
result, err := k.env.runCommand(cmd, "config", "view", "--output", "yaml", "--minify")
|
2021-02-12 12:39:20 -08:00
|
|
|
displayError := k.props.getBool(DisplayError, false)
|
|
|
|
if err != nil && displayError {
|
2021-11-21 07:02:51 -08:00
|
|
|
k.setError("KUBECTL ERR")
|
2021-02-10 18:23:00 -08:00
|
|
|
return true
|
|
|
|
}
|
2021-02-12 12:39:20 -08:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2021-02-10 18:23:00 -08:00
|
|
|
|
2021-12-17 11:54:43 -08:00
|
|
|
var config KubeConfig
|
|
|
|
err = yaml.Unmarshal([]byte(result), &config)
|
|
|
|
if err != nil {
|
2021-12-15 10:06:08 -08:00
|
|
|
return false
|
|
|
|
}
|
2021-12-17 11:54:43 -08:00
|
|
|
k.Context = config.CurrentContext
|
|
|
|
if len(config.Contexts) > 0 {
|
|
|
|
k.KubeContext = *config.Contexts[0].Context
|
|
|
|
}
|
|
|
|
return true
|
2021-11-21 07:02:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (k *kubectl) setError(message string) {
|
|
|
|
if len(k.Context) == 0 {
|
|
|
|
k.Context = message
|
|
|
|
}
|
|
|
|
k.Namespace = message
|
|
|
|
k.User = message
|
|
|
|
k.Cluster = message
|
2020-10-15 10:48:41 -07:00
|
|
|
}
|