Skip to content

Commit 4142fb7

Browse files
Remove annotations
1 parent fb45b0a commit 4142fb7

3 files changed

Lines changed: 189 additions & 7 deletions

File tree

helm/kube_resources.go

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,21 @@ func mapRuntimeObjects(ctx context.Context, kc *kube.Client, objects []runtime.O
137137
return nil, diags
138138
}
139139

140+
// volatile metadata always removed
140141
accessor.SetUID(types.UID(""))
141142
accessor.SetCreationTimestamp(metav1.Time{})
142143
accessor.SetResourceVersion("")
143144
accessor.SetManagedFields(nil)
144145

145-
objJSON, err := json.Marshal(obj)
146+
// >>> unify cleanup at the choke point <<<
147+
umap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
148+
if err != nil {
149+
diags.AddError("Unstructured Conversion Error", err.Error())
150+
return nil, diags
151+
}
152+
normalizeK8sObject(umap)
153+
154+
objJSON, err := json.Marshal(umap)
146155
if err != nil {
147156
diags.AddError("Marshal Error", err.Error())
148157
return nil, diags
@@ -205,7 +214,7 @@ func getLiveResources(ctx context.Context, r *release.Release, m *Meta) (map[str
205214
diags.AddError("Kube Client Error", err.Error())
206215
return nil, diags
207216
}
208-
resources, resDiags := mapResources(ctx, actionConfig, r, func(i *resource.Info) (runtime.Object, error) {
217+
rawResources, resDiags := mapResources(ctx, actionConfig, r, func(i *resource.Info) (runtime.Object, error) {
209218
gvk := i.Object.GetObjectKind().GroupVersionKind()
210219
return kc.Factory.NewBuilder().
211220
Unstructured().
@@ -216,10 +225,28 @@ func getLiveResources(ctx context.Context, r *release.Release, m *Meta) (map[str
216225
Object()
217226
})
218227
diags.Append(resDiags...)
219-
return resources, diags
228+
if resDiags.HasError() {
229+
return rawResources, diags
230+
}
231+
232+
cleaned := make(map[string]string, len(rawResources))
233+
for k, v := range rawResources {
234+
var obj map[string]any
235+
if err := json.Unmarshal([]byte(v), &obj); err != nil {
236+
cleaned[k] = v
237+
continue
238+
}
239+
normalizeK8sObject(obj)
240+
if b, err := json.Marshal(obj); err == nil {
241+
cleaned[k] = string(b)
242+
} else {
243+
cleaned[k] = v
244+
}
245+
}
246+
247+
return cleaned, diags
220248
}
221249

222-
// getDryRunResources simulates applying a manifest and returns the resulting objects.
223250
func getDryRunResources(ctx context.Context, r *release.Release, m *Meta) (map[string]string, diag.Diagnostics) {
224251
var diags diag.Diagnostics
225252

@@ -238,7 +265,7 @@ func getDryRunResources(ctx context.Context, r *release.Release, m *Meta) (map[s
238265
fieldManager = filepath.Base(os.Args[0])
239266
}
240267

241-
resources, resDiags := mapResources(ctx, actionConfig, r, func(i *resource.Info) (runtime.Object, error) {
268+
rawResources, resDiags := mapResources(ctx, actionConfig, r, func(i *resource.Info) (runtime.Object, error) {
242269
info := &diff.InfoObject{
243270
LocalObj: i.Object,
244271
Info: i,
@@ -252,5 +279,23 @@ func getDryRunResources(ctx context.Context, r *release.Release, m *Meta) (map[s
252279
return info.Merged()
253280
})
254281
diags.Append(resDiags...)
255-
return resources, diags
282+
if resDiags.HasError() {
283+
return rawResources, diags
284+
}
285+
cleaned := make(map[string]string, len(rawResources))
286+
for k, v := range rawResources {
287+
var obj map[string]any
288+
if err := json.Unmarshal([]byte(v), &obj); err != nil {
289+
cleaned[k] = v
290+
continue
291+
}
292+
normalizeK8sObject(obj)
293+
if b, err := json.Marshal(obj); err == nil {
294+
cleaned[k] = string(b)
295+
} else {
296+
cleaned[k] = v
297+
}
298+
}
299+
300+
return cleaned, diags
256301
}

helm/resource_helm_release.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,3 +2448,121 @@ func valuesUnknown(plan HelmReleaseModel) bool {
24482448
}
24492449
return false
24502450
}
2451+
func isInternalAnno(key string) bool {
2452+
u, err := url.Parse("//" + key)
2453+
if err != nil {
2454+
return false
2455+
}
2456+
host := u.Hostname()
2457+
2458+
// allow some known external prefixes to remain (examples)
2459+
if host == "app.kubernetes.io" || host == "service.beta.kubernetes.io" {
2460+
return false
2461+
}
2462+
// internal *.kubernetes.io (and .k8s.io, just in case)
2463+
if strings.HasSuffix(host, "kubernetes.io") || strings.HasSuffix(host, "k8s.io") {
2464+
return true
2465+
}
2466+
// server-generated DaemonSet thing
2467+
if strings.Contains(key, "deprecated.daemonset.template.generation") {
2468+
return true
2469+
}
2470+
return false
2471+
}
2472+
2473+
func stripServerSideAnnotations(obj map[string]any) {
2474+
md, _ := obj["metadata"].(map[string]any)
2475+
if md == nil {
2476+
return
2477+
}
2478+
ann, _ := md["annotations"].(map[string]any)
2479+
if ann == nil {
2480+
return
2481+
}
2482+
2483+
for k := range ann {
2484+
if isInternalAnno(k) {
2485+
delete(ann, k)
2486+
}
2487+
}
2488+
if len(ann) == 0 {
2489+
delete(md, "annotations")
2490+
}
2491+
}
2492+
2493+
// Always remove Helm meta annotations (dry-run usually lacks them; live adds them)
2494+
func stripHelmMetaAnnotations(obj map[string]any) {
2495+
md, _ := obj["metadata"].(map[string]any)
2496+
if md == nil {
2497+
return
2498+
}
2499+
ann, _ := md["annotations"].(map[string]any)
2500+
if ann == nil {
2501+
return
2502+
}
2503+
2504+
changed := false
2505+
for k := range ann {
2506+
if strings.HasPrefix(k, "meta.helm.sh/") {
2507+
delete(ann, k)
2508+
changed = true
2509+
}
2510+
}
2511+
if changed && len(ann) == 0 {
2512+
delete(md, "annotations")
2513+
}
2514+
}
2515+
2516+
// Remove fields that commonly differ; keep metadata.generation
2517+
func stripVolatileFields(obj map[string]any) {
2518+
if md, _ := obj["metadata"].(map[string]any); md != nil {
2519+
delete(md, "managedFields")
2520+
delete(md, "resourceVersion")
2521+
delete(md, "uid")
2522+
delete(md, "creationTimestamp")
2523+
// keep "generation"
2524+
}
2525+
2526+
// Service fields assigned by API server
2527+
if kind, _ := obj["kind"].(string); kind == "Service" {
2528+
if spec, _ := obj["spec"].(map[string]any); spec != nil {
2529+
delete(spec, "clusterIP")
2530+
delete(spec, "clusterIPs")
2531+
}
2532+
}
2533+
}
2534+
2535+
// Historical tweak: drop managed-by label only for Secrets
2536+
func stripSecretManagedByLabel(obj map[string]any) {
2537+
if kind, _ := obj["kind"].(string); kind != "Secret" {
2538+
return
2539+
}
2540+
md, _ := obj["metadata"].(map[string]any)
2541+
if md == nil {
2542+
return
2543+
}
2544+
labels, _ := md["labels"].(map[string]any)
2545+
if labels == nil {
2546+
return
2547+
}
2548+
2549+
delete(labels, "app.kubernetes.io/managed-by")
2550+
if len(labels) == 0 {
2551+
delete(md, "labels")
2552+
}
2553+
}
2554+
2555+
// If "status" exists, force it to null; don't add if missing
2556+
func coerceStatusToNull(obj map[string]any) {
2557+
if _, ok := obj["status"]; ok {
2558+
obj["status"] = nil
2559+
}
2560+
}
2561+
2562+
func normalizeK8sObject(obj map[string]any) {
2563+
stripServerSideAnnotations(obj) // internal k8s junk
2564+
stripHelmMetaAnnotations(obj) // meta.helm.sh/* on ALL kinds
2565+
stripVolatileFields(obj)
2566+
stripSecretManagedByLabel(obj)
2567+
coerceStatusToNull(obj)
2568+
}

helm/resource_helm_release_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2798,7 +2798,26 @@ func getReleaseJSONResourcesPF(t *testing.T, namespace, name string) map[string]
27982798
if diags.HasError() {
27992799
t.Fatalf("failed to map runtime objects: %v", diags)
28002800
}
2801-
return result
2801+
2802+
// IMPORTANT: mirror provider cleanup (normalizeK8sObject) so tests compare like-for-like.
2803+
cleaned := make(map[string]string, len(result))
2804+
for k, v := range result {
2805+
var obj map[string]any
2806+
if err := json.Unmarshal([]byte(v), &obj); err != nil {
2807+
// if we somehow can't unmarshal, fall back to raw
2808+
cleaned[k] = v
2809+
continue
2810+
}
2811+
normalizeK8sObject(obj) // strips server-side + Helm meta (per kind), redacts, etc.
2812+
b, err := json.Marshal(obj)
2813+
if err != nil {
2814+
cleaned[k] = v
2815+
continue
2816+
}
2817+
cleaned[k] = string(b)
2818+
}
2819+
2820+
return cleaned
28022821
}
28032822

28042823
// patchDeploymentPF patches a Deployment resource and waits until it stabilizes.

0 commit comments

Comments
 (0)