Unverified Commit 9c0daebf authored by Jesse Suen's avatar Jesse Suen
Browse files

Fix diff falsely reporting OutOfSync due to namespace/annotation defaulting

parent f2a0ca56
Showing with 96 additions and 6 deletions
+96 -6
......@@ -56,6 +56,7 @@ func TwoWayDiff(config, live *unstructured.Unstructured) *DiffResult {
// ThreeWayDiff performs a diff with the understanding of how to incorporate the
// last-applied-configuration annotation in the diff.
func ThreeWayDiff(orig, config, live *unstructured.Unstructured) *DiffResult {
orig = removeNamespaceAnnotation(orig)
// remove extra fields in the live, that were not in the original object
liveObj := RemoveMapFields(orig.Object, live.Object)
// now we have a pruned live object
......@@ -84,6 +85,22 @@ func ThreeWayDiff(orig, config, live *unstructured.Unstructured) *DiffResult {
return &dr
}
func removeNamespaceAnnotation(orig *unstructured.Unstructured) *unstructured.Unstructured {
orig = orig.DeepCopy()
// remove the namespace an annotation from the
if metadataIf, ok := orig.Object["metadata"]; ok {
metadata := metadataIf.(map[string]interface{})
delete(metadata, "namespace")
if annotationsIf, ok := metadata["annotations"]; ok {
annotation := annotationsIf.(map[string]interface{})
if len(annotation) == 0 {
delete(metadata, "annotations")
}
}
}
return orig
}
func threeWayMergePatch(orig, config, live *unstructured.Unstructured) ([]byte, error) {
origBytes, err := json.Marshal(orig.Object)
if err != nil {
......
......@@ -15,12 +15,23 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
var (
formatOpts = formatter.AsciiFormatterConfig{
Coloring: terminal.IsTerminal(int(os.Stdout.Fd())),
}
)
func TestDiff(t *testing.T) {
leftDep := test.DemoDeployment()
leftUn := kube.MustToUnstructured(leftDep)
diffRes := Diff(leftUn, leftUn)
assert.False(t, diffRes.Diff.Modified())
ascii, err := diffRes.ASCIIFormat(leftUn, formatOpts)
assert.Nil(t, err)
if ascii != "" {
log.Println(ascii)
}
}
func TestDiffWithNils(t *testing.T) {
......@@ -86,6 +97,7 @@ func TestDiffArrayModification(t *testing.T) {
func TestThreeWayDiff(t *testing.T) {
// 1. get config and live to be the same. Both have a foo annotation.
configDep := test.DemoDeployment()
configDep.ObjectMeta.Namespace = ""
configDep.Annotations = map[string]string{
"foo": "bar",
}
......@@ -93,11 +105,15 @@ func TestThreeWayDiff(t *testing.T) {
// 2. add a extra field to the live. this simulates kubernetes adding default values in the
// object. We should not consider defaulted values as a difference
liveDep.Annotations["some-default-val"] = "default"
liveDep.SetNamespace("default")
configUn := kube.MustToUnstructured(configDep)
liveUn := kube.MustToUnstructured(liveDep)
res := Diff(configUn, liveUn)
assert.False(t, res.Modified)
if !assert.False(t, res.Modified) {
ascii, err := res.ASCIIFormat(configUn, formatOpts)
assert.Nil(t, err)
log.Println(ascii)
}
// 3. Add a last-applied-configuration annotation in the live. There should still not be any
// difference
......@@ -107,7 +123,11 @@ func TestThreeWayDiff(t *testing.T) {
configUn = kube.MustToUnstructured(configDep)
liveUn = kube.MustToUnstructured(liveDep)
res = Diff(configUn, liveUn)
assert.False(t, res.Modified)
if !assert.False(t, res.Modified) {
ascii, err := res.ASCIIFormat(configUn, formatOpts)
assert.Nil(t, err)
log.Println(ascii)
}
// 4. Remove the foo annotation from config and perform the diff again. We should detect a
// difference since three-way diff detects the removal of a managed field
......@@ -125,9 +145,6 @@ func TestThreeWayDiff(t *testing.T) {
configUn = kube.MustToUnstructured(configDep)
liveUn = kube.MustToUnstructured(liveDep)
res = Diff(configUn, liveUn)
formatOpts := formatter.AsciiFormatterConfig{
Coloring: terminal.IsTerminal(int(os.Stdout.Fd())),
}
ascii, err := res.ASCIIFormat(configUn, formatOpts)
assert.Nil(t, err)
if ascii != "" {
......@@ -135,3 +152,59 @@ func TestThreeWayDiff(t *testing.T) {
}
assert.False(t, res.Modified)
}
var demoConfig = `
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"labels": {
"applications.argoproj.io/app-name": "argocd-demo"
},
"name": "application-controller"
}
}
`
var demoLive = `
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"annotations\":{},\"labels\":{\"applications.argoproj.io/app-name\":\"argocd-demo\"},\"name\":\"application-controller\",\"namespace\":\"argocd-demo\"}}\n"
},
"creationTimestamp": "2018-04-16T22:08:57Z",
"labels": {
"applications.argoproj.io/app-name": "argocd-demo"
},
"name": "application-controller",
"namespace": "argocd-demo",
"resourceVersion": "7584502",
"selfLink": "/api/v1/namespaces/argocd-demo/serviceaccounts/application-controller",
"uid": "c22bb2b4-41c2-11e8-978a-028445d52ec8"
},
"secrets": [
{
"name": "application-controller-token-kfxct"
}
]
}
`
// Tests a real world example
func TestDiffActualExample(t *testing.T) {
var configUn, liveUn unstructured.Unstructured
err := json.Unmarshal([]byte(demoConfig), &configUn.Object)
assert.Nil(t, err)
err = json.Unmarshal([]byte(demoLive), &liveUn.Object)
assert.Nil(t, err)
dr := Diff(&configUn, &liveUn)
assert.False(t, dr.Modified)
ascii, err := dr.ASCIIFormat(&configUn, formatOpts)
assert.Nil(t, err)
if ascii != "" {
log.Println(ascii)
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment