schemars icon indicating copy to clipboard operation
schemars copied to clipboard

support for k8s "structural" schemas

Open cassandracomar opened this issue 4 years ago • 2 comments
trafficstars

docs: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema

currently, schemars generates schemas that are rejected as non-structural for complex enumerations of the type:

enum MyType {
    Variant1(Variant1),
    Variant2(Variant2),
...
    VariantN(VariantN),
}

where Variant1, Variant2, ..., VariantN are themselves structs. as this is a common pattern to lift enumeration variants into the rust type system, this happens all over the place in idiomatic rust code. moreover, the structs generated by the k8s-openapi crate necessarily produces complex enums of this sort in the process of translating the k8s api types.

there may also be other kinds of structs that produce non-structural schemas and I'll document them here as I find them.

I'm happy to take on implementation of a fix for this issue if I can get some direction on how best to do so. is a crate-level feature a suitable way to toggle how enums are handled? this makes the update to k8s-openapi more straightforward but I notice that most features of this sort are handled as per-type macro arguments, currently.

cassandracomar avatar May 24 '21 19:05 cassandracomar

More concretely, this is because schemars currently serializes enums as:

properties:
  enum:
    oneOf:
      - type: object
      - properties:
          variantOne:
            # properties...
          required: [variantOne]
      - type: object
        properties:
          variantTwo:
            # properties...
        required: [variantTwo]

Kubernetes doesn't allow the structure to depend on which variant is selected, so it instead requires all variants to be declared up-front, with oneOf used to select which variant is active. That would look like this instead:

properties:
  enum:
    type: object
    properties:
      variantOne:
        # properties...
      variantTwo:
        # properties...
    oneOf:
      - required: [variantOne]
      - required: [variantTwo]

It shouldn't be too difficult to implement, but AFAIK it doesn't accomodate cases where multiple variants share the same tag (with #[serde(rename)]), or untagged variants (or at least those would both be messier to support...). Thus, I'd propose that this be opt-in in some form, either by adding a #[schemars] attribute, or by a toggle in SchemaSettings.

nightkr avatar Jan 13 '22 10:01 nightkr

FWIW I ended up implementing this in kube-rs as a schemars Visitor: https://github.com/kube-rs/kube-rs/pull/779.

nightkr avatar Jan 13 '22 16:01 nightkr