From c3412af009ae44439875cf17e98f0d1d4b6f67e2 Mon Sep 17 00:00:00 2001
From: Tom Wilkie <tom.wilkie@gmail.com>
Date: Thu, 6 Jul 2017 13:51:12 +0100
Subject: [PATCH] Add 'subset' diff stategy option that checks the live state
 is a subset of the config state.

---
 cmd/diff.go | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/cmd/diff.go b/cmd/diff.go
index 71a14225..5d2dc424 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -31,7 +31,10 @@ import (
 	"github.com/ksonnet/kubecfg/utils"
 )
 
+var diffStrategy string
+
 func init() {
+	diffCmd.Flags().StringVar(&diffStrategy, "diff-strategy", "all", "Diff strategy, all or subset.")
 	RootCmd.AddCommand(diffCmd)
 }
 
@@ -82,13 +85,17 @@ var diffCmd = &cobra.Command{
 				continue
 			}
 
-			diff := gojsondiff.New().CompareObjects(liveObj.Object, obj.Object)
+			liveObjObject := liveObj.Object
+			if diffStrategy == "subset" {
+				liveObjObject = removeMapFields(obj.Object, liveObjObject)
+			}
+			diff := gojsondiff.New().CompareObjects(liveObjObject, obj.Object)
 
 			if diff.Modified() {
 				fcfg := formatter.AsciiFormatterConfig{
 					Coloring: istty(out),
 				}
-				formatter := formatter.NewAsciiFormatter(liveObj.Object, fcfg)
+				formatter := formatter.NewAsciiFormatter(liveObjObject, fcfg)
 				text, err := formatter.Format(diff)
 				if err != nil {
 					return err
@@ -103,6 +110,41 @@ var diffCmd = &cobra.Command{
 	},
 }
 
+func removeFields(config, live interface{}) interface{} {
+	switch c := config.(type) {
+	case map[string]interface{}:
+		return removeMapFields(c, live.(map[string]interface{}))
+	case []interface{}:
+		return removeListFields(c, live.([]interface{}))
+	default:
+		return live
+	}
+}
+
+func removeMapFields(config, live map[string]interface{}) map[string]interface{} {
+	result := map[string]interface{}{}
+	for k, v1 := range config {
+		v2, ok := live[k]
+		if !ok {
+			continue
+		}
+		result[k] = removeFields(v1, v2)
+	}
+	return result
+}
+
+func removeListFields(config, live []interface{}) []interface{} {
+	result := []interface{}{}
+	for i, v2 := range live {
+		if len(config) > i {
+			result = append(result, removeFields(config[i], v2))
+		} else {
+			result = append(result, v2)
+		}
+	}
+	return result
+}
+
 func istty(w io.Writer) bool {
 	if f, ok := w.(*os.File); ok {
 		return isatty.IsTerminal(f.Fd())
-- 
GitLab