Skip to content

Commit 09b63e1

Browse files
committed
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 c21af9d commit 09b63e1

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
@@ -791,8 +791,11 @@ func copyableCSVHash(original *v1alpha1.ClusterServiceVersion) (string, string,
791791
}
792792

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

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

835872
prototype.Namespace = existing.Namespace
836873
prototype.ResourceVersion = existing.ResourceVersion

0 commit comments

Comments
 (0)