@@ -273,6 +273,15 @@ impl Transform for StructuralSchemaRewriter {
273273 // Untagged enums are serialized using `any_of`
274274 hoist_subschema_properties ( any_of, & mut schema. object , & mut schema. instance_type ) ;
275275 }
276+
277+ // FIXME: hack for https://github.com/kube-rs/kube/issues/1821
278+ if let Some ( any_of) = & mut subschemas. any_of {
279+ if let Some ( new_schema) = optional_enum_flatten_hack ( any_of) {
280+ let metadata = schema. metadata ;
281+ schema = new_schema. clone ( ) ;
282+ schema. metadata = metadata;
283+ }
284+ }
276285 }
277286
278287 // check for maps without with properties (i.e. flattened maps)
@@ -424,3 +433,69 @@ fn merge_metadata(
424433 }
425434 }
426435}
436+
437+ /// In kube 2.x the schema output behavior for `Option<Enum>` types changed.
438+ ///
439+ /// Previously given an enum like:
440+ ///
441+ /// ```rust
442+ /// enum LogLevel {
443+ /// Debug,
444+ /// Info,
445+ /// Error,
446+ /// }
447+ /// ```
448+ ///
449+ /// The following would be generated for Optional<LogLevel>:
450+ ///
451+ /// ```json
452+ /// { "enum": ["Debug", "Info", "Error"], "type": "string", "nullable": true }
453+ /// ```
454+ ///
455+ /// Now, schemars generates `anyOf` for `Option<LogLevel>` like:
456+ ///
457+ /// ```json
458+ /// {
459+ /// "anyOf": [
460+ /// { "enum": ["Debug", "Info", "Error"], "type": "string" },
461+ /// { "enum": [null], "nullable": true }
462+ /// ]
463+ /// }
464+ /// ```
465+ ///
466+ /// This is breaking, as Kubernetes validation will reject this structure. This
467+ /// issue was reported in:
468+ ///
469+ /// https://github.com/kube-rs/kube/issues/1821
470+ ///
471+ /// This hack does a precise check for this "empty" second enum that would
472+ /// break validation, and removes it, flattening the schema object.
473+ ///
474+ /// FIXME: This should be removed once the problem is properly resolved.
475+ fn optional_enum_flatten_hack ( any_of : & mut Vec < Schema > ) -> Option < & SchemaObject > {
476+ if let [
477+ Schema :: Object ( obj) ,
478+ Schema :: Object ( SchemaObject {
479+ enum_values : Some ( null_enum) ,
480+ metadata : None ,
481+ instance_type : None ,
482+ format : None ,
483+ subschemas : None ,
484+ array : None ,
485+ object : None ,
486+ extensions,
487+ other : Value :: Object ( other) ,
488+ } ) ,
489+ ] = any_of. as_mut_slice ( )
490+ && null_enum. as_slice ( ) == [ Value :: Null ]
491+ && extensions. len ( ) == 1
492+ && extensions. get ( "nullable" ) == Some ( & Value :: Bool ( true ) )
493+ && other. len ( ) == 1
494+ && other. get ( "nullable" ) == Some ( & Value :: Bool ( true ) )
495+ {
496+ obj. extensions . insert ( "nullable" . into ( ) , Value :: Bool ( true ) ) ;
497+ return Some ( obj) ;
498+ }
499+
500+ None
501+ }
0 commit comments