Skip to content

Commit 91f642b

Browse files
authored
Merge pull request #2633 from alvaroaleman/pointer
⚠️ Fakeclient: Only set TypeMeta for unstructured
2 parents 7f316f1 + f6052ab commit 91f642b

File tree

2 files changed

+228
-44
lines changed

2 files changed

+228
-44
lines changed

pkg/client/fake/client.go

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,12 @@ func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Ob
334334
// tries to assign whatever it finds into a ListType it gets from schema.New() - Thus we have to ensure
335335
// we save as the very same type, otherwise subsequent List requests will fail.
336336
func convertFromUnstructuredIfNecessary(s *runtime.Scheme, o runtime.Object) (runtime.Object, error) {
337-
gvk := o.GetObjectKind().GroupVersionKind()
338-
339337
u, isUnstructured := o.(runtime.Unstructured)
340-
if !isUnstructured || !s.Recognizes(gvk) {
338+
if !isUnstructured {
339+
return o, nil
340+
}
341+
gvk := o.GetObjectKind().GroupVersionKind()
342+
if !s.Recognizes(gvk) {
341343
return o, nil
342344
}
343345

@@ -380,12 +382,9 @@ func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Ob
380382
field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")})
381383
}
382384

383-
gvk := obj.GetObjectKind().GroupVersionKind()
384-
if gvk.Empty() {
385-
gvk, err = apiutil.GVKForObject(obj, t.scheme)
386-
if err != nil {
387-
return err
388-
}
385+
gvk, err := apiutil.GVKForObject(obj, t.scheme)
386+
if err != nil {
387+
return err
389388
}
390389

391390
oldObject, err := t.ObjectTracker.Get(gvr, ns, accessor.GetName())
@@ -464,25 +463,25 @@ func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.O
464463
return err
465464
}
466465

467-
gvk, err := apiutil.GVKForObject(obj, c.scheme)
468-
if err != nil {
469-
return err
470-
}
471-
ta, err := meta.TypeAccessor(o)
472-
if err != nil {
473-
return err
466+
if _, isUnstructured := obj.(runtime.Unstructured); isUnstructured {
467+
gvk, err := apiutil.GVKForObject(obj, c.scheme)
468+
if err != nil {
469+
return err
470+
}
471+
ta, err := meta.TypeAccessor(o)
472+
if err != nil {
473+
return err
474+
}
475+
ta.SetKind(gvk.Kind)
476+
ta.SetAPIVersion(gvk.GroupVersion().String())
474477
}
475-
ta.SetKind(gvk.Kind)
476-
ta.SetAPIVersion(gvk.GroupVersion().String())
477478

478479
j, err := json.Marshal(o)
479480
if err != nil {
480481
return err
481482
}
482-
decoder := scheme.Codecs.UniversalDecoder()
483483
zero(obj)
484-
_, _, err = decoder.Decode(j, nil, obj)
485-
return err
484+
return json.Unmarshal(j, obj)
486485
}
487486

488487
func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
@@ -527,21 +526,21 @@ func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...cl
527526
return err
528527
}
529528

