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