Skip to content

Commit

Permalink
feat(cmd/kubernetes): Diff support
Browse files Browse the repository at this point in the history
Implements diff command

Adds diff support to Kubernetes
  • Loading branch information
sh0rez committed Jul 30, 2019
1 parent 0778708 commit a959f38
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 7 deletions.
29 changes: 27 additions & 2 deletions cmd/tk/provider.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package main

import (
"encoding/json"
"fmt"
"log"
"os"

"github.com/alecthomas/chroma/quick"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)

func providerCmd() *cobra.Command {
Expand Down Expand Up @@ -58,7 +60,30 @@ func diffCmd() *cobra.Command {
Use: "diff",
Short: "[Requires Provider] print differences between the configuration and the target",
}
cmd.Run = func(cmd *cobra.Command, args []string) {}
cmd.Run = func(cmd *cobra.Command, args []string) {
raw, err := evalDict()
if err != nil {
log.Fatalln("evaluating jsonnet:", err)
}

desired, err := prov.Reconcile(raw)
if err != nil {
log.Fatalln("reconciling:", err)
}

changes, err := prov.Diff(desired)
if err != nil {
log.Fatalln("diffing:", err)
}

if terminal.IsTerminal(int(os.Stdout.Fd())) {
if err := quick.Highlight(os.Stdout, changes, "diff", "terminal", "vim"); err != nil {
log.Fatalln("highlighting:", err)
}
} else {
fmt.Println(changes)
}
}
return cmd
}

Expand Down
60 changes: 60 additions & 0 deletions pkg/provider/kubernetes/kubectl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package kubernetes

import (
"bytes"
"encoding/json"
"fmt"
"os"
"os/exec"
)

// Kubectl uses the `kubectl` command to operate on a Kubernetes cluster
type Kubectl struct{}

// Get retrieves an Kubernetes object from the API
func (k Kubectl) Get(namespace, kind, name string) (map[string]interface{}, error) {
argv := []string{"get", "-o", "json", "-n", namespace, kind, name}
cmd := exec.Command("kubectl", argv...)
raw := bytes.Buffer{}
cmd.Stdout = &raw
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, err
}
var obj map[string]interface{}
if err := json.Unmarshal(raw.Bytes(), &obj); err != nil {
return nil, err
}
return obj, nil
}

// Diff takes a desired state as yaml and returns the differences
// to the system in common diff format
func (k Kubectl) Diff(yaml string) (string, error) {
argv := []string{"diff", "-f", "-"}
cmd := exec.Command("kubectl", argv...)
raw := bytes.Buffer{}
cmd.Stdout = &raw

stdin, err := cmd.StdinPipe()
if err != nil {
return "", err
}

go func() {
fmt.Fprintln(stdin, yaml)
stdin.Close()
}()

if err := cmd.Run(); err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
// kubectl uses this to tell us that there is a diff
if exitError.ExitCode() == 1 {
return raw.String(), nil
}
}
return "", err
}

return raw.String(), nil
}
14 changes: 9 additions & 5 deletions pkg/provider/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type Kubernetes struct {
Namespace string
}

var client = Kubectl{}

// Reconcile receives the raw evaluated jsonnet as a marshaled json dict and
// shall return it reconciled as a state object of the target system
func (k *Kubernetes) Reconcile(raw map[string]interface{}) (state interface{}, err error) {
Expand Down Expand Up @@ -53,11 +55,13 @@ func (k *Kubernetes) Apply(desired interface{}) error {
panic("not implemented")
}

// State shall return the current state of the target system.
// It receives the desired state object generated using `Format()`.
// This is used for diffing afterwards.
func (k *Kubernetes) State(desired interface{}) (real map[string]interface{}, err error) {
panic("not implemented")
// Diff takes the desired state and returns the differences from the cluster
func (k *Kubernetes) Diff(state interface{}) (string, error) {
yaml, err := k.Fmt(state)
if err != nil {
return "", err
}
return client.Diff(yaml)
}

// Cmd shall return a command to be available under `tk provider`
Expand Down

0 comments on commit a959f38

Please sign in to comment.