@@ -212,6 +212,87 @@ func (wh *Webhook) allocateDstObject(apiVersion, kind string) (runtime.Object, e
212
212
return obj , nil
213
213
}
214
214
215
+ // CheckConvertibility determines if given type is convertible or not. For a type
216
+ // to be convertible, the group-kind needs to have a Hub type defined and all
217
+ // non-hub types must be able to convert to/from Hub.
218
+ func CheckConvertibility (scheme * runtime.Scheme , obj runtime.Object ) error {
219
+ var hubs , spokes , nonSpokes []runtime.Object
220
+
221
+ gvks , _ , err := scheme .ObjectKinds (obj )
222
+ if err != nil {
223
+ return fmt .Errorf ("error retriving object kinds for given object : %v" , err )
224
+ }
225
+
226
+ for _ , gvk := range gvks {
227
+ instance , err := scheme .New (gvk )
228
+ if err != nil {
229
+ return fmt .Errorf ("failed to allocate an instance for gvk %v %v" , gvk , err )
230
+ }
231
+
232
+ if isHub (instance ) {
233
+ hubs = append (hubs , instance )
234
+ continue
235
+ }
236
+
237
+ if ! isConvertible (instance ) {
238
+ nonSpokes = append (nonSpokes , instance )
239
+ continue
240
+ }
241
+
242
+ spokes = append (spokes , instance )
243
+ }
244
+
245
+ if len (gvks ) == 1 {
246
+ return nil // single version
247
+ }
248
+
249
+ if len (hubs ) == 0 && len (spokes ) == 0 {
250
+ // multiple version detected with no conversion implementation. This is
251
+ // true for multi-version built-in types.
252
+ return nil
253
+ }
254
+
255
+ if len (hubs ) == 1 && len (nonSpokes ) == 0 { // convertible
256
+ spokeVersions := []string {}
257
+ for _ , sp := range spokes {
258
+ spokeVersions = append (spokeVersions , sp .GetObjectKind ().GroupVersionKind ().String ())
259
+ }
260
+ log .V (1 ).Info ("conversion enabled for kind" , "kind" ,
261
+ gvks [0 ].GroupKind (), "hub" , hubs [0 ], "spokes" , spokeVersions )
262
+ return nil
263
+ }
264
+
265
+ return PartialImplementationError {
266
+ hubs : hubs ,
267
+ nonSpokes : nonSpokes ,
268
+ spokes : spokes ,
269
+ }
270
+ }
271
+
272
+ // PartialImplementationError represents an error due to partial conversion
273
+ // implementation such as hub without spokes, multiple hubs or spokes without hub.
274
+ type PartialImplementationError struct {
275
+ gvk schema.GroupVersionKind
276
+ hubs []runtime.Object
277
+ nonSpokes []runtime.Object
278
+ spokes []runtime.Object
279
+ }
280
+
281
+ func (e PartialImplementationError ) Error () string {
282
+ if len (e .hubs ) == 0 {
283
+ return fmt .Sprintf ("no hub defined for gvk %s" , e .gvk )
284
+ }
285
+ if len (e .hubs ) > 1 {
286
+ return fmt .Sprintf ("multiple(%d) hubs defined for group-kind '%s' " ,
287
+ len (e .hubs ), e .gvk .GroupKind ())
288
+ }
289
+ if len (e .nonSpokes ) > 0 {
290
+ return fmt .Sprintf ("%d inconvertible types detected for group-kind '%s'" ,
291
+ len (e .nonSpokes ), e .gvk .GroupKind ())
292
+ }
293
+ return ""
294
+ }
295
+
215
296
// isHub determines if passed-in object is a Hub or not.
216
297
func isHub (obj runtime.Object ) bool {
217
298
_ , yes := obj .(conversion.Hub )
0 commit comments