Skip to content

Commit 6ab5f16

Browse files
committed
Expose errors generated while retrieving catalog content.
Failing to fetch catalog content should not silently return an empty cache. Instead, it should fail outright with an error that indicates which catalog(s) could not be fetched. Signed-off-by: Ben Luddy <[email protected]>
1 parent 167e031 commit 6ab5f16

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

pkg/controller/registry/resolver/cache.go

+25
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"sync"
99
"time"
1010

11+
"k8s.io/apimachinery/pkg/util/errors"
12+
1113
"github.com/sirupsen/logrus"
1214

1315
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
@@ -79,6 +81,19 @@ type NamespacedOperatorCache struct {
7981
snapshots map[registry.CatalogKey]*CatalogSnapshot
8082
}
8183

84+
func (c *NamespacedOperatorCache) Error() error {
85+
var errs []error
86+
for key, snapshot := range c.snapshots {
87+
snapshot.m.Lock()
88+
err := snapshot.err
89+
snapshot.m.Unlock()
90+
if err != nil {
91+
errs = append(errs, fmt.Errorf("error using catalog %s (in namespace %s): %w", key.Name, key.Namespace, err))
92+
}
93+
}
94+
return errors.NewAggregate(errs)
95+
}
96+
8297
func (c *OperatorCache) Expire(catalog registry.CatalogKey) {
8398
c.m.Lock()
8499
defer c.m.Unlock()
@@ -183,6 +198,12 @@ func (c *OperatorCache) Namespaced(namespaces ...string) MultiCatalogOperatorFin
183198

184199
func (c *OperatorCache) populate(ctx context.Context, snapshot *CatalogSnapshot, registry client.Interface) {
185200
defer snapshot.m.Unlock()
201+
defer func() {
202+
// Don't cache an errorred snapshot.
203+
if snapshot.err != nil {
204+
snapshot.expiry = time.Time{}
205+
}
206+
}()
186207

187208
c.sem <- struct{}{}
188209
defer func() { <-c.sem }()
@@ -195,6 +216,7 @@ func (c *OperatorCache) populate(ctx context.Context, snapshot *CatalogSnapshot,
195216
it, err := registry.ListBundles(ctx)
196217
if err != nil {
197218
snapshot.logger.Errorf("failed to list bundles: %s", err.Error())
219+
snapshot.err = err
198220
return
199221
}
200222
c.logger.WithField("catalog", snapshot.key.String()).Debug("updating cache")
@@ -223,6 +245,7 @@ func (c *OperatorCache) populate(ctx context.Context, snapshot *CatalogSnapshot,
223245
}
224246
if err := it.Error(); err != nil {
225247
snapshot.logger.Warnf("error encountered while listing bundles: %s", err.Error())
248+
snapshot.err = err
226249
}
227250
snapshot.operators = operators
228251
}
@@ -293,6 +316,7 @@ type CatalogSnapshot struct {
293316
m sync.RWMutex
294317
pop context.CancelFunc
295318
priority catalogSourcePriority
319+
err error
296320
}
297321

298322
func (s *CatalogSnapshot) Cancel() {
@@ -400,6 +424,7 @@ type MultiCatalogOperatorFinder interface {
400424
Catalog(registry.CatalogKey) OperatorFinder
401425
FindPreferred(*registry.CatalogKey, ...OperatorPredicate) []*Operator
402426
WithExistingOperators(*CatalogSnapshot) MultiCatalogOperatorFinder
427+
Error() error
403428
OperatorFinder
404429
}
405430

pkg/controller/registry/resolver/cache_test.go

+23-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package resolver
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"io"
78
"math/rand"
@@ -10,6 +11,7 @@ import (
1011
"time"
1112

1213
"github.com/sirupsen/logrus"
14+
"github.com/sirupsen/logrus/hooks/test"
1315
"github.com/stretchr/testify/assert"
1416
"github.com/stretchr/testify/require"
1517

@@ -35,6 +37,8 @@ func (s *BundleStreamStub) Recv() (*api.Bundle, error) {
3537

3638
type RegistryClientStub struct {
3739
BundleIterator *client.BundleIterator
40+
41+
ListBundlesError error
3842
}
3943

4044
func (s *RegistryClientStub) Get() (client.Interface, error) {
@@ -58,7 +62,7 @@ func (s *RegistryClientStub) GetBundleThatProvides(ctx context.Context, group, v
5862
}
5963

6064
func (s *RegistryClientStub) ListBundles(ctx context.Context) (*client.BundleIterator, error) {
61-
return s.BundleIterator, nil
65+
return s.BundleIterator, s.ListBundlesError
6266
}
6367

6468
func (s *RegistryClientStub) GetPackage(ctx context.Context, packageName string) (*api.Package, error) {
@@ -339,3 +343,21 @@ func TestStripPluralRequiredAndProvidedAPIKeys(t *testing.T) {
339343
assert.Equal(t, "K.v1.g", result[0].providedAPIs.String())
340344
assert.Equal(t, "K2.v2.g2", result[0].requiredAPIs.String())
341345
}
346+
347+
func TestNamespaceOperatorCacheError(t *testing.T) {
348+
rcp := RegistryClientProviderStub{}
349+
catsrcLister := operatorlister.NewLister().OperatorsV1alpha1().CatalogSourceLister()
350+
key := registry.CatalogKey{Namespace: "dummynamespace", Name: "dummyname"}
351+
rcp[key] = &RegistryClientStub{
352+
ListBundlesError: errors.New("testing"),
353+
}
354+
355+
logger, _ := test.NewNullLogger()
356+
c := NewOperatorCache(rcp, logger, catsrcLister)
357+
require.EqualError(t, c.Namespaced("dummynamespace").Error(), "error using catalog dummyname (in namespace dummynamespace): testing")
358+
if snapshot, ok := c.snapshots[key]; !ok {
359+
t.Fatalf("cache snapshot not found")
360+
} else {
361+
require.Zero(t, snapshot.expiry)
362+
}
363+
}

pkg/controller/registry/resolver/resolver.go

+4
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
103103

104104
r.addInvariants(namespacedCache, installables)
105105

106+
if err := namespacedCache.Error(); err != nil {
107+
return nil, err
108+
}
109+
106110
input := make([]solver.Installable, 0)
107111
for _, i := range installables {
108112
input = append(input, i)

pkg/controller/registry/types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (k *CatalogKey) Virtual() bool {
3333

3434
func NewVirtualCatalogKey(namespace string) CatalogKey {
3535
return CatalogKey{
36-
Name: ExistingOperatorKey,
36+
Name: ExistingOperatorKey,
3737
Namespace: namespace,
3838
}
3939
}

0 commit comments

Comments
 (0)