Skip to content

Commit d055f28

Browse files
tmshorteverettravenbentito
authored
🐛 OCPBUGS-37982: Reduce Frequency of Update Requests for Copied CSVs (#3597)
* (bugfix): reduce frequency of update requests for CSVs by adding annotations to copied CSVs that are populated with hashes of the non-status fields and the status fields. This seems to be how this was intended to work, but was not actually working this way because the annotations never actually existed on the copied CSV. This resulted in a hot loop of update requests being made on all copied CSVs. Signed-off-by: everettraven <everettraven@gmail.com> * update unit tests Signed-off-by: everettraven <everettraven@gmail.com> * updates to test so far Signed-off-by: everettraven <everettraven@gmail.com> * Small changes Signed-off-by: Brett Tofel <btofel@redhat.com> * 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 <btofel@redhat.com> * Tests for metadata guard Verifies that exactly three updates (spec, status, guard) are issued when the observedGeneration doesn’t match. Signed-off-by: Brett Tofel <btofel@redhat.com> * Persist observed annotations on all status updates Signed-off-by: Brett Tofel <btofel@redhat.com> * GCI the file Signed-off-by: Brett Tofel <btofel@redhat.com> * Use TransformFunc Unit tests not updated Signed-off-by: Todd Short <todd.short@me.com> * Update operatorgroup tests to compile Signed-off-by: Todd Short <todd.short@me.com> * Restore operatorgroup_test from master Remove metadatalister Signed-off-by: Todd Short <todd.short@me.com> * Remove more PartialObjectMetadata Signed-off-by: Todd Short <todd.short@me.com> * Remove hashes from operator_test Signed-off-by: Todd Short <todd.short@me.com> * Fix error messages for static-analysis Signed-off-by: Todd Short <todd.short@me.com> * Update test annotations and test client Signed-off-by: Todd Short <todd.short@me.com> * Rename pruning to listerwatcher Signed-off-by: Todd Short <todd.short@me.com> * Set resync to 6h Signed-off-by: Todd Short <todd.short@me.com> * Add CSV copy revert syncer Signed-off-by: Todd Short <todd.short@me.com> * Log tweaks Signed-off-by: Todd Short <todd.short@me.com> * Consolidate revert and gc syncers Signed-off-by: Todd Short <todd.short@me.com> * Add logging and reduce the amount of metadata in the TransformFunc Signed-off-by: Todd Short <todd.short@me.com> * Handle the copy CSV revert via a requeue of the primary CSV Signed-off-by: Todd Short <todd.short@me.com> * Revert "Set resync to 6h" This reverts commit 855f940. Signed-off-by: Todd Short <todd.short@me.com> * Add delete handler for copied csv Signed-off-by: Todd Short <todd.short@me.com> * Revert whitespace change Signed-off-by: Todd Short <todd.short@me.com> * Rename function, fix comment Signed-off-by: Todd Short <todd.short@me.com> --------- Signed-off-by: everettraven <everettraven@gmail.com> Signed-off-by: Brett Tofel <btofel@redhat.com> Signed-off-by: Todd Short <todd.short@me.com> Co-authored-by: everettraven <everettraven@gmail.com> Co-authored-by: Brett Tofel <btofel@redhat.com>
1 parent 86838d6 commit d055f28

File tree

8 files changed

+268
-171
lines changed

8 files changed

+268
-171
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ import (
6464
olmerrors "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/errors"
6565
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
6666
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription"
67-
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/pruning"
67+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/listerwatcher"
6868
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
6969
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc"
7070
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler"
@@ -230,38 +230,53 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
230230

231231
// Fields are pruned from local copies of the objects managed
232232
// by this informer in order to reduce cached size.
233-
prunedCSVInformer := cache.NewSharedIndexInformer(
234-
pruning.NewListerWatcher(op.client, metav1.NamespaceAll,
233+
prunedCSVInformer := cache.NewSharedIndexInformerWithOptions(
234+
listerwatcher.NewListerWatcher(
235+
op.client,
236+
metav1.NamespaceAll,
235237
func(options *metav1.ListOptions) {
236238
options.LabelSelector = fmt.Sprintf("!%s", v1alpha1.CopiedLabelKey)
237239
},
238-
pruning.PrunerFunc(func(csv *v1alpha1.ClusterServiceVersion) {
239-
*csv = v1alpha1.ClusterServiceVersion{
240-
TypeMeta: csv.TypeMeta,
241-
ObjectMeta: metav1.ObjectMeta{
242-
Name: csv.Name,
243-
Namespace: csv.Namespace,
244-
Labels: csv.Labels,
245-
Annotations: csv.Annotations,
246-
},
247-
Spec: v1alpha1.ClusterServiceVersionSpec{
248-
CustomResourceDefinitions: csv.Spec.CustomResourceDefinitions,
249-
APIServiceDefinitions: csv.Spec.APIServiceDefinitions,
250-
Replaces: csv.Spec.Replaces,
251-
Version: csv.Spec.Version,
252-
},
253-
Status: v1alpha1.ClusterServiceVersionStatus{
254-
Phase: csv.Status.Phase,
255-
Reason: csv.Status.Reason,
256-
},
257-
}
258-
})),
240+
),
259241
&v1alpha1.ClusterServiceVersion{},
260-
resyncPeriod(),
261-
cache.Indexers{
262-
cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
242+
cache.SharedIndexInformerOptions{
243+
ResyncPeriod: resyncPeriod(),
244+
Indexers: cache.Indexers{
245+
cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
246+
},
263247
},
264248
)
249+
250+
// Transformed the CSV to be just the necessary data
251+
prunedCSVTransformFunc := func(i interface{}) (interface{}, error) {
252+
if csv, ok := i.(*v1alpha1.ClusterServiceVersion); ok {
253+
*csv = v1alpha1.ClusterServiceVersion{
254+
TypeMeta: csv.TypeMeta,
255+
ObjectMeta: metav1.ObjectMeta{
256+
Name: csv.Name,
257+
Namespace: csv.Namespace,
258+
Labels: csv.Labels,
259+
Annotations: csv.Annotations,
260+
},
261+
Spec: v1alpha1.ClusterServiceVersionSpec{
262+
CustomResourceDefinitions: csv.Spec.CustomResourceDefinitions,
263+
APIServiceDefinitions: csv.Spec.APIServiceDefinitions,
264+
Replaces: csv.Spec.Replaces,
265+
Version: csv.Spec.Version,
266+
},
267+
Status: v1alpha1.ClusterServiceVersionStatus{
268+
Phase: csv.Status.Phase,
269+
Reason: csv.Status.Reason,
270+
},
271+
}
272+
return csv, nil
273+
}
274+
return nil, fmt.Errorf("unable to convert input to CSV")
275+
}
276+
277+
if err := prunedCSVInformer.SetTransform(prunedCSVTransformFunc); err != nil {
278+
return nil, err
279+
}
265280
csvLister := operatorsv1alpha1listers.NewClusterServiceVersionLister(prunedCSVInformer.GetIndexer())
266281
op.lister.OperatorsV1alpha1().RegisterClusterServiceVersionLister(metav1.NamespaceAll, csvLister)
267282
if err := op.RegisterInformer(prunedCSVInformer); err != nil {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package listerwatcher
2+
3+
import (
4+
"context"
5+
6+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7+
"k8s.io/apimachinery/pkg/runtime"
8+
"k8s.io/apimachinery/pkg/watch"
9+
"k8s.io/client-go/tools/cache"
10+
11+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
12+
)
13+
14+
func NewListerWatcher(client versioned.Interface, namespace string, override func(*metav1.ListOptions)) cache.ListerWatcher {
15+
return &cache.ListWatch{
16+
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
17+
override(&options)
18+
return client.OperatorsV1alpha1().ClusterServiceVersions(namespace).List(context.TODO(), options)
19+
},
20+
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
21+
override(&options)
22+
return client.OperatorsV1alpha1().ClusterServiceVersions(namespace).Watch(context.TODO(), options)
23+
},
24+
}
25+
}

pkg/controller/operators/internal/pruning/listerwatcher.go

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)