mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-30 00:40:21 +00:00
323 lines
9.6 KiB
Go
323 lines
9.6 KiB
Go
|
/*
|
||
|
Copyright 2022 The Kubernetes Authors.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package openapiconv
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
|
||
|
klog "k8s.io/klog/v2"
|
||
|
builderutil "k8s.io/kube-openapi/pkg/builder3/util"
|
||
|
"k8s.io/kube-openapi/pkg/spec3"
|
||
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||
|
)
|
||
|
|
||
|
var OpenAPIV2DefPrefix = "#/definitions/"
|
||
|
var OpenAPIV3DefPrefix = "#/components/schemas/"
|
||
|
|
||
|
// ConvertV2ToV3 converts an OpenAPI V2 object into V3.
|
||
|
// Certain references may be shared between the V2 and V3 objects in the conversion.
|
||
|
func ConvertV2ToV3(v2Spec *spec.Swagger) *spec3.OpenAPI {
|
||
|
v3Spec := &spec3.OpenAPI{
|
||
|
Version: "3.0.0",
|
||
|
Info: v2Spec.Info,
|
||
|
ExternalDocs: ConvertExternalDocumentation(v2Spec.ExternalDocs),
|
||
|
Paths: ConvertPaths(v2Spec.Paths),
|
||
|
Components: ConvertComponents(v2Spec.SecurityDefinitions, v2Spec.Definitions, v2Spec.Responses, v2Spec.Produces),
|
||
|
}
|
||
|
|
||
|
return v3Spec
|
||
|
}
|
||
|
|
||
|
func ConvertExternalDocumentation(v2ED *spec.ExternalDocumentation) *spec3.ExternalDocumentation {
|
||
|
if v2ED == nil {
|
||
|
return nil
|
||
|
}
|
||
|
return &spec3.ExternalDocumentation{
|
||
|
ExternalDocumentationProps: spec3.ExternalDocumentationProps{
|
||
|
Description: v2ED.Description,
|
||
|
URL: v2ED.URL,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func ConvertComponents(v2SecurityDefinitions spec.SecurityDefinitions, v2Definitions spec.Definitions, v2Responses map[string]spec.Response, produces []string) *spec3.Components {
|
||
|
components := &spec3.Components{}
|
||
|
|
||
|
if v2Definitions != nil {
|
||
|
components.Schemas = make(map[string]*spec.Schema)
|
||
|
}
|
||
|
for s, schema := range v2Definitions {
|
||
|
components.Schemas[s] = ConvertSchema(&schema)
|
||
|
}
|
||
|
if v2SecurityDefinitions != nil {
|
||
|
components.SecuritySchemes = make(spec3.SecuritySchemes)
|
||
|
}
|
||
|
for s, securityScheme := range v2SecurityDefinitions {
|
||
|
components.SecuritySchemes[s] = ConvertSecurityScheme(securityScheme)
|
||
|
}
|
||
|
if v2Responses != nil {
|
||
|
components.Responses = make(map[string]*spec3.Response)
|
||
|
}
|
||
|
for r, response := range v2Responses {
|
||
|
components.Responses[r] = ConvertResponse(&response, produces)
|
||
|
}
|
||
|
|
||
|
return components
|
||
|
}
|
||
|
|
||
|
func ConvertSchema(v2Schema *spec.Schema) *spec.Schema {
|
||
|
if v2Schema == nil {
|
||
|
return nil
|
||
|
}
|
||
|
v3Schema := spec.Schema{
|
||
|
VendorExtensible: v2Schema.VendorExtensible,
|
||
|
SchemaProps: v2Schema.SchemaProps,
|
||
|
SwaggerSchemaProps: v2Schema.SwaggerSchemaProps,
|
||
|
ExtraProps: v2Schema.ExtraProps,
|
||
|
}
|
||
|
|
||
|
if refString := v2Schema.Ref.String(); refString != "" {
|
||
|
if idx := strings.Index(refString, OpenAPIV2DefPrefix); idx != -1 {
|
||
|
v3Schema.Ref = spec.MustCreateRef(OpenAPIV3DefPrefix + refString[idx+len(OpenAPIV2DefPrefix):])
|
||
|
} else {
|
||
|
klog.Errorf("Error: Swagger V2 Ref %s does not contain #/definitions\n", refString)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v2Schema.Properties != nil {
|
||
|
v3Schema.Properties = make(map[string]spec.Schema)
|
||
|
for key, property := range v2Schema.Properties {
|
||
|
v3Schema.Properties[key] = *ConvertSchema(&property)
|
||
|
}
|
||
|
}
|
||
|
if v2Schema.Items != nil {
|
||
|
v3Schema.Items = &spec.SchemaOrArray{
|
||
|
Schema: ConvertSchema(v2Schema.Items.Schema),
|
||
|
Schemas: ConvertSchemaList(v2Schema.Items.Schemas),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v2Schema.AdditionalProperties != nil {
|
||
|
v3Schema.AdditionalProperties = &spec.SchemaOrBool{
|
||
|
Schema: ConvertSchema(v2Schema.AdditionalProperties.Schema),
|
||
|
Allows: v2Schema.AdditionalProperties.Allows,
|
||
|
}
|
||
|
}
|
||
|
if v2Schema.AdditionalItems != nil {
|
||
|
v3Schema.AdditionalItems = &spec.SchemaOrBool{
|
||
|
Schema: ConvertSchema(v2Schema.AdditionalItems.Schema),
|
||
|
Allows: v2Schema.AdditionalItems.Allows,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return builderutil.WrapRefs(&v3Schema)
|
||
|
}
|
||
|
|
||
|
func ConvertSchemaList(v2SchemaList []spec.Schema) []spec.Schema {
|
||
|
if v2SchemaList == nil {
|
||
|
return nil
|
||
|
}
|
||
|
v3SchemaList := []spec.Schema{}
|
||
|
for _, s := range v2SchemaList {
|
||
|
v3SchemaList = append(v3SchemaList, *ConvertSchema(&s))
|
||
|
}
|
||
|
return v3SchemaList
|
||
|
}
|
||
|
|
||
|
func ConvertSecurityScheme(v2securityScheme *spec.SecurityScheme) *spec3.SecurityScheme {
|
||
|
if v2securityScheme == nil {
|
||
|
return nil
|
||
|
}
|
||
|
securityScheme := &spec3.SecurityScheme{
|
||
|
VendorExtensible: v2securityScheme.VendorExtensible,
|
||
|
SecuritySchemeProps: spec3.SecuritySchemeProps{
|
||
|
Description: v2securityScheme.Description,
|
||
|
Type: v2securityScheme.Type,
|
||
|
Name: v2securityScheme.Name,
|
||
|
In: v2securityScheme.In,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
if v2securityScheme.Flow != "" {
|
||
|
securityScheme.Flows = make(map[string]*spec3.OAuthFlow)
|
||
|
securityScheme.Flows[v2securityScheme.Flow] = &spec3.OAuthFlow{
|
||
|
OAuthFlowProps: spec3.OAuthFlowProps{
|
||
|
AuthorizationUrl: v2securityScheme.AuthorizationURL,
|
||
|
TokenUrl: v2securityScheme.TokenURL,
|
||
|
Scopes: v2securityScheme.Scopes,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
return securityScheme
|
||
|
}
|
||
|
|
||
|
func ConvertPaths(v2Paths *spec.Paths) *spec3.Paths {
|
||
|
if v2Paths == nil {
|
||
|
return nil
|
||
|
}
|
||
|
paths := &spec3.Paths{
|
||
|
VendorExtensible: v2Paths.VendorExtensible,
|
||
|
}
|
||
|
|
||
|
if v2Paths.Paths != nil {
|
||
|
paths.Paths = make(map[string]*spec3.Path)
|
||
|
}
|
||
|
for k, v := range v2Paths.Paths {
|
||
|
paths.Paths[k] = ConvertPathItem(v)
|
||
|
}
|
||
|
return paths
|
||
|
}
|
||
|
|
||
|
func ConvertPathItem(v2pathItem spec.PathItem) *spec3.Path {
|
||
|
path := &spec3.Path{
|
||
|
Refable: v2pathItem.Refable,
|
||
|
PathProps: spec3.PathProps{
|
||
|
Get: ConvertOperation(v2pathItem.Get),
|
||
|
Put: ConvertOperation(v2pathItem.Put),
|
||
|
Post: ConvertOperation(v2pathItem.Post),
|
||
|
Delete: ConvertOperation(v2pathItem.Delete),
|
||
|
Options: ConvertOperation(v2pathItem.Options),
|
||
|
Head: ConvertOperation(v2pathItem.Head),
|
||
|
Patch: ConvertOperation(v2pathItem.Patch),
|
||
|
},
|
||
|
VendorExtensible: v2pathItem.VendorExtensible,
|
||
|
}
|
||
|
for _, param := range v2pathItem.Parameters {
|
||
|
path.Parameters = append(path.Parameters, ConvertParameter(param))
|
||
|
}
|
||
|
return path
|
||
|
}
|
||
|
|
||
|
func ConvertOperation(v2Operation *spec.Operation) *spec3.Operation {
|
||
|
if v2Operation == nil {
|
||
|
return nil
|
||
|
}
|
||
|
operation := &spec3.Operation{
|
||
|
VendorExtensible: v2Operation.VendorExtensible,
|
||
|
OperationProps: spec3.OperationProps{
|
||
|
Description: v2Operation.Description,
|
||
|
ExternalDocs: ConvertExternalDocumentation(v2Operation.OperationProps.ExternalDocs),
|
||
|
Tags: v2Operation.Tags,
|
||
|
Summary: v2Operation.Summary,
|
||
|
Deprecated: v2Operation.Deprecated,
|
||
|
OperationId: v2Operation.ID,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, param := range v2Operation.Parameters {
|
||
|
if param.ParamProps.Name == "body" && param.ParamProps.Schema != nil {
|
||
|
operation.OperationProps.RequestBody = &spec3.RequestBody{
|
||
|
RequestBodyProps: spec3.RequestBodyProps{},
|
||
|
}
|
||
|
if v2Operation.Consumes != nil {
|
||
|
operation.RequestBody.Content = make(map[string]*spec3.MediaType)
|
||
|
}
|
||
|
for _, consumer := range v2Operation.Consumes {
|
||
|
operation.RequestBody.Content[consumer] = &spec3.MediaType{
|
||
|
MediaTypeProps: spec3.MediaTypeProps{
|
||
|
Schema: ConvertSchema(param.ParamProps.Schema),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
operation.Parameters = append(operation.Parameters, ConvertParameter(param))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
operation.Responses = &spec3.Responses{ResponsesProps: spec3.ResponsesProps{
|
||
|
Default: ConvertResponse(v2Operation.Responses.Default, v2Operation.Produces),
|
||
|
},
|
||
|
VendorExtensible: v2Operation.Responses.VendorExtensible,
|
||
|
}
|
||
|
|
||
|
if v2Operation.Responses.StatusCodeResponses != nil {
|
||
|
operation.Responses.StatusCodeResponses = make(map[int]*spec3.Response)
|
||
|
}
|
||
|
for k, v := range v2Operation.Responses.StatusCodeResponses {
|
||
|
operation.Responses.StatusCodeResponses[k] = ConvertResponse(&v, v2Operation.Produces)
|
||
|
}
|
||
|
return operation
|
||
|
}
|
||
|
|
||
|
func ConvertResponse(v2Response *spec.Response, produces []string) *spec3.Response {
|
||
|
if v2Response == nil {
|
||
|
return nil
|
||
|
}
|
||
|
response := &spec3.Response{
|
||
|
Refable: ConvertRefableResponse(v2Response.Refable),
|
||
|
VendorExtensible: v2Response.VendorExtensible,
|
||
|
ResponseProps: spec3.ResponseProps{
|
||
|
Description: v2Response.Description,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
if v2Response.Schema != nil {
|
||
|
if produces != nil {
|
||
|
response.Content = make(map[string]*spec3.MediaType)
|
||
|
}
|
||
|
for _, producer := range produces {
|
||
|
response.ResponseProps.Content[producer] = &spec3.MediaType{
|
||
|
MediaTypeProps: spec3.MediaTypeProps{
|
||
|
Schema: ConvertSchema(v2Response.Schema),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return response
|
||
|
}
|
||
|
|
||
|
func ConvertParameter(v2Param spec.Parameter) *spec3.Parameter {
|
||
|
param := &spec3.Parameter{
|
||
|
Refable: ConvertRefableParameter(v2Param.Refable),
|
||
|
VendorExtensible: v2Param.VendorExtensible,
|
||
|
ParameterProps: spec3.ParameterProps{
|
||
|
Name: v2Param.Name,
|
||
|
Description: v2Param.Description,
|
||
|
In: v2Param.In,
|
||
|
Required: v2Param.Required,
|
||
|
Schema: ConvertSchema(v2Param.Schema),
|
||
|
AllowEmptyValue: v2Param.AllowEmptyValue,
|
||
|
},
|
||
|
}
|
||
|
// Convert SimpleSchema into Schema
|
||
|
if param.Schema == nil {
|
||
|
param.Schema = &spec.Schema{
|
||
|
SchemaProps: spec.SchemaProps{
|
||
|
Type: []string{v2Param.Type},
|
||
|
Format: v2Param.Format,
|
||
|
UniqueItems: v2Param.UniqueItems,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return param
|
||
|
}
|
||
|
|
||
|
func ConvertRefableParameter(refable spec.Refable) spec.Refable {
|
||
|
if refable.Ref.String() != "" {
|
||
|
return spec.Refable{Ref: spec.MustCreateRef(strings.Replace(refable.Ref.String(), "#/parameters/", "#/components/parameters/", 1))}
|
||
|
}
|
||
|
return refable
|
||
|
}
|
||
|
|
||
|
func ConvertRefableResponse(refable spec.Refable) spec.Refable {
|
||
|
if refable.Ref.String() != "" {
|
||
|
return spec.Refable{Ref: spec.MustCreateRef(strings.Replace(refable.Ref.String(), "#/responses/", "#/components/responses/", 1))}
|
||
|
}
|
||
|
return refable
|
||
|
}
|