cisco-open / k8s-objectmatcher

A Kubernetes object matcher library to avoid unnecessary K8s object updates
Apache License 2.0
157 stars 29 forks source link

DefaultPatchMaker patch deployment result error #41

Closed smallersoup closed 3 years ago

smallersoup commented 3 years ago

Describe the bug A clear and concise description of what the bug is.

Steps to reproduce the issue: Please describe the steps to reproduce the issue. 1、The following test code:

package test

import (
    "testing"

    "github.com/banzaicloud/k8s-objectmatcher/patch"
    "github.com/stretchr/testify/assert"
    "github.com/xdf/rocketmq-operator/pkg/k8sutil"
    appsv1 "k8s.io/api/apps/v1"
    "k8s.io/apimachinery/pkg/util/json"
)

var (
     currentDepJson = `
{
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "metadata": {
        "annotations": {
            "deployment.kubernetes.io/revision": "1",
            "prometheus.io/port": "5557",
            "prometheus.io/scrape": "true"
        },
        "creationTimestamp": "2021-06-11T06:28:55Z",
        "generation": 1,
        "labels": {
            "app": "exporter",
            "exporterName": "zz-480",
            "mq_cr": "zz-480"
        },
        "managedFields": [
            {
                "apiVersion": "apps/v1",
                "fieldsType": "FieldsV1",
                "fieldsV1": {
                    "f:metadata": {
                        "f:annotations": {
                            ".": {},
                            "f:prometheus.io/port": {},
                            "f:prometheus.io/scrape": {}
                        },
                        "f:labels": {
                            ".": {},
                            "f:app": {},
                            "f:exporterName": {},
                            "f:mq_cr": {}
                        },
                        "f:ownerReferences": {
                            ".": {},
                            "k:{\"uid\":\"16abf70c-f889-448c-8873-b48880cd4a35\"}": {
                                ".": {},
                                "f:apiVersion": {},
                                "f:blockOwnerDeletion": {},
                                "f:controller": {},
                                "f:kind": {},
                                "f:name": {},
                                "f:uid": {}
                            }
                        }
                    },
                    "f:spec": {
                        "f:progressDeadlineSeconds": {},
                        "f:replicas": {},
                        "f:revisionHistoryLimit": {},
                        "f:selector": {
                            "f:matchLabels": {
                                ".": {},
                                "f:app": {},
                                "f:exporterName": {}
                            }
                        },
                        "f:strategy": {
                            "f:rollingUpdate": {
                                ".": {},
                                "f:maxSurge": {},
                                "f:maxUnavailable": {}
                            },
                            "f:type": {}
                        },
                        "f:template": {
                            "f:metadata": {
                                "f:annotations": {
                                    ".": {},
                                    "f:prometheus.io/port": {},
                                    "f:prometheus.io/scrape": {}
                                },
                                "f:labels": {
                                    ".": {},
                                    "f:app": {},
                                    "f:exporterName": {},
                                    "f:mq_cr": {}
                                }
                            },
                            "f:spec": {
                                "f:containers": {
                                    "k:{\"name\":\"mq-exporter\"}": {
                                        ".": {},
                                        "f:args": {},
                                        "f:image": {},
                                        "f:imagePullPolicy": {},
                                        "f:livenessProbe": {
                                            ".": {},
                                            "f:failureThreshold": {},
                                            "f:initialDelaySeconds": {},
                                            "f:periodSeconds": {},
                                            "f:successThreshold": {},
                                            "f:tcpSocket": {
                                                ".": {},
                                                "f:port": {}
                                            },
                                            "f:timeoutSeconds": {}
                                        },
                                        "f:name": {},
                                        "f:ports": {
                                            ".": {},
                                            "k:{\"containerPort\":5557,\"protocol\":\"TCP\"}": {
                                                ".": {},
                                                "f:containerPort": {},
                                                "f:name": {},
                                                "f:protocol": {}
                                            }
                                        },
                                        "f:readinessProbe": {
                                            ".": {},
                                            "f:failureThreshold": {},
                                            "f:initialDelaySeconds": {},
                                            "f:periodSeconds": {},
                                            "f:successThreshold": {},
                                            "f:tcpSocket": {
                                                ".": {},
                                                "f:port": {}
                                            },
                                            "f:timeoutSeconds": {}
                                        },
                                        "f:resources": {
                                            ".": {},
                                            "f:limits": {
                                                ".": {},
                                                "f:cpu": {},
                                                "f:memory": {}
                                            },
                                            "f:requests": {
                                                ".": {},
                                                "f:cpu": {},
                                                "f:memory": {}
                                            }
                                        },
                                        "f:terminationMessagePath": {},
                                        "f:terminationMessagePolicy": {},
                                        "f:volumeMounts": {
                                            ".": {},
                                            "k:{\"mountPath\":\"/home/rocketmq/rocketmq-4.8.0/bin/runbroker.sh\"}": {
                                                ".": {},
                                                "f:mountPath": {},
                                                "f:name": {},
                                                "f:subPath": {}
                                            },
                                            "k:{\"mountPath\":\"/home/rocketmq/rocketmq-4.8.0/bin/runserver.sh\"}": {
                                                ".": {},
                                                "f:mountPath": {},
                                                "f:name": {},
                                                "f:subPath": {}
                                            },
                                            "k:{\"mountPath\":\"/tmp/rocketmq-exporter/data/\"}": {
                                                ".": {},
                                                "f:mountPath": {},
                                                "f:name": {}
                                            }
                                        }
                                    }
                                },
                                "f:dnsPolicy": {},
                                "f:restartPolicy": {},
                                "f:schedulerName": {},
                                "f:securityContext": {
                                    ".": {},
                                    "f:fsGroup": {}
                                },
                                "f:terminationGracePeriodSeconds": {},
                                "f:volumes": {
                                    ".": {},
                                    "k:{\"name\":\"config\"}": {
                                        ".": {},
                                        "f:configMap": {
                                            ".": {},
                                            "f:defaultMode": {},
                                            "f:name": {}
                                        },
                                        "f:name": {}
                                    },
                                    "k:{\"name\":\"mq-run-script\"}": {
                                        ".": {},
                                        "f:configMap": {
                                            ".": {},
                                            "f:defaultMode": {},
                                            "f:name": {}
                                        },
                                        "f:name": {}
                                    }
                                }
                            }
                        }
                    }
                },
                "manager": "___go_build_github_com_smaller_rocketmq_operator",
                "operation": "Update",
                "time": "2021-06-11T06:28:55Z"
            },
            {
                "apiVersion": "apps/v1",
                "fieldsType": "FieldsV1",
                "fieldsV1": {
                    "f:metadata": {
                        "f:annotations": {
                            "f:deployment.kubernetes.io/revision": {}
                        }
                    },
                    "f:status": {
                        "f:availableReplicas": {},
                        "f:conditions": {
                            ".": {},
                            "k:{\"type\":\"Available\"}": {
                                ".": {},
                                "f:lastTransitionTime": {},
                                "f:lastUpdateTime": {},
                                "f:message": {},
                                "f:reason": {},
                                "f:status": {},
                                "f:type": {}
                            },
                            "k:{\"type\":\"Progressing\"}": {
                                ".": {},
                                "f:lastTransitionTime": {},
                                "f:lastUpdateTime": {},
                                "f:message": {},
                                "f:reason": {},
                                "f:status": {},
                                "f:type": {}
                            }
                        },
                        "f:observedGeneration": {},
                        "f:readyReplicas": {},
                        "f:replicas": {},
                        "f:updatedReplicas": {}
                    }
                },
                "manager": "kube-controller-manager",
                "operation": "Update",
                "time": "2021-06-11T06:29:20Z"
            }
        ],
        "name": "zz-480-exporter",
        "namespace": "rocketmq",
        "ownerReferences": [
            {
                "apiVersion": "rocketmq.apache.org/v1alpha1",
                "blockOwnerDeletion": true,
                "controller": true,
                "kind": "RocketMQCluster",
                "name": "zz-480",
                "uid": "16abf70c-f889-448c-8873-b48880cd4a35"
            }
        ],
        "resourceVersion": "227460798",
        "selfLink": "/apis/apps/v1/namespaces/rocketmq/deployments/zz-480-exporter",
        "uid": "d7d05f49-6c3e-4f46-a352-f5c3af89547f"
    },
    "spec": {
        "progressDeadlineSeconds": 600,
        "replicas": 1,
        "revisionHistoryLimit": 10,
        "selector": {
            "matchLabels": {
                "app": "exporter",
                "exporterName": "zz-480"
            }
        },
        "strategy": {
            "rollingUpdate": {
                "maxSurge": "25%",
                "maxUnavailable": "25%"
            },
            "type": "RollingUpdate"
        },
        "template": {
            "metadata": {
                "annotations": {
                    "prometheus.io/port": "5557",
                    "prometheus.io/scrape": "true"
                },
                "labels": {
                    "app": "exporter",
                    "exporterName": "zz-480",
                    "mq_cr": "zz-480"
                }
            },
            "spec": {
                "containers": [
                    {
                        "args": [
                            "--spring.config.location=/tmp/rocketmq-exporter/data/"
                        ],
                        "image": "harbor-xadd.staff.smaller.cn/library/rocketmq-exporter:v1.0.1",
                        "imagePullPolicy": "IfNotPresent",
                        "livenessProbe": {
                            "failureThreshold": 3,
                            "initialDelaySeconds": 15,
                            "periodSeconds": 20,
                            "successThreshold": 1,
                            "tcpSocket": {
                                "port": "mq-exporter"
                            },
                            "timeoutSeconds": 1
                        },
                        "name": "mq-exporter",
                        "ports": [
                            {
                                "containerPort": 5557,
                                "name": "mq-exporter",
                                "protocol": "TCP"
                            }
                        ],
                        "readinessProbe": {
                            "failureThreshold": 3,
                            "initialDelaySeconds": 15,
                            "periodSeconds": 20,
                            "successThreshold": 1,
                            "tcpSocket": {
                                "port": "mq-exporter"
                            },
                            "timeoutSeconds": 1
                        },
                        "resources": {
                            "limits": {
                                "cpu": "2",
                                "memory": "4Gi"
                            },
                            "requests": {
                                "cpu": "500m",
                                "memory": "2Gi"
                            }
                        },
                        "terminationMessagePath": "/dev/termination-log",
                        "terminationMessagePolicy": "File",
                        "volumeMounts": [
                            {
                                "mountPath": "/home/rocketmq/rocketmq-4.8.0/bin/runbroker.sh",
                                "name": "mq-run-script",
                                "subPath": "runbroker.sh"
                            },
                            {
                                "mountPath": "/home/rocketmq/rocketmq-4.8.0/bin/runserver.sh",
                                "name": "mq-run-script",
                                "subPath": "runserver.sh"
                            },
                            {
                                "mountPath": "/tmp/rocketmq-exporter/data/",
                                "name": "config"
                            }
                        ]
                    }
                ],
                "dnsPolicy": "ClusterFirst",
                "restartPolicy": "Always",
                "schedulerName": "xlss-scheduler",
                "securityContext": {
                    "fsGroup": 1000
                },
                "terminationGracePeriodSeconds": 30,
                "volumes": [
                    {
                        "configMap": {
                            "defaultMode": 493,
                            "name": "mq-run-script"
                        },
                        "name": "mq-run-script"
                    },
                    {
                        "configMap": {
                            "defaultMode": 493,
                            "name": "zz-480-exporter-config"
                        },
                        "name": "config"
                    }
                ]
            }
        }
    }
}`

     modifiedDepJson = `
{
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "metadata": {
        "annotations": {
            "prometheus.io/port": "5557",
            "prometheus.io/scrape": "true"
        },
        "creationTimestamp": "2021-06-11T06:28:55Z",
        "generation": 1,
        "labels": {
            "app": "exporter",
            "exporterName": "zz-480",
            "mq_cr": "zz-480"
        },
        "managedFields": [
            {
                "apiVersion": "apps/v1",
                "fieldsType": "FieldsV1",
                "fieldsV1": {
                    "f:metadata": {
                        "f:annotations": {
                            ".": {},
                            "f:prometheus.io/port": {},
                            "f:prometheus.io/scrape": {}
                        },
                        "f:labels": {
                            ".": {},
                            "f:app": {},
                            "f:exporterName": {},
                            "f:mq_cr": {}
                        },
                        "f:ownerReferences": {
                            ".": {},
                            "k:{\"uid\":\"16abf70c-f889-448c-8873-b48880cd4a35\"}": {
                                ".": {},
                                "f:apiVersion": {},
                                "f:blockOwnerDeletion": {},
                                "f:controller": {},
                                "f:kind": {},
                                "f:name": {},
                                "f:uid": {}
                            }
                        }
                    },
                    "f:spec": {
                        "f:progressDeadlineSeconds": {},
                        "f:replicas": {},
                        "f:revisionHistoryLimit": {},
                        "f:selector": {
                            "f:matchLabels": {
                                ".": {},
                                "f:app": {},
                                "f:exporterName": {}
                            }
                        },
                        "f:strategy": {
                            "f:rollingUpdate": {
                                ".": {},
                                "f:maxSurge": {},
                                "f:maxUnavailable": {}
                            },
                            "f:type": {}
                        },
                        "f:template": {
                            "f:metadata": {
                                "f:annotations": {
                                    ".": {},
                                    "f:prometheus.io/port": {},
                                    "f:prometheus.io/scrape": {}
                                },
                                "f:labels": {
                                    ".": {},
                                    "f:app": {},
                                    "f:exporterName": {},
                                    "f:mq_cr": {}
                                }
                            },
                            "f:spec": {
                                "f:containers": {
                                    "k:{\"name\":\"mq-exporter\"}": {
                                        ".": {},
                                        "f:args": {},
                                        "f:image": {},
                                        "f:imagePullPolicy": {},
                                        "f:livenessProbe": {
                                            ".": {},
                                            "f:failureThreshold": {},
                                            "f:initialDelaySeconds": {},
                                            "f:periodSeconds": {},
                                            "f:successThreshold": {},
                                            "f:tcpSocket": {
                                                ".": {},
                                                "f:port": {}
                                            },
                                            "f:timeoutSeconds": {}
                                        },
                                        "f:name": {},
                                        "f:ports": {
                                            ".": {},
                                            "k:{\"containerPort\":5557,\"protocol\":\"TCP\"}": {
                                                ".": {},
                                                "f:containerPort": {},
                                                "f:name": {},
                                                "f:protocol": {}
                                            }
                                        },
                                        "f:readinessProbe": {
                                            ".": {},
                                            "f:failureThreshold": {},
                                            "f:initialDelaySeconds": {},
                                            "f:periodSeconds": {},
                                            "f:successThreshold": {},
                                            "f:tcpSocket": {
                                                ".": {},
                                                "f:port": {}
                                            },
                                            "f:timeoutSeconds": {}
                                        },
                                        "f:resources": {
                                            ".": {},
                                            "f:limits": {
                                                ".": {},
                                                "f:cpu": {},
                                                "f:memory": {}
                                            },
                                            "f:requests": {
                                                ".": {},
                                                "f:cpu": {},
                                                "f:memory": {}
                                            }
                                        },
                                        "f:terminationMessagePath": {},
                                        "f:terminationMessagePolicy": {},
                                        "f:volumeMounts": {
                                            ".": {},
                                            "k:{\"mountPath\":\"/home/rocketmq/rocketmq-4.8.0/bin/runbroker.sh\"}": {
                                                ".": {},
                                                "f:mountPath": {},
                                                "f:name": {},
                                                "f:subPath": {}
                                            },
                                            "k:{\"mountPath\":\"/home/rocketmq/rocketmq-4.8.0/bin/runserver.sh\"}": {
                                                ".": {},
                                                "f:mountPath": {},
                                                "f:name": {},
                                                "f:subPath": {}
                                            },
                                            "k:{\"mountPath\":\"/tmp/rocketmq-exporter/data/\"}": {
                                                ".": {},
                                                "f:mountPath": {},
                                                "f:name": {}
                                            }
                                        }
                                    }
                                },
                                "f:dnsPolicy": {},
                                "f:restartPolicy": {},
                                "f:schedulerName": {},
                                "f:securityContext": {
                                    ".": {},
                                    "f:fsGroup": {}
                                },
                                "f:terminationGracePeriodSeconds": {},
                                "f:volumes": {
                                    ".": {},
                                    "k:{\"name\":\"config\"}": {
                                        ".": {},
                                        "f:configMap": {
                                            ".": {},
                                            "f:defaultMode": {},
                                            "f:name": {}
                                        },
                                        "f:name": {}
                                    },
                                    "k:{\"name\":\"mq-run-script\"}": {
                                        ".": {},
                                        "f:configMap": {
                                            ".": {},
                                            "f:defaultMode": {},
                                            "f:name": {}
                                        },
                                        "f:name": {}
                                    }
                                }
                            }
                        }
                    }
                },
                "manager": "___go_build_github_com_smaller_rocketmq_operator",
                "operation": "Update",
                "time": "2021-06-11T06:28:55Z"
            },
            {
                "apiVersion": "apps/v1",
                "fieldsType": "FieldsV1",
                "fieldsV1": {
                    "f:metadata": {
                        "f:annotations": {
                            "f:deployment.kubernetes.io/revision": {}
                        }
                    },
                    "f:status": {
                        "f:availableReplicas": {},
                        "f:conditions": {
                            ".": {},
                            "k:{\"type\":\"Available\"}": {
                                ".": {},
                                "f:lastTransitionTime": {},
                                "f:lastUpdateTime": {},
                                "f:message": {},
                                "f:reason": {},
                                "f:status": {},
                                "f:type": {}
                            },
                            "k:{\"type\":\"Progressing\"}": {
                                ".": {},
                                "f:lastTransitionTime": {},
                                "f:lastUpdateTime": {},
                                "f:message": {},
                                "f:reason": {},
                                "f:status": {},
                                "f:type": {}
                            }
                        },
                        "f:observedGeneration": {},
                        "f:readyReplicas": {},
                        "f:replicas": {},
                        "f:updatedReplicas": {}
                    }
                },
                "manager": "kube-controller-manager",
                "operation": "Update",
                "time": "2021-06-11T06:29:20Z"
            }
        ],
        "name": "zz-480-exporter",
        "namespace": "rocketmq",
        "ownerReferences": [
            {
                "apiVersion": "rocketmq.apache.org/v1alpha1",
                "blockOwnerDeletion": true,
                "controller": true,
                "kind": "RocketMQCluster",
                "name": "zz-480",
                "uid": "16abf70c-f889-448c-8873-b48880cd4a35"
            }
        ],
        "resourceVersion": "227460798",
        "selfLink": "/apis/apps/v1/namespaces/rocketmq/deployments/zz-480-exporter",
        "uid": "d7d05f49-6c3e-4f46-a352-f5c3af89547f"
    },
    "spec": {
        "replicas": 1,
        "selector": {
            "matchLabels": {
                "app": "exporter",
                "exporterName": "zz-480"
            }
        },
        "strategy": {
            "rollingUpdate": {
                "maxSurge": "25%",
                "maxUnavailable": "25%"
            },
            "type": "RollingUpdate"
        },
        "template": {
            "metadata": {
                "annotations": {
                    "prometheus.io/port": "5557",
                    "prometheus.io/scrape": "true"
                },
                "labels": {
                    "app": "exporter",
                    "exporterName": "zz-480",
                    "mq_cr": "zz-480"
                }
            },
            "spec": {
                "containers": [
                    {
                        "args": [
                            "--spring.config.location=/tmp/rocketmq-exporter/data/"
                        ],
                        "image": "harbor-xadd.staff.smaller.cn/library/rocketmq-exporter:v1.0.1",
                        "livenessProbe": {
                            "initialDelaySeconds": 15,
                            "periodSeconds": 20,
                            "tcpSocket": {
                                "port": "mq-exporter"
                            }
                        },
                        "name": "mq-exporter",
                        "ports": [
                            {
                                "containerPort": 5557,
                                "name": "mq-exporter",
                                "protocol": "TCP"
                            }
                        ],
                        "readinessProbe": {
                            "initialDelaySeconds": 15,
                            "periodSeconds": 20,
                            "tcpSocket": {
                                "port": "mq-exporter"
                            }
                        },
                        "resources": {
                            "limits": {
                                "cpu": "2",
                                "memory": "4Gi"
                            },
                            "requests": {
                                "cpu": "500m",
                                "memory": "2Gi"
                            }
                        },
                        "volumeMounts": [
                            {
                                "mountPath": "/tmp/rocketmq-exporter/data/",
                                "name": "config"
                            }
                        ]
                    }
                ],
                "schedulerName": "xlss-scheduler",
                "securityContext": {
                    "fsGroup": 1000
                },
                "volumes": [
                    {
                        "configMap": {
                            "defaultMode": 493,
                            "name": "zz-480-exporter-config"
                        },
                        "name": "config"
                    }
                ]
            }
        }
    }
}`
)

func TestDeploymentPatchResult(t *testing.T) {
    currentDep, modifiedDep :=  &appsv1.Deployment{}, &appsv1.Deployment{}
    err := json.Unmarshal([]byte(currentDepJson), currentDep)
    if err != nil {
        t.Fatalf(err.Error())
    }

    err = json.Unmarshal([]byte(modifiedDepJson), modifiedDep)
    if err != nil {
        t.Fatalf(err.Error())
    }

    assert.True(t, len(currentDep.Spec.Template.Spec.Containers[0].VolumeMounts) != len(modifiedDep.Spec.Template.Spec.Containers[0].VolumeMounts))
    assert.True(t, len(currentDep.Spec.Template.Spec.Volumes) != len(modifiedDep.Spec.Template.Spec.Volumes))
    patchResult, err := patch.DefaultPatchMaker.Calculate(currentDep, modifiedDep, k8sutil.PatchOptions...)
    if err != nil {
        t.Fatalf(err.Error())
    }

    assert.False(t, patchResult.IsEmpty())
}

Expected behavior A clear and concise description of what you expected to happen.

Screenshots If applicable, add screenshots to help explain your problem.

Additional context Add any other context about the problem like release numberm version, branch, etc.