@@ -169,6 +169,11 @@ func (t versionedTracker) Add(obj runtime.Object) error {
169
169
// be recognized
170
170
accessor .SetResourceVersion (trackerAddResourceVersion )
171
171
}
172
+
173
+ obj , err = convertFromUnstructuredIfNecessary (t .scheme , obj )
174
+ if err != nil {
175
+ return err
176
+ }
172
177
if err := t .ObjectTracker .Add (obj ); err != nil {
173
178
return err
174
179
}
@@ -192,13 +197,45 @@ func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Ob
192
197
return apierrors .NewBadRequest ("resourceVersion can not be set for Create requests" )
193
198
}
194
199
accessor .SetResourceVersion ("1" )
200
+ obj , err = convertFromUnstructuredIfNecessary (t .scheme , obj )
201
+ if err != nil {
202
+ return err
203
+ }
195
204
if err := t .ObjectTracker .Create (gvr , obj , ns ); err != nil {
196
205
accessor .SetResourceVersion ("" )
197
206
return err
198
207
}
208
+
199
209
return nil
200
210
}
201
211
212
+ // convertFromUnstructuredIfNecessary will convert *unstructured.Unstructured for a GVK that is recocnized
213
+ // by the schema into the whatever the schema produces with New() for said GVK.
214
+ // This is required because the tracker unconditionally saves on manipulations, but it's List() implementation
215
+ // tries to assign whatever it finds into a ListType it gets from schema.New() - Thus we have to ensure
216
+ // we save as the very same type, otherwise subsequent List requests will fail.
217
+ func convertFromUnstructuredIfNecessary (s * runtime.Scheme , o runtime.Object ) (runtime.Object , error ) {
218
+ u , isUnstructured := o .(* unstructured.Unstructured )
219
+ if ! isUnstructured || ! s .Recognizes (u .GroupVersionKind ()) {
220
+ return o , nil
221
+ }
222
+
223
+ typed , err := s .New (u .GroupVersionKind ())
224
+ if err != nil {
225
+ return nil , fmt .Errorf ("scheme recognizes %s but failed to produce an object for it: %w" , u .GroupVersionKind ().String (), err )
226
+ }
227
+
228
+ unstructuredSerialized , err := json .Marshal (u )
229
+ if err != nil {
230
+ return nil , fmt .Errorf ("failed to serialize %T: %w" , unstructuredSerialized , err )
231
+ }
232
+ if err := json .Unmarshal (unstructuredSerialized , typed ); err != nil {
233
+ return nil , fmt .Errorf ("failed to unmarshal the content of %T into %T: %w" , u , typed , err )
234
+ }
235
+
236
+ return typed , nil
237
+ }
238
+
202
239
func (t versionedTracker ) Update (gvr schema.GroupVersionResource , obj runtime.Object , ns string ) error {
203
240
accessor , err := meta .Accessor (obj )
204
241
if err != nil {
@@ -255,6 +292,10 @@ func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Ob
255
292
if ! accessor .GetDeletionTimestamp ().IsZero () && len (accessor .GetFinalizers ()) == 0 {
256
293
return t .ObjectTracker .Delete (gvr , accessor .GetNamespace (), accessor .GetName ())
257
294
}
295
+ obj , err = convertFromUnstructuredIfNecessary (t .scheme , obj )
296
+ if err != nil {
297
+ return err
298
+ }
258
299
return t .ObjectTracker .Update (gvr , obj , ns )
259
300
}
260
301
@@ -318,7 +359,7 @@ func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...cl
318
359
}
319
360
320
361
if _ , isUnstructuredList := obj .(* unstructured.UnstructuredList ); isUnstructuredList && ! c .scheme .Recognizes (gvk ) {
321
- // We need tor register the ListKind with UnstructuredList:
362
+ // We need to register the ListKind with UnstructuredList:
322
363
// https://github.com/kubernetes/kubernetes/blob/7b2776b89fb1be28d4e9203bdeec079be903c103/staging/src/k8s.io/client-go/dynamic/fake/simple.go#L44-L51
323
364
c .schemeWriteLock .Lock ()
324
365
c .scheme .AddKnownTypeWithName (gvk .GroupVersion ().WithKind (gvk .Kind + "List" ), & unstructured.UnstructuredList {})
0 commit comments