530-
ta, err := meta.TypeAccessor(o)
531-
if err != nil {
532-
return err
529+
if _, isUnstructured := obj.(runtime.Unstructured); isUnstructured {
530+
ta, err := meta.TypeAccessor(o)
531+
if err != nil {
532+
return err
533+
}
534+
ta.SetKind(originalKind)
535+
ta.SetAPIVersion(gvk.GroupVersion().String())
533536
}
534-
ta.SetKind(originalKind)
535-
ta.SetAPIVersion(gvk.GroupVersion().String())
536537

537538
j, err := json.Marshal(o)
538539
if err != nil {
539540
return err
540541
}
541-
decoder := scheme.Codecs.UniversalDecoder()
542542
zero(obj)
543-
_, _, err = decoder.Decode(j, nil, obj)
544-
if err != nil {
543+
if err := json.Unmarshal(j, obj); err != nil {
545544
return err
546545
}
547546

@@ -869,21 +868,22 @@ func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client
869868
if !handled {
870869
panic("tracker could not handle patch method")
871870
}
872-
ta, err := meta.TypeAccessor(o)
873-
if err != nil {
874-
return err
871+
872+
if _, isUnstructured := obj.(runtime.Unstructured); isUnstructured {
873+
ta, err := meta.TypeAccessor(o)
874+
if err != nil {
875+
return err
876+
}
877+
ta.SetKind(gvk.Kind)
878+
ta.SetAPIVersion(gvk.GroupVersion().String())
875879
}
876-
ta.SetKind(gvk.Kind)
877-
ta.SetAPIVersion(gvk.GroupVersion().String())
878880

879881
j, err := json.Marshal(o)
880882
if err != nil {
881883
return err
882884
}
883-
decoder := scheme.Codecs.UniversalDecoder()
884885
zero(obj)
885-
_, _, err = decoder.Decode(j, nil, obj)
886-
return err
886+
return json.Unmarshal(j, obj)
887887
}
888888

889889
// Applying a patch results in a deletionTimestamp that is truncated to the nearest second.

pkg/client/fake/client_test.go

Lines changed: 191 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ import (
3737
"k8s.io/apimachinery/pkg/fields"
3838
"k8s.io/apimachinery/pkg/labels"
3939
"k8s.io/apimachinery/pkg/runtime"
40+
"k8s.io/apimachinery/pkg/runtime/schema"
4041
"k8s.io/apimachinery/pkg/types"
4142
"k8s.io/apimachinery/pkg/watch"
4243
"k8s.io/client-go/kubernetes/fake"
4344
"k8s.io/utils/ptr"
4445

4546
"sigs.k8s.io/controller-runtime/pkg/client"
4647
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
48+
"sigs.k8s.io/controller-runtime/pkg/scheme"
4749
)
4850

4951
const (
@@ -1354,10 +1356,6 @@ var _ = Describe("Fake client", func() {
13541356
Expect(cl.Get(context.Background(), types.NamespacedName{Name: "cm"}, retrieved)).To(Succeed())
13551357

13561358
reference := &corev1.Secret{
1357-
TypeMeta: metav1.TypeMeta{
1358-
APIVersion: "v1",
1359-
Kind: "Secret",
1360-
},
13611359
ObjectMeta: metav1.ObjectMeta{
13621360
Name: "cm",
13631361
ResourceVersion: "999",
@@ -1771,8 +1769,6 @@ var _ = Describe("Fake client", func() {
17711769

17721770
actual := &corev1.Pod{}
17731771
Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(obj), actual)).To(Succeed())
1774-
obj.APIVersion = "v1"
1775-
obj.Kind = "Pod"
17761772
obj.ResourceVersion = actual.ResourceVersion
17771773
// only the status mutation should persist
17781774
obj.Status.Phase = corev1.PodRunning
@@ -1877,13 +1873,201 @@ var _ = Describe("Fake client", func() {
18771873
}
18781874

18791875
It("should error when creating an eviction with the wrong type", func() {
1880-
18811876
cl := NewClientBuilder().Build()
18821877
err := cl.SubResource("eviction").Create(context.Background(), &corev1.Pod{}, &corev1.Namespace{})
18831878
Expect(apierrors.IsBadRequest(err)).To(BeTrue())
18841879
})
1880+
1881+
It("should leave typemeta empty on typed get", func() {
1882+
cl := NewClientBuilder().WithObjects(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{
1883+
Namespace: "default",
1884+
Name: "foo",
1885+
}}).Build()
1886+
1887+
var pod corev1.Pod
1888+
Expect(cl.Get(context.Background(), client.ObjectKey{Namespace: "default", Name: "foo"}, &pod)).NotTo(HaveOccurred())
1889+
1890+
Expect(pod.TypeMeta).To(Equal(metav1.TypeMeta{}))
1891+
})
1892+
1893+
It("should leave typemeta empty on typed list", func() {
1894+
cl := NewClientBuilder().WithObjects(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{
1895+
Namespace: "default",
1896+
Name: "foo",
1897+
}}).Build()
1898+
1899+
var podList corev1.PodList
1900+
Expect(cl.List(context.Background(), &podList)).NotTo(HaveOccurred())
1901+
Expect(podList.ListMeta).To(Equal(metav1.ListMeta{}))
1902+
Expect(podList.Items[0].TypeMeta).To(Equal(metav1.TypeMeta{}))
1903+
})
1904+
1905+
It("should be able to Get an object that has pointer fields for metadata", func() {
1906+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
1907+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
1908+
scheme := runtime.NewScheme()
1909+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
1910+
1911+
cl := NewClientBuilder().
1912+
WithScheme(scheme).
1913+
WithObjects(&WithPointerMeta{ObjectMeta: &metav1.ObjectMeta{
1914+
Name: "foo",
1915+
}}).
1916+
Build()
1917+
1918+
var object WithPointerMeta
1919+
Expect(cl.Get(context.Background(), client.ObjectKey{Name: "foo"}, &object)).NotTo(HaveOccurred())
1920+
})
1921+
1922+
It("should be able to List an object type that has pointer fields for metadata", func() {
1923+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
1924+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
1925+
scheme := runtime.NewScheme()
1926+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
1927+
1928+
cl := NewClientBuilder().
1929+
WithScheme(scheme).
1930+
WithObjects(&WithPointerMeta{ObjectMeta: &metav1.ObjectMeta{
1931+
Name: "foo",
1932+
}}).
1933+
Build()
1934+
1935+
var objectList WithPointerMetaList
1936+
Expect(cl.List(context.Background(), &objectList)).NotTo(HaveOccurred())
1937+
Expect(objectList.Items).To(HaveLen(1))
1938+
})
1939+
1940+
It("should be able to List an object type that has pointer fields for metadata with no results", func() {
1941+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
1942+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
1943+
scheme := runtime.NewScheme()
1944+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
1945+
1946+
cl := NewClientBuilder().
1947+
WithScheme(scheme).
1948+
Build()
1949+
1950+
var objectList WithPointerMetaList
1951+
Expect(cl.List(context.Background(), &objectList)).NotTo(HaveOccurred())
1952+
Expect(objectList.Items).To(BeEmpty())
1953+
})
1954+
1955+
It("should be able to Patch an object type that has pointer fields for metadata", func() {
1956+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
1957+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
1958+
scheme := runtime.NewScheme()
1959+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
1960+
1961+
obj := &WithPointerMeta{ObjectMeta: &metav1.ObjectMeta{
1962+
Name: "foo",
1963+
}}
1964+
cl := NewClientBuilder().
1965+
WithScheme(scheme).
1966+
WithObjects(obj).
1967+
Build()
1968+
1969+
original := obj.DeepCopy()
1970+
obj.Labels = map[string]string{"foo": "bar"}
1971+
Expect(cl.Patch(context.Background(), obj, client.MergeFrom(original))).NotTo(HaveOccurred())
1972+
1973+
Expect(cl.Get(context.Background(), client.ObjectKey{Name: "foo"}, obj)).NotTo(HaveOccurred())
1974+
Expect(obj.Labels).To(Equal(map[string]string{"foo": "bar"}))
1975+
})
1976+
1977+
It("should be able to Update an object type that has pointer fields for metadata", func() {
1978+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
1979+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
1980+
scheme := runtime.NewScheme()
1981+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
1982+
1983+
obj := &WithPointerMeta{ObjectMeta: &metav1.ObjectMeta{
1984+
Name: "foo",
1985+
}}
1986+
cl := NewClientBuilder().
1987+
WithScheme(scheme).
1988+
WithObjects(obj).
1989+
Build()
1990+
1991+
Expect(cl.Get(context.Background(), client.ObjectKey{Name: "foo"}, obj)).NotTo(HaveOccurred())
1992+
1993+
obj.Labels = map[string]string{"foo": "bar"}
1994+
Expect(cl.Update(context.Background(), obj)).NotTo(HaveOccurred())
1995+
1996+
Expect(cl.Get(context.Background(), client.ObjectKey{Name: "foo"}, obj)).NotTo(HaveOccurred())
1997+
Expect(obj.Labels).To(Equal(map[string]string{"foo": "bar"}))
1998+
})
1999+
2000+
It("should be able to Delete an object type that has pointer fields for metadata", func() {
2001+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
2002+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
2003+
scheme := runtime.NewScheme()
2004+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
2005+
2006+
obj := &WithPointerMeta{ObjectMeta: &metav1.ObjectMeta{
2007+
Name: "foo",
2008+
}}
2009+
cl := NewClientBuilder().
2010+
WithScheme(scheme).
2011+
WithObjects(obj).
2012+
Build()
2013+
2014+
Expect(cl.Delete(context.Background(), obj)).NotTo(HaveOccurred())
2015+
2016+
err := cl.Get(context.Background(), client.ObjectKey{Name: "foo"}, obj)
2017+
Expect(apierrors.IsNotFound(err)).To(BeTrue())
2018+
})
18852019
})
18862020

2021+
type WithPointerMetaList struct {
2022+
*metav1.ListMeta
2023+
*metav1.TypeMeta
2024+
Items []*WithPointerMeta
2025+
}
2026+
2027+
func (t *WithPointerMetaList) DeepCopy() *WithPointerMetaList {
2028+
l := &WithPointerMetaList{
2029+
ListMeta: t.ListMeta.DeepCopy(),
2030+
}
2031+
if t.TypeMeta != nil {
2032+
l.TypeMeta = &metav1.TypeMeta{
2033+
APIVersion: t.APIVersion,
2034+
Kind: t.Kind,
2035+
}
2036+
}
2037+
for _, item := range t.Items {
2038+
l.Items = append(l.Items, item.DeepCopy())
2039+
}
2040+
2041+
return l
2042+
}
2043+
2044+
func (t *WithPointerMetaList) DeepCopyObject() runtime.Object {
2045+
return t.DeepCopy()
2046+
}
2047+
2048+
type WithPointerMeta struct {
2049+
*metav1.TypeMeta
2050+
*metav1.ObjectMeta
2051+
}
2052+
2053+
func (t *WithPointerMeta) DeepCopy() *WithPointerMeta {
2054+
w := &WithPointerMeta{
2055+
ObjectMeta: t.ObjectMeta.DeepCopy(),
2056+
}
2057+
if t.TypeMeta != nil {
2058+
w.TypeMeta = &metav1.TypeMeta{
2059+
APIVersion: t.APIVersion,
2060+
Kind: t.Kind,
2061+
}
2062+
}
2063+
2064+
return w
2065+
}
2066+
2067+
func (t *WithPointerMeta) DeepCopyObject() runtime.Object {
2068+
return t.DeepCopy()
2069+
}
2070+
18872071
var _ = Describe("Fake client builder", func() {
18882072
It("panics when an index with the same name and GroupVersionKind is registered twice", func() {
18892073
// We need any realistic GroupVersionKind, the choice of apps/v1 Deployment is arbitrary.

0 commit comments

Comments
 (0)