@@ -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,41 @@ 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+ gvk , err = gvkFromApplyConfiguration (ac )
106+ if err != nil {
107+ return nil , err
108+ }
109+ isApplyConfiguration = true
110+ default :
111+ return nil , fmt .Errorf ("bug: %T is neither a runtime.Object nor a runtime.ApplyConfiguration" , o )
82112 }
83113
84114 _ , isUnstructured := obj .(runtime.Unstructured )
115+ forceDisableProtoBuf := isUnstructured || isApplyConfiguration
85116
86117 // It's better to do creation work twice than to not let multiple
87118 // people make requests at once
@@ -97,10 +128,15 @@ func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, er
97128 return r , nil
98129 }
99130
131+ var isList bool
132+ if runtimeObject , ok := obj .(runtime.Object ); ok && meta .IsListType (runtimeObject ) {
133+ isList = true
134+ }
135+
100136 // Initialize a new Client
101137 c .mu .Lock ()
102138 defer c .mu .Unlock ()
103- r , err = c .newResource (gvk , meta . IsListType ( obj ) , isUnstructured )
139+ r , err = c .newResource (gvk , isList , forceDisableProtoBuf , isUnstructured )
104140 if err != nil {
105141 return nil , err
106142 }
@@ -109,16 +145,29 @@ func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, er
109145}
110146
111147// getObjMeta returns objMeta containing both type and object metadata and state.
112- func (c * clientRestResources ) getObjMeta (obj runtime. Object ) (* objMeta , error ) {
148+ func (c * clientRestResources ) getObjMeta (obj any ) (* objMeta , error ) {
113149 r , err := c .getResource (obj )
114150 if err != nil {
115151 return nil , err
116152 }
117- m , err := meta .Accessor (obj )
118- if err != nil {
119- return nil , err
153+ objMeta := & objMeta {resourceMeta : r }
154+
155+ switch o := obj .(type ) {
156+ case runtime.Object :
157+ m , err := meta .Accessor (obj )
158+ if err != nil {
159+ return nil , err
160+ }
161+ objMeta .namespace = m .GetNamespace ()
162+ objMeta .name = m .GetName ()
163+ case applyConfiguration :
164+ objMeta .namespace = ptr .Deref (o .GetNamespace (), "" )
165+ objMeta .name = ptr .Deref (o .GetName (), "" )
166+ default :
167+ return nil , fmt .Errorf ("object %T is neither a runtime.Object nor a runtime.ApplyConfiguration" , obj )
120168 }
121- return & objMeta {resourceMeta : r , Object : m }, err
169+
170+ return objMeta , nil
122171}
123172
124173// resourceMeta stores state for a Kubernetes type.
@@ -146,6 +195,6 @@ type objMeta struct {
146195 // resourceMeta contains type information for the object
147196 * resourceMeta
148197
149- // Object contains meta data for the object instance
150- metav1. Object
198+ namespace string
199+ name string
151200}
0 commit comments