diff --git a/pkg/kubecfg/diff.go b/pkg/kubecfg/diff.go index 92a3f823..18455c9b 100644 --- a/pkg/kubecfg/diff.go +++ b/pkg/kubecfg/diff.go @@ -102,6 +102,28 @@ func (c DiffCmd) Run(apiObjects []*unstructured.Unstructured, out io.Writer) err return nil } +// See also feature request for golang reflect pkg at +func isEmptyValue(i interface{}) bool { + switch v := i.(type) { + case []interface{}: + return len(v) == 0 + case []string: + return len(v) == 0 + case map[string]interface{}: + return len(v) == 0 + case bool: + return !v + case float64: + return v == 0 + case string: + return v == "" + case nil: + return true + default: + panic(fmt.Sprintf("Found unexpected type %T in json unmarshal (value=%v)", i, i)) + } +} + func removeFields(config, live interface{}) interface{} { switch c := config.(type) { case map[string]interface{}: @@ -118,6 +140,11 @@ func removeMapFields(config, live map[string]interface{}) map[string]interface{} for k, v1 := range config { v2, ok := live[k] if !ok { + // Copy empty value from config, as API won't return them, + // see https://github.com/ksonnet/kubecfg/issues/179 + if isEmptyValue(v1) { + result[k] = v1 + } continue } result[k] = removeFields(v1, v2) diff --git a/pkg/kubecfg/diff_test.go b/pkg/kubecfg/diff_test.go index 3f0cdee1..ec404d02 100644 --- a/pkg/kubecfg/diff_test.go +++ b/pkg/kubecfg/diff_test.go @@ -76,6 +76,11 @@ func TestRemoveMapFields(t *testing.T) { } func TestRemoveFields(t *testing.T) { + emptyVal := map[string]interface{}{ + "args": map[string]interface{}{}, + "volumes": []string{}, + "stdin": false, + } for _, tc := range []struct { config, live, expected interface{} }{ @@ -99,6 +104,13 @@ func TestRemoveFields(t *testing.T) { live: "b", expected: "b", }, + // Check we handle empty configs by copying them as if were live + // (API won't return them) + { + config: emptyVal, + live: map[string]interface{}{}, + expected: emptyVal, + }, // Check we can handle combinations. {