K8S Diff Utilities
This project contains Kubernetes-oriented Golang diff utilities. The only function exposed so far is CompareIgnoreDesiredObjectEmpties()
,
which performs a recursive diff of two structs, but in a way that is customized to a particular situation within a Kubernetes operator.
The situation is this: Usually, Kubernetes controllers generate a "desired" state for some Kubernetes object
(deployment, service, ingress, etc), and then periodically ensure that the "live" state of that object is updated to the desired state.
The operator could simply call Update() via the Kubernetes API, but if the operator is dealing with a large number of objects,
the number of API calls quickly gets out of control. So what is needed is the ability to diff the live
object with the desired object, and only call Update() when they are different. The issue, however, is that
the live object (fetched via the Kubernetes API) is populated with a ton of (potentially deeply nested) default values,
filled in dynamically by Kubernetes. So a simple recursive diff between the live and desired objects will always return diffs
(unless the operator code is somehow able to fill in every default value in the desired object, which is a lot of work).
The solution is to compare the live and desired objects using a customized recursive diff function: one that ignores
"empty" values in the desired object. For our purposes here, "empty" means a Go "zero value" (0, false, "", nil), or
an empty slice or map.
I couldn't find any existing utilities that accomplished the above. There were a few options for implementation approaches...
One option was to take one of the open source DeepCompare utilities, fork it, and hack it up to ignore empty values in the
target object. This seemed pretty messy and hard to maintain, so the option I ended up going with was this:
- Run the diff through github.com/kylelemons/godebug/pretty, which
itself produces predictable diff output.
- Parse through the output of the above tool, filtering out the diffs we don't care about: those caused by empty values in the target object.
Contributions
Pull requests welcome. Also, any feedback on a better way to accomplish the above goals would be much appreciated!
Installing
go get github.com/dansimone/k8sdiff
Using
import (
"github.com/dansimone/k8sdiff"
)
Fetch the live Kubernetes object in question, for example:
liveDeployment := deploymentsLister.Deployments(namespace).Get(deploymentName)
Construct your desired object:
desiredDeployment := createMyDeploymentObject()
Run the comparison:
diffs := k8sdiff.CompareIgnoreDesiredObjectEmpties(liveDeployment, desiredDeployment)
if diffs != "" {
fmt.Println("Diffs: " + diffs)
}