-
Notifications
You must be signed in to change notification settings - Fork 111
HelmRelease drift detection generates JSON patch that replaces entire metadata instead of annotations and labels
#1055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
23c3333 to
d09e85d
Compare
|
Please rebase with upstream main and force push. Thanks! |
Done |
stefanprodan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks @yozel 🏅
|
Thanks for fixing this @yozel! I was wondering what would happen e.g. if the object already had existing annotations, looks like the code generates the appropriate patch targeting only the changed annotations i.e. diff --git a/ssa/jsondiff/testdata/empty-configmap.yaml b/ssa/jsondiff/testdata/empty-configmap.yaml
index ba47038..8e2eeec 100644
--- a/ssa/jsondiff/testdata/empty-configmap.yaml
+++ b/ssa/jsondiff/testdata/empty-configmap.yaml
@@ -3,3 +3,5 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: "configmap-data"
+ annotations:
+ prev: some-previous-valueThe test you added showed me this: === RUN TestUnstructured/ConfigMap_with_added_label_and_annotation
/home/matheus/Documents/github.com/fluxcd/pkg/ssa/jsondiff/unstructured_test.go:915: Unstructured() mismatch (-want +got):
&jsondiff.Diff{
Type: "update",
DesiredObject: &unstructured.Unstructured{Object: {"apiVersion": string("v1"), "kind": string("ConfigMap"), "metadata": map[string]any{"annotations": map[string]any{"annotated": string("yes"), "prev": string("some-previous-value")}, "labels": map[string]any{"labeled": string("yes")}, "name": string("configmap-data"), "namespace": string("test-resource-gq8ll")}}},
ClusterObject: &unstructured.Unstructured{Object: {"apiVersion": string("v1"), "kind": string("ConfigMap"), "metadata": map[string]any{"annotations": map[string]any{"prev": string("some-previous-value")}, "creationTimestamp": string("2026-01-08T09:33:41Z"), "managedFields": []any{map[string]any{"apiVersion": string("v1"), "fieldsType": string("FieldsV1"), "fieldsV1": map[string]any{"f:metadata": map[string]any{"f:annotations": map[string]any{"f:prev": map[string]any{}}}}, "manager": string("dummy"), ...}}, "name": string("configmap-data"), ...}}},
Patch: jsondiff.Patch{
{
- Value: map[string]any{"annotated": string("yes")},
+ Value: string("yes"),
OldValue: nil,
Type: "add",
From: "",
- Path: "/metadata/annotations",
+ Path: "/metadata/annotations/annotated",
... // 1 ignored field
},
{Value: map[string]any{"labeled": string("yes")}, Type: "add", Path: "/metadata/labels"},
},
}
--- FAIL: TestUnstructured/ConfigMap_with_added_label_and_annotation (0.02s)
--- FAIL: TestUnstructured (0.02s)Can you please add a new test ConfigMap YAML with a pre-existing annotation and a test for that? Thanks! 🙏 |
When annotations and labels were missing on the cluster object but present on the desired object, drift detection produced an "add /metadata" patch. JSON Patch interprets this as replacing the entire metadata block, dropping fields like metadata.name. This update preserves metadata.name in copyAnnotationsAndLabels and emits separate add operations for annotations and labels. A test verifies the correct behavior. Signed-off-by: Yasin Özel <yozel@nebius.com>
matheuscscp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🚀
|
@yozel |
Describe the bug
When drift detection computes a JSON patch for changes limited to
metadata.annotationsandmetadata.labels, the generated patch targets/metadataand replaces the entiremetadataobject, instead of adding onlyannotationsandlabels.This leads to an incorrect patch that would drop required metadata fields such as
name,namespace,uid, etc.To Reproduce
Given the following current object in the cluster:
And the desired object rendered by Helm is:
Drift detection produces the following JSON patch:
[ { "value": { "annotations": { "foo": "bar" }, "labels": { "baz": "qux" } }, "op": "add", "path": "/metadata" } ]In JSON Patch semantics,
op: "add"withpath: "/metadata"on an existing key replaces the entiremetadataobject. This means every existing field undermetadatathat is not part of this value is effectively removed.Expected behavior
The generated JSON patch should target only the changed subtrees under
metadata, for example:[ { "value": { "foo": "bar" }, "op": "add", "path": "/metadata/annotations" }, { "value": { "baz": "qux" }, "op": "add", "path": "/metadata/labels" } ]This way, existing fields under
metadatasuch asname,namespace,uid,resourceVersion, and any other keys are preserved.Fix
This PR preserves metadata.name in copyAnnotationsAndLabels and that prevents the resulting metadata to be empty, which solves the issue with wrong JSON patch