OpenAPI, JSON Schema and int-to-string issue

41 views
Skip to first unread message

Gareth Rushgrove

unread,
Jul 2, 2017, 9:28:59 AM7/2/17
to kubernetes-sig...@googlegroups.com, kubernete...@googlegroups.com
Hi all

Hopefully this is the right place to post this. If not please let me
know. If a GitHub issue is preferred just let me know and I'll open.


I've recently been playing with extracting the type definitions from
the Kubernetes OpenAPI description, and published individual schemas
for the types. You can see these published here:

https://github.com/garethr/kubernetes-json-schema

The intention is for these schemas to be used in other tools, I'm
particularly interested in developer tooling. Kubeval
(https://github.com/garethr/kubeval) is a simple example, but we've
talked about Helm validation, support in editors, ksonnet validation
and more in a few forums. For more background see
https://www.morethanseven.net/2017/06/26/schemas-for-kubernetes-types/.

In doing this I hit an issue with how Kubernetes uses OpenAPI/JSON
Schema which I'd love to get some thoughts on, in particular the
"int-or-string" format.

Here's a quick example from the Service API:
https://github.com/garethr/kubernetes-json-schema/blob/master/master-standalone/service.json#L108-L111

If you use the above JSON Schema (which is the same as the data from
the full description at
https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json)
to validate a service description which uses a target port specified
as an integer it will fail using standard jsonschema libraries:

https://github.com/garethr/kubeval/blob/int-or-string/fixtures/int_or_string.yaml

This is because it fails the type check (ie. it's not a string, it's a
JSON number).

The OpenAPI spec says:

"Primitive data types in the Swagger Specification are based on the
types supported by the JSON-Schema Draft 4."

(those are listed here for reference:
https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5)

and also says:

"Primitives have an optional modifier property format. Swagger uses
several known formats to more finely define the data type being used."

and

"However, the format property is an open string-valued property, and
can have any value to support documentation needs"

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types


So, my reading of this is that format is intended to "more finely
define the data type". In the case of int-or-string it's actually
being used to broaden the data types accepted, ie. from it being a
string to it being an integer or a string.

This doesn't invalidate the OpenAPI document because format "can have
any value". But the intention in that case is to "support
documentation". In the case of int-or-string this isn't documentation,
it's parsing rules.


The current usage of int-or-string is unfortunately incompatible with
using standard JSON Schema tooling with the same data.

It could also be argued that the usage of OpenAPI here is incorrect,
even if the Kubernetes OpenAPI description is technically valid.

Note that OpenAPI does have a documented mechanism for vendor
extensions, so it might be possible to see this as a new type, ie.
x-int-or-string, rather than a string with a formatting instruction.

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#vendorExtensions

JSON Schema also supports extensions so these could be passed down to
relevant tooling I think.
http://json-schema.org/latest/json-schema-core.html#rfc.section.6.4

(Sidenote: "Implementations SHOULD ignore keywords they do not
support", which I think would mean x-* types should *just work* with
most clients. In practice I know at least the Go client doesn't do
this, but I'd argue that's a bug in the client.)

I'd be interested in someone sense checking the above. It's a twisty
maze of nested specs and producer and consumer behaviour.

If the above is right, I'd be interested in how it might be possible
to fix it. I think usage of the type definitions in higher-level tools
opens up a bunch of possibilities (see the post above or the brief
conversation at SIG Apps a few weeks back).

Thanks

Gareth

--
Gareth Rushgrove
@garethr

devopsweekly.com
morethanseven.net
garethrushgrove.com

Mehdy Bohlool

unread,
Jul 2, 2017, 10:17:21 AM7/2/17
to Gareth Rushgrove, K8s API Machinery SIG, kubernetes-sig-apps
Hi Gareth,

Thanks for starting (or rather re-igniting) this discussion. int-or-string was a long problem of our Spec and last time we visited it, we couldn't find a good solution for it. With some recent changes in OpenAPI spec, these are solutions comes to my mind:

1- Use `OneOf` feature of OpenAPI 3.0 spec (OpenAPI 3.0 has limited tooling support yet).
2- Support string for everything in Kubernetes (right now a port number 80, for example, should be integer and it cannot be "80"). Kubernetes can try to convert string to integer and use it. This way, at least we have a workaround but this could be a backward incompatible change so we need to be careful here.

I think what you are suggesting is an extension type "x-int-or-string" instead of "string"? That is not allowed according to the spec (here, here). If I did not understand your suggestion correctly, please elaborate.

Best,
Mehdy

--
You received this message because you are subscribed to the Google Groups "K8s API Machinery SIG" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kubernetes-sig-api-machinery+unsubs...@googlegroups.com.
To post to this group, send email to kubernetes-sig-api-machinery@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kubernetes-sig-api-machinery/CAFi_6yKt4dMQEPvbx_J%2B_kzK_QwSphKkaUgO7ZC7TWFfj8s70A%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Gareth Rushgrove

unread,
Jul 2, 2017, 1:27:57 PM7/2/17
to Mehdy Bohlool, K8s API Machinery SIG, kubernetes-sig-apps
On 2 July 2017 at 15:16, Mehdy Bohlool <me...@google.com> wrote:
> Hi Gareth,
>
> Thanks for starting (or rather re-igniting) this discussion. int-or-string
> was a long problem of our Spec and last time we visited it, we couldn't find
> a good solution for it. With some recent changes in OpenAPI spec, these are
> solutions comes to my mind:
>
> 1- Use `OneOf` feature of OpenAPI 3.0 spec (OpenAPI 3.0 has limited tooling
> support yet).
> 2- Support string for everything in Kubernetes (right now a port number 80,
> for example, should be integer and it cannot be "80"). Kubernetes can try to
> convert string to integer and use it. This way, at least we have a
> workaround but this could be a backward incompatible change so we need to be
> careful here.
>
> I think what you are suggesting is an extension type "x-int-or-string"
> instead of "string"? That is not allowed according to the spec (here, here).
> If I did not understand your suggestion correctly, please elaborate.
>

A bit more reading and you're right. Extensions are for field names
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#patterned-fields-6

So this just affects the JSON Schema part at least. Extending the
simpleTypes, by publishing a meta schema for the int-or-string type,
might work according to the spec:

"Authors of extensions to JSON Schema are encouraged to write their
own meta-schemas, which extend the existing meta-schemas using
"allOf". This extended meta-schema SHOULD be referenced using the
"$schema" keyword, to allow tools to follow the correct behaviour."

http://json-schema.org/latest/json-schema-core.html#rfc.section.6.4

So adding to: https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json

But that leaves a problem with tooling based on my experience of clients so far.

Of the two options you mention, I think 1 works best for my particular
tastes. From the tool builders point of view I can work around
int-or-string in the short term. OneOf is valid JSON Schema, so for my
purposes library support already exists. And when Kubernetes publishes
an OpenApi 3.0 compatible description I can point at that and kill my
work arounds.

I might be able to _upgrade_ the schemas I'm extracting from the
OpenAPI definition to add OneOf as part of a post-processing step.

In case anyone else finds this interesting I found the relevant thread
for the OpenAPI discussion of this as well (warning, it's 2 years
worth of debate)

https://github.com/OAI/OpenAPI-Specification/issues/333

And it looks like go-openapi is tracking support for the 3.0 spec
here: https://github.com/go-openapi/spec/issues/21

Thanks

Gareth
>> email to kubernetes-sig-api-m...@googlegroups.com.
>> To post to this group, send email to
>> kubernetes-sig...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages