ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

KubeVirt 中的 Swagger 2.0 校验实践:go-openapi/validate 的能力清单、内部机制与源码级解析

KubeVirt 中的 Swagger 2.0 校验实践:go-openapi/validate 的能力清单、内部机制与源码级解析 云原生【免费下载链接】kubevirtKubernetes Virtualization API and runtime in order to define and manage virtual machines.项目地址https://gitcode.com/gh_mirrors/ku/kubevirt点击查看免费下载本篇文章以 kubevirt 仓库 vendor 目录下引入的go-openapi/validate库README 与 doc.go为研究主体梳理该库面向 Swagger 2.0OpenAPI 2.0规范校验、JSON Schema draft4 数据校验以及单值辅助校验函数的完整能力并结合 kubevirt 自身的 OpenAPI 构建与准入校验代码如 pkg/util/openapi/openapi.go还原它在真实项目中的调用方式。读完本文你将掌握该校验库的三大入口、18 个单值校验函数的语义以及它如何支撑 KubeVirt API 的 spec/status 字段校验。一、这个库解决什么问题go-openapi/validate是 go-swagger 生态中的校验组件提供三类核心能力Swagger 2.0 规范校验器校验一份 Swagger/OpenAPI 2.0 描述文档本身是否合法JSON Schema 层面 无法用 JSON Schema 表达的业务规则JSON Schema draft4 数据校验器用 schema 校验任意 JSON 数据支持完整的 draft4 关键字词表包括 Swagger 本身不用的additionalItems等单值辅助校验函数供 go-swagger 生成的代码以及业务代码直接调用逐字段校验枚举、边界、正则、格式等。它被 kubevirt 通过 Go module vendor 机制引入vendor 目录清单用于 KubeVirt API 的 OpenAPI 文档构建与 VirtualMachineInstance 对象的准入校验。二、三大入口与内部校验流程2.1 规范校验Spec() / NewSpecValidator() / Validate()规范校验的入口定义在 spec.gofunc Spec(doc *loads.Document, formats strfmt.Registry) error func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidator func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) // 返回 (错误, 警告)Spec()是简化入口先加载loads.Document再调用NewSpecValidator(...).Validate(...)最终把错误折叠成一个errors.CompositeValidationError。Validate()内部严格分阶段执行且每个阶段之间会检查ContinueOnErrors选项来决定是否提前终止Swagger schema 校验用 Swagger 2.0 自身的 JSON Schema 校验原始文档json.Unmarshal后的对象引用合法性校验validateReferencesValid每个$ref必须指向合法对象operationId 唯一性校验validateDuplicateOperationIDs属性名重复校验validateDuplicatePropertyNames参数校验validateParameters路径参数唯一、每个 path 参数与占位符一一对应、nametype组合唯一、每个 operation 至多一个 body 参数items 校验validateItemsarray类型必须声明itemsrequired 定义校验validateRequiredDefinitionsrequired 数组里列出的属性必须真的定义在 properties 中default 值校验由defaultValidator完成——每个 default 值必须能通过对应 schema 的校验example 值校验由exampleValidator完成——schema/property 的 example 必须通过自身 schema 校验路径参数名与空路径检查validateNonEmptyPathParamNames及引用对象可达性检查validateReferenced仅产生警告。2.2 规范校验报出的错误与警告结合 doc.go 与 spec.go 中的实现可以整理出如下完整清单。作为错误error上报的规则definition 不能声明祖先模型已定义的属性definition 的祖先不能同时是该模型的子孙继承关系成环路径唯一性每个 API path 去掉路径参数名后按 method 必须唯一可通过关闭StrictPathParamUniqueness放宽每个 security 引用中的 scopes 必须唯一每个 security definition 中的 scope 必须唯一路径中的参数必须唯一每个 path 参数必须与路径占位符一一对应每个可引用的 definition 必须至少被引用一次required 数组中列出的属性必须定义在模型的 properties 中每个参数必须具有唯一的nametype组合每个 operation 只能有一个 body 类型参数每个$ref必须指向合法对象每个 default 值必须通过该属性的 schema 校验所有array类型的 schema/definition 必须声明items路径参数必须声明为 requiredheader 中不允许出现$refschema 与 property 提供的 example 必须通过对应 schema 校验。作为警告warning上报的规则path 参数不应包含{、}、\w之外的字符空路径未使用的 definition非 JSON 媒体类型的 example 无法校验无 schema 的 response 中的 examplereadOnly 属性不应同时是 required。2.3 Schema 数据校验AgainstSchema() / NewSchemaValidator()数据校验入口在 schema.gofunc AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registry, options ...Option) error func NewSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, options ...Option) *SchemaValidatorAgainstSchema()是便捷封装内部创建SchemaValidator并自动开启WithRecycleValidators(true)与结果回收若有错误则返回聚合错误否则返回nilNewSchemaValidator()构建完整校验器。构造时若 schema 带ID或$ref会先执行spec.ExpandSchema展开引用展开失败会直接 panic调用方需保证传入 schema 合法Validate(data)会先处理nil数据仅跑类型与公共校验再判断数据类型struct 通过swag.ToDynamicJSON转成map[string]interface{}json.Number根据 schema 的 integer/number 类型无损转为int64/float64最后按序驱动一组内部校验器。三、SchemaValidator 的内部构成8 个 valueValidator在 validator.go 与 schema.go 中可以看到SchemaValidator内部持有固定长度为 8 的校验器数组按顺序执行s.validators [8]valueValidator{ s.typeValidator(), // 类型string/integer/number/boolean/array/object... s.schemaPropsValidator(),// schema 组合关键字allOf/anyOf/oneOf/not s.stringValidator(), // MinLength/MaxLength/Pattern s.formatValidator(), // Format依赖 strfmt.Registry s.numberValidator(), // MultipleOf/Maximum/Minimum/ExclusiveMaximum/ExclusiveMinimum s.sliceValidator(), // MaxItems/MinItems/UniqueItems/items s.commonValidator(), // Enum s.objectValidator(), // properties/required/additionalProperties/... }每次调用Validate时只有Applies(root, kind)返回 true 的校验器才会被真正执行其错误会通过Result.Merge聚合若出现硬错误HasErrors()则提前中断后续校验。参数ParamValidator、headerHeaderValidator与数组元素itemsValidator则是同一套valueValidator机制的轻量复用例如ParamValidator的 6 个校验器恰好对应 type/string/format/number/slice/common。值得注意的实现细节当开启回收选项recycleValidators/recycleResult时校验器与结果对象会从pools.go定义的对象池借出、使用后归还避免高并发校验场景下的重复分配Validator数组中被使用过的槽位会被置为nil防止对象池对象被二次误用。四、18 个单值校验辅助函数README 列出了 go-swagger 生成代码会用到的一组辅助函数实现在 values.go 中统一签名风格为(path, in string, data ...) *errors.Validation其中path标识错误位置如spec、bodyin标识来源上下文如body、header、query、response。函数语义与实现要点Required(path, in, data)校验数据非零值reflect.DeepEqual(data, zero)视为缺失values.goRequiredNumber(path, in, data float64)数值场景的必填校验RequiredString(path, in, data string)字符串场景的必填校验空串视为缺失ReadOnly(ctx, path, in, data)仅当上下文操作类型为请求时生效extractOperationType(ctx) request要求数据为其类型的零值UniqueItems(path, in, data)逐个元素用reflect.DeepEqual两两比较发现重复即报DuplicateItemsMaxItems(path, in, size, max)size max时报告元素过多MinItems(path, in, size, min)size min时报告元素过少Enum(path, in, data, enum)等价于EnumCase(path, in, data, enum, true)大小写敏感比较EnumCase(path, in, data, enum, caseSensitive)大小写不敏感模式先把枚举值与数据统一转小写再EqualFold比较同时支持类型可转换场景下的深度比较Pattern(path, in, data, pattern)用 Go regexp 校验字符串匹配MinLength(path, in, data, minLength)以utf8.RuneCountInString统计字符数非字节数小于下限报TooShortMaxLength(path, in, data, maxLength)同上大于上限报TooLongMinimum(path, in, data, min, exclusive)边界校验exclusive控制是否包含等值Maximum(path, in, data, max, exclusive)同上MultipleOf(path, in, data, factor)检查数据是否为 factor 的整数倍FormatOf(path, in, format, data, registry)通过strfmt.Registry校验字符串格式如 date-time、uuid、ipv4 等其中EnumCase的类型转换后比较逻辑值得一提当数据的类型与枚举值类型可相互转换ConvertibleTo时会先转换再DeepEqual从而兼容 JSON 反序列化造成的 int/int64/float64 差异。五、在 KubeVirt 中的落地从 OpenAPI 构建到准入校验5.1 构建 ValidatorCreateOpenAPIValidatorkubevirt 在 pkg/util/openapi/openapi.go 中封装了CreateOpenAPIValidator(webServices)用 k8s 的kube-openapi从 restful 路由构建 Swagger 文档LoadOpenAPISpec并做一系列修补——把Quantity类型放宽为string/integer/number、把creationTimestamp/lastProbeTime/lastTransitionTime修正为string/null、把status引用对象置为Nullable、移除PersistentVolumeClaimSpec.dataSource的 required 等序列化后分别json.Unmarshal出specSchema与statusSchema两份 schema对 specSchema 的所有 definition 强制AdditionalPropertiesfalse、AdditionalItemsfalse拒绝未知字段而 statusSchema 保持宽松对两份 schema 分别执行spec.ExpandSchema展开$ref。5.2 准入校验Validate / ValidateSpec / ValidateStatusValidator.Validate(gvk, obj)首先检查对象顶层只能包含kind、apiVersion、spec、status、metadata五个键openapi.go并强制spec必须存在随后分别调用result : openapi_validate.NewSchemaValidator(schema, nil, spec, strfmt.Default).Validate(obj[spec]) result : openapi_validate.NewSchemaValidator(schema, nil, status, strfmt.Default).Validate(obj[status])这正是本文第二节NewSchemaValidator的真实用法root参数传spec/status作为错误路径前缀strfmt.Default提供内置格式注册表。5.3 接入 Admission 链路pkg/virt-api/definitions/validator.go 中全局构造var Validator openapi.CreateOpenAPIValidator(ComposeAPIDefinitions())pkg/util/webhooks/webhooks.go 的ValidateStatus(data)把 AdmissionReview 中的对象原始 JSON 反序列化为map[string]interface{}通过unstructured.Unstructured解析出GroupVersionKind再调用definitions.Validator.ValidateStatus发现错误即转换为AdmissionResponse拒绝请求pkg/virt-api/webhooks/validating-webhook/admitters/status-admitter.go 在 status 子资源的更新请求上调用上述校验pkg/util/openapi/openapi_test.go 用 Ginkgo 验证合法对象的ValidateSpec/ValidateStatus返回空错误切片篡改后的非法对象则能稳定报错——这是该库在仓库内被测试用例直接印证的行为。从这条调用链可以看出go-openapi/validate在 KubeVirt 中扮演的是API 合约的最后一道防线让客户端写入的 VMI spec/status 在进入 etcd 之前先经过以官方 OpenAPI 文档为蓝本的 schema 校验。六、已知限制与边界doc.go 明确列出了当前版本未支持或受限的能力使用时应规避错误与警告不携带 spec 中的键名/行号response 上的 default 与 example 仅支持application/json生产类型Minimum等数值约束本身不校验其合法性只对 default/example 值校验collectionFormat规则未实现多态discriminator无校验规则Go regexp 引擎不支持的合法 ECMA 正则会被判为非法不支持任意大数上限为math.MaxFloat64。七、FAQ为什么不支持 OpenAPI 3README 的 FAQ 给出了明确答复该包当前只支持 OpenAPI 2.0Swagger 2.0没有向 OpenAPI 3.x 演进的计划早期尝试位于独立的go-openapi/spec3仓库。因此当你在 KubeVirt 中看到它时它服务的对象是 Swagger 2.0 形态的 API 文档例如 api/openapi-spec/swagger.json需要 OpenAPI 3 能力的项目应寻找其他实现。八、结语go-openapi/validate以规范校验 schema 数据校验 单值辅助校验三位一体的设计为 Swagger 2.0 生态提供了从文档到数据的完整验证闭环。kubevirt 仓库将它的NewSchemaValidator与 k8s 的 OpenAPI 构建器组合构建出对 VMI 等资源 spec/status 的严格准入校验——理解这个库也就理解了 KubeVirt API 校验链路的底层实现。读者可以继续阅读 vendor/github.com/go-openapi/validate/spec.go 与 vendor/github.com/go-openapi/validate/values.go 深入每个规则的具体实现。赞分享云原生【免费下载链接】kubevirtKubernetes Virtualization API and runtime in order to define and manage virtual machines.项目地址https://gitcode.com/gh_mirrors/ku/kubevirt点击查看免费下载相关推荐KubeSphere 中的 Swagger 2.0 与 JSON Schema 校验go-openapi/validate 使用指南与源码解析KubeSphere 中的 Swagger 2.0 与 JSON Schema 校验go openapi/validate 使用指南与源码解析 导读 本文围绕后端云原生容器编排微服务go-openapi/validate 详解基于 moby 仓库实践 Swagger 2.0OpenAPI 2.0规范与 JSON Schema Draft 4 校验go openapi/validate 详解基于 moby 仓库实践 Swagger 2.0OpenAPI 2.0规范与 JSON Schema Draf云原生容器运行时虚拟化容器编排John the Ripper快速上手教程5分钟从零安装并破解你的第一个密码哈希John the Ripper快速上手教程5分钟从零安装并破解你的第一个密码哈希 John the RipperJtRjumbo 是一款经典的开源离线密码云原生上一篇如何快速上手OpenEuler kata_integration5步搭建Kata Containers开发环境下一篇ScyllaDB Admin REST API 实战指南Swagger UI 与 scylla-api-client 的使用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表