k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/common/common.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package common 18 19 import ( 20 "net/http" 21 "strings" 22 23 "github.com/emicklei/go-restful/v3" 24 25 "k8s.io/kube-openapi/pkg/spec3" 26 "k8s.io/kube-openapi/pkg/validation/spec" 27 ) 28 29 const ( 30 // TODO: Make this configurable. 31 ExtensionPrefix = "x-kubernetes-" 32 ExtensionV2Schema = ExtensionPrefix + "v2-schema" 33 ) 34 35 // OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi. 36 type OpenAPIDefinition struct { 37 Schema spec.Schema 38 Dependencies []string 39 } 40 41 type ReferenceCallback func(path string) spec.Ref 42 43 // GetOpenAPIDefinitions is collection of all definitions. 44 type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition 45 46 // OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface, 47 // the definition returned by it will be used, otherwise the auto-generated definitions will be used. See 48 // GetOpenAPITypeFormat for more information about trade-offs of using this interface or GetOpenAPITypeFormat method when 49 // possible. 50 type OpenAPIDefinitionGetter interface { 51 OpenAPIDefinition() *OpenAPIDefinition 52 } 53 54 type OpenAPIV3DefinitionGetter interface { 55 OpenAPIV3Definition() *OpenAPIDefinition 56 } 57 58 type PathHandler interface { 59 Handle(path string, handler http.Handler) 60 } 61 62 type PathHandlerByGroupVersion interface { 63 Handle(path string, handler http.Handler) 64 HandlePrefix(path string, handler http.Handler) 65 } 66 67 // Config is set of configuration for openAPI spec generation. 68 type Config struct { 69 // List of supported protocols such as https, http, etc. 70 ProtocolList []string 71 72 // Info is general information about the API. 73 Info *spec.Info 74 75 // DefaultResponse will be used if an operation does not have any responses listed. It 76 // will show up as ... "responses" : {"default" : $DefaultResponse} in the spec. 77 DefaultResponse *spec.Response 78 79 // ResponseDefinitions will be added to "responses" under the top-level swagger object. This is an object 80 // that holds responses definitions that can be used across operations. This property does not define 81 // global responses for all operations. For more info please refer: 82 // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields 83 ResponseDefinitions map[string]spec.Response 84 85 // CommonResponses will be added as a response to all operation specs. This is a good place to add common 86 // responses such as authorization failed. 87 CommonResponses map[int]spec.Response 88 89 // List of webservice's path prefixes to ignore 90 IgnorePrefixes []string 91 92 // OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map 93 // or any of the models will result in spec generation failure. 94 GetDefinitions GetOpenAPIDefinitions 95 96 // Provides the definition for all models used by routes. One of GetDefinitions or Definitions must be defined to generate a spec. 97 // This takes precedent over the GetDefinitions function 98 Definitions map[string]OpenAPIDefinition 99 100 // GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs. 101 // 102 // Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route 103 // interface set of funcs. 104 GetOperationIDAndTags func(r *restful.Route) (string, []string, error) 105 106 // GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs. 107 GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error) 108 109 // GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition. 110 // It is an optional function to customize model names. 111 GetDefinitionName func(name string) (string, spec.Extensions) 112 113 // PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving. 114 PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error) 115 116 // SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config 117 // is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses. 118 SecurityDefinitions *spec.SecurityDefinitions 119 120 // DefaultSecurity for all operations. This will pass as spec.SwaggerProps.Security to OpenAPI. 121 // For most cases, this will be list of acceptable definitions in SecurityDefinitions. 122 DefaultSecurity []map[string][]string 123 } 124 125 // OpenAPIV3Config is set of configuration for OpenAPI V3 spec generation. 126 type OpenAPIV3Config struct { 127 // Info is general information about the API. 128 Info *spec.Info 129 130 // DefaultResponse will be used if an operation does not have any responses listed. It 131 // will show up as ... "responses" : {"default" : $DefaultResponse} in the spec. 132 DefaultResponse *spec3.Response 133 134 // ResponseDefinitions will be added to responses component. This is an object 135 // that holds responses that can be used across operations. 136 ResponseDefinitions map[string]*spec3.Response 137 138 // CommonResponses will be added as a response to all operation specs. This is a good place to add common 139 // responses such as authorization failed. 140 CommonResponses map[int]*spec3.Response 141 142 // List of webservice's path prefixes to ignore 143 IgnorePrefixes []string 144 145 // OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map 146 // or any of the models will result in spec generation failure. 147 // One of GetDefinitions or Definitions must be defined to generate a spec. 148 GetDefinitions GetOpenAPIDefinitions 149 150 // Provides the definition for all models used by routes. One of GetDefinitions or Definitions must be defined to generate a spec. 151 // This takes precedent over the GetDefinitions function 152 Definitions map[string]OpenAPIDefinition 153 154 // GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs. 155 // 156 // Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route 157 // interface set of funcs. 158 GetOperationIDAndTags func(r *restful.Route) (string, []string, error) 159 160 // GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs. 161 GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error) 162 163 // GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition. 164 // It is an optional function to customize model names. 165 GetDefinitionName func(name string) (string, spec.Extensions) 166 167 // PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving. 168 PostProcessSpec func(*spec3.OpenAPI) (*spec3.OpenAPI, error) 169 170 // SecuritySchemes is list of all security schemes for OpenAPI service. 171 SecuritySchemes spec3.SecuritySchemes 172 173 // DefaultSecurity for all operations. 174 DefaultSecurity []map[string][]string 175 } 176 177 type typeInfo struct { 178 name string 179 format string 180 zero interface{} 181 } 182 183 var schemaTypeFormatMap = map[string]typeInfo{ 184 "uint": {"integer", "int32", 0.}, 185 "uint8": {"integer", "byte", 0.}, 186 "uint16": {"integer", "int32", 0.}, 187 "uint32": {"integer", "int64", 0.}, 188 "uint64": {"integer", "int64", 0.}, 189 "int": {"integer", "int32", 0.}, 190 "int8": {"integer", "byte", 0.}, 191 "int16": {"integer", "int32", 0.}, 192 "int32": {"integer", "int32", 0.}, 193 "int64": {"integer", "int64", 0.}, 194 "byte": {"integer", "byte", 0}, 195 "float64": {"number", "double", 0.}, 196 "float32": {"number", "float", 0.}, 197 "bool": {"boolean", "", false}, 198 "time.Time": {"string", "date-time", ""}, 199 "string": {"string", "", ""}, 200 "integer": {"integer", "", 0.}, 201 "number": {"number", "", 0.}, 202 "boolean": {"boolean", "", false}, 203 "[]byte": {"string", "byte", ""}, // base64 encoded characters 204 "interface{}": {"object", "", interface{}(nil)}, 205 } 206 207 // This function is a reference for converting go (or any custom type) to a simple open API type,format pair. There are 208 // two ways to customize spec for a type. If you add it here, a type will be converted to a simple type and the type 209 // comment (the comment that is added before type definition) will be lost. The spec will still have the property 210 // comment. The second way is to implement OpenAPIDefinitionGetter interface. That function can customize the spec (so 211 // the spec does not need to be simple type,format) or can even return a simple type,format (e.g. IntOrString). For simple 212 // type formats, the benefit of adding OpenAPIDefinitionGetter interface is to keep both type and property documentation. 213 // Example: 214 // 215 // type Sample struct { 216 // ... 217 // // port of the server 218 // port IntOrString 219 // ... 220 // } 221 // 222 // // IntOrString documentation... 223 // type IntOrString { ... } 224 // 225 // Adding IntOrString to this function: 226 // 227 // "port" : { 228 // format: "string", 229 // type: "int-or-string", 230 // Description: "port of the server" 231 // } 232 // 233 // Implement OpenAPIDefinitionGetter for IntOrString: 234 // 235 // "port" : { 236 // $Ref: "#/definitions/IntOrString" 237 // Description: "port of the server" 238 // } 239 // 240 // ... 241 // definitions: 242 // 243 // { 244 // "IntOrString": { 245 // format: "string", 246 // type: "int-or-string", 247 // Description: "IntOrString documentation..." // new 248 // } 249 // } 250 func OpenAPITypeFormat(typeName string) (string, string) { 251 mapped, ok := schemaTypeFormatMap[typeName] 252 if !ok { 253 return "", "" 254 } 255 return mapped.name, mapped.format 256 } 257 258 // Returns the zero-value for the given type along with true if the type 259 // could be found. 260 func OpenAPIZeroValue(typeName string) (interface{}, bool) { 261 mapped, ok := schemaTypeFormatMap[typeName] 262 if !ok { 263 return nil, false 264 } 265 return mapped.zero, true 266 } 267 268 func EscapeJsonPointer(p string) string { 269 // Escaping reference name using rfc6901 270 p = strings.Replace(p, "~", "~0", -1) 271 p = strings.Replace(p, "/", "~1", -1) 272 return p 273 } 274 275 func EmbedOpenAPIDefinitionIntoV2Extension(main OpenAPIDefinition, embedded OpenAPIDefinition) OpenAPIDefinition { 276 if main.Schema.Extensions == nil { 277 main.Schema.Extensions = make(map[string]interface{}) 278 } 279 main.Schema.Extensions[ExtensionV2Schema] = embedded.Schema 280 return main 281 } 282 283 // GenerateOpenAPIV3OneOfSchema generate the set of schemas that MUST be assigned to SchemaProps.OneOf 284 func GenerateOpenAPIV3OneOfSchema(types []string) (oneOf []spec.Schema) { 285 for _, t := range types { 286 oneOf = append(oneOf, spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{t}}}) 287 } 288 return 289 }