自动生成OpenAPI和JSONSchema的Go结构体

4
我是一名有用的助手,可以为您翻译文本。

我有一个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 的扩展。
现在我所使用的方法是为我的结构体MinimalPod 生成definitionPodSpec的定义将从Kubernetes的上游OpenAPI规范中获取。在上游OpenAPI规范中,PodSpec有一个键io.k8s.kubernetes.pkg.api.v1.PodSpec,此定义从那里注入到我的属性中。现在,在解析上述结构体的代码中,如果结构体字段是string,我有模板来指导该怎么做。
如果字段有一个注释,k8s: ...开头,下一部分是Kubernetes对象的OpenAPI定义键。在我们的情况下,OpenAPI定义键io.k8s.kubernetes.pkg.api.v1.PodSpec。因此,我从上游OpenAPI定义中检索该字段的定义,并将其嵌入到我的结构的定义中。
一旦我为此结构生成了一个OpenAPI定义,它被注入到Kubernetes OpenAPI模式的定义中,键为io.myapp.MinimalPod。现在,我可以使用工具openapi2jsonschema将其生成为JSONSchema。这将生成一个名为MinimalPod.json的JSONSchema文件。
现在,jsonschema工具和文件MinimalPod.json可以用于验证输入给我的解析器工具的正确性。
这是正确的做法吗?还是有工具/库,如果我将Go结构提供给它,它会给我OpenAPI模式?即使自动解析Go结构并给出OpenAPI定义时无法确定在哪里注入Kubernetes OpenAPI模式,也可以使用。请注意保留HTML标签。

更新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.Containerk8s.io/client-go/pkg/api/v1.Probe 的定义缺失,而当我使用 k8s.io/api/core/v1 作为导入时,所有内容都被生成。

注意:要生成上述步骤,请在 GOPATH 中执行 git clone https://github.com/kedgeproject/kedge


1
生成structs的openapi定义很容易,建立用于生成openapi路径的路由更具挑战性。您可以在此处查看我的类似问题:https://groups.google.com/forum/#!topic/kubernetes-users/_ipF9ocbIQE - MarkNS
1个回答

3
你可以使用kube-openapi包来实现这个。我将在存储库中添加一个示例,但我已经测试了这个简单的模型:
// 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 魔法和稍微更改命令行,我能够为您的模型生成模型。以下是您应该在代码中更改的内容:

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
}

然后稍微修改运行命令以包含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

这是我得到的内容:https://gist.github.com/mbohlool/e399ac2458d12e48cc13081289efc55a


感谢您详细的回答,我尝试了您建议的方法,它对我有效。但请注意问题中的更新#1,当PodSpec的导入位置不同时,它无法正常工作。期待您的进一步指导! - surajd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接