Skip to content

Commit bc91403

Browse files
authored
Merge pull request #627 from alvaroaleman/informer-error
🐛 Return error when trying to read from an unstarted cache
2 parents 4ba0a3b + 782b674 commit bc91403

File tree

5 files changed

+33
-10
lines changed

5 files changed

+33
-10
lines changed

pkg/cache/informer_cache.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ var (
3838
_ Cache = &informerCache{}
3939
)
4040

41+
// ErrCacheNotStarted is returned when trying to read from the cache that wasn't started.
42+
type ErrCacheNotStarted struct{}
43+
44+
func (*ErrCacheNotStarted) Error() string {
45+
return "the cache is not started, can not read objects"
46+
}
47+
4148
// informerCache is a Kubernetes Object cache populated from InformersMap. informerCache wraps an InformersMap.
4249
type informerCache struct {
4350
*internal.InformersMap
@@ -50,10 +57,14 @@ func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out runt
5057
return err
5158
}
5259

53-
cache, err := ip.InformersMap.Get(gvk, out)
60+
started, cache, err := ip.InformersMap.Get(gvk, out)
5461
if err != nil {
5562
return err
5663
}
64+
65+
if !started {
66+
return &ErrCacheNotStarted{}
67+
}
5768
return cache.Reader.Get(ctx, key, out)
5869
}
5970

@@ -90,11 +101,15 @@ func (ip *informerCache) List(ctx context.Context, out runtime.Object, opts ...c
90101
}
91102
}
92103

93-
cache, err := ip.InformersMap.Get(gvk, cacheTypeObj)
104+
started, cache, err := ip.InformersMap.Get(gvk, cacheTypeObj)
94105
if err != nil {
95106
return err
96107
}
97108

109+
if !started {
110+
return &ErrCacheNotStarted{}
111+
}
112+
98113
return cache.Reader.List(ctx, out, opts...)
99114
}
100115

@@ -105,7 +120,7 @@ func (ip *informerCache) GetInformerForKind(gvk schema.GroupVersionKind) (Inform
105120
if err != nil {
106121
return nil, err
107122
}
108-
i, err := ip.InformersMap.Get(gvk, obj)
123+
_, i, err := ip.InformersMap.Get(gvk, obj)
109124
if err != nil {
110125
return nil, err
111126
}
@@ -118,7 +133,7 @@ func (ip *informerCache) GetInformer(obj runtime.Object) (Informer, error) {
118133
if err != nil {
119134
return nil, err
120135
}
121-
i, err := ip.InformersMap.Get(gvk, obj)
136+
_, i, err := ip.InformersMap.Get(gvk, obj)
122137
if err != nil {
123138
return nil, err
124139
}

pkg/cache/internal/cache_reader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import (
3232
"sigs.k8s.io/controller-runtime/pkg/client"
3333
)
3434

35-
// CacheReader is a CacheReader
35+
// CacheReader is a client.Reader
3636
var _ client.Reader = &CacheReader{}
3737

3838
// CacheReader wraps a cache.Index to implement the client.CacheReader interface for a single type

pkg/cache/internal/deleg_map.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (m *InformersMap) WaitForCacheSync(stop <-chan struct{}) bool {
7373

7474
// Get will create a new Informer and add it to the map of InformersMap if none exists. Returns
7575
// the Informer from the map.
76-
func (m *InformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Object) (*MapEntry, error) {
76+
func (m *InformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) {
7777
_, isUnstructured := obj.(*unstructured.Unstructured)
7878
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
7979
isUnstructured = isUnstructured || isUnstructuredList

pkg/cache/internal/informers_map.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func (ip *specificInformersMap) HasSyncedFuncs() []cache.InformerSynced {
145145

146146
// Get will create a new Informer and add it to the map of specificInformersMap if none exists. Returns
147147
// the Informer from the map.
148-
func (ip *specificInformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Object) (*MapEntry, error) {
148+
func (ip *specificInformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) {
149149
// Return the informer if it is found
150150
i, started, ok := func() (*MapEntry, bool, bool) {
151151
ip.mu.RLock()
@@ -157,18 +157,18 @@ func (ip *specificInformersMap) Get(gvk schema.GroupVersionKind, obj runtime.Obj
157157
if !ok {
158158
var err error
159159
if i, started, err = ip.addInformerToMap(gvk, obj); err != nil {
160-
return nil, err
160+
return started, nil, err
161161
}
162162
}
163163

164164
if started && !i.Informer.HasSynced() {
165165
// Wait for it to sync before returning the Informer so that folks don't read from a stale cache.
166166
if !cache.WaitForCacheSync(ip.stop, i.Informer.HasSynced) {
167-
return nil, fmt.Errorf("failed waiting for %T Informer to sync", obj)
167+
return started, nil, fmt.Errorf("failed waiting for %T Informer to sync", obj)
168168
}
169169
}
170170

171-
return i, nil
171+
return started, i, nil
172172
}
173173

174174
func (ip *specificInformersMap) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.Object) (*MapEntry, bool, error) {

pkg/controller/controller_integration_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ limitations under the License.
1717
package controller_test
1818

1919
import (
20+
"context"
21+
2022
appsv1 "k8s.io/api/apps/v1"
2123
corev1 "k8s.io/api/core/v1"
2224
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2325
"k8s.io/apimachinery/pkg/runtime/schema"
2426
"k8s.io/apimachinery/pkg/types"
27+
"sigs.k8s.io/controller-runtime/pkg/cache"
2528
"sigs.k8s.io/controller-runtime/pkg/controller"
2629
"sigs.k8s.io/controller-runtime/pkg/handler"
2730
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -73,6 +76,11 @@ var _ = Describe("controller", func() {
7376
err = instance.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForObject{})
7477
Expect(err).NotTo(HaveOccurred())
7578

79+
err = cm.GetClient().Get(context.Background(), types.NamespacedName{Name: "foo"}, &corev1.Namespace{})
80+
Expect(err).To(Equal(&cache.ErrCacheNotStarted{}))
81+
err = cm.GetClient().List(context.Background(), &corev1.NamespaceList{})
82+
Expect(err).To(Equal(&cache.ErrCacheNotStarted{}))
83+
7684
By("Starting the Manager")
7785
go func() {
7886
defer GinkgoRecover()

0 commit comments

Comments
 (0)