@@ -17,16 +17,17 @@ limitations under the License.
1717package client
1818
1919import (
20+ "fmt"
2021 "net/http"
2122 "strings"
2223 "sync"
2324
2425 "k8s.io/apimachinery/pkg/api/meta"
25- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626 "k8s.io/apimachinery/pkg/runtime"
2727 "k8s.io/apimachinery/pkg/runtime/schema"
2828 "k8s.io/apimachinery/pkg/runtime/serializer"
2929 "k8s.io/client-go/rest"
30+ "k8s.io/utils/ptr"
3031 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3132)
3233
@@ -56,13 +57,17 @@ type clientRestResources struct {
5657
5758// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource.
5859// If the object is a list, the resource represents the item's type instead.
59- func (c * clientRestResources ) newResource (gvk schema.GroupVersionKind , isList , isUnstructured bool ) (* resourceMeta , error ) {
60+ func (c * clientRestResources ) newResource (gvk schema.GroupVersionKind ,
61+ isList bool ,
62+ forceDisableProtoBuf bool ,
63+ isUnstructured bool ,
64+ ) (* resourceMeta , error ) {
6065 if strings .HasSuffix (gvk .Kind , "List" ) && isList {
6166 // if this was a list, treat it as a request for the item's resource
6267 gvk .Kind = gvk .Kind [:len (gvk .Kind )- 4 ]
6368 }
6469
65- client , err := apiutil .RESTClientForGVK (gvk , isUnstructured , c .config , c .codecs , c .httpClient )
70+ client , err := apiutil .RESTClientForGVK (gvk , forceDisableProtoBuf , isUnstructured , c .config , c .codecs , c .httpClient )
6671 if err != nil {
6772 return nil , err
6873 }
@@ -73,15 +78,44 @@ func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, i
7378 return & resourceMeta {Interface : client , mapping : mapping , gvk : gvk }, nil
7479}
7580
81+ type applyConfiguration interface {
82+ GetName () * string
83+ GetNamespace () * string
84+ GetKind () * string
85+ GetAPIVersion () * string
86+ }
87+
7688// getResource returns the resource meta information for the given type of object.
7789// If the object is a list, the resource represents the item's type instead.
78- func (c * clientRestResources ) getResource (obj runtime.Object ) (* resourceMeta , error ) {
79- gvk , err := apiutil .GVKForObject (obj , c .scheme )
80- if err != nil {
81- return nil , err
90+ func (c * clientRestResources ) getResource (obj any ) (* resourceMeta , error ) {
91+ var gvk schema.GroupVersionKind
92+ var err error
93+ var isApplyConfiguration bool
94+ switch o := obj .(type ) {
95+ case runtime.Object :
96+ gvk , err = apiutil .GVKForObject (o , c .scheme )
97+ if err != nil {
98+ return nil , err
99+ }
100+ case runtime.ApplyConfiguration :
101+ ac , ok := o .(applyConfiguration )
102+ if ! ok {
103+ return nil , fmt .Errorf ("%T is a runtime.ApplyConfiguration but not an applyConfiguration" , o )
104+ }
105+ gv , err := schema .ParseGroupVersion (ptr .Deref (ac .GetAPIVersion (), "" ))
106+ if err != nil {
107+ return nil , fmt .Errorf ("failed to parse %q as GroupVersion: %w" , ptr .Deref (ac .GetAPIVersion (), "" ), err )
108+ }
109+ gvk .Group = gv .Group
110+ gvk .Version = gv .Version
111+ gvk .Kind = ptr .Deref (ac .GetKind (), "" )
112+ isApplyConfiguration = true
113+ default :
114+ return nil , fmt .Errorf ("bug: %T is neither a runtime.Object nor a runtime.ApplyConfiguration" , o )
82115 }
83116
84117 _ , isUnstructured := obj .(runtime.Unstructured )
118+ disableProtoBuf := isUnstructured || isApplyConfiguration
85119
86120 // It's better to do creation work twice than to not let multiple
87121 // people make requests at once
@@ -97,10 +131,15 @@ func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, er
97131 return r , nil
98132 }
99133
134+ var isList bool
135+ if runtimeObject , ok := obj .(runtime.Object ); ok && meta .IsListType (runtimeObject ) {
136+ isList = true
137+ }
138+
100139 // Initialize a new Client
101140 c .mu .Lock ()
102141 defer c .mu .Unlock ()
103- r , err = c .newResource (gvk , meta . IsListType ( obj ) , isUnstructured )
142+ r , err = c .newResource (gvk , isList , disableProtoBuf , isUnstructured )
104143 if err != nil {
105144 return nil , err
106145 }
@@ -109,16 +148,29 @@ func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, er
109148}
110149
111150// getObjMeta returns objMeta containing both type and object metadata and state.
112- func (c * clientRestResources ) getObjMeta (obj runtime. Object ) (* objMeta , error ) {
151+ func (c * clientRestResources ) getObjMeta (obj any ) (* objMeta , error ) {
113152 r , err := c .getResource (obj )
114153 if err != nil {
115154 return nil , err
116155 }
117- m , err := meta .Accessor (obj )
118- if err != nil {
119- return nil , err
156+ objMeta := & objMeta {resourceMeta : r }
157+
158+ switch o := obj .(type ) {
159+ case runtime.Object :
160+ m , err := meta .Accessor (obj )
161+ if err != nil {
162+ return nil , err
163+ }
164+ objMeta .namespace = m .GetNamespace ()
165+ objMeta .name = m .GetName ()
166+ case applyConfiguration :
167+ objMeta .namespace = ptr .Deref (o .GetNamespace (), "" )
168+ objMeta .name = ptr .Deref (o .GetName (), "" )
169+ default :
170+ return nil , fmt .Errorf ("object %T is neither a runtime.Object nor a runtime.ApplyConfiguration" , obj )
120171 }
121- return & objMeta {resourceMeta : r , Object : m }, err
172+
173+ return objMeta , nil
122174}
123175
124176// resourceMeta stores state for a Kubernetes type.
@@ -146,6 +198,6 @@ type objMeta struct {
146198 // resourceMeta contains type information for the object
147199 * resourceMeta
148200
149- // Object contains meta data for the object instance
150- metav1. Object
201+ namespace string
202+ name string
151203}
0 commit comments