Skip to content

Commit

Permalink
feat(kubernetes): apply note
Browse files Browse the repository at this point in the history
  • Loading branch information
sh0rez committed Jul 30, 2019
1 parent 8fcb4c1 commit 4c6414f
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 13 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.12
require (
github.com/Masterminds/semver v1.4.2
github.com/alecthomas/chroma v0.6.6
github.com/fatih/color v1.7.0
github.com/google/go-jsonnet v0.13.0
github.com/mitchellh/mapstructure v1.1.2
github.com/spf13/cobra v0.0.5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down Expand Up @@ -90,6 +91,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
Expand Down
50 changes: 37 additions & 13 deletions pkg/provider/kubernetes/kubectl.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package kubernetes

import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"

"github.com/Masterminds/semver"
"github.com/fatih/color"
"github.com/stretchr/objx"
funk "github.com/thoas/go-funk"
)

var (
alert = color.New(color.FgRed, color.Bold).SprintFunc()
)

// Kubectl uses the `kubectl` command to operate on a Kubernetes cluster
type Kubectl struct {
context string
context objx.Map
cluster objx.Map
APIServer string
}

Expand All @@ -23,7 +31,7 @@ func (k Kubectl) Version() (client, server semver.Version, err error) {
zero := *semver.MustParse("0.0.0")
cmd := exec.Command("kubectl", "version",
"-o", "json",
"--context", k.context,
"--context", k.context.Get("name").MustStr(),
)
var buf bytes.Buffer
cmd.Stdout = &buf
Expand All @@ -37,7 +45,7 @@ func (k Kubectl) Version() (client, server semver.Version, err error) {
}

// setupContext uses `kubectl config view` to obtain the KUBECONFIG and extracts the correct context from it
func (k Kubectl) setupContext() error {
func (k *Kubectl) setupContext() error {
cmd := exec.Command("kubectl", "config", "view", "-o", "json")
cfgJSON := bytes.Buffer{}
cmd.Stdout = &cfgJSON
Expand All @@ -50,36 +58,36 @@ func (k Kubectl) setupContext() error {
}

var err error
k.context, err = contextFromKubeconfig(cfg, k.APIServer)
k.cluster, k.context, err = contextFromKubeconfig(cfg, k.APIServer)
if err != nil {
return err
}
return nil
}

// contextFromKubeconfig searches a kubeconfig for a context of a cluster that matches the apiServer
func contextFromKubeconfig(kubeconfig map[string]interface{}, apiServer string) (string, error) {
func contextFromKubeconfig(kubeconfig map[string]interface{}, apiServer string) (cluster, context objx.Map, err error) {
cfg := objx.New(kubeconfig)

// find the correct cluster
cluster := objx.New(funk.Find(cfg.Get("clusters").MustMSISlice(), func(x map[string]interface{}) bool {
cluster = objx.New(funk.Find(cfg.Get("clusters").MustMSISlice(), func(x map[string]interface{}) bool {
host := objx.New(x).Get("cluster.server").MustStr()
return host == apiServer
}))
if !(len(cluster) > 0) { // empty map means no result
return "", fmt.Errorf("no cluster that matches the apiServer `%s` was found. Please check your $KUBECONFIG", apiServer)
return nil, nil, fmt.Errorf("no cluster that matches the apiServer `%s` was found. Please check your $KUBECONFIG", apiServer)
}

// find a context that uses the cluster
context := objx.New(funk.Find(cfg.Get("contexts").MustMSISlice(), func(x map[string]interface{}) bool {
context = objx.New(funk.Find(cfg.Get("contexts").MustMSISlice(), func(x map[string]interface{}) bool {
c := objx.New(x)
return c.Get("context.cluster").MustStr() == cluster.Get("name").MustStr()
}))
if !(len(context) > 0) {
return "", fmt.Errorf("no context that matches the cluster `%s` was found. Please check your $KUBECONFIG", cluster.Get("name").MustStr())
return nil, nil, fmt.Errorf("no context that matches the cluster `%s` was found. Please check your $KUBECONFIG", cluster.Get("name").MustStr())
}

return context.Get("name").MustStr(), nil
return cluster, context, nil
}

// Get retrieves an Kubernetes object from the API
Expand All @@ -90,7 +98,7 @@ func (k Kubectl) Get(namespace, kind, name string) (map[string]interface{}, erro
argv := []string{"get",
"-o", "json",
"-n", namespace,
"--context", k.context,
"--context", k.context.Get("name").MustStr(),
kind, name,
}
cmd := exec.Command("kubectl", argv...)
Expand All @@ -112,8 +120,24 @@ func (k Kubectl) Apply(yaml string) error {
if err := k.setupContext(); err != nil {
return err
}

reader := bufio.NewReader(os.Stdin)
fmt.Printf(`!!! Applying to cluster '%s' at '%s' using context '%s'.
!!! Please type 'yes' to perform: `,
alert(k.cluster.Get("name").MustStr()),
alert(k.cluster.Get("cluster.server").MustStr()),
alert(k.context.Get("name").MustStr()),
)
approve, err := reader.ReadString('\n')
if err != nil {
return err
}
if approve != "yes\n" {
return errors.New("aborted by user")
}

argv := []string{"apply",
"--context", k.context,
"--context", k.context.Get("name").MustStr(),
"-f", "-",
}
cmd := exec.Command("kubectl", argv...)
Expand Down Expand Up @@ -149,7 +173,7 @@ func (k Kubectl) Diff(yaml string) (string, error) {
}

argv := []string{"diff",
"--context", k.context,
"--context", k.context.Get("name").MustStr(),
"-f", "-",
}
cmd := exec.Command("kubectl", argv...)
Expand Down

0 comments on commit 4c6414f

Please sign in to comment.