doumei3828 2017-10-05 18:01
浏览 280

将结构转到OpenAPI自动生成JSONSchema

I have a Go struct for which I want to generate an OpenAPI schema automatically. Once I have an OpenAPI definition of that struct I wanna generate JSONSchema of it, so that I can validate the input data that comes and is gonna be parsed into those structs.

The struct looks like the following:

// mySpec: io.myapp.MinimalPod
type MinimalPod struct {
    Name string `json:"name"`

    // k8s: io.k8s.kubernetes.pkg.api.v1.PodSpec
    v1.PodSpec    
}

Above struct is clearly an augmentation of what Kubernetes PodSpec is.

Now the approach that I have used is to generate definition part for my struct MinimalPod, the definition for PodSpec will come from upstream OpenAPI spec of Kubernetes. PodSpec has a key io.k8s.kubernetes.pkg.api.v1.PodSpec in the upstream OpenAPI spec, this definition is injected from there in my Properties. Now in my code that parses above struct I have templates of what to do if struct field is string.

If the field has a comment that starts with k8s: ... the next part is Kubernetes object's OpenAPI definition key. In our case the OpenAPI definition key is io.k8s.kubernetes.pkg.api.v1.PodSpec. So I retrieve that field's definition from the upstream OpenAPI definition and embed it into the definition of my struct.

Once I have generated an OpenAPI definition for this struct which is injected in Kubernetes OpenAPI schema's definition with key being io.myapp.MinimalPod. Now I can use the tool openapi2jsonschema to generate JSONSchema out of this one. Which generates a JSONSchema file named MinimalPod.json.

Now jsonschema tool and the file MinimalPod.json can be used for validating input given to my tool parser to see if all fields were given right.

Is this the right approach of doing things, or is there a tool/library and if I feed Go structs to it, it gives me OpenAPI schema? It would be fine if it does not identify where to inject Kubernetes OpenAPI schema from even automatic parsing of Go structs and giving OpenAPI definition would be much appreciated.


Update 1

After following @mehdy 's instructions, this is what I have tried:

I have used this import path github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1 to import the PodSpec definition instead of k8s.io/api/core/v1 and code looks like this:

package foomodel

import "github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1"

// MinimalPod is a minimal pod.
// +k8s:openapi-gen=true
type MinimalPod struct {
        Name string `json:"name"`

        v1.PodSpec
}

Now when I generate the same with flag -i changed from k8s.io/api/core/v1 to github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1

$ go run example/openapi-gen/main.go -i k8s.io/kube-openapi/example/model,github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1 -h example/foomodel/header.txt -p k8s.io/kube-openapi/example/foomodel

This is what is generated:

$ cat openapi_generated.go 
// +build !ignore_autogenerated

/*
======

Some random text


======
*/

// This file was autogenerated by openapi-gen. Do not edit it manually!

package foomodel

import (
        spec "github.com/go-openapi/spec"
        common "k8s.io/kube-openapi/pkg/common"
)

func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
        return map[string]common.OpenAPIDefinition{
                "k8s.io/kube-openapi/example/model.Container": {
                        Schema: spec.Schema{
                                SchemaProps: spec.SchemaProps{
                                        Description: "Container defines a single application container that you want to run within a pod.",
                                        Properties: map[string]spec.Schema{
                                                "health": {
                                                        SchemaProps: spec.SchemaProps{
                                                                Description: "One common definitions for 'livenessProbe' and 'readinessProbe' this allows to have only one place to define both probes (if they are the same) Periodic probe of container liveness and readiness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
                                                                Ref:         ref("k8s.io/client-go/pkg/api/v1.Probe"),
                                                        },
                                                },
                                                "Container": {
                                                        SchemaProps: spec.SchemaProps{
                                                                Ref: ref("k8s.io/client-go/pkg/api/v1.Container"),
                                                        },
                                                },
                                        },
                                        Required: []string{"Container"},
                                },
                        },
                        Dependencies: []string{
                                "k8s.io/client-go/pkg/api/v1.Container", "k8s.io/client-go/pkg/api/v1.Probe"},
                },
        }
}

I get only this much of the configuration generated. While when I switch back to "k8s.io/api/core/v1" I get config code auto generated which is more than 8k lines. What am I missing here?

Here definition of k8s.io/client-go/pkg/api/v1.Container and k8s.io/client-go/pkg/api/v1.Probe is missing while when I use k8s.io/api/core/v1 as import everything is generated.

Note: To generate above steps, please git clone https://github.com/kedgeproject/kedge in GOPATH.

  • 写回答

1条回答 默认 最新

  • dream5694 2017-10-06 23:38
    关注

    You can use kube-openapi package for this. I am going to add a sample to the repo but I've tested this simple model:

    // Car is a simple car model.
    // +k8s:openapi-gen=true
    type Car struct {
        Color    string
        Capacity int
        // +k8s:openapi-gen=false
        HiddenFeature string
    }
    

    If you assume you created this file in

    go run example/openapi-gen/main.go -h example/model/header.txt -i k8s.io/kube-openapi/example/model -p k8s.io/kube-openapi/example/model
    

    (you also need to add a header.txt file). You should see a new file created in example/model folder called openapi_generated.go. This is an intermediate generated file that has your OpenAPI model in it:

    func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
        return map[string]common.OpenAPIDefinition{
            "k8s.io/kube-openapi/example/model.Car": {
                Schema: spec.Schema{
                    SchemaProps: spec.SchemaProps{
                        Description: "Car is a simple car model.",
                        Properties: map[string]spec.Schema{
                            "Color": {
                                SchemaProps: spec.SchemaProps{
                                    Type:   []string{"string"},
                                    Format: "",
                                },
                            },
                            "Capacity": {
                                SchemaProps: spec.SchemaProps{
                                    Type:   []string{"integer"},
                                    Format: "int32",
                                },
                            },
                        },
                        Required: []string{"Color", "Capacity"},
                    },
                },
                Dependencies: []string{},
            },
        }
    }
    

    From there you should be able to call the generated method, get the model for your Type and get its Schema.

    With some go get magic and changing the command line a little, I was able to generate the model for your model. Here is what you should change in your code:

    package model
    
    import "k8s.io/api/core/v1"
    
    // MinimalPod is a minimal pod.
    // +k8s:openapi-gen=true
    type MinimalPod struct {
        Name string `json:"name"`
    
        v1.PodSpec
    }
    

    and then change the run command a little to include PodSpec in the generation:

    go run example/openapi-gen/main.go -h example/model/header.txt -i k8s.io/kube-openapi/example/model,k8s.io/api/core/v1 -p k8s.io/kube-openapi/example/model
    

    Here is what I got: https://gist.github.com/mbohlool/e399ac2458d12e48cc13081289efc55a

    评论

报告相同问题?

悬赏问题

  • ¥20 iqoo11 如何下载安装工程模式
  • ¥15 本题的答案是不是有问题
  • ¥15 关于#r语言#的问题:(svydesign)为什么在一个大的数据集中抽取了一个小数据集
  • ¥15 C++使用Gunplot
  • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 蓝桥杯单片机第十三届第一场,整点继电器吸合,5s后断开出现了问题
  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?