Skip to content

Commit a94b0ce

Browse files
committed
Make sure cache Reader still works
The cache refactor broke the cache reader implementation (invalid assumptions about names, arguments, and the way reflection works). This fixes it, and adds back in some working tests to ensure that it doesn't break again.
1 parent b4748ac commit a94b0ce

File tree

4 files changed

+98
-13
lines changed

4 files changed

+98
-13
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@
1111
# Output of the go coverage tool, specifically when used with LiteIDE
1212
*.out
1313

14+
# editor and IDE paraphernalia
1415
.idea
16+
*.swp
17+
*.swo
18+
*~

pkg/cache/cache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ type Informers interface {
5555
GetInformerForKind(gvk schema.GroupVersionKind) (toolscache.SharedIndexInformer, error)
5656

5757
// Start runs all the informers known to this cache until the given channel is closed.
58-
// It does not block.
58+
// It blocks.
5959
Start(stopCh <-chan struct{}) error
6060

6161
// WaitForCacheSync waits for all the caches to sync. Returns false if it could not sync a cache.

pkg/cache/cache_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,83 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package cache
17+
package cache_test
1818

1919
import (
20+
"context"
21+
2022
. "github.com/onsi/ginkgo"
23+
. "github.com/onsi/gomega"
24+
kcorev1 "k8s.io/api/core/v1"
25+
26+
"sigs.k8s.io/controller-runtime/pkg/cache"
27+
"sigs.k8s.io/controller-runtime/pkg/client"
2128
)
2229

30+
var _ = Describe("Informer Cache", func() {
31+
var stop chan struct{}
32+
33+
BeforeEach(func() {
34+
stop = make(chan struct{})
35+
Expect(cfg).NotTo(BeNil())
36+
})
37+
AfterEach(func() {
38+
close(stop)
39+
})
40+
41+
Describe("as a Reader", func() {
42+
It("should be able to list objects that haven't been watched previously", func() {
43+
By("Creating the cache")
44+
reader, err := cache.New(cfg, cache.Options{})
45+
Expect(err).NotTo(HaveOccurred())
46+
47+
By("running the cache and waiting for it to sync")
48+
go func() {
49+
defer GinkgoRecover()
50+
Expect(reader.Start(stop)).ToNot(HaveOccurred())
51+
}()
52+
Expect(reader.WaitForCacheSync(stop)).NotTo(BeFalse())
53+
54+
By("Listing all services in the cluster")
55+
listObj := &kcorev1.ServiceList{}
56+
Expect(reader.List(context.Background(), nil, listObj)).NotTo(HaveOccurred())
57+
58+
By("Verifying that the returned list contains the Kubernetes service")
59+
// NB: there has to be at least the kubernetes service in the cluster
60+
Expect(listObj.Items).NotTo(BeEmpty())
61+
hasKubeService := false
62+
for _, svc := range listObj.Items {
63+
if svc.Namespace == "default" && svc.Name == "kubernetes" {
64+
hasKubeService = true
65+
break
66+
}
67+
}
68+
Expect(hasKubeService).To(BeTrue())
69+
})
70+
71+
It("should be able to get objects that haven't been watched previously", func() {
72+
By("Creating the cache")
73+
reader, err := cache.New(cfg, cache.Options{})
74+
Expect(err).NotTo(HaveOccurred())
75+
76+
By("running the cache and waiting for it to sync")
77+
go func() {
78+
defer GinkgoRecover()
79+
Expect(reader.Start(stop)).ToNot(HaveOccurred())
80+
}()
81+
Expect(reader.WaitForCacheSync(stop)).NotTo(BeFalse())
82+
83+
By("Getting the Kubernetes service")
84+
svc := &kcorev1.Service{}
85+
Expect(reader.Get(context.Background(), client.ObjectKey{Namespace: "default", Name: "kubernetes"}, svc)).NotTo(HaveOccurred())
86+
87+
By("Verifying that the returned service looks reasonable")
88+
Expect(svc.Name).To(Equal("kubernetes"))
89+
Expect(svc.Namespace).To(Equal("default"))
90+
})
91+
})
92+
})
93+
2394
var _ = Describe("Indexers", func() {
2495
//three := int64(3)
2596
//knownPodKey := client.ObjectKey{Name: "some-pod", Namespace: "some-ns"}

pkg/cache/informer_cache.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"reflect"
23+
"strings"
2324

2425
apimeta "k8s.io/apimachinery/pkg/api/meta"
2526
"k8s.io/apimachinery/pkg/runtime"
@@ -30,9 +31,11 @@ import (
3031
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3132
)
3233

33-
var _ Informers = &informerCache{}
34-
var _ client.Reader = &informerCache{}
35-
var _ Cache = &informerCache{}
34+
var (
35+
_ Informers = &informerCache{}
36+
_ client.Reader = &informerCache{}
37+
_ Cache = &informerCache{}
38+
)
3639

3740
// informerCache is a Kubernetes Object cache populated from InformersMap. cache wraps an InformersMap.
3841
type informerCache struct {
@@ -60,19 +63,26 @@ func (ip *informerCache) List(ctx context.Context, opts *client.ListOptions, out
6063
return nil
6164
}
6265

63-
// http://knowyourmeme.com/memes/this-is-fine
64-
outType := reflect.Indirect(reflect.ValueOf(itemsPtr)).Type().Elem()
65-
cacheType, ok := outType.(runtime.Object)
66-
if !ok {
67-
return fmt.Errorf("cannot get cache for %T, its element is not a runtime.Object", out)
68-
}
69-
7066
gvk, err := apiutil.GVKForObject(out, ip.Scheme)
7167
if err != nil {
7268
return err
7369
}
7470

75-
cache, err := ip.InformersMap.Get(gvk, cacheType)
71+
if !strings.HasSuffix(gvk.Kind, "List") {
72+
return fmt.Errorf("non-list type %T (kind %q) passed as output", out, gvk)
73+
}
74+
// we need the non-list GVK, so chop off the "List" from the end of the kind
75+
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
76+
77+
// http://knowyourmeme.com/memes/this-is-fine
78+
elemType := reflect.Indirect(reflect.ValueOf(itemsPtr)).Type().Elem()
79+
cacheTypeValue := reflect.Zero(reflect.PtrTo(elemType))
80+
cacheTypeObj, ok := cacheTypeValue.Interface().(runtime.Object)
81+
if !ok {
82+
return fmt.Errorf("cannot get cache for %T, its element %T is not a runtime.Object", out, cacheTypeValue.Interface())
83+
}
84+
85+
cache, err := ip.InformersMap.Get(gvk, cacheTypeObj)
7686
if err != nil {
7787
return err
7888
}

0 commit comments

Comments
 (0)