Skip to content

Commit 11eb5ac

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 11eb5ac

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
@@ -30,9 +30,15 @@ import (
3030
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3131
)
3232

33-
var _ Informers = &informerCache{}
34-
var _ client.Reader = &informerCache{}
35-
var _ Cache = &informerCache{}
33+
var (
34+
_ Informers = &informerCache{}
35+
_ client.Reader = &informerCache{}
36+
_ Cache = &informerCache{}
37+
)
38+
39+
var (
40+
runtimeObjType = reflect.TypeOf((runtime.Object)(nil))
41+
)
3642

3743
// informerCache is a Kubernetes Object cache populated from InformersMap. cache wraps an InformersMap.
3844
type informerCache struct {
@@ -60,19 +66,23 @@ func (ip *informerCache) List(ctx context.Context, opts *client.ListOptions, out
6066
return nil
6167
}
6268

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-
7069
gvk, err := apiutil.GVKForObject(out, ip.Scheme)
7170
if err != nil {
7271
return err
7372
}
7473

75-
cache, err := ip.InformersMap.Get(gvk, cacheType)
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 is not a runtime.Object", out)
83+
}
84+
85+
cache, err := ip.InformersMap.Get(gvk, cacheTypeObj)
7686
if err != nil {
7787
return err
7888
}

0 commit comments

Comments
 (0)