Skip to content

Commit da1e61f

Browse files
bentitotmshort
authored andcommitted
Add metadata drift guard to copyToNamespace
Since we switched to a PartialObjectMetadata cache to save memory, we lost visibility into copied CSV spec and status fields, and the reintroduced nonStatusCopyHash/statusCopyHash annotations only partially solved the problem. Manual edits to a copied CSV could still go undetected, causing drift without reconciliation. This commit adds two new annotations: olm.operatorframework.io/observedGeneration and olm.operatorframework.io/observedResourceVersion. It implements a mechanism to guard agains metadata drift at the top of the existing-copy path in copyToNamespace. If a stored observedGeneration or observedResourceVersion no longer matches the live object, the operator now: • Updates the spec and hash annotations • Updates the status subresource • Records the new generation and resourceVersion in the guard annotations Because the guard only fires when its annotations are already present, all existing unit tests pass unchanged. We preserve the memory benefits of the metadata‐only informer, avoid extra GETs, and eliminate unnecessary API churn. Future work may explore a WithTransform informer to regain full object visibility with minimal memory impact. Signed-off-by: Brett Tofel <[email protected]>
1 parent 71dfbd2 commit da1e61f

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

pkg/controller/operators/olm/operatorgroup.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,11 @@ func copyableCSVHash(original *v1alpha1.ClusterServiceVersion) (string, string,
792792
}
793793

794794
const (
795-
nonStatusCopyHashAnnotation = "olm.operatorframework.io/nonStatusCopyHash"
796-
statusCopyHashAnnotation = "olm.operatorframework.io/statusCopyHash"
795+
nonStatusCopyHashAnnotation = "olm.operatorframework.io/nonStatusCopyHash"
796+
statusCopyHashAnnotation = "olm.operatorframework.io/statusCopyHash"
797+
// annotations for metadata drift guard
798+
observedGenerationAnnotation = "olm.operatorframework.io/observedGeneration"
799+
observedResourceVersionAnnotation = "olm.operatorframework.io/observedResourceVersion"
797800
)
798801

799802
// If returned error is not nil, the returned ClusterServiceVersion
@@ -829,9 +832,43 @@ func (a *Operator) copyToNamespace(prototype *v1alpha1.ClusterServiceVersion, ns
829832
UID: created.UID,
830833
},
831834
}, nil
832-
} else if err != nil {
833-
return nil, err
834-
}
835+
} else if err != nil {
836+
return nil, err
837+
}
838+
// metadata drift guard: detect manual modifications to spec or status
839+
if og, orv := existing.Annotations[observedGenerationAnnotation], existing.Annotations[observedResourceVersionAnnotation]; (og != "" && og != fmt.Sprint(existing.GetGeneration())) || (orv != "" && orv != existing.ResourceVersion) {
840+
// full resync for metadata drift
841+
// prepare prototype for update
842+
prototype.Namespace = existing.Namespace
843+
prototype.ResourceVersion = existing.ResourceVersion
844+
prototype.UID = existing.UID
845+
// sync hash annotations
846+
prototype.Annotations[nonStatusCopyHashAnnotation] = nonstatus
847+
prototype.Annotations[statusCopyHashAnnotation] = status
848+
// update spec and annotations
849+
updated, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).Update(context.TODO(), prototype, metav1.UpdateOptions{})
850+
if err != nil {
851+
return nil, fmt.Errorf("failed to resync spec for metadata drift guard: %w", err)
852+
}
853+
// update status subresource
854+
updated.Status = prototype.Status
855+
if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{}); err != nil {
856+
return nil, fmt.Errorf("failed to resync status for metadata drift guard: %w", err)
857+
}
858+
// record observed generation and resourceVersion
859+
updated.Annotations[observedGenerationAnnotation] = fmt.Sprint(updated.GetGeneration())
860+
updated.Annotations[observedResourceVersionAnnotation] = updated.ResourceVersion
861+
if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).Update(context.TODO(), updated, metav1.UpdateOptions{}); err != nil {
862+
return nil, fmt.Errorf("failed to update metadata guard annotations: %w", err)
863+
}
864+
return &v1alpha1.ClusterServiceVersion{
865+
ObjectMeta: metav1.ObjectMeta{
866+
Name: updated.Name,
867+
Namespace: updated.Namespace,
868+
UID: updated.UID,
869+
},
870+
}, nil
871+
}
835872

836873
prototype.Namespace = existing.Namespace
837874
prototype.ResourceVersion = existing.ResourceVersion

0 commit comments

Comments
 (0)