Go 自动将结构转到OpenAPI以生成JSONSchema

Go 自动将结构转到OpenAPI以生成JSONSchema,go,kubernetes,swagger,jsonschema,openapi,Go,Kubernetes,Swagger,Jsonschema,Openapi,我有一个Go结构,我想为它自动生成一个OpenAPI模式。一旦我有了这个结构的OpenAPI定义,我想生成它的JSONSchema,这样我就可以验证输入数据,这些数据将被解析成这些结构 结构如下所示: // mySpec: io.myapp.MinimalPod type MinimalPod struct { Name string `json:"name"` // k8s: io.k8s.kubernetes.pkg.api.v1.PodSpec v1.PodSpe

我有一个Go结构,我想为它自动生成一个OpenAPI模式。一旦我有了这个结构的OpenAPI定义,我想生成它的JSONSchema,这样我就可以验证输入数据,这些数据将被解析成这些结构

结构如下所示:

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

    // k8s: io.k8s.kubernetes.pkg.api.v1.PodSpec
    v1.PodSpec    
}
上面的结构显然是Kubernetes
PodSpec
的扩展

现在我使用的方法是为我的struct
minimapod
分割,
PodSpec
的定义将来自Kubernetes
PodSpec
在中有一个键
io.k8s.kubernetes.pkg.api.v1.PodSpec
,此定义为。现在,在我解析上述结构的代码中,我有了一些模板,说明了如果发生这种情况该怎么办

如果该字段有注释,说明下一部分是Kubernetes对象的OpenAPI定义键。在我们的例子中,OpenAPI定义键是
io.k8s.kubernetes.pkg.api.v1.PodSpec
。因此,我从上游OpenAPI定义中检索该字段的定义,并将其嵌入到我的结构的定义中

一旦我为这个结构生成了一个OpenAPI定义,它被注入到Kubernetes OpenAPI模式的定义中,密钥是
io.myapp.minimapod
。现在我可以使用这个工具来生成JSONSchema了。它生成一个名为
minimapod.json
的JSONSchema文件

现在可以使用
jsonschema
工具和文件
minimapod.json
来验证提供给工具解析器的输入,以查看是否所有字段都正确

这是做事情的正确方法,还是有一个工具/库,如果我向它提供Go结构,它会给我OpenAPI模式?如果它不确定从哪里注入Kubernetes OpenAPI模式,即使是从Go结构的自动解析和给出OpenAPI定义也会非常感激


更新1 在遵循@mehdy的指示后,我尝试了以下内容:

我使用此导入路径
github.com/kedgeproject/kedge/vendor/k8s.io/client go/pkg/api/v1
导入
PodSpec
定义,而不是
k8s.io/api/core/v1
,代码如下所示:

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
}
现在,当我使用标志
-I
生成相同的代码时,它从
k8s.io/api/core/v1
更改为
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
这就是产生的结果:

$ 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"},
                },
        }
}
我只得到生成的大部分配置。当我切换回
“k8s.io/api/core/v1”
时,我会自动生成超过8k行的配置代码。我错过了什么

这里缺少
k8s.io/client go/pkg/api/v1.Container
k8s.io/client go/pkg/api/v1.Probe
的定义,而当我使用
k8s.io/api/core/v1
作为导入时,会生成所有内容

注意:要生成上述步骤,请
git clonehttps://github.com/kedgeproject/kedge
GOPATH

中,您可以使用该软件包进行此操作。我将在回购协议中添加一个样本,但我已经测试了这个简单的模型:

// Car is a simple car model.
// +k8s:openapi-gen=true
type Car struct {
    Color    string
    Capacity int
    // +k8s:openapi-gen=false
    HiddenFeature string
}
如果假设您在中创建了此文件

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
(您还需要添加header.txt文件)。您应该会看到在example/model文件夹中创建的名为openapi_generated.go的新文件。这是一个中间生成的文件,其中包含您的OpenAPI模型:

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{},
        },
    }
}
从那里,您应该能够调用生成的方法,获取类型的模型并获取其模式

通过一些go get magic和稍微更改命令行,我能够为您的模型生成模型。以下是您应该在代码中更改的内容:

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
}
然后稍微更改run命令,将PodSpec包含在生成中:

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

以下是我得到的:

为结构生成openapi定义是最简单的部分。构建用于生成openapi路径的路由更具挑战性。您可以在这里查看我的类似问题:感谢您的详细回答,我已经尝试了您的建议,它对我有效,但请查看问题中的更新#1它不适用于
PodSpec
的不同导入位置,非常感谢您的输入!