Skip to content

Commit d0cefa5

Browse files
Add UnsafeDisableDeepCopy to GetOptions
1 parent 71f7db5 commit d0cefa5

File tree

4 files changed

+86
-21
lines changed

4 files changed

+86
-21
lines changed

pkg/cache/cache_test.go

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,27 +2462,43 @@ func CacheTest(createCacheFunc func(config *rest.Config, opts cache.Options) (ca
24622462
})
24632463
})
24642464
})
2465-
Describe("use UnsafeDisableDeepCopy list options", func() {
2466-
It("should be able to change object in informer cache", func() {
2467-
By("listing pods")
2468-
out := corev1.PodList{}
2469-
Expect(informerCache.List(context.Background(), &out, client.UnsafeDisableDeepCopy)).To(Succeed())
2470-
for _, item := range out.Items {
2471-
if strings.Compare(item.Name, "test-pod-3") == 0 { // test-pod-3 has labels
2472-
item.Labels["UnsafeDisableDeepCopy"] = "true"
2473-
break
2465+
Context("using UnsafeDisableDeepCopy", func() {
2466+
Describe("with ListOptions", func() {
2467+
It("should be able to change object in informer cache", func() {
2468+
By("listing pods")
2469+
out := corev1.PodList{}
2470+
Expect(informerCache.List(context.Background(), &out, client.UnsafeDisableDeepCopy)).To(Succeed())
2471+
for _, item := range out.Items {
2472+
if strings.Compare(item.Name, "test-pod-3") == 0 { // test-pod-3 has labels
2473+
item.Labels["UnsafeDisableDeepCopy"] = "true"
2474+
break
2475+
}
24742476
}
2475-
}
24762477

2477-
By("verifying that the returned pods were changed")
2478-
out2 := corev1.PodList{}
2479-
Expect(informerCache.List(context.Background(), &out, client.UnsafeDisableDeepCopy)).To(Succeed())
2480-
for _, item := range out2.Items {
2481-
if strings.Compare(item.Name, "test-pod-3") == 0 {
2482-
Expect(item.Labels["UnsafeDisableDeepCopy"]).To(Equal("true"))
2483-
break
2478+
By("verifying that the returned pods were changed")
2479+
out2 := corev1.PodList{}
2480+
Expect(informerCache.List(context.Background(), &out, client.UnsafeDisableDeepCopy)).To(Succeed())
2481+
for _, item := range out2.Items {
2482+
if strings.Compare(item.Name, "test-pod-3") == 0 {
2483+
Expect(item.Labels["UnsafeDisableDeepCopy"]).To(Equal("true"))
2484+
break
2485+
}
24842486
}
2485-
}
2487+
})
2488+
})
2489+
Describe("with GetOptions", func() {
2490+
It("should be able to change object in informer cache", func() {
2491+
out := corev1.Pod{}
2492+
podKey := client.ObjectKey{Name: "test-pod-2", Namespace: testNamespaceTwo}
2493+
Expect(informerCache.Get(context.Background(), podKey, &out, client.UnsafeDisableDeepCopy)).To(Succeed())
2494+
2495+
out.Labels["UnsafeDisableDeepCopy"] = "true"
2496+
2497+
By("verifying that the returned pod was changed")
2498+
out2 := corev1.Pod{}
2499+
Expect(informerCache.Get(context.Background(), podKey, &out2, client.UnsafeDisableDeepCopy)).To(Succeed())
2500+
Expect(out2.Labels["UnsafeDisableDeepCopy"]).To(Equal("true"))
2501+
})
24862502
})
24872503
})
24882504
})

pkg/cache/internal/cache_reader.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ type CacheReader struct {
5454
}
5555

5656
// Get checks the indexer for the object and writes a copy of it if found.
57-
func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object, _ ...client.GetOption) error {
57+
func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
58+
getOpts := client.GetOptions{}
59+
getOpts.ApplyOptions(opts)
60+
5861
if c.scopeName == apimeta.RESTScopeNameRoot {
5962
key.Namespace = ""
6063
}
@@ -81,7 +84,7 @@ func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Ob
8184
return fmt.Errorf("cache contained %T, which is not an Object", obj)
8285
}
8386

84-
if c.disableDeepCopy {
87+
if c.disableDeepCopy || (getOpts.UnsafeDisableDeepCopy != nil && *getOpts.UnsafeDisableDeepCopy) {
8588
// skip deep copy which might be unsafe
8689
// you must DeepCopy any object before mutating it outside
8790
} else {
@@ -97,7 +100,7 @@ func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Ob
97100
return fmt.Errorf("cache had type %s, but %s was asked for", objVal.Type(), outVal.Type())
98101
}
99102
reflect.Indirect(outVal).Set(reflect.Indirect(objVal))
100-
if !c.disableDeepCopy {
103+
if !c.disableDeepCopy && (getOpts.UnsafeDisableDeepCopy == nil || !*getOpts.UnsafeDisableDeepCopy) {
101104
out.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
102105
}
103106

pkg/client/options.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,12 @@ type GetOptions struct {
431431
// Raw represents raw GetOptions, as passed to the API server. Note
432432
// that these may not be respected by all implementations of interface.
433433
Raw *metav1.GetOptions
434+
435+
// UnsafeDisableDeepCopy indicates not to deep copy objects during get object.
436+
// Be very careful with this, when enabled you must DeepCopy any object before mutating it,
437+
// otherwise you will mutate the object in the cache.
438+
// +optional
439+
UnsafeDisableDeepCopy *bool
434440
}
435441

436442
var _ GetOption = &GetOptions{}
@@ -440,6 +446,9 @@ func (o *GetOptions) ApplyToGet(lo *GetOptions) {
440446
if o.Raw != nil {
441447
lo.Raw = o.Raw
442448
}
449+
if o.UnsafeDisableDeepCopy != nil {
450+
lo.UnsafeDisableDeepCopy = o.UnsafeDisableDeepCopy
451+
}
443452
}
444453

445454
// AsGetOptions returns these options as a flattened metav1.GetOptions.
@@ -692,6 +701,17 @@ func (l Limit) ApplyToList(opts *ListOptions) {
692701
// otherwise you will mutate the object in the cache.
693702
type UnsafeDisableDeepCopyOption bool
694703

704+
// ApplyToGet applies this configuration to the given an Get options.
705+
func (d UnsafeDisableDeepCopyOption) ApplyToGet(opts *GetOptions) {
706+
definitelyTrue := true
707+
definitelyFalse := false
708+
if d {
709+
opts.UnsafeDisableDeepCopy = &definitelyTrue
710+
} else {
711+
opts.UnsafeDisableDeepCopy = &definitelyFalse
712+
}
713+
}
714+
695715
// ApplyToList applies this configuration to the given an List options.
696716
func (d UnsafeDisableDeepCopyOption) ApplyToList(opts *ListOptions) {
697717
definitelyTrue := true

pkg/client/options_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@ var _ = Describe("ListOptions", func() {
6666
o.ApplyToList(newListOpts)
6767
Expect(newListOpts).To(Equal(o))
6868
})
69+
It("Should set UnsafeDisableDeepCopy", func() {
70+
definitelyTrue := true
71+
o := &client.ListOptions{UnsafeDisableDeepCopy: &definitelyTrue}
72+
newListOpts := &client.ListOptions{}
73+
o.ApplyToList(newListOpts)
74+
Expect(newListOpts).To(Equal(o))
75+
})
76+
It("Should set UnsafeDisableDeepCopy through option", func() {
77+
listOpts := &client.ListOptions{}
78+
client.UnsafeDisableDeepCopy.ApplyToList(listOpts)
79+
Expect(listOpts.UnsafeDisableDeepCopy).ToNot(BeNil())
80+
Expect(*listOpts.UnsafeDisableDeepCopy).To(BeTrue())
81+
})
6982
It("Should not set anything", func() {
7083
o := &client.ListOptions{}
7184
newListOpts := &client.ListOptions{}
@@ -81,6 +94,19 @@ var _ = Describe("GetOptions", func() {
8194
o.ApplyToGet(newGetOpts)
8295
Expect(newGetOpts).To(Equal(o))
8396
})
97+
It("Should set UnsafeDisableDeepCopy", func() {
98+
definitelyTrue := true
99+
o := &client.GetOptions{UnsafeDisableDeepCopy: &definitelyTrue}
100+
newGetOpts := &client.GetOptions{}
101+
o.ApplyToGet(newGetOpts)
102+
Expect(newGetOpts).To(Equal(o))
103+
})
104+
It("Should set UnsafeDisableDeepCopy through option", func() {
105+
getOpts := &client.GetOptions{}
106+
client.UnsafeDisableDeepCopy.ApplyToGet(getOpts)
107+
Expect(getOpts.UnsafeDisableDeepCopy).ToNot(BeNil())
108+
Expect(*getOpts.UnsafeDisableDeepCopy).To(BeTrue())
109+
})
84110
})
85111

86112
var _ = Describe("CreateOptions", func() {

0 commit comments

Comments
 (0)