Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Nitive committed Jul 25, 2020
0 parents commit b8af993
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
kubectl-current-context
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.PHONY: *

run:
@ go run main.go

benchmark-go:
@ go build -ldflags '-s -w' -o kubectl-current-context main.go
@ hyperfine --warmup 3 './kubectl-current-context -o json'

benchmark-kubectl:
@ hyperfine --warmup 3 'kubectl config current-context && kubectl config view --minify --output "jsonpath={..namespace}"'
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/Nitive/kubectl-current-context

go 1.14

require gopkg.in/yaml.v2 v2.3.0
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
151 changes: 151 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"sync"

yaml "gopkg.in/yaml.v2"
)

type Context struct {
Context struct {
Namespace string `yaml:"namespace"`
} `yaml:"context"`
Name string `yaml:"name"`
}

// Kubeconfig is struct for parsing Kubeconfig file
type Kubeconfig struct {
CurrentContext string `yaml:"current-context"`
Contexts []Context `yaml:"contexts"`
}

func getCurrentContext(configs []Kubeconfig) string {
for _, config := range configs {
if config.CurrentContext != "" {
return config.CurrentContext
}
}
return ""
}

func getContextNamespace(context string, configs []Kubeconfig) string {
for _, config := range configs {
for _, ctx := range config.Contexts {
if ctx.Name == context {
return ctx.Context.Namespace
}
}
}
return "default"
}

var allowedOutput = []string{"json", "slug", "context", "namespace"}

func validateOutputFlag(output string) string {
for _, variant := range allowedOutput {
if output == variant {
return ""
}
}

return fmt.Sprintf(`Unexpected output value "%s". Allowed values: %s`, output, strings.Join(allowedOutput, ", "))
}

func main() {
kubeconfigRawEnv := os.Getenv("KUBECONFIG")
if kubeconfigRawEnv == "" {
fmt.Fprintln(os.Stderr, "Empty KUBECONFIG env variable")
os.Exit(1)
}

outputFlag := flag.String("o", "slug", `Output values. Either "json", "context", "namespace" or "slug" (context/namespace)`)
flag.Parse()

validationError := validateOutputFlag(*outputFlag)
if validationError != "" {
fmt.Println(validationError)
os.Exit(1)
}

output := *outputFlag

debugMode := os.Getenv("DEBUG") != ""
kubeconfigFilePaths := strings.Split(kubeconfigRawEnv, ":")
for i, path := range kubeconfigFilePaths {
kubeconfigFilePaths[i] = strings.TrimSpace(path)
}

parsedKubeconfigs := []Kubeconfig{}

var wg sync.WaitGroup
wg.Add(len(kubeconfigFilePaths))

for _, file := range kubeconfigFilePaths {
// Parse all files, skip files with syntax errors
go func(fileName string) {
defer wg.Done()

fileContext, err := ioutil.ReadFile(fileName)
if err != nil {
if debugMode {
log.Fatal(err)
}
return
}

var config Kubeconfig
err = yaml.Unmarshal(fileContext, &config)
if err != nil {
if debugMode {
log.Fatal(err)
}
return
}

parsedKubeconfigs = append(parsedKubeconfigs, config)
}(file)
}

wg.Wait()

currentContext := getCurrentContext(parsedKubeconfigs)

if output == "context" {
fmt.Print(currentContext)
}

currentNamespace := getContextNamespace(currentContext, parsedKubeconfigs)

if output == "namespace" {
fmt.Print(currentNamespace)
}

if output == "slug" {
fmt.Printf("%s/%s", currentContext, currentNamespace)
}

if output == "json" {
jsonOutput := struct {
Context string `json:"context"`
Namespace string `json:"namespace"`
}{
Context: currentContext,
Namespace: currentNamespace,
}

bytes, err := json.Marshal(&jsonOutput)
if err != nil {
fmt.Printf("Error while formatting json\n%s", err)
os.Exit(1)
}

fmt.Print(string(bytes))
}
}

0 comments on commit b8af993

Please sign in to comment.