|
| 1 | +## Intro to JSONSchema |
| 2 | + |
| 3 | +JSON Schema is a vocabulary that allows you to annotate and validate JSON/YAML |
| 4 | +documents. |
| 5 | + |
| 6 | +- describes your existing data format |
| 7 | +- clear, human- and machine-readable documentation |
| 8 | +- complete structural validation, useful for |
| 9 | +- automated testing |
| 10 | +- validating client-submitted data |
| 11 | + |
| 12 | +## Intro to OpenAPI or SwaggerSchame |
| 13 | + |
| 14 | +The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to |
| 15 | +RESTful APIs which allows both humans and computers to discover and understand the |
| 16 | +capabilities of the service without access to source code, documentation, or |
| 17 | +through network traffic inspection. When properly defined, a consumer can |
| 18 | +understand and interact with the remote service with a minimal amount of |
| 19 | +implementation logic. |
| 20 | + |
| 21 | +An OpenAPI definition can then be used by documentation generation tools to |
| 22 | +display the API, code generation tools to generate servers and clients in various |
| 23 | +programming languages, testing tools, and many other use cases. |
| 24 | + |
| 25 | + |
| 26 | +## Where do we get the OpenAPI for kedge from? |
| 27 | + |
| 28 | +This could be an obvious question that comes to your mind because Kedge is not any |
| 29 | +web service where we have defined RESTful APIs. So even if Kedge is not a service, |
| 30 | +but it has it's language specification defined in the form or [golang structs](https://github.com/kedgeproject/kedge/blob/master/pkg/spec/types.go), |
| 31 | +which forms the basis of the language. Also since we are embedding the golang |
| 32 | +structs from upstream Kubernetes, and Kubernetes has it's own OpenAPI schema defined |
| 33 | +for each struct. So for Kedge this is good news, because now we have less work. |
| 34 | + |
| 35 | +So the complete OpenAPI definition looks like the following, if you just look at the |
| 36 | +root keys: ([Kubernetes 1.7 OpenAPI definition](https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.7/api/openapi-spec/swagger.json)) |
| 37 | + |
| 38 | +```json |
| 39 | +{ |
| 40 | + "swagger": "2.0", |
| 41 | + "info": {...}, |
| 42 | + "paths": {...}, |
| 43 | + "definitions": {...}, |
| 44 | + "securityDefinitions": {...}, |
| 45 | + "security": {...} |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +Now the part of interest for us is the root level field `"definitions": {...}`, it |
| 50 | +has definition of all Kubernetes structs in OpenAPI format. If we dig deeper in |
| 51 | +the `definitions` part, you will see something like this: |
| 52 | + |
| 53 | +```json |
| 54 | +{ |
| 55 | + "swagger": "2.0", |
| 56 | + "definitions": { |
| 57 | + "io.k8s.kubernetes.pkg.api.v1.Pod": {...}, |
| 58 | + "io.k8s.kubernetes.pkg.api.v1.PodAffinity": {...}, |
| 59 | + "io.k8s.kubernetes.pkg.api.v1.PodAffinityTerm": {...}, |
| 60 | + "io.k8s.kubernetes.pkg.api.v1.PodAntiAffinity": {...}, |
| 61 | + ... |
| 62 | + "io.k8s.kubernetes.pkg.apis.apps.v1beta1.Deployment": {...}, |
| 63 | + "io.k8s.kubernetes.pkg.apis.apps.v1beta1.DeploymentCondition": {...}, |
| 64 | + "io.k8s.kubernetes.pkg.apis.apps.v1beta1.DeploymentList": {...}, |
| 65 | + ... |
| 66 | + }, |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +So all we need to do is inject the definition of Pod from here into our defintion. |
| 71 | +But before we do that kinda injection first we need to know what to inject where. |
| 72 | +To identify that we have introduced a convention in Kedge schema's golang struct |
| 73 | +definition which looks something like the following. More information about the |
| 74 | +conventions used in Kedge's golang struct definition can be found [here](https://github.com/kedgeproject/kedge/blob/3ade8541e2209148c21c636464e12aea75e35e3a/docs/development.md#specgo-conventions). |
| 75 | + |
| 76 | +```go |
| 77 | +// Container defines a single application container that you want to run within a pod. |
| 78 | +// kedgeSpec: io.kedge.ContainerSpec |
| 79 | +type Container struct { |
| 80 | + // One common definitions for 'livenessProbe' and 'readinessProbe' |
| 81 | + // this allows to have only one place to define both probes (if they are the same) |
| 82 | + // Periodic probe of container liveness and readiness. Container will be restarted |
| 83 | + // if the probe fails. Cannot be updated. More info: |
| 84 | + // https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes |
| 85 | + // ref: io.k8s.kubernetes.pkg.api.v1.Probe |
| 86 | + // +optional |
| 87 | + Health *api_v1.Probe `json:"health,omitempty"` |
| 88 | + // k8s: io.k8s.kubernetes.pkg.api.v1.Container |
| 89 | + api_v1.Container `json:",inline"` |
| 90 | +} |
| 91 | +``` |
| 92 | +Above code can be found [here](https://github.com/kedgeproject/kedge/blob/ecc7df1b0bb46ff43d5f830e08c0d0ddafd8e710/pkg/spec/types.go#L84-L97). |
| 93 | + |
| 94 | +Line `api_v1.Container `json:",inline"`` has a comment above it |
| 95 | +`k8s: io.k8s.kubernetes.pkg.api.v1.Container` in this |
| 96 | +`io.k8s.kubernetes.pkg.api.v1.Container` is a key of the Container definition in |
| 97 | +Kubernetes's OpenAPI schema. This is how we know that for the Kedge's container |
| 98 | +definition, the definition of upstream container comes from |
| 99 | +`io.k8s.kubernetes.pkg.api.v1.Container` key in comment. |
| 100 | + |
| 101 | +Fields those are embedded are put in with `k8s` as the way to tell that this |
| 102 | +definition comes from Kubernetes. |
| 103 | + |
| 104 | + |
| 105 | +Similarly ```Health *api_v1.Probe `json:"health,omitempty"` ``` has multiple |
| 106 | +comments one says `+optional` which means that this field in this struct while |
| 107 | +generation of definition is marked optional. And then there are bunch of comments |
| 108 | +above `Health` field which explains what it does. These comments then become |
| 109 | +description of the field in OpenAPI schema. |
| 110 | + |
| 111 | +Above struct definition you can also see the comment |
| 112 | +`kedgeSpec: io.kedge.ContainerSpec`. Here `io.kedge.ContainerSpec` is the key for |
| 113 | +the Kedge's Container definition in the final output of the OpenAPI for Kedge. |
| 114 | + |
| 115 | +With help of these conventions and parsing of go code and injecting upstream |
| 116 | +Kubernetes OpenAPI schema into the Kedge's OpenAPI schema we generate final |
| 117 | +OpenAPI schema which is superset of the Kubernetes OpenAPI schema. |
| 118 | + |
| 119 | +## JSONSchema for Kedge |
| 120 | + |
| 121 | +This the easiest part, we hand off this work to the tool called |
| 122 | +[openapi2jsonschema](https://github.com/garethr/openapi2jsonschema). This then |
| 123 | +reads all the keys from the definition part and creates JSONSchema for each key in |
| 124 | +the definitions part of the OpenAPI Schema for kedge. All the JSONSchemas for the |
| 125 | +Kedge can be found at [github.com/kedgeproject/json-schema](https://github.com/kedgeproject/json-schema/tree/master/schema). |
| 126 | + |
| 127 | +Depending on what is the input at root level there are multiple schema files like |
| 128 | +for Kubernetes Deployment with kedge we have [deploymentspecmod.json](https://github.com/kedgeproject/json-schema/blob/master/schema/deploymentspecmod.json), [jobspecmod.json](https://github.com/kedgeproject/json-schema/blob/master/schema/jobspecmod.json). |
| 129 | + |
| 130 | +## Ref: |
| 131 | + |
| 132 | +- JSON Schema http://json-schema.org/ |
| 133 | +- OpenAPI Specification https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md |
| 134 | +- Kubernetes master OpenAPI definition https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json |
| 135 | +- openapi2jsonschema - https://github.com/garethr/openapi2jsonschema |
| 136 | +- kedgeproject/json-schema - https://github.com/kedgeproject/json-schema |
0 commit comments