Skip to content

Commit 71df193

Browse files
committed
Bug 1744245: recreate of sub should not fail install
Back to back delete and recreate of a subscription object causes operator install to fail. How to reproduce: - Create a CatalogSource object - Create a subscription that refers to the CatalogSource above. - Wait for the operator to install successfully. - Update the CatalogSource - Wait for the CatalogSource to become healthy - Delete the Subscription object ( from above ). - Create the Subscription object ( no time delay between delete and create ). Delete and Create can be done one after another, there is no need to make them concurrent. The operator install will fail, Subscription status will have an error condition `ReferencedInstallPlanNotFound`. The new install plan object created by OLM gets deleted by GC. Root cause: - OLM uses a lister to get the list of Subscription(s) in a given namespace and sets the relevant subscriptions(s) found in the list as owner of the installplan object(s). - Because lister uses cache, it will return a deleted subscription until the cache is synced. - The new installplan object may get an owner ref that points to the deleted subscription. - GC garbage collects the deleted subscription and consequently deletes the new InstallPlan. - Subscription reconciler reports that the new InstallPlan object is missing and moves the Subscription to a Failed state. The api audit log has entries that validates that GC is rightfully "deleting" the new InstallPlan object. Fix: - For now, use a direct non-cached client to retrieve the list of Subscription. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1744245 Jira: https://jira.coreos.com/browse/OLM-1245
1 parent 574aecf commit 71df193

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
131131
client: crClient,
132132
lister: lister,
133133
namespace: operatorNamespace,
134-
resolver: resolver.NewOperatorsV1alpha1Resolver(lister),
134+
resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient),
135135
catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(),
136136
subQueueSet: queueinformer.NewEmptyResourceQueueSet(),
137137
csvProvidedAPIsIndexer: map[string]cache.Indexer{},
@@ -702,7 +702,7 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
702702

703703
logger.Debug("checking if subscriptions need update")
704704

705-
subs, err := o.lister.OperatorsV1alpha1().SubscriptionLister().Subscriptions(namespace).List(labels.Everything())
705+
subs, err := o.listSubscriptions(namespace)
706706
if err != nil {
707707
logger.WithError(err).Debug("couldn't list subscriptions")
708708
return err
@@ -1513,6 +1513,20 @@ func (o *Operator) getUpdatedOwnerReferences(refs []metav1.OwnerReference, names
15131513
return updated, nil
15141514
}
15151515

1516+
func (o *Operator) listSubscriptions(namespace string) (subs []*v1alpha1.Subscription, err error) {
1517+
list, err := o.client.OperatorsV1alpha1().Subscriptions(namespace).List(metav1.ListOptions{})
1518+
if err != nil {
1519+
return
1520+
}
1521+
1522+
subs = make([]*v1alpha1.Subscription, 0)
1523+
for i := range list.Items {
1524+
subs = append(subs, &list.Items[i])
1525+
}
1526+
1527+
return
1528+
}
1529+
15161530
// competingCRDOwnersExist returns true if there exists a CSV that owns at least one of the given CSVs owned CRDs (that's not the given CSV)
15171531
func competingCRDOwnersExist(namespace string, csv *v1alpha1.ClusterServiceVersion, existingOwners map[string][]string) (bool, error) {
15181532
// Attempt to find a pre-existing owner in the namespace for any owned crd
@@ -1542,3 +1556,4 @@ func getCSVNameSet(plan *v1alpha1.InstallPlan) map[string]struct{} {
15421556

15431557
return csvNameSet
15441558
}
1559+

pkg/controller/registry/resolver/resolver.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"k8s.io/apimachinery/pkg/labels"
1212

1313
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
14+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
1415
v1alpha1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
1516
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
1617
)
@@ -24,14 +25,16 @@ type Resolver interface {
2425
type OperatorsV1alpha1Resolver struct {
2526
subLister v1alpha1listers.SubscriptionLister
2627
csvLister v1alpha1listers.ClusterServiceVersionLister
28+
client versioned.Interface
2729
}
2830

2931
var _ Resolver = &OperatorsV1alpha1Resolver{}
3032

31-
func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister) *OperatorsV1alpha1Resolver {
33+
func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister, client versioned.Interface) *OperatorsV1alpha1Resolver {
3234
return &OperatorsV1alpha1Resolver{
3335
subLister: lister.OperatorsV1alpha1().SubscriptionLister(),
3436
csvLister: lister.OperatorsV1alpha1().ClusterServiceVersionLister(),
37+
client: client,
3538
}
3639
}
3740

@@ -55,7 +58,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier
5558
}
5659
}
5760

