Skip to content

Commit

Permalink
feat: kubectl namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
tradiff authored and JanDeDobbeleer committed Feb 11, 2021
1 parent bf44a44 commit 731ebf6
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 37 deletions.
24 changes: 22 additions & 2 deletions docs/docs/segment-kubectl.md
Expand Up @@ -6,7 +6,7 @@ sidebar_label: Kubectl

## What

Display the currently active Kubernetes context name.
Display the currently active Kubernetes context name and namespace name.

## Sample Configuration

Expand All @@ -18,7 +18,27 @@ Display the currently active Kubernetes context name.
"foreground": "#000000",
"background": "#ebcc34",
"properties": {
"prefix": " \uFD31 "
"prefix": " \uFD31 ",
"template": "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}"
}
}
```

## Properties

- template: `string` - A go [text/template][go-text-template] template utilizing the properties below.
Defaults to `{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}`

## Template Properties

- `.Context`: `string` - the current kubectl context
- `.Namespace`: `string` - the current kubectl namespace

## Tips

It is common for the Kubernetes "default" namespace to be used when no namespace is provided. If you want your prompt to
render an empty current namespace using the word "default", you can use something like this for the template:

`{{.Context}} :: {{if .Namespace}}{{.Namespace}}{{else}}default{{end}}`

[go-text-template]: https://golang.org/pkg/text/template/
31 changes: 25 additions & 6 deletions src/segment_kubectl.go
@@ -1,13 +1,23 @@
package main

import (
"strings"
)

type kubectl struct {
props *properties
env environmentInfo
contextName string
props *properties
env environmentInfo
Context string
Namespace string
}

func (k *kubectl) string() string {
return k.contextName
segmentTemplate := k.props.getString(SegmentTemplate, "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}")
template := &textTemplate{
Template: segmentTemplate,
Context: k,
}
return template.render()
}

func (k *kubectl) init(props *properties, env environmentInfo) {
Expand All @@ -20,6 +30,15 @@ func (k *kubectl) enabled() bool {
if !k.env.hasCommand(cmd) {
return false
}
k.contextName, _ = k.env.runCommand(cmd, "config", "current-context")
return k.contextName != ""
result, err := k.env.runCommand(cmd, "config", "view", "--minify", "--output", "jsonpath={..current-context},{..namespace}")
if err != nil {
k.Context = "KUBECTL ERR"
k.Namespace = k.Context
return true
}

values := strings.Split(result, ",")
k.Context = values[0]
k.Namespace = values[1]
return k.Context != ""
}
78 changes: 49 additions & 29 deletions src/segment_kubectl_test.go
Expand Up @@ -7,45 +7,65 @@ import (
)

type kubectlArgs struct {
enabled bool
contextName string
kubectlExists bool
kubectlErr bool
template string
context string
namespace string
}

func bootStrapKubectlTest(args *kubectlArgs) *kubectl {
env := new(MockedEnvironment)
env.On("hasCommand", "kubectl").Return(args.enabled)
env.On("runCommand", "kubectl", []string{"config", "current-context"}).Return(args.contextName, nil)
env.On("hasCommand", "kubectl").Return(args.kubectlExists)
kubectlOut := args.context + "," + args.namespace
var kubectlErr error = nil
if args.kubectlErr {
kubectlErr = &commandError{
err: "oops",
exitCode: 1,
}
}
env.On("runCommand", "kubectl", []string{"config", "view", "--minify", "--output", "jsonpath={..current-context},{..namespace}"}).Return(kubectlOut, kubectlErr)
k := &kubectl{
env: env,
props: &properties{},
env: env,
props: &properties{
values: map[Property]interface{}{
SegmentTemplate: args.template,
},
},
}
return k
}

func TestKubectlWriterDisabled(t *testing.T) {
args := &kubectlArgs{
enabled: false,
func TestKubectlSegment(t *testing.T) {
standardTemplate := "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}"
cases := []struct {
Case string
Template string
KubectlExists bool
Context string
Namespace string
KubectlErr bool
ExpectedEnabled bool
ExpectedString string
}{
{Case: "disabled", Template: standardTemplate, KubectlExists: false, Context: "aaa", Namespace: "bbb", ExpectedString: "", ExpectedEnabled: false},
{Case: "normal", Template: standardTemplate, KubectlExists: true, Context: "aaa", Namespace: "bbb", ExpectedString: "aaa :: bbb", ExpectedEnabled: true},
{Case: "no namespace", Template: standardTemplate, KubectlExists: true, Context: "aaa", Namespace: "", ExpectedString: "aaa", ExpectedEnabled: true},
{Case: "kubectl error", Template: standardTemplate, KubectlExists: true, Context: "aaa", Namespace: "bbb", KubectlErr: true,
ExpectedString: "KUBECTL ERR :: KUBECTL ERR", ExpectedEnabled: true},
}
kubectl := bootStrapKubectlTest(args)
assert.False(t, kubectl.enabled())
}

func TestKubectlEnabled(t *testing.T) {
expected := "context-name"
args := &kubectlArgs{
enabled: true,
contextName: expected,
}
kubectl := bootStrapKubectlTest(args)
assert.True(t, kubectl.enabled())
assert.Equal(t, expected, kubectl.string())
}

func TestKubectlNoContext(t *testing.T) {
args := &kubectlArgs{
enabled: true,
contextName: "",
for _, tc := range cases {
args := &kubectlArgs{
kubectlExists: tc.KubectlExists,
template: tc.Template,
context: tc.Context,
namespace: tc.Namespace,
kubectlErr: tc.KubectlErr,
}
kubectl := bootStrapKubectlTest(args)
assert.Equal(t, tc.ExpectedEnabled, kubectl.enabled(), tc.Case)
assert.Equal(t, tc.ExpectedString, kubectl.string(), tc.Case)
}
kubectl := bootStrapKubectlTest(args)
assert.False(t, kubectl.enabled())
}

0 comments on commit 731ebf6

Please sign in to comment.