58-
subs, err := r.subLister.Subscriptions(namespace).List(labels.Everything())
61+
subs, err := r.listSubscriptions(namespace)
5962
if err != nil {
6063
return nil, nil, err
6164
}
@@ -168,3 +171,17 @@ func (r *OperatorsV1alpha1Resolver) sourceInfoToSubscriptions(subs []*v1alpha1.S
168171
}
169172
return
170173
}
174+
175+
func (r *OperatorsV1alpha1Resolver) listSubscriptions(namespace string) (subs []*v1alpha1.Subscription, err error) {
176+
list, err := r.client.OperatorsV1alpha1().Subscriptions(namespace).List(metav1.ListOptions{})
177+
if err != nil {
178+
return
179+
}
180+
181+
subs = make([]*v1alpha1.Subscription, 0)
182+
for i := range list.Items {
183+
subs = append(subs, &list.Items[i])
184+
}
185+
186+
return
187+
}

pkg/controller/registry/resolver/resolver_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"k8s.io/client-go/tools/cache"
1515

1616
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
17+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
1718
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake"
1819
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
1920
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
@@ -375,12 +376,12 @@ func TestNamespaceResolver(t *testing.T) {
375376
for _, steps := range tt.out.steps {
376377
expectedSteps = append(expectedSteps, steps...)
377378
}
378-
informerFactory, _ := StartResolverInformers(namespace, stopc, tt.clusterState...)
379+
clientFake, informerFactory, _ := StartResolverInformers(namespace, stopc, tt.clusterState...)
379380
lister := operatorlister.NewLister()
380381
lister.OperatorsV1alpha1().RegisterSubscriptionLister(namespace, informerFactory.Operators().V1alpha1().Subscriptions().Lister())
381382
lister.OperatorsV1alpha1().RegisterClusterServiceVersionLister(namespace, informerFactory.Operators().V1alpha1().ClusterServiceVersions().Lister())
382383

383-
resolver := NewOperatorsV1alpha1Resolver(lister)
384+
resolver := NewOperatorsV1alpha1Resolver(lister, clientFake)
384385
steps, subs, err := resolver.ResolveSteps(namespace, tt.querier)
385386
require.Equal(t, tt.out.err, err)
386387
t.Logf("%#v", steps)
@@ -448,12 +449,12 @@ func TestNamespaceResolverRBAC(t *testing.T) {
448449
for _, steps := range tt.out.steps {
449450
expectedSteps = append(expectedSteps, steps...)
450451
}
451-
informerFactory, _ := StartResolverInformers(namespace, stopc, tt.clusterState...)
452+
clientFake, informerFactory, _ := StartResolverInformers(namespace, stopc, tt.clusterState...)
452453
lister := operatorlister.NewLister()
453454
lister.OperatorsV1alpha1().RegisterSubscriptionLister(namespace, informerFactory.Operators().V1alpha1().Subscriptions().Lister())
454455
lister.OperatorsV1alpha1().RegisterClusterServiceVersionLister(namespace, informerFactory.Operators().V1alpha1().ClusterServiceVersions().Lister())
455456

456-
resolver := NewOperatorsV1alpha1Resolver(lister)
457+
resolver := NewOperatorsV1alpha1Resolver(lister, clientFake)
457458
querier := NewFakeSourceQuerier(map[CatalogKey][]*opregistry.Bundle{catalog: tt.bundlesInCatalog})
458459
steps, subs, err := resolver.ResolveSteps(namespace, querier)
459460
require.Equal(t, tt.out.err, err)
@@ -465,7 +466,7 @@ func TestNamespaceResolverRBAC(t *testing.T) {
465466

466467
// Helpers for resolver tests
467468

468-
func StartResolverInformers(namespace string, stopCh <-chan struct{}, objs ...runtime.Object) (externalversions.SharedInformerFactory, []cache.InformerSynced) {
469+
func StartResolverInformers(namespace string, stopCh <-chan struct{}, objs ...runtime.Object) (versioned.Interface, externalversions.SharedInformerFactory, []cache.InformerSynced) {
469470
// Create client fakes
470471
clientFake := fake.NewSimpleClientset(objs...)
471472

@@ -484,7 +485,7 @@ func StartResolverInformers(namespace string, stopCh <-chan struct{}, objs ...ru
484485
panic("failed to wait for caches to sync")
485486
}
486487

487-
return nsInformerFactory, hasSyncedCheckFns
488+
return clientFake, nsInformerFactory, hasSyncedCheckFns
488489
}
489490

490491
func newSub(namespace, pkg, channel string, catalog CatalogKey) *v1alpha1.Subscription {

0 commit comments

Comments
 (0)