mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
build: move e2e dependencies into e2e/go.mod
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
15da101b1b
commit
bec6090996
20
e2e/vendor/k8s.io/kube-openapi/pkg/builder/doc.go
generated
vendored
Normal file
20
e2e/vendor/k8s.io/kube-openapi/pkg/builder/doc.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2016 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 builder contains code to generate OpenAPI discovery spec (which
|
||||
// initial version of it also known as Swagger 2.0).
|
||||
// For more details: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
|
||||
package builder
|
468
e2e/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
generated
vendored
Normal file
468
e2e/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
generated
vendored
Normal file
@ -0,0 +1,468 @@
|
||||
/*
|
||||
Copyright 2016 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 builder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
restful "github.com/emicklei/go-restful/v3"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/common/restfuladapter"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
OpenAPIVersion = "2.0"
|
||||
)
|
||||
|
||||
type openAPI struct {
|
||||
config *common.Config
|
||||
swagger *spec.Swagger
|
||||
protocolList []string
|
||||
definitions map[string]common.OpenAPIDefinition
|
||||
}
|
||||
|
||||
// BuildOpenAPISpec builds OpenAPI spec given a list of route containers and common.Config to customize it.
|
||||
//
|
||||
// Deprecated: BuildOpenAPISpecFromRoutes should be used instead.
|
||||
func BuildOpenAPISpec(routeContainers []*restful.WebService, config *common.Config) (*spec.Swagger, error) {
|
||||
return BuildOpenAPISpecFromRoutes(restfuladapter.AdaptWebServices(routeContainers), config)
|
||||
}
|
||||
|
||||
// BuildOpenAPISpecFromRoutes builds OpenAPI spec given a list of route containers and common.Config to customize it.
|
||||
func BuildOpenAPISpecFromRoutes(routeContainers []common.RouteContainer, config *common.Config) (*spec.Swagger, error) {
|
||||
o := newOpenAPI(config)
|
||||
err := o.buildPaths(routeContainers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.finalizeSwagger()
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it.
|
||||
func BuildOpenAPIDefinitionsForResource(model interface{}, config *common.Config) (*spec.Definitions, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
_, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
swagger, err := o.finalizeSwagger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &swagger.Definitions, nil
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResources returns the OpenAPI spec which includes the definitions for the
|
||||
// passed type names.
|
||||
func BuildOpenAPIDefinitionsForResources(config *common.Config, names ...string) (*spec.Swagger, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
for _, name := range names {
|
||||
_, err := o.toSchema(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return o.finalizeSwagger()
|
||||
}
|
||||
|
||||
// newOpenAPI sets up the openAPI object so we can build the spec.
|
||||
func newOpenAPI(config *common.Config) openAPI {
|
||||
o := openAPI{
|
||||
config: config,
|
||||
swagger: &spec.Swagger{
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
Swagger: OpenAPIVersion,
|
||||
Definitions: spec.Definitions{},
|
||||
Responses: config.ResponseDefinitions,
|
||||
Paths: &spec.Paths{Paths: map[string]spec.PathItem{}},
|
||||
Info: config.Info,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if o.config.GetOperationIDAndTagsFromRoute == nil {
|
||||
// Map the deprecated handler to the common interface, if provided.
|
||||
if o.config.GetOperationIDAndTags != nil {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
restfulRouteAdapter, ok := r.(*restfuladapter.RouteAdapter)
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("config.GetOperationIDAndTags specified but route is not a restful v1 Route")
|
||||
}
|
||||
|
||||
return o.config.GetOperationIDAndTags(restfulRouteAdapter.Route)
|
||||
}
|
||||
} else {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
return r.OperationName(), nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.config.GetDefinitionName == nil {
|
||||
o.config.GetDefinitionName = func(name string) (string, spec.Extensions) {
|
||||
return name[strings.LastIndex(name, "/")+1:], nil
|
||||
}
|
||||
}
|
||||
o.definitions = o.config.GetDefinitions(func(name string) spec.Ref {
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return spec.MustCreateRef("#/definitions/" + common.EscapeJsonPointer(defName))
|
||||
})
|
||||
if o.config.CommonResponses == nil {
|
||||
o.config.CommonResponses = map[int]spec.Response{}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// finalizeSwagger is called after the spec is built and returns the final spec.
|
||||
// NOTE: finalizeSwagger also make changes to the final spec, as specified in the config.
|
||||
func (o *openAPI) finalizeSwagger() (*spec.Swagger, error) {
|
||||
if o.config.SecurityDefinitions != nil {
|
||||
o.swagger.SecurityDefinitions = *o.config.SecurityDefinitions
|
||||
o.swagger.Security = o.config.DefaultSecurity
|
||||
}
|
||||
if o.config.PostProcessSpec != nil {
|
||||
var err error
|
||||
o.swagger, err = o.config.PostProcessSpec(o.swagger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return deduplicateParameters(o.swagger)
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionRecursively(name string) error {
|
||||
uniqueName, extensions := o.config.GetDefinitionName(name)
|
||||
if _, ok := o.swagger.Definitions[uniqueName]; ok {
|
||||
return nil
|
||||
}
|
||||
if item, ok := o.definitions[name]; ok {
|
||||
schema := spec.Schema{
|
||||
VendorExtensible: item.Schema.VendorExtensible,
|
||||
SchemaProps: item.Schema.SchemaProps,
|
||||
SwaggerSchemaProps: item.Schema.SwaggerSchemaProps,
|
||||
}
|
||||
if extensions != nil {
|
||||
if schema.Extensions == nil {
|
||||
schema.Extensions = spec.Extensions{}
|
||||
}
|
||||
for k, v := range extensions {
|
||||
schema.Extensions[k] = v
|
||||
}
|
||||
}
|
||||
if v, ok := item.Schema.Extensions[common.ExtensionV2Schema]; ok {
|
||||
if v2Schema, isOpenAPISchema := v.(spec.Schema); isOpenAPISchema {
|
||||
schema = v2Schema
|
||||
}
|
||||
}
|
||||
o.swagger.Definitions[uniqueName] = schema
|
||||
for _, v := range item.Dependencies {
|
||||
if err := o.buildDefinitionRecursively(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("cannot find model definition for %v. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildDefinitionForType build a definition for a given type and return a referable name to its definition.
|
||||
// This is the main function that keep track of definitions used in this spec and is depend on code generated
|
||||
// by k8s.io/kubernetes/cmd/libs/go2idl/openapi-gen.
|
||||
func (o *openAPI) buildDefinitionForType(name string) (string, error) {
|
||||
if err := o.buildDefinitionRecursively(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return "#/definitions/" + common.EscapeJsonPointer(defName), nil
|
||||
}
|
||||
|
||||
// buildPaths builds OpenAPI paths using go-restful's web services.
|
||||
func (o *openAPI) buildPaths(routeContainers []common.RouteContainer) error {
|
||||
pathsToIgnore := util.NewTrie(o.config.IgnorePrefixes)
|
||||
duplicateOpId := make(map[string]string)
|
||||
for _, w := range routeContainers {
|
||||
rootPath := w.RootPath()
|
||||
if pathsToIgnore.HasPrefix(rootPath) {
|
||||
continue
|
||||
}
|
||||
commonParams, err := o.buildParameters(w.PathParameters())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for path, routes := range groupRoutesByPath(w.Routes()) {
|
||||
// go-swagger has special variable definition {$NAME:*} that can only be
|
||||
// used at the end of the path and it is not recognized by OpenAPI.
|
||||
if strings.HasSuffix(path, ":*}") {
|
||||
path = path[:len(path)-3] + "}"
|
||||
}
|
||||
if pathsToIgnore.HasPrefix(path) {
|
||||
continue
|
||||
}
|
||||
// Aggregating common parameters make API spec (and generated clients) simpler
|
||||
inPathCommonParamsMap, err := o.findCommonParameters(routes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathItem, exists := o.swagger.Paths.Paths[path]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate webservice route has been found for path: %v", path)
|
||||
}
|
||||
pathItem = spec.PathItem{
|
||||
PathItemProps: spec.PathItemProps{
|
||||
Parameters: make([]spec.Parameter, 0),
|
||||
},
|
||||
}
|
||||
// add web services's parameters as well as any parameters appears in all ops, as common parameters
|
||||
pathItem.Parameters = append(pathItem.Parameters, commonParams...)
|
||||
for _, p := range inPathCommonParamsMap {
|
||||
pathItem.Parameters = append(pathItem.Parameters, p)
|
||||
}
|
||||
sortParameters(pathItem.Parameters)
|
||||
for _, route := range routes {
|
||||
op, err := o.buildOperations(route, inPathCommonParamsMap)
|
||||
sortParameters(op.Parameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dpath, exists := duplicateOpId[op.ID]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate Operation ID %v for path %v and %v", op.ID, dpath, path)
|
||||
} else {
|
||||
duplicateOpId[op.ID] = path
|
||||
}
|
||||
switch strings.ToUpper(route.Method()) {
|
||||
case "GET":
|
||||
pathItem.Get = op
|
||||
case "POST":
|
||||
pathItem.Post = op
|
||||
case "HEAD":
|
||||
pathItem.Head = op
|
||||
case "PUT":
|
||||
pathItem.Put = op
|
||||
case "DELETE":
|
||||
pathItem.Delete = op
|
||||
case "OPTIONS":
|
||||
pathItem.Options = op
|
||||
case "PATCH":
|
||||
pathItem.Patch = op
|
||||
}
|
||||
}
|
||||
o.swagger.Paths.Paths[path] = pathItem
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildOperations builds operations for each webservice path
|
||||
func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[interface{}]spec.Parameter) (ret *spec.Operation, err error) {
|
||||
ret = &spec.Operation{
|
||||
OperationProps: spec.OperationProps{
|
||||
Description: route.Description(),
|
||||
Consumes: route.Consumes(),
|
||||
Produces: route.Produces(),
|
||||
Schemes: o.config.ProtocolList,
|
||||
Responses: &spec.Responses{
|
||||
ResponsesProps: spec.ResponsesProps{
|
||||
StatusCodeResponses: make(map[int]spec.Response),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range route.Metadata() {
|
||||
if strings.HasPrefix(k, common.ExtensionPrefix) {
|
||||
if ret.Extensions == nil {
|
||||
ret.Extensions = spec.Extensions{}
|
||||
}
|
||||
ret.Extensions.Add(k, v)
|
||||
}
|
||||
}
|
||||
if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTagsFromRoute(route); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Build responses
|
||||
for _, resp := range route.StatusCodeResponses() {
|
||||
ret.Responses.StatusCodeResponses[resp.Code()], err = o.buildResponse(resp.Model(), resp.Message())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
// If there is no response but a write sample, assume that write sample is an http.StatusOK response.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 && route.ResponsePayloadSample() != nil {
|
||||
ret.Responses.StatusCodeResponses[http.StatusOK], err = o.buildResponse(route.ResponsePayloadSample(), "OK")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
for code, resp := range o.config.CommonResponses {
|
||||
if _, exists := ret.Responses.StatusCodeResponses[code]; !exists {
|
||||
ret.Responses.StatusCodeResponses[code] = resp
|
||||
}
|
||||
}
|
||||
// If there is still no response, use default response provided.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 {
|
||||
ret.Responses.Default = o.config.DefaultResponse
|
||||
}
|
||||
|
||||
// Build non-common Parameters
|
||||
ret.Parameters = make([]spec.Parameter, 0)
|
||||
for _, param := range route.Parameters() {
|
||||
if _, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]; !isCommon {
|
||||
openAPIParam, err := o.buildParameter(param, route.RequestPayloadSample())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
ret.Parameters = append(ret.Parameters, openAPIParam)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildResponse(model interface{}, description string) (spec.Response, error) {
|
||||
schema, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return spec.Response{}, err
|
||||
}
|
||||
return spec.Response{
|
||||
ResponseProps: spec.ResponseProps{
|
||||
Description: description,
|
||||
Schema: schema,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) findCommonParameters(routes []common.Route) (map[interface{}]spec.Parameter, error) {
|
||||
commonParamsMap := make(map[interface{}]spec.Parameter, 0)
|
||||
paramOpsCountByName := make(map[interface{}]int, 0)
|
||||
paramNameKindToDataMap := make(map[interface{}]common.Parameter, 0)
|
||||
for _, route := range routes {
|
||||
routeParamDuplicateMap := make(map[interface{}]bool)
|
||||
s := ""
|
||||
params := route.Parameters()
|
||||
for _, param := range params {
|
||||
m, _ := json.Marshal(param)
|
||||
s += string(m) + "\n"
|
||||
key := mapKeyFromParam(param)
|
||||
if routeParamDuplicateMap[key] {
|
||||
msg, _ := json.Marshal(params)
|
||||
return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v", param.Name(), string(msg), s)
|
||||
}
|
||||
routeParamDuplicateMap[key] = true
|
||||
paramOpsCountByName[key]++
|
||||
paramNameKindToDataMap[key] = param
|
||||
}
|
||||
}
|
||||
for key, count := range paramOpsCountByName {
|
||||
paramData := paramNameKindToDataMap[key]
|
||||
if count == len(routes) && paramData.Kind() != common.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(paramData, nil)
|
||||
if err != nil {
|
||||
return commonParamsMap, err
|
||||
}
|
||||
commonParamsMap[key] = openAPIParam
|
||||
}
|
||||
}
|
||||
return commonParamsMap, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) toSchema(name string) (_ *spec.Schema, err error) {
|
||||
if openAPIType, openAPIFormat := common.OpenAPITypeFormat(name); openAPIType != "" {
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
ref, err := o.buildDefinitionForType(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: spec.MustCreateRef(ref),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameter(restParam common.Parameter, bodySample interface{}) (ret spec.Parameter, err error) {
|
||||
ret = spec.Parameter{
|
||||
ParamProps: spec.ParamProps{
|
||||
Name: restParam.Name(),
|
||||
Description: restParam.Description(),
|
||||
Required: restParam.Required(),
|
||||
},
|
||||
}
|
||||
switch restParam.Kind() {
|
||||
case common.BodyParameterKind:
|
||||
if bodySample != nil {
|
||||
ret.In = "body"
|
||||
ret.Schema, err = o.toSchema(util.GetCanonicalTypeName(bodySample))
|
||||
return ret, err
|
||||
} else {
|
||||
// There is not enough information in the body parameter to build the definition.
|
||||
// Body parameter has a data type that is a short name but we need full package name
|
||||
// of the type to create a definition.
|
||||
return ret, fmt.Errorf("restful body parameters are not supported: %v", restParam.DataType())
|
||||
}
|
||||
case common.PathParameterKind:
|
||||
ret.In = "path"
|
||||
if !restParam.Required() {
|
||||
return ret, fmt.Errorf("path parameters should be marked at required for parameter %v", restParam)
|
||||
}
|
||||
case common.QueryParameterKind:
|
||||
ret.In = "query"
|
||||
case common.HeaderParameterKind:
|
||||
ret.In = "header"
|
||||
case common.FormParameterKind:
|
||||
ret.In = "formData"
|
||||
default:
|
||||
return ret, fmt.Errorf("unknown restful operation kind : %v", restParam.Kind())
|
||||
}
|
||||
openAPIType, openAPIFormat := common.OpenAPITypeFormat(restParam.DataType())
|
||||
if openAPIType == "" {
|
||||
return ret, fmt.Errorf("non-body Restful parameter type should be a simple type, but got : %v", restParam.DataType())
|
||||
}
|
||||
ret.Type = openAPIType
|
||||
ret.Format = openAPIFormat
|
||||
ret.UniqueItems = !restParam.AllowMultiple()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameters(restParam []common.Parameter) (ret []spec.Parameter, err error) {
|
||||
ret = make([]spec.Parameter, len(restParam))
|
||||
for i, v := range restParam {
|
||||
ret[i], err = o.buildParameter(v, nil)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
259
e2e/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go
generated
vendored
Normal file
259
e2e/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go
generated
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
Copyright 2023 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 builder
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// deduplicateParameters finds parameters that are shared across multiple endpoints and replace them with
|
||||
// references to the shared parameters in order to avoid repetition.
|
||||
//
|
||||
// deduplicateParameters does not mutate the source.
|
||||
func deduplicateParameters(sp *spec.Swagger) (*spec.Swagger, error) {
|
||||
names, parameters, err := collectSharedParameters(sp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sp.Parameters != nil {
|
||||
return nil, fmt.Errorf("shared parameters already exist") // should not happen with the builder, but to be sure
|
||||
}
|
||||
|
||||
clone := *sp
|
||||
clone.Parameters = parameters
|
||||
return replaceSharedParameters(names, &clone)
|
||||
}
|
||||
|
||||
// collectSharedParameters finds parameters that show up for many endpoints. These
|
||||
// are basically all parameters with the exceptions of those where we know they are
|
||||
// endpoint specific, e.g. because they reference the schema of the kind, or have
|
||||
// the kind or resource name in the description.
|
||||
func collectSharedParameters(sp *spec.Swagger) (namesByJSON map[string]string, ret map[string]spec.Parameter, err error) {
|
||||
if sp == nil || sp.Paths == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
countsByJSON := map[string]int{}
|
||||
shared := map[string]spec.Parameter{}
|
||||
var keys []string
|
||||
|
||||
collect := func(p *spec.Parameter) error {
|
||||
if (p.In == "query" || p.In == "path") && p.Name == "name" {
|
||||
return nil // ignore name parameter as they are never shared with the Kind in the description
|
||||
}
|
||||
if p.In == "query" && p.Name == "fieldValidation" {
|
||||
return nil // keep fieldValidation parameter unshared because kubectl uses it (until 1.27) to detect server-side field validation support
|
||||
}
|
||||
if p.In == "query" && p.Name == "dryRun" {
|
||||
return nil // keep fieldValidation parameter unshared because kubectl uses it (until 1.26) to detect dry-run support
|
||||
}
|
||||
if p.Schema != nil && p.In == "body" && p.Name == "body" && !strings.HasPrefix(p.Schema.Ref.String(), "#/definitions/io.k8s.apimachinery") {
|
||||
return nil // ignore non-generic body parameters as they reference the custom schema of the kind
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k := string(bs)
|
||||
countsByJSON[k]++
|
||||
if count := countsByJSON[k]; count == 1 {
|
||||
shared[k] = *p
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, path := range sp.Paths.Paths {
|
||||
// per operation parameters
|
||||
for _, op := range operations(&path) {
|
||||
if op == nil {
|
||||
continue // shouldn't happen, but ignore if it does; tested through unit test
|
||||
}
|
||||
for _, p := range op.Parameters {
|
||||
if p.Ref.String() != "" {
|
||||
// shouldn't happen, but ignore if it does
|
||||
continue
|
||||
}
|
||||
if err := collect(&p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// per path parameters
|
||||
for _, p := range path.Parameters {
|
||||
if p.Ref.String() != "" {
|
||||
continue // shouldn't happen, but ignore if it does
|
||||
}
|
||||
if err := collect(&p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// name deterministically
|
||||
sort.Strings(keys)
|
||||
ret = map[string]spec.Parameter{}
|
||||
namesByJSON = map[string]string{}
|
||||
for _, k := range keys {
|
||||
name := shared[k].Name
|
||||
if name == "" {
|
||||
// this should never happen as the name is a required field. But if it does, let's be safe.
|
||||
name = "param"
|
||||
}
|
||||
name += "-" + base64Hash(k)
|
||||
i := 0
|
||||
for {
|
||||
if _, ok := ret[name]; !ok {
|
||||
ret[name] = shared[k]
|
||||
namesByJSON[k] = name
|
||||
break
|
||||
}
|
||||
i++ // only on hash conflict, unlikely with our few variants
|
||||
name = shared[k].Name + "-" + strconv.Itoa(i)
|
||||
}
|
||||
}
|
||||
|
||||
return namesByJSON, ret, nil
|
||||
}
|
||||
|
||||
func operations(path *spec.PathItem) []*spec.Operation {
|
||||
return []*spec.Operation{path.Get, path.Put, path.Post, path.Delete, path.Options, path.Head, path.Patch}
|
||||
}
|
||||
|
||||
func base64Hash(s string) string {
|
||||
hash := fnv.New64()
|
||||
hash.Write([]byte(s)) //nolint:errcheck
|
||||
return base64.URLEncoding.EncodeToString(hash.Sum(make([]byte, 0, 8))[:6]) // 8 characters
|
||||
}
|
||||
|
||||
func replaceSharedParameters(sharedParameterNamesByJSON map[string]string, sp *spec.Swagger) (*spec.Swagger, error) {
|
||||
if sp == nil || sp.Paths == nil {
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
ret := sp
|
||||
|
||||
firstPathChange := true
|
||||
for k, path := range sp.Paths.Paths {
|
||||
pathChanged := false
|
||||
|
||||
// per operation parameters
|
||||
for _, op := range []**spec.Operation{&path.Get, &path.Put, &path.Post, &path.Delete, &path.Options, &path.Head, &path.Patch} {
|
||||
if *op == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
firstParamChange := true
|
||||
for i := range (*op).Parameters {
|
||||
p := (*op).Parameters[i]
|
||||
|
||||
if p.Ref.String() != "" {
|
||||
// shouldn't happen, but be idem-potent if it does
|
||||
continue
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if name, ok := sharedParameterNamesByJSON[string(bs)]; ok {
|
||||
if firstParamChange {
|
||||
orig := *op
|
||||
*op = &spec.Operation{}
|
||||
**op = *orig
|
||||
(*op).Parameters = make([]spec.Parameter, len(orig.Parameters))
|
||||
copy((*op).Parameters, orig.Parameters)
|
||||
firstParamChange = false
|
||||
}
|
||||
|
||||
(*op).Parameters[i] = spec.Parameter{
|
||||
Refable: spec.Refable{
|
||||
Ref: spec.MustCreateRef("#/parameters/" + name),
|
||||
},
|
||||
}
|
||||
pathChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// per path parameters
|
||||
firstParamChange := true
|
||||
for i := range path.Parameters {
|
||||
p := path.Parameters[i]
|
||||
|
||||
if p.Ref.String() != "" {
|
||||
// shouldn't happen, but be idem-potent if it does
|
||||
continue
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if name, ok := sharedParameterNamesByJSON[string(bs)]; ok {
|
||||
if firstParamChange {
|
||||
orig := path.Parameters
|
||||
path.Parameters = make([]spec.Parameter, len(orig))
|
||||
copy(path.Parameters, orig)
|
||||
firstParamChange = false
|
||||
}
|
||||
|
||||
path.Parameters[i] = spec.Parameter{
|
||||
Refable: spec.Refable{
|
||||
Ref: spec.MustCreateRef("#/parameters/" + name),
|
||||
},
|
||||
}
|
||||
pathChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
if pathChanged {
|
||||
if firstPathChange {
|
||||
clone := *sp
|
||||
ret = &clone
|
||||
|
||||
pathsClone := *ret.Paths
|
||||
ret.Paths = &pathsClone
|
||||
|
||||
ret.Paths.Paths = make(map[string]spec.PathItem, len(sp.Paths.Paths))
|
||||
for k, v := range sp.Paths.Paths {
|
||||
ret.Paths.Paths[k] = v
|
||||
}
|
||||
|
||||
firstPathChange = false
|
||||
}
|
||||
ret.Paths.Paths[k] = path
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
61
e2e/vendor/k8s.io/kube-openapi/pkg/builder/util.go
generated
vendored
Normal file
61
e2e/vendor/k8s.io/kube-openapi/pkg/builder/util.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2016 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 builder
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
type parameters []spec.Parameter
|
||||
|
||||
func (s parameters) Len() int { return len(s) }
|
||||
func (s parameters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// byNameIn used in sorting parameters by Name and In fields.
|
||||
type byNameIn struct {
|
||||
parameters
|
||||
}
|
||||
|
||||
func (s byNameIn) Less(i, j int) bool {
|
||||
return s.parameters[i].Name < s.parameters[j].Name || (s.parameters[i].Name == s.parameters[j].Name && s.parameters[i].In < s.parameters[j].In)
|
||||
}
|
||||
|
||||
// SortParameters sorts parameters by Name and In fields.
|
||||
func sortParameters(p []spec.Parameter) {
|
||||
sort.Sort(byNameIn{p})
|
||||
}
|
||||
|
||||
func groupRoutesByPath(routes []common.Route) map[string][]common.Route {
|
||||
pathToRoutes := make(map[string][]common.Route)
|
||||
for _, r := range routes {
|
||||
pathToRoutes[r.Path()] = append(pathToRoutes[r.Path()], r)
|
||||
}
|
||||
return pathToRoutes
|
||||
}
|
||||
|
||||
func mapKeyFromParam(param common.Parameter) interface{} {
|
||||
return struct {
|
||||
Name string
|
||||
Kind common.ParameterKind
|
||||
}{
|
||||
Name: param.Name(),
|
||||
Kind: param.Kind(),
|
||||
}
|
||||
}
|
498
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go
generated
vendored
Normal file
498
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go
generated
vendored
Normal file
@ -0,0 +1,498 @@
|
||||
/*
|
||||
Copyright 2021 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 builder3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
restful "github.com/emicklei/go-restful/v3"
|
||||
|
||||
builderutil "k8s.io/kube-openapi/pkg/builder3/util"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/common/restfuladapter"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
OpenAPIVersion = "3.0"
|
||||
)
|
||||
|
||||
type openAPI struct {
|
||||
config *common.OpenAPIV3Config
|
||||
spec *spec3.OpenAPI
|
||||
definitions map[string]common.OpenAPIDefinition
|
||||
}
|
||||
|
||||
func groupRoutesByPath(routes []common.Route) map[string][]common.Route {
|
||||
pathToRoutes := make(map[string][]common.Route)
|
||||
for _, r := range routes {
|
||||
pathToRoutes[r.Path()] = append(pathToRoutes[r.Path()], r)
|
||||
}
|
||||
return pathToRoutes
|
||||
}
|
||||
|
||||
func (o *openAPI) buildResponse(model interface{}, description string, content []string) (*spec3.Response, error) {
|
||||
response := &spec3.Response{
|
||||
ResponseProps: spec3.ResponseProps{
|
||||
Description: description,
|
||||
Content: make(map[string]*spec3.MediaType),
|
||||
},
|
||||
}
|
||||
|
||||
s, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, contentType := range content {
|
||||
response.ResponseProps.Content[contentType] = &spec3.MediaType{
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: s,
|
||||
},
|
||||
}
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[interface{}]*spec3.Parameter) (*spec3.Operation, error) {
|
||||
ret := &spec3.Operation{
|
||||
OperationProps: spec3.OperationProps{
|
||||
Description: route.Description(),
|
||||
Responses: &spec3.Responses{
|
||||
ResponsesProps: spec3.ResponsesProps{
|
||||
StatusCodeResponses: make(map[int]*spec3.Response),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range route.Metadata() {
|
||||
if strings.HasPrefix(k, common.ExtensionPrefix) {
|
||||
if ret.Extensions == nil {
|
||||
ret.Extensions = spec.Extensions{}
|
||||
}
|
||||
ret.Extensions.Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if ret.OperationId, ret.Tags, err = o.config.GetOperationIDAndTagsFromRoute(route); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Build responses
|
||||
for _, resp := range route.StatusCodeResponses() {
|
||||
ret.Responses.StatusCodeResponses[resp.Code()], err = o.buildResponse(resp.Model(), resp.Message(), route.Produces())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no response but a write sample, assume that write sample is an http.StatusOK response.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 && route.ResponsePayloadSample() != nil {
|
||||
ret.Responses.StatusCodeResponses[http.StatusOK], err = o.buildResponse(route.ResponsePayloadSample(), "OK", route.Produces())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
for code, resp := range o.config.CommonResponses {
|
||||
if _, exists := ret.Responses.StatusCodeResponses[code]; !exists {
|
||||
ret.Responses.StatusCodeResponses[code] = resp
|
||||
}
|
||||
}
|
||||
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 {
|
||||
ret.Responses.Default = o.config.DefaultResponse
|
||||
}
|
||||
|
||||
params := route.Parameters()
|
||||
for _, param := range params {
|
||||
_, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]
|
||||
if !isCommon && param.Kind() != common.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(param)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
ret.Parameters = append(ret.Parameters, openAPIParam)
|
||||
}
|
||||
}
|
||||
|
||||
body, err := o.buildRequestBody(params, route.Consumes(), route.RequestPayloadSample())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if body != nil {
|
||||
ret.RequestBody = body
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildRequestBody(parameters []common.Parameter, consumes []string, bodySample interface{}) (*spec3.RequestBody, error) {
|
||||
for _, param := range parameters {
|
||||
if param.Kind() == common.BodyParameterKind && bodySample != nil {
|
||||
schema, err := o.toSchema(util.GetCanonicalTypeName(bodySample))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &spec3.RequestBody{
|
||||
RequestBodyProps: spec3.RequestBodyProps{
|
||||
Content: map[string]*spec3.MediaType{},
|
||||
Description: param.Description(),
|
||||
Required: param.Required(),
|
||||
},
|
||||
}
|
||||
for _, consume := range consumes {
|
||||
r.Content[consume] = &spec3.MediaType{
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: schema,
|
||||
},
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func newOpenAPI(config *common.OpenAPIV3Config) openAPI {
|
||||
o := openAPI{
|
||||
config: config,
|
||||
spec: &spec3.OpenAPI{
|
||||
Version: "3.0.0",
|
||||
Info: config.Info,
|
||||
Paths: &spec3.Paths{
|
||||
Paths: map[string]*spec3.Path{},
|
||||
},
|
||||
Components: &spec3.Components{
|
||||
Schemas: map[string]*spec.Schema{},
|
||||
},
|
||||
},
|
||||
}
|
||||
if len(o.config.ResponseDefinitions) > 0 {
|
||||
o.spec.Components.Responses = make(map[string]*spec3.Response)
|
||||
|
||||
}
|
||||
for k, response := range o.config.ResponseDefinitions {
|
||||
o.spec.Components.Responses[k] = response
|
||||
}
|
||||
|
||||
if len(o.config.SecuritySchemes) > 0 {
|
||||
o.spec.Components.SecuritySchemes = make(spec3.SecuritySchemes)
|
||||
|
||||
}
|
||||
for k, securityScheme := range o.config.SecuritySchemes {
|
||||
o.spec.Components.SecuritySchemes[k] = securityScheme
|
||||
}
|
||||
|
||||
if o.config.GetOperationIDAndTagsFromRoute == nil {
|
||||
// Map the deprecated handler to the common interface, if provided.
|
||||
if o.config.GetOperationIDAndTags != nil {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
restfulRouteAdapter, ok := r.(*restfuladapter.RouteAdapter)
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("config.GetOperationIDAndTags specified but route is not a restful v1 Route")
|
||||
}
|
||||
|
||||
return o.config.GetOperationIDAndTags(restfulRouteAdapter.Route)
|
||||
}
|
||||
} else {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
return r.OperationName(), nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.config.GetDefinitionName == nil {
|
||||
o.config.GetDefinitionName = func(name string) (string, spec.Extensions) {
|
||||
return name[strings.LastIndex(name, "/")+1:], nil
|
||||
}
|
||||
}
|
||||
|
||||
if o.config.Definitions != nil {
|
||||
o.definitions = o.config.Definitions
|
||||
} else {
|
||||
o.definitions = o.config.GetDefinitions(func(name string) spec.Ref {
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return spec.MustCreateRef("#/components/schemas/" + common.EscapeJsonPointer(defName))
|
||||
})
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error {
|
||||
pathsToIgnore := util.NewTrie(o.config.IgnorePrefixes)
|
||||
for _, w := range webServices {
|
||||
rootPath := w.RootPath()
|
||||
if pathsToIgnore.HasPrefix(rootPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
commonParams, err := o.buildParameters(w.PathParameters())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for path, routes := range groupRoutesByPath(w.Routes()) {
|
||||
// go-swagger has special variable definition {$NAME:*} that can only be
|
||||
// used at the end of the path and it is not recognized by OpenAPI.
|
||||
if strings.HasSuffix(path, ":*}") {
|
||||
path = path[:len(path)-3] + "}"
|
||||
}
|
||||
if pathsToIgnore.HasPrefix(path) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Aggregating common parameters make API spec (and generated clients) simpler
|
||||
inPathCommonParamsMap, err := o.findCommonParameters(routes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathItem, exists := o.spec.Paths.Paths[path]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate webservice route has been found for path: %v", path)
|
||||
}
|
||||
|
||||
pathItem = &spec3.Path{
|
||||
PathProps: spec3.PathProps{},
|
||||
}
|
||||
|
||||
// add web services's parameters as well as any parameters appears in all ops, as common parameters
|
||||
pathItem.Parameters = append(pathItem.Parameters, commonParams...)
|
||||
for _, p := range inPathCommonParamsMap {
|
||||
pathItem.Parameters = append(pathItem.Parameters, p)
|
||||
}
|
||||
sortParameters(pathItem.Parameters)
|
||||
|
||||
for _, route := range routes {
|
||||
op, err := o.buildOperations(route, inPathCommonParamsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sortParameters(op.Parameters)
|
||||
|
||||
switch strings.ToUpper(route.Method()) {
|
||||
case "GET":
|
||||
pathItem.Get = op
|
||||
case "POST":
|
||||
pathItem.Post = op
|
||||
case "HEAD":
|
||||
pathItem.Head = op
|
||||
case "PUT":
|
||||
pathItem.Put = op
|
||||
case "DELETE":
|
||||
pathItem.Delete = op
|
||||
case "OPTIONS":
|
||||
pathItem.Options = op
|
||||
case "PATCH":
|
||||
pathItem.Patch = op
|
||||
}
|
||||
|
||||
}
|
||||
o.spec.Paths.Paths[path] = pathItem
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildOpenAPISpec builds OpenAPI v3 spec given a list of route containers and common.Config to customize it.
|
||||
//
|
||||
// Deprecated: BuildOpenAPISpecFromRoutes should be used instead.
|
||||
func BuildOpenAPISpec(webServices []*restful.WebService, config *common.OpenAPIV3Config) (*spec3.OpenAPI, error) {
|
||||
return BuildOpenAPISpecFromRoutes(restfuladapter.AdaptWebServices(webServices), config)
|
||||
}
|
||||
|
||||
// BuildOpenAPISpecFromRoutes builds OpenAPI v3 spec given a list of route containers and common.Config to customize it.
|
||||
func BuildOpenAPISpecFromRoutes(webServices []common.RouteContainer, config *common.OpenAPIV3Config) (*spec3.OpenAPI, error) {
|
||||
a := newOpenAPI(config)
|
||||
err := a.buildOpenAPISpec(webServices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.PostProcessSpec != nil {
|
||||
return config.PostProcessSpec(a.spec)
|
||||
}
|
||||
return a.spec, nil
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it.
|
||||
// BuildOpenAPIDefinitionsForResources returns the OpenAPI spec which includes the definitions for the
|
||||
// passed type names.
|
||||
func BuildOpenAPIDefinitionsForResources(config *common.OpenAPIV3Config, names ...string) (map[string]*spec.Schema, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
for _, name := range names {
|
||||
_, err := o.toSchema(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return o.spec.Components.Schemas, nil
|
||||
}
|
||||
func (o *openAPI) findCommonParameters(routes []common.Route) (map[interface{}]*spec3.Parameter, error) {
|
||||
commonParamsMap := make(map[interface{}]*spec3.Parameter, 0)
|
||||
paramOpsCountByName := make(map[interface{}]int, 0)
|
||||
paramNameKindToDataMap := make(map[interface{}]common.Parameter, 0)
|
||||
for _, route := range routes {
|
||||
routeParamDuplicateMap := make(map[interface{}]bool)
|
||||
s := ""
|
||||
params := route.Parameters()
|
||||
for _, param := range params {
|
||||
m, _ := json.Marshal(param)
|
||||
s += string(m) + "\n"
|
||||
key := mapKeyFromParam(param)
|
||||
if routeParamDuplicateMap[key] {
|
||||
msg, _ := json.Marshal(params)
|
||||
return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v", param.Name(), string(msg), s)
|
||||
}
|
||||
routeParamDuplicateMap[key] = true
|
||||
paramOpsCountByName[key]++
|
||||
paramNameKindToDataMap[key] = param
|
||||
}
|
||||
}
|
||||
for key, count := range paramOpsCountByName {
|
||||
paramData := paramNameKindToDataMap[key]
|
||||
if count == len(routes) && paramData.Kind() != common.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(paramData)
|
||||
if err != nil {
|
||||
return commonParamsMap, err
|
||||
}
|
||||
commonParamsMap[key] = openAPIParam
|
||||
}
|
||||
}
|
||||
return commonParamsMap, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameters(restParam []common.Parameter) (ret []*spec3.Parameter, err error) {
|
||||
ret = make([]*spec3.Parameter, len(restParam))
|
||||
for i, v := range restParam {
|
||||
ret[i], err = o.buildParameter(v)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameter(restParam common.Parameter) (ret *spec3.Parameter, err error) {
|
||||
ret = &spec3.Parameter{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: restParam.Name(),
|
||||
Description: restParam.Description(),
|
||||
Required: restParam.Required(),
|
||||
},
|
||||
}
|
||||
switch restParam.Kind() {
|
||||
case common.BodyParameterKind:
|
||||
return nil, nil
|
||||
case common.PathParameterKind:
|
||||
ret.In = "path"
|
||||
if !restParam.Required() {
|
||||
return ret, fmt.Errorf("path parameters should be marked as required for parameter %v", restParam)
|
||||
}
|
||||
case common.QueryParameterKind:
|
||||
ret.In = "query"
|
||||
case common.HeaderParameterKind:
|
||||
ret.In = "header"
|
||||
/* TODO: add support for the cookie param */
|
||||
default:
|
||||
return ret, fmt.Errorf("unsupported restful parameter kind : %v", restParam.Kind())
|
||||
}
|
||||
openAPIType, openAPIFormat := common.OpenAPITypeFormat(restParam.DataType())
|
||||
if openAPIType == "" {
|
||||
return ret, fmt.Errorf("non-body Restful parameter type should be a simple type, but got : %v", restParam.DataType())
|
||||
}
|
||||
|
||||
ret.Schema = &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
UniqueItems: !restParam.AllowMultiple(),
|
||||
},
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionRecursively(name string) error {
|
||||
uniqueName, extensions := o.config.GetDefinitionName(name)
|
||||
if _, ok := o.spec.Components.Schemas[uniqueName]; ok {
|
||||
return nil
|
||||
}
|
||||
if item, ok := o.definitions[name]; ok {
|
||||
schema := &spec.Schema{
|
||||
VendorExtensible: item.Schema.VendorExtensible,
|
||||
SchemaProps: item.Schema.SchemaProps,
|
||||
SwaggerSchemaProps: item.Schema.SwaggerSchemaProps,
|
||||
}
|
||||
if extensions != nil {
|
||||
if schema.Extensions == nil {
|
||||
schema.Extensions = spec.Extensions{}
|
||||
}
|
||||
for k, v := range extensions {
|
||||
schema.Extensions[k] = v
|
||||
}
|
||||
}
|
||||
// delete the embedded v2 schema if exists, otherwise no-op
|
||||
delete(schema.VendorExtensible.Extensions, common.ExtensionV2Schema)
|
||||
schema = builderutil.WrapRefs(schema)
|
||||
o.spec.Components.Schemas[uniqueName] = schema
|
||||
for _, v := range item.Dependencies {
|
||||
if err := o.buildDefinitionRecursively(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("cannot find model definition for %v. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionForType(name string) (string, error) {
|
||||
if err := o.buildDefinitionRecursively(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return "#/components/schemas/" + common.EscapeJsonPointer(defName), nil
|
||||
}
|
||||
|
||||
func (o *openAPI) toSchema(name string) (_ *spec.Schema, err error) {
|
||||
if openAPIType, openAPIFormat := common.OpenAPITypeFormat(name); openAPIType != "" {
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
ref, err := o.buildDefinitionForType(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: spec.MustCreateRef(ref),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
52
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util.go
generated
vendored
Normal file
52
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2021 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 builder3
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
)
|
||||
|
||||
func mapKeyFromParam(param common.Parameter) interface{} {
|
||||
return struct {
|
||||
Name string
|
||||
Kind common.ParameterKind
|
||||
}{
|
||||
Name: param.Name(),
|
||||
Kind: param.Kind(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s parameters) Len() int { return len(s) }
|
||||
func (s parameters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
type parameters []*spec3.Parameter
|
||||
|
||||
type byNameIn struct {
|
||||
parameters
|
||||
}
|
||||
|
||||
func (s byNameIn) Less(i, j int) bool {
|
||||
return s.parameters[i].Name < s.parameters[j].Name || (s.parameters[i].Name == s.parameters[j].Name && s.parameters[i].In < s.parameters[j].In)
|
||||
}
|
||||
|
||||
// SortParameters sorts parameters by Name and In fields.
|
||||
func sortParameters(p []*spec3.Parameter) {
|
||||
sort.Sort(byNameIn{p})
|
||||
}
|
51
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go
generated
vendored
Normal file
51
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/schemamutation"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// wrapRefs wraps OpenAPI V3 Schema refs that contain sibling elements.
|
||||
// AllOf is used to wrap the Ref to prevent references from having sibling elements
|
||||
// Please see https://github.com/kubernetes/kubernetes/issues/106387#issuecomment-967640388
|
||||
func WrapRefs(schema *spec.Schema) *spec.Schema {
|
||||
walker := schemamutation.Walker{
|
||||
SchemaCallback: func(schema *spec.Schema) *spec.Schema {
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = new(spec.Schema)
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
if schema.Ref.String() != "" && !reflect.DeepEqual(*schema, spec.Schema{SchemaProps: spec.SchemaProps{Ref: schema.Ref}}) {
|
||||
clone()
|
||||
refSchema := new(spec.Schema)
|
||||
refSchema.Ref = schema.Ref
|
||||
schema.Ref = spec.Ref{}
|
||||
schema.AllOf = []spec.Schema{*refSchema}
|
||||
}
|
||||
return schema
|
||||
},
|
||||
RefCallback: schemamutation.RefCallbackNoop,
|
||||
}
|
||||
return walker.WalkSchema(schema)
|
||||
}
|
290
e2e/vendor/k8s.io/kube-openapi/pkg/cached/cache.go
generated
vendored
Normal file
290
e2e/vendor/k8s.io/kube-openapi/pkg/cached/cache.go
generated
vendored
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
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 cached provides a cache mechanism based on etags to lazily
|
||||
// build, and/or cache results from expensive operation such that those
|
||||
// operations are not repeated unnecessarily. The operations can be
|
||||
// created as a tree, and replaced dynamically as needed.
|
||||
//
|
||||
// All the operations in this module are thread-safe.
|
||||
//
|
||||
// # Dependencies and types of caches
|
||||
//
|
||||
// This package uses a source/transform/sink model of caches to build
|
||||
// the dependency tree, and can be used as follows:
|
||||
// - [Func]: A source cache that recomputes the content every time.
|
||||
// - [Once]: A source cache that always produces the
|
||||
// same content, it is only called once.
|
||||
// - [Transform]: A cache that transforms data from one format to
|
||||
// another. It's only refreshed when the source changes.
|
||||
// - [Merge]: A cache that aggregates multiple caches in a map into one.
|
||||
// It's only refreshed when the source changes.
|
||||
// - [MergeList]: A cache that aggregates multiple caches in a list into one.
|
||||
// It's only refreshed when the source changes.
|
||||
// - [Atomic]: A cache adapter that atomically replaces the source with a new one.
|
||||
// - [LastSuccess]: A cache adapter that caches the last successful and returns
|
||||
// it if the next call fails. It extends [Atomic].
|
||||
//
|
||||
// # Etags
|
||||
//
|
||||
// Etags in this library is a cache version identifier. It doesn't
|
||||
// necessarily strictly match to the semantics of http `etags`, but are
|
||||
// somewhat inspired from it and function with the same principles.
|
||||
// Hashing the content is a good way to guarantee that your function is
|
||||
// never going to be called spuriously. In Kubernetes world, this could
|
||||
// be a `resourceVersion`, this can be an actual etag, a hash, a UUID
|
||||
// (if the cache always changes), or even a made-up string when the
|
||||
// content of the cache never changes.
|
||||
package cached
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Value is wrapping a value behind a getter for lazy evaluation.
|
||||
type Value[T any] interface {
|
||||
Get() (value T, etag string, err error)
|
||||
}
|
||||
|
||||
// Result is wrapping T and error into a struct for cases where a tuple is more
|
||||
// convenient or necessary in Golang.
|
||||
type Result[T any] struct {
|
||||
Value T
|
||||
Etag string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (r Result[T]) Get() (T, string, error) {
|
||||
return r.Value, r.Etag, r.Err
|
||||
}
|
||||
|
||||
// Func wraps a (thread-safe) function as a Value[T].
|
||||
func Func[T any](fn func() (T, string, error)) Value[T] {
|
||||
return valueFunc[T](fn)
|
||||
}
|
||||
|
||||
type valueFunc[T any] func() (T, string, error)
|
||||
|
||||
func (c valueFunc[T]) Get() (T, string, error) {
|
||||
return c()
|
||||
}
|
||||
|
||||
// Static returns constant values.
|
||||
func Static[T any](value T, etag string) Value[T] {
|
||||
return Result[T]{Value: value, Etag: etag}
|
||||
}
|
||||
|
||||
// Merge merges a of cached values. The merge function only gets called if any of
|
||||
// the dependency has changed.
|
||||
//
|
||||
// If any of the dependency returned an error before, or any of the
|
||||
// dependency returned an error this time, or if the mergeFn failed
|
||||
// before, then the function is run again.
|
||||
//
|
||||
// Note that this assumes there is no "partial" merge, the merge
|
||||
// function will remerge all the dependencies together everytime. Since
|
||||
// the list of dependencies is constant, there is no way to save some
|
||||
// partial merge information either.
|
||||
//
|
||||
// Also note that Golang map iteration is not stable. If the mergeFn
|
||||
// depends on the order iteration to be stable, it will need to
|
||||
// implement its own sorting or iteration order.
|
||||
func Merge[K comparable, T, V any](mergeFn func(results map[K]Result[T]) (V, string, error), caches map[K]Value[T]) Value[V] {
|
||||
list := make([]Value[T], 0, len(caches))
|
||||
|
||||
// map from index to key
|
||||
indexes := make(map[int]K, len(caches))
|
||||
i := 0
|
||||
for k := range caches {
|
||||
list = append(list, caches[k])
|
||||
indexes[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
return MergeList(func(results []Result[T]) (V, string, error) {
|
||||
if len(results) != len(indexes) {
|
||||
panic(fmt.Errorf("invalid result length %d, expected %d", len(results), len(indexes)))
|
||||
}
|
||||
m := make(map[K]Result[T], len(results))
|
||||
for i := range results {
|
||||
m[indexes[i]] = results[i]
|
||||
}
|
||||
return mergeFn(m)
|
||||
}, list)
|
||||
}
|
||||
|
||||
// MergeList merges a list of cached values. The function only gets called if
|
||||
// any of the dependency has changed.
|
||||
//
|
||||
// The benefit of ListMerger over the basic Merger is that caches are
|
||||
// stored in an ordered list so the order of the cache will be
|
||||
// preserved in the order of the results passed to the mergeFn.
|
||||
//
|
||||
// If any of the dependency returned an error before, or any of the
|
||||
// dependency returned an error this time, or if the mergeFn failed
|
||||
// before, then the function is reran.
|
||||
//
|
||||
// Note that this assumes there is no "partial" merge, the merge
|
||||
// function will remerge all the dependencies together everytime. Since
|
||||
// the list of dependencies is constant, there is no way to save some
|
||||
// partial merge information either.
|
||||
func MergeList[T, V any](mergeFn func(results []Result[T]) (V, string, error), delegates []Value[T]) Value[V] {
|
||||
return &listMerger[T, V]{
|
||||
mergeFn: mergeFn,
|
||||
delegates: delegates,
|
||||
}
|
||||
}
|
||||
|
||||
type listMerger[T, V any] struct {
|
||||
lock sync.Mutex
|
||||
mergeFn func([]Result[T]) (V, string, error)
|
||||
delegates []Value[T]
|
||||
cache []Result[T]
|
||||
result Result[V]
|
||||
}
|
||||
|
||||
func (c *listMerger[T, V]) prepareResultsLocked() []Result[T] {
|
||||
cacheResults := make([]Result[T], len(c.delegates))
|
||||
ch := make(chan struct {
|
||||
int
|
||||
Result[T]
|
||||
}, len(c.delegates))
|
||||
for i := range c.delegates {
|
||||
go func(index int) {
|
||||
value, etag, err := c.delegates[index].Get()
|
||||
ch <- struct {
|
||||
int
|
||||
Result[T]
|
||||
}{index, Result[T]{Value: value, Etag: etag, Err: err}}
|
||||
}(i)
|
||||
}
|
||||
for i := 0; i < len(c.delegates); i++ {
|
||||
res := <-ch
|
||||
cacheResults[res.int] = res.Result
|
||||
}
|
||||
return cacheResults
|
||||
}
|
||||
|
||||
func (c *listMerger[T, V]) needsRunningLocked(results []Result[T]) bool {
|
||||
if c.cache == nil {
|
||||
return true
|
||||
}
|
||||
if c.result.Err != nil {
|
||||
return true
|
||||
}
|
||||
if len(results) != len(c.cache) {
|
||||
panic(fmt.Errorf("invalid number of results: %v (expected %v)", len(results), len(c.cache)))
|
||||
}
|
||||
for i, oldResult := range c.cache {
|
||||
newResult := results[i]
|
||||
if newResult.Etag != oldResult.Etag || newResult.Err != nil || oldResult.Err != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *listMerger[T, V]) Get() (V, string, error) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
cacheResults := c.prepareResultsLocked()
|
||||
if c.needsRunningLocked(cacheResults) {
|
||||
c.cache = cacheResults
|
||||
c.result.Value, c.result.Etag, c.result.Err = c.mergeFn(c.cache)
|
||||
}
|
||||
return c.result.Value, c.result.Etag, c.result.Err
|
||||
}
|
||||
|
||||
// Transform the result of another cached value. The transformFn will only be called
|
||||
// if the source has updated, otherwise, the result will be returned.
|
||||
//
|
||||
// If the dependency returned an error before, or it returns an error
|
||||
// this time, or if the transformerFn failed before, the function is
|
||||
// reran.
|
||||
func Transform[T, V any](transformerFn func(T, string, error) (V, string, error), source Value[T]) Value[V] {
|
||||
return MergeList(func(delegates []Result[T]) (V, string, error) {
|
||||
if len(delegates) != 1 {
|
||||
panic(fmt.Errorf("invalid cache for transformer cache: %v", delegates))
|
||||
}
|
||||
return transformerFn(delegates[0].Value, delegates[0].Etag, delegates[0].Err)
|
||||
}, []Value[T]{source})
|
||||
}
|
||||
|
||||
// Once calls Value[T].Get() lazily and only once, even in case of an error result.
|
||||
func Once[T any](d Value[T]) Value[T] {
|
||||
return &once[T]{
|
||||
data: d,
|
||||
}
|
||||
}
|
||||
|
||||
type once[T any] struct {
|
||||
once sync.Once
|
||||
data Value[T]
|
||||
result Result[T]
|
||||
}
|
||||
|
||||
func (c *once[T]) Get() (T, string, error) {
|
||||
c.once.Do(func() {
|
||||
c.result.Value, c.result.Etag, c.result.Err = c.data.Get()
|
||||
})
|
||||
return c.result.Value, c.result.Etag, c.result.Err
|
||||
}
|
||||
|
||||
// Replaceable extends the Value[T] interface with the ability to change the
|
||||
// underlying Value[T] after construction.
|
||||
type Replaceable[T any] interface {
|
||||
Value[T]
|
||||
Store(Value[T])
|
||||
}
|
||||
|
||||
// Atomic wraps a Value[T] as an atomic value that can be replaced. It implements
|
||||
// Replaceable[T].
|
||||
type Atomic[T any] struct {
|
||||
value atomic.Pointer[Value[T]]
|
||||
}
|
||||
|
||||
var _ Replaceable[[]byte] = &Atomic[[]byte]{}
|
||||
|
||||
func (x *Atomic[T]) Store(val Value[T]) { x.value.Store(&val) }
|
||||
func (x *Atomic[T]) Get() (T, string, error) { return (*x.value.Load()).Get() }
|
||||
|
||||
// LastSuccess calls Value[T].Get(), but hides errors by returning the last
|
||||
// success if there has been any.
|
||||
type LastSuccess[T any] struct {
|
||||
Atomic[T]
|
||||
success atomic.Pointer[Result[T]]
|
||||
}
|
||||
|
||||
var _ Replaceable[[]byte] = &LastSuccess[[]byte]{}
|
||||
|
||||
func (c *LastSuccess[T]) Get() (T, string, error) {
|
||||
success := c.success.Load()
|
||||
value, etag, err := c.Atomic.Get()
|
||||
if err == nil {
|
||||
if success == nil {
|
||||
c.success.CompareAndSwap(nil, &Result[T]{Value: value, Etag: etag, Err: err})
|
||||
}
|
||||
return value, etag, err
|
||||
}
|
||||
|
||||
if success != nil {
|
||||
return success.Value, success.Etag, success.Err
|
||||
}
|
||||
|
||||
return value, etag, err
|
||||
}
|
289
e2e/vendor/k8s.io/kube-openapi/pkg/common/common.go
generated
vendored
Normal file
289
e2e/vendor/k8s.io/kube-openapi/pkg/common/common.go
generated
vendored
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
Copyright 2016 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 common
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: Make this configurable.
|
||||
ExtensionPrefix = "x-kubernetes-"
|
||||
ExtensionV2Schema = ExtensionPrefix + "v2-schema"
|
||||
)
|
||||
|
||||
// OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi.
|
||||
type OpenAPIDefinition struct {
|
||||
Schema spec.Schema
|
||||
Dependencies []string
|
||||
}
|
||||
|
||||
type ReferenceCallback func(path string) spec.Ref
|
||||
|
||||
// GetOpenAPIDefinitions is collection of all definitions.
|
||||
type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition
|
||||
|
||||
// OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface,
|
||||
// the definition returned by it will be used, otherwise the auto-generated definitions will be used. See
|
||||
// GetOpenAPITypeFormat for more information about trade-offs of using this interface or GetOpenAPITypeFormat method when
|
||||
// possible.
|
||||
type OpenAPIDefinitionGetter interface {
|
||||
OpenAPIDefinition() *OpenAPIDefinition
|
||||
}
|
||||
|
||||
type OpenAPIV3DefinitionGetter interface {
|
||||
OpenAPIV3Definition() *OpenAPIDefinition
|
||||
}
|
||||
|
||||
type PathHandler interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
}
|
||||
|
||||
type PathHandlerByGroupVersion interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
HandlePrefix(path string, handler http.Handler)
|
||||
}
|
||||
|
||||
// Config is set of configuration for openAPI spec generation.
|
||||
type Config struct {
|
||||
// List of supported protocols such as https, http, etc.
|
||||
ProtocolList []string
|
||||
|
||||
// Info is general information about the API.
|
||||
Info *spec.Info
|
||||
|
||||
// DefaultResponse will be used if an operation does not have any responses listed. It
|
||||
// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec.
|
||||
DefaultResponse *spec.Response
|
||||
|
||||
// ResponseDefinitions will be added to "responses" under the top-level swagger object. This is an object
|
||||
// that holds responses definitions that can be used across operations. This property does not define
|
||||
// global responses for all operations. For more info please refer:
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields
|
||||
ResponseDefinitions map[string]spec.Response
|
||||
|
||||
// CommonResponses will be added as a response to all operation specs. This is a good place to add common
|
||||
// responses such as authorization failed.
|
||||
CommonResponses map[int]spec.Response
|
||||
|
||||
// List of webservice's path prefixes to ignore
|
||||
IgnorePrefixes []string
|
||||
|
||||
// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
|
||||
// or any of the models will result in spec generation failure.
|
||||
GetDefinitions GetOpenAPIDefinitions
|
||||
|
||||
// Provides the definition for all models used by routes. One of GetDefinitions or Definitions must be defined to generate a spec.
|
||||
// This takes precedent over the GetDefinitions function
|
||||
Definitions map[string]OpenAPIDefinition
|
||||
|
||||
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
|
||||
//
|
||||
// Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route
|
||||
// interface set of funcs.
|
||||
GetOperationIDAndTags func(r *restful.Route) (string, []string, error)
|
||||
|
||||
// GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs.
|
||||
GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error)
|
||||
|
||||
// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
|
||||
// It is an optional function to customize model names.
|
||||
GetDefinitionName func(name string) (string, spec.Extensions)
|
||||
|
||||
// PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving.
|
||||
PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error)
|
||||
|
||||
// SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config
|
||||
// is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses.
|
||||
SecurityDefinitions *spec.SecurityDefinitions
|
||||
|
||||
// DefaultSecurity for all operations. This will pass as spec.SwaggerProps.Security to OpenAPI.
|
||||
// For most cases, this will be list of acceptable definitions in SecurityDefinitions.
|
||||
DefaultSecurity []map[string][]string
|
||||
}
|
||||
|
||||
// OpenAPIV3Config is set of configuration for OpenAPI V3 spec generation.
|
||||
type OpenAPIV3Config struct {
|
||||
// Info is general information about the API.
|
||||
Info *spec.Info
|
||||
|
||||
// DefaultResponse will be used if an operation does not have any responses listed. It
|
||||
// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec.
|
||||
DefaultResponse *spec3.Response
|
||||
|
||||
// ResponseDefinitions will be added to responses component. This is an object
|
||||
// that holds responses that can be used across operations.
|
||||
ResponseDefinitions map[string]*spec3.Response
|
||||
|
||||
// CommonResponses will be added as a response to all operation specs. This is a good place to add common
|
||||
// responses such as authorization failed.
|
||||
CommonResponses map[int]*spec3.Response
|
||||
|
||||
// List of webservice's path prefixes to ignore
|
||||
IgnorePrefixes []string
|
||||
|
||||
// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
|
||||
// or any of the models will result in spec generation failure.
|
||||
// One of GetDefinitions or Definitions must be defined to generate a spec.
|
||||
GetDefinitions GetOpenAPIDefinitions
|
||||
|
||||
// Provides the definition for all models used by routes. One of GetDefinitions or Definitions must be defined to generate a spec.
|
||||
// This takes precedent over the GetDefinitions function
|
||||
Definitions map[string]OpenAPIDefinition
|
||||
|
||||
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
|
||||
//
|
||||
// Deprecated: GetOperationIDAndTagsFromRoute should be used instead. This cannot be specified if using the new Route
|
||||
// interface set of funcs.
|
||||
GetOperationIDAndTags func(r *restful.Route) (string, []string, error)
|
||||
|
||||
// GetOperationIDAndTagsFromRoute returns operation id and tags for a Route. It is an optional function to customize operation IDs.
|
||||
GetOperationIDAndTagsFromRoute func(r Route) (string, []string, error)
|
||||
|
||||
// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
|
||||
// It is an optional function to customize model names.
|
||||
GetDefinitionName func(name string) (string, spec.Extensions)
|
||||
|
||||
// PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving.
|
||||
PostProcessSpec func(*spec3.OpenAPI) (*spec3.OpenAPI, error)
|
||||
|
||||
// SecuritySchemes is list of all security schemes for OpenAPI service.
|
||||
SecuritySchemes spec3.SecuritySchemes
|
||||
|
||||
// DefaultSecurity for all operations.
|
||||
DefaultSecurity []map[string][]string
|
||||
}
|
||||
|
||||
type typeInfo struct {
|
||||
name string
|
||||
format string
|
||||
zero interface{}
|
||||
}
|
||||
|
||||
var schemaTypeFormatMap = map[string]typeInfo{
|
||||
"uint": {"integer", "int32", 0.},
|
||||
"uint8": {"integer", "byte", 0.},
|
||||
"uint16": {"integer", "int32", 0.},
|
||||
"uint32": {"integer", "int64", 0.},
|
||||
"uint64": {"integer", "int64", 0.},
|
||||
"int": {"integer", "int32", 0.},
|
||||
"int8": {"integer", "byte", 0.},
|
||||
"int16": {"integer", "int32", 0.},
|
||||
"int32": {"integer", "int32", 0.},
|
||||
"int64": {"integer", "int64", 0.},
|
||||
"byte": {"integer", "byte", 0},
|
||||
"float64": {"number", "double", 0.},
|
||||
"float32": {"number", "float", 0.},
|
||||
"bool": {"boolean", "", false},
|
||||
"time.Time": {"string", "date-time", ""},
|
||||
"string": {"string", "", ""},
|
||||
"integer": {"integer", "", 0.},
|
||||
"number": {"number", "", 0.},
|
||||
"boolean": {"boolean", "", false},
|
||||
"[]byte": {"string", "byte", ""}, // base64 encoded characters
|
||||
"interface{}": {"object", "", interface{}(nil)},
|
||||
}
|
||||
|
||||
// This function is a reference for converting go (or any custom type) to a simple open API type,format pair. There are
|
||||
// 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
|
||||
// comment (the comment that is added before type definition) will be lost. The spec will still have the property
|
||||
// comment. The second way is to implement OpenAPIDefinitionGetter interface. That function can customize the spec (so
|
||||
// the spec does not need to be simple type,format) or can even return a simple type,format (e.g. IntOrString). For simple
|
||||
// type formats, the benefit of adding OpenAPIDefinitionGetter interface is to keep both type and property documentation.
|
||||
// Example:
|
||||
//
|
||||
// type Sample struct {
|
||||
// ...
|
||||
// // port of the server
|
||||
// port IntOrString
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// // IntOrString documentation...
|
||||
// type IntOrString { ... }
|
||||
//
|
||||
// Adding IntOrString to this function:
|
||||
//
|
||||
// "port" : {
|
||||
// format: "string",
|
||||
// type: "int-or-string",
|
||||
// Description: "port of the server"
|
||||
// }
|
||||
//
|
||||
// Implement OpenAPIDefinitionGetter for IntOrString:
|
||||
//
|
||||
// "port" : {
|
||||
// $Ref: "#/definitions/IntOrString"
|
||||
// Description: "port of the server"
|
||||
// }
|
||||
//
|
||||
// ...
|
||||
// definitions:
|
||||
//
|
||||
// {
|
||||
// "IntOrString": {
|
||||
// format: "string",
|
||||
// type: "int-or-string",
|
||||
// Description: "IntOrString documentation..." // new
|
||||
// }
|
||||
// }
|
||||
func OpenAPITypeFormat(typeName string) (string, string) {
|
||||
mapped, ok := schemaTypeFormatMap[typeName]
|
||||
if !ok {
|
||||
return "", ""
|
||||
}
|
||||
return mapped.name, mapped.format
|
||||
}
|
||||
|
||||
// Returns the zero-value for the given type along with true if the type
|
||||
// could be found.
|
||||
func OpenAPIZeroValue(typeName string) (interface{}, bool) {
|
||||
mapped, ok := schemaTypeFormatMap[typeName]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return mapped.zero, true
|
||||
}
|
||||
|
||||
func EscapeJsonPointer(p string) string {
|
||||
// Escaping reference name using rfc6901
|
||||
p = strings.Replace(p, "~", "~0", -1)
|
||||
p = strings.Replace(p, "/", "~1", -1)
|
||||
return p
|
||||
}
|
||||
|
||||
func EmbedOpenAPIDefinitionIntoV2Extension(main OpenAPIDefinition, embedded OpenAPIDefinition) OpenAPIDefinition {
|
||||
if main.Schema.Extensions == nil {
|
||||
main.Schema.Extensions = make(map[string]interface{})
|
||||
}
|
||||
main.Schema.Extensions[ExtensionV2Schema] = embedded.Schema
|
||||
return main
|
||||
}
|
||||
|
||||
// GenerateOpenAPIV3OneOfSchema generate the set of schemas that MUST be assigned to SchemaProps.OneOf
|
||||
func GenerateOpenAPIV3OneOfSchema(types []string) (oneOf []spec.Schema) {
|
||||
for _, t := range types {
|
||||
oneOf = append(oneOf, spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{t}}})
|
||||
}
|
||||
return
|
||||
}
|
19
e2e/vendor/k8s.io/kube-openapi/pkg/common/doc.go
generated
vendored
Normal file
19
e2e/vendor/k8s.io/kube-openapi/pkg/common/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2016 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 common holds shared code and types between open API code
|
||||
// generator and spec generator.
|
||||
package common
|
88
e2e/vendor/k8s.io/kube-openapi/pkg/common/interfaces.go
generated
vendored
Normal file
88
e2e/vendor/k8s.io/kube-openapi/pkg/common/interfaces.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
package common
|
||||
|
||||
// RouteContainer is the entrypoint for a service, which may contain multiple
|
||||
// routes under a common path with a common set of path parameters.
|
||||
type RouteContainer interface {
|
||||
// RootPath is the path that all contained routes are nested under.
|
||||
RootPath() string
|
||||
// PathParameters are common parameters defined in the root path.
|
||||
PathParameters() []Parameter
|
||||
// Routes are all routes exposed under the root path.
|
||||
Routes() []Route
|
||||
}
|
||||
|
||||
// Route is a logical endpoint of a service.
|
||||
type Route interface {
|
||||
// Method defines the HTTP Method.
|
||||
Method() string
|
||||
// Path defines the route's endpoint.
|
||||
Path() string
|
||||
// OperationName defines a machine-readable ID for the route.
|
||||
OperationName() string
|
||||
// Parameters defines the list of accepted parameters.
|
||||
Parameters() []Parameter
|
||||
// Description is a human-readable route description.
|
||||
Description() string
|
||||
// Consumes defines the consumed content-types.
|
||||
Consumes() []string
|
||||
// Produces defines the produced content-types.
|
||||
Produces() []string
|
||||
// Metadata allows adding extensions to the generated spec.
|
||||
Metadata() map[string]interface{}
|
||||
// RequestPayloadSample defines an example request payload. Can return nil.
|
||||
RequestPayloadSample() interface{}
|
||||
// ResponsePayloadSample defines an example response payload. Can return nil.
|
||||
ResponsePayloadSample() interface{}
|
||||
// StatusCodeResponses defines a mapping of HTTP Status Codes to the specific response(s).
|
||||
// Multiple responses with the same HTTP Status Code are acceptable.
|
||||
StatusCodeResponses() []StatusCodeResponse
|
||||
}
|
||||
|
||||
// StatusCodeResponse is an explicit response type with an HTTP Status Code.
|
||||
type StatusCodeResponse interface {
|
||||
// Code defines the HTTP Status Code.
|
||||
Code() int
|
||||
// Message returns the human-readable message.
|
||||
Message() string
|
||||
// Model defines an example payload for this response.
|
||||
Model() interface{}
|
||||
}
|
||||
|
||||
// Parameter is a Route parameter.
|
||||
type Parameter interface {
|
||||
// Name defines the unique-per-route identifier.
|
||||
Name() string
|
||||
// Description is the human-readable description of the param.
|
||||
Description() string
|
||||
// Required defines if this parameter must be provided.
|
||||
Required() bool
|
||||
// Kind defines the type of the parameter itself.
|
||||
Kind() ParameterKind
|
||||
// DataType defines the type of data the parameter carries.
|
||||
DataType() string
|
||||
// AllowMultiple defines if more than one value can be supplied for the parameter.
|
||||
AllowMultiple() bool
|
||||
}
|
||||
|
||||
// ParameterKind is an enum of route parameter types.
|
||||
type ParameterKind int
|
||||
|
||||
const (
|
||||
// PathParameterKind indicates the request parameter type is "path".
|
||||
PathParameterKind = ParameterKind(iota)
|
||||
|
||||
// QueryParameterKind indicates the request parameter type is "query".
|
||||
QueryParameterKind
|
||||
|
||||
// BodyParameterKind indicates the request parameter type is "body".
|
||||
BodyParameterKind
|
||||
|
||||
// HeaderParameterKind indicates the request parameter type is "header".
|
||||
HeaderParameterKind
|
||||
|
||||
// FormParameterKind indicates the request parameter type is "form".
|
||||
FormParameterKind
|
||||
|
||||
// UnknownParameterKind indicates the request parameter type has not been specified.
|
||||
UnknownParameterKind
|
||||
)
|
15
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/adapter.go
generated
vendored
Normal file
15
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/adapter.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
// AdaptWebServices adapts a slice of restful.WebService into the common interfaces.
|
||||
func AdaptWebServices(webServices []*restful.WebService) []common.RouteContainer {
|
||||
var containers []common.RouteContainer
|
||||
for _, ws := range webServices {
|
||||
containers = append(containers, &WebServiceAdapter{ws})
|
||||
}
|
||||
return containers
|
||||
}
|
54
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/param_adapter.go
generated
vendored
Normal file
54
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/param_adapter.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.Parameter = &ParamAdapter{}
|
||||
|
||||
type ParamAdapter struct {
|
||||
Param *restful.Parameter
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(r.Param)
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Name() string {
|
||||
return r.Param.Data().Name
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Description() string {
|
||||
return r.Param.Data().Description
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Required() bool {
|
||||
return r.Param.Data().Required
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Kind() common.ParameterKind {
|
||||
switch r.Param.Kind() {
|
||||
case restful.PathParameterKind:
|
||||
return common.PathParameterKind
|
||||
case restful.QueryParameterKind:
|
||||
return common.QueryParameterKind
|
||||
case restful.BodyParameterKind:
|
||||
return common.BodyParameterKind
|
||||
case restful.HeaderParameterKind:
|
||||
return common.HeaderParameterKind
|
||||
case restful.FormParameterKind:
|
||||
return common.FormParameterKind
|
||||
default:
|
||||
return common.UnknownParameterKind
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) DataType() string {
|
||||
return r.Param.Data().DataType
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) AllowMultiple() bool {
|
||||
return r.Param.Data().AllowMultiple
|
||||
}
|
25
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/response_error_adapter.go
generated
vendored
Normal file
25
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/response_error_adapter.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.StatusCodeResponse = &ResponseErrorAdapter{}
|
||||
|
||||
// ResponseErrorAdapter adapts a restful.ResponseError to common.StatusCodeResponse.
|
||||
type ResponseErrorAdapter struct {
|
||||
Err *restful.ResponseError
|
||||
}
|
||||
|
||||
func (r *ResponseErrorAdapter) Message() string {
|
||||
return r.Err.Message
|
||||
}
|
||||
|
||||
func (r *ResponseErrorAdapter) Model() interface{} {
|
||||
return r.Err.Model
|
||||
}
|
||||
|
||||
func (r *ResponseErrorAdapter) Code() int {
|
||||
return r.Err.Code
|
||||
}
|
68
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/route_adapter.go
generated
vendored
Normal file
68
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/route_adapter.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.Route = &RouteAdapter{}
|
||||
|
||||
// RouteAdapter adapts a restful.Route to common.Route.
|
||||
type RouteAdapter struct {
|
||||
Route *restful.Route
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) StatusCodeResponses() []common.StatusCodeResponse {
|
||||
// go-restful uses the ResponseErrors field to contain both error and regular responses.
|
||||
var responses []common.StatusCodeResponse
|
||||
for _, res := range r.Route.ResponseErrors {
|
||||
localRes := res
|
||||
responses = append(responses, &ResponseErrorAdapter{&localRes})
|
||||
}
|
||||
|
||||
return responses
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) OperationName() string {
|
||||
return r.Route.Operation
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Method() string {
|
||||
return r.Route.Method
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Path() string {
|
||||
return r.Route.Path
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Parameters() []common.Parameter {
|
||||
var params []common.Parameter
|
||||
for _, rParam := range r.Route.ParameterDocs {
|
||||
params = append(params, &ParamAdapter{rParam})
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Description() string {
|
||||
return r.Route.Doc
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Consumes() []string {
|
||||
return r.Route.Consumes
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Produces() []string {
|
||||
return r.Route.Produces
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Metadata() map[string]interface{} {
|
||||
return r.Route.Metadata
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) RequestPayloadSample() interface{} {
|
||||
return r.Route.ReadSample
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) ResponsePayloadSample() interface{} {
|
||||
return r.Route.WriteSample
|
||||
}
|
34
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/webservice_adapter.go
generated
vendored
Normal file
34
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/webservice_adapter.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.RouteContainer = &WebServiceAdapter{}
|
||||
|
||||
// WebServiceAdapter adapts a restful.WebService to common.RouteContainer.
|
||||
type WebServiceAdapter struct {
|
||||
WebService *restful.WebService
|
||||
}
|
||||
|
||||
func (r *WebServiceAdapter) RootPath() string {
|
||||
return r.WebService.RootPath()
|
||||
}
|
||||
|
||||
func (r *WebServiceAdapter) PathParameters() []common.Parameter {
|
||||
var params []common.Parameter
|
||||
for _, rParam := range r.WebService.PathParameters() {
|
||||
params = append(params, &ParamAdapter{rParam})
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (r *WebServiceAdapter) Routes() []common.Route {
|
||||
var routes []common.Route
|
||||
for _, rRoute := range r.WebService.Routes() {
|
||||
localRoute := rRoute
|
||||
routes = append(routes, &RouteAdapter{&localRoute})
|
||||
}
|
||||
return routes
|
||||
}
|
208
e2e/vendor/k8s.io/kube-openapi/pkg/handler/default_pruning.go
generated
vendored
Normal file
208
e2e/vendor/k8s.io/kube-openapi/pkg/handler/default_pruning.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright 2020 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 handler
|
||||
|
||||
import "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
// PruneDefaults remove all the defaults recursively from all the
|
||||
// schemas in the definitions, and does not modify the definitions in
|
||||
// place.
|
||||
func PruneDefaults(definitions spec.Definitions) spec.Definitions {
|
||||
definitionsCloned := false
|
||||
for k, v := range definitions {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
orig := definitions
|
||||
definitions = make(spec.Definitions, len(orig))
|
||||
for k2, v2 := range orig {
|
||||
definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
definitions[k] = *s
|
||||
}
|
||||
}
|
||||
return definitions
|
||||
}
|
||||
|
||||
// PruneDefaultsSchema remove all the defaults recursively from the
|
||||
// schema in place.
|
||||
func PruneDefaultsSchema(schema *spec.Schema) *spec.Schema {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = &spec.Schema{}
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Default != nil {
|
||||
clone()
|
||||
schema.Default = nil
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range schema.Definitions {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
schema.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
schema.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
propertiesCloned := false
|
||||
for k, v := range schema.Properties {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !propertiesCloned {
|
||||
propertiesCloned = true
|
||||
clone()
|
||||
schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
|
||||
for k2, v2 := range orig.Properties {
|
||||
schema.Properties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Properties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
patternPropertiesCloned := false
|
||||
for k, v := range schema.PatternProperties {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !patternPropertiesCloned {
|
||||
patternPropertiesCloned = true
|
||||
clone()
|
||||
schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
|
||||
for k2, v2 := range orig.PatternProperties {
|
||||
schema.PatternProperties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.PatternProperties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
dependenciesCloned := false
|
||||
for k, v := range schema.Dependencies {
|
||||
if s := PruneDefaultsSchema(v.Schema); s != v.Schema {
|
||||
if !dependenciesCloned {
|
||||
dependenciesCloned = true
|
||||
clone()
|
||||
schema.Dependencies = make(spec.Dependencies, len(orig.Dependencies))
|
||||
for k2, v2 := range orig.Dependencies {
|
||||
schema.Dependencies[k2] = v2
|
||||
}
|
||||
}
|
||||
v.Schema = s
|
||||
schema.Dependencies[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
allOfCloned := false
|
||||
for i := range schema.AllOf {
|
||||
if s := PruneDefaultsSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
|
||||
if !allOfCloned {
|
||||
allOfCloned = true
|
||||
clone()
|
||||
schema.AllOf = make([]spec.Schema, len(orig.AllOf))
|
||||
copy(schema.AllOf, orig.AllOf)
|
||||
}
|
||||
schema.AllOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
anyOfCloned := false
|
||||
for i := range schema.AnyOf {
|
||||
if s := PruneDefaultsSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
|
||||
if !anyOfCloned {
|
||||
anyOfCloned = true
|
||||
clone()
|
||||
schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
|
||||
copy(schema.AnyOf, orig.AnyOf)
|
||||
}
|
||||
schema.AnyOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
oneOfCloned := false
|
||||
for i := range schema.OneOf {
|
||||
if s := PruneDefaultsSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
|
||||
if !oneOfCloned {
|
||||
oneOfCloned = true
|
||||
clone()
|
||||
schema.OneOf = make([]spec.Schema, len(orig.OneOf))
|
||||
copy(schema.OneOf, orig.OneOf)
|
||||
}
|
||||
schema.OneOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Not != nil {
|
||||
if s := PruneDefaultsSchema(schema.Not); s != schema.Not {
|
||||
clone()
|
||||
schema.Not = s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
if s := PruneDefaultsSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
|
||||
clone()
|
||||
schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
if s := PruneDefaultsSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
|
||||
clone()
|
||||
schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
if s := PruneDefaultsSchema(schema.Items.Schema); s != schema.Items.Schema {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{Schema: s}
|
||||
}
|
||||
} else {
|
||||
itemsCloned := false
|
||||
for i := range schema.Items.Schemas {
|
||||
if s := PruneDefaultsSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
|
||||
if !itemsCloned {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{
|
||||
Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
|
||||
}
|
||||
itemsCloned = true
|
||||
copy(schema.Items.Schemas, orig.Items.Schemas)
|
||||
}
|
||||
schema.Items.Schemas[i] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
202
e2e/vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
Normal file
202
e2e/vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
Copyright 2017 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 handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
openapi_v2 "github.com/google/gnostic-models/openapiv2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/munnerz/goautoneg"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
klog "k8s.io/klog/v2"
|
||||
"k8s.io/kube-openapi/pkg/builder"
|
||||
"k8s.io/kube-openapi/pkg/cached"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/common/restfuladapter"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
subTypeProtobufDeprecated = "com.github.proto-openapi.spec.v2@v1.0+protobuf"
|
||||
subTypeProtobuf = "com.github.proto-openapi.spec.v2.v1.0+protobuf"
|
||||
subTypeJSON = "json"
|
||||
)
|
||||
|
||||
func computeETag(data []byte) string {
|
||||
if data == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%X", sha512.Sum512(data))
|
||||
}
|
||||
|
||||
type timedSpec struct {
|
||||
spec []byte
|
||||
lastModified time.Time
|
||||
}
|
||||
|
||||
// OpenAPIService is the service responsible for serving OpenAPI spec. It has
|
||||
// the ability to safely change the spec while serving it.
|
||||
type OpenAPIService struct {
|
||||
specCache cached.LastSuccess[*spec.Swagger]
|
||||
jsonCache cached.Value[timedSpec]
|
||||
protoCache cached.Value[timedSpec]
|
||||
}
|
||||
|
||||
// NewOpenAPIService builds an OpenAPIService starting with the given spec.
|
||||
func NewOpenAPIService(swagger *spec.Swagger) *OpenAPIService {
|
||||
return NewOpenAPIServiceLazy(cached.Static(swagger, uuid.New().String()))
|
||||
}
|
||||
|
||||
// NewOpenAPIServiceLazy builds an OpenAPIService from lazy spec.
|
||||
func NewOpenAPIServiceLazy(swagger cached.Value[*spec.Swagger]) *OpenAPIService {
|
||||
o := &OpenAPIService{}
|
||||
o.UpdateSpecLazy(swagger)
|
||||
|
||||
o.jsonCache = cached.Transform[*spec.Swagger](func(spec *spec.Swagger, etag string, err error) (timedSpec, string, error) {
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
json, err := spec.MarshalJSON()
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
return timedSpec{spec: json, lastModified: time.Now()}, computeETag(json), nil
|
||||
}, &o.specCache)
|
||||
o.protoCache = cached.Transform(func(ts timedSpec, etag string, err error) (timedSpec, string, error) {
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
proto, err := ToProtoBinary(ts.spec)
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
// We can re-use the same etag as json because of the Vary header.
|
||||
return timedSpec{spec: proto, lastModified: ts.lastModified}, etag, nil
|
||||
}, o.jsonCache)
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateSpec(swagger *spec.Swagger) error {
|
||||
o.UpdateSpecLazy(cached.Static(swagger, uuid.New().String()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateSpecLazy(swagger cached.Value[*spec.Swagger]) {
|
||||
o.specCache.Store(swagger)
|
||||
}
|
||||
|
||||
func ToProtoBinary(json []byte) ([]byte, error) {
|
||||
document, err := openapi_v2.ParseDocument(json)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(document)
|
||||
}
|
||||
|
||||
// RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec.
|
||||
//
|
||||
// Deprecated: use OpenAPIService.RegisterOpenAPIVersionedService instead.
|
||||
func RegisterOpenAPIVersionedService(spec *spec.Swagger, servePath string, handler common.PathHandler) *OpenAPIService {
|
||||
o := NewOpenAPIService(spec)
|
||||
o.RegisterOpenAPIVersionedService(servePath, handler)
|
||||
return o
|
||||
}
|
||||
|
||||
// RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec.
|
||||
func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handler common.PathHandler) {
|
||||
accepted := []struct {
|
||||
Type string
|
||||
SubType string
|
||||
ReturnedContentType string
|
||||
GetDataAndEtag cached.Value[timedSpec]
|
||||
}{
|
||||
{"application", subTypeJSON, "application/" + subTypeJSON, o.jsonCache},
|
||||
{"application", subTypeProtobufDeprecated, "application/" + subTypeProtobuf, o.protoCache},
|
||||
{"application", subTypeProtobuf, "application/" + subTypeProtobuf, o.protoCache},
|
||||
}
|
||||
|
||||
handler.Handle(servePath, gziphandler.GzipHandler(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
decipherableFormats := r.Header.Get("Accept")
|
||||
if decipherableFormats == "" {
|
||||
decipherableFormats = "*/*"
|
||||
}
|
||||
clauses := goautoneg.ParseAccept(decipherableFormats)
|
||||
w.Header().Add("Vary", "Accept")
|
||||
for _, clause := range clauses {
|
||||
for _, accepts := range accepted {
|
||||
if clause.Type != accepts.Type && clause.Type != "*" {
|
||||
continue
|
||||
}
|
||||
if clause.SubType != accepts.SubType && clause.SubType != "*" {
|
||||
continue
|
||||
}
|
||||
// serve the first matching media type in the sorted clause list
|
||||
ts, etag, err := accepts.GetDataAndEtag.Get()
|
||||
if err != nil {
|
||||
klog.Errorf("Error in OpenAPI handler: %s", err)
|
||||
// only return a 503 if we have no older cache data to serve
|
||||
if ts.spec == nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Set Content-Type header in the reponse
|
||||
w.Header().Set("Content-Type", accepts.ReturnedContentType)
|
||||
|
||||
// ETag must be enclosed in double quotes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
||||
w.Header().Set("Etag", strconv.Quote(etag))
|
||||
// ServeContent will take care of caching using eTag.
|
||||
http.ServeContent(w, r, servePath, ts.lastModified, bytes.NewReader(ts.spec))
|
||||
return
|
||||
}
|
||||
}
|
||||
// Return 406 for not acceptable format
|
||||
w.WriteHeader(406)
|
||||
return
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
// BuildAndRegisterOpenAPIVersionedService builds the spec and registers a handler to provide access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIVersionedService.
|
||||
//
|
||||
// Deprecated: BuildAndRegisterOpenAPIVersionedServiceFromRoutes should be used instead.
|
||||
func BuildAndRegisterOpenAPIVersionedService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
return BuildAndRegisterOpenAPIVersionedServiceFromRoutes(servePath, restfuladapter.AdaptWebServices(webServices), config, handler)
|
||||
}
|
||||
|
||||
// BuildAndRegisterOpenAPIVersionedServiceFromRoutes builds the spec and registers a handler to provide access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIVersionedService.
|
||||
func BuildAndRegisterOpenAPIVersionedServiceFromRoutes(servePath string, routeContainers []common.RouteContainer, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
spec, err := builder.BuildOpenAPISpecFromRoutes(routeContainers, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o := NewOpenAPIService(spec)
|
||||
o.RegisterOpenAPIVersionedService(servePath, handler)
|
||||
return o, nil
|
||||
}
|
295
e2e/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go
generated
vendored
Normal file
295
e2e/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
Copyright 2021 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 handler3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
openapi_v3 "github.com/google/gnostic-models/openapiv3"
|
||||
"github.com/google/uuid"
|
||||
"github.com/munnerz/goautoneg"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kube-openapi/pkg/cached"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
)
|
||||
|
||||
const (
|
||||
subTypeProtobufDeprecated = "com.github.proto-openapi.spec.v3@v1.0+protobuf"
|
||||
subTypeProtobuf = "com.github.proto-openapi.spec.v3.v1.0+protobuf"
|
||||
subTypeJSON = "json"
|
||||
)
|
||||
|
||||
// OpenAPIV3Discovery is the format of the Discovery document for OpenAPI V3
|
||||
// It maps Discovery paths to their corresponding URLs with a hash parameter included
|
||||
type OpenAPIV3Discovery struct {
|
||||
Paths map[string]OpenAPIV3DiscoveryGroupVersion `json:"paths"`
|
||||
}
|
||||
|
||||
// OpenAPIV3DiscoveryGroupVersion includes information about a group version and URL
|
||||
// for accessing the OpenAPI. The URL includes a hash parameter to support client side caching
|
||||
type OpenAPIV3DiscoveryGroupVersion struct {
|
||||
// Path is an absolute path of an OpenAPI V3 document in the form of /openapi/v3/apis/apps/v1?hash=014fbff9a07c
|
||||
ServerRelativeURL string `json:"serverRelativeURL"`
|
||||
}
|
||||
|
||||
func ToV3ProtoBinary(json []byte) ([]byte, error) {
|
||||
document, err := openapi_v3.ParseDocument(json)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(document)
|
||||
}
|
||||
|
||||
type timedSpec struct {
|
||||
spec []byte
|
||||
lastModified time.Time
|
||||
}
|
||||
|
||||
// This type is protected by the lock on OpenAPIService.
|
||||
type openAPIV3Group struct {
|
||||
specCache cached.LastSuccess[*spec3.OpenAPI]
|
||||
pbCache cached.Value[timedSpec]
|
||||
jsonCache cached.Value[timedSpec]
|
||||
}
|
||||
|
||||
func newOpenAPIV3Group() *openAPIV3Group {
|
||||
o := &openAPIV3Group{}
|
||||
o.jsonCache = cached.Transform[*spec3.OpenAPI](func(spec *spec3.OpenAPI, etag string, err error) (timedSpec, string, error) {
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
json, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
return timedSpec{spec: json, lastModified: time.Now()}, computeETag(json), nil
|
||||
}, &o.specCache)
|
||||
o.pbCache = cached.Transform(func(ts timedSpec, etag string, err error) (timedSpec, string, error) {
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
proto, err := ToV3ProtoBinary(ts.spec)
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
return timedSpec{spec: proto, lastModified: ts.lastModified}, etag, nil
|
||||
}, o.jsonCache)
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *openAPIV3Group) UpdateSpec(openapi cached.Value[*spec3.OpenAPI]) {
|
||||
o.specCache.Store(openapi)
|
||||
}
|
||||
|
||||
// OpenAPIService is the service responsible for serving OpenAPI spec. It has
|
||||
// the ability to safely change the spec while serving it.
|
||||
type OpenAPIService struct {
|
||||
// Mutex protects the schema map.
|
||||
mutex sync.Mutex
|
||||
v3Schema map[string]*openAPIV3Group
|
||||
|
||||
discoveryCache cached.LastSuccess[timedSpec]
|
||||
}
|
||||
|
||||
func computeETag(data []byte) string {
|
||||
if data == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%X", sha512.Sum512(data))
|
||||
}
|
||||
|
||||
func constructServerRelativeURL(gvString, etag string) string {
|
||||
u := url.URL{Path: path.Join("/openapi/v3", gvString)}
|
||||
query := url.Values{}
|
||||
query.Set("hash", etag)
|
||||
u.RawQuery = query.Encode()
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// NewOpenAPIService builds an OpenAPIService starting with the given spec.
|
||||
func NewOpenAPIService() *OpenAPIService {
|
||||
o := &OpenAPIService{}
|
||||
o.v3Schema = make(map[string]*openAPIV3Group)
|
||||
// We're not locked because we haven't shared the structure yet.
|
||||
o.discoveryCache.Store(o.buildDiscoveryCacheLocked())
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) buildDiscoveryCacheLocked() cached.Value[timedSpec] {
|
||||
caches := make(map[string]cached.Value[timedSpec], len(o.v3Schema))
|
||||
for gvName, group := range o.v3Schema {
|
||||
caches[gvName] = group.jsonCache
|
||||
}
|
||||
return cached.Merge(func(results map[string]cached.Result[timedSpec]) (timedSpec, string, error) {
|
||||
discovery := &OpenAPIV3Discovery{Paths: make(map[string]OpenAPIV3DiscoveryGroupVersion)}
|
||||
for gvName, result := range results {
|
||||
if result.Err != nil {
|
||||
return timedSpec{}, "", result.Err
|
||||
}
|
||||
discovery.Paths[gvName] = OpenAPIV3DiscoveryGroupVersion{
|
||||
ServerRelativeURL: constructServerRelativeURL(gvName, result.Etag),
|
||||
}
|
||||
}
|
||||
j, err := json.Marshal(discovery)
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
return timedSpec{spec: j, lastModified: time.Now()}, computeETag(j), nil
|
||||
}, caches)
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) getSingleGroupBytes(getType string, group string) ([]byte, string, time.Time, error) {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
v, ok := o.v3Schema[group]
|
||||
if !ok {
|
||||
return nil, "", time.Now(), fmt.Errorf("Cannot find CRD group %s", group)
|
||||
}
|
||||
switch getType {
|
||||
case subTypeJSON:
|
||||
ts, etag, err := v.jsonCache.Get()
|
||||
return ts.spec, etag, ts.lastModified, err
|
||||
case subTypeProtobuf, subTypeProtobufDeprecated:
|
||||
ts, etag, err := v.pbCache.Get()
|
||||
return ts.spec, etag, ts.lastModified, err
|
||||
default:
|
||||
return nil, "", time.Now(), fmt.Errorf("Invalid accept clause %s", getType)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateGroupVersionLazy adds or updates an existing group with the new cached.
|
||||
func (o *OpenAPIService) UpdateGroupVersionLazy(group string, openapi cached.Value[*spec3.OpenAPI]) {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
if _, ok := o.v3Schema[group]; !ok {
|
||||
o.v3Schema[group] = newOpenAPIV3Group()
|
||||
// Since there is a new item, we need to re-build the cache map.
|
||||
o.discoveryCache.Store(o.buildDiscoveryCacheLocked())
|
||||
}
|
||||
o.v3Schema[group].UpdateSpec(openapi)
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateGroupVersion(group string, openapi *spec3.OpenAPI) {
|
||||
o.UpdateGroupVersionLazy(group, cached.Static(openapi, uuid.New().String()))
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) DeleteGroupVersion(group string) {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
delete(o.v3Schema, group)
|
||||
// Rebuild the merge cache map since the items have changed.
|
||||
o.discoveryCache.Store(o.buildDiscoveryCacheLocked())
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) HandleDiscovery(w http.ResponseWriter, r *http.Request) {
|
||||
ts, etag, err := o.discoveryCache.Get()
|
||||
if err != nil {
|
||||
klog.Errorf("Error serving discovery: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Etag", strconv.Quote(etag))
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
http.ServeContent(w, r, "/openapi/v3", ts.lastModified, bytes.NewReader(ts.spec))
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) HandleGroupVersion(w http.ResponseWriter, r *http.Request) {
|
||||
url := strings.SplitAfterN(r.URL.Path, "/", 4)
|
||||
group := url[3]
|
||||
|
||||
decipherableFormats := r.Header.Get("Accept")
|
||||
if decipherableFormats == "" {
|
||||
decipherableFormats = "*/*"
|
||||
}
|
||||
clauses := goautoneg.ParseAccept(decipherableFormats)
|
||||
w.Header().Add("Vary", "Accept")
|
||||
|
||||
if len(clauses) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
accepted := []struct {
|
||||
Type string
|
||||
SubType string
|
||||
ReturnedContentType string
|
||||
}{
|
||||
{"application", subTypeJSON, "application/" + subTypeJSON},
|
||||
{"application", subTypeProtobuf, "application/" + subTypeProtobuf},
|
||||
{"application", subTypeProtobufDeprecated, "application/" + subTypeProtobuf},
|
||||
}
|
||||
|
||||
for _, clause := range clauses {
|
||||
for _, accepts := range accepted {
|
||||
if clause.Type != accepts.Type && clause.Type != "*" {
|
||||
continue
|
||||
}
|
||||
if clause.SubType != accepts.SubType && clause.SubType != "*" {
|
||||
continue
|
||||
}
|
||||
data, etag, lastModified, err := o.getSingleGroupBytes(accepts.SubType, group)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Set Content-Type header in the reponse
|
||||
w.Header().Set("Content-Type", accepts.ReturnedContentType)
|
||||
|
||||
// ETag must be enclosed in double quotes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
||||
w.Header().Set("Etag", strconv.Quote(etag))
|
||||
|
||||
if hash := r.URL.Query().Get("hash"); hash != "" {
|
||||
if hash != etag {
|
||||
u := constructServerRelativeURL(group, etag)
|
||||
http.Redirect(w, r, u, 301)
|
||||
return
|
||||
}
|
||||
// The Vary header is required because the Accept header can
|
||||
// change the contents returned. This prevents clients from caching
|
||||
// protobuf as JSON and vice versa.
|
||||
w.Header().Set("Vary", "Accept")
|
||||
|
||||
// Only set these headers when a hash is given.
|
||||
w.Header().Set("Cache-Control", "public, immutable")
|
||||
// Set the Expires directive to the maximum value of one year from the request,
|
||||
// effectively indicating that the cache never expires.
|
||||
w.Header().Set("Expires", time.Now().AddDate(1, 0, 0).Format(time.RFC1123))
|
||||
}
|
||||
http.ServeContent(w, r, "", lastModified, bytes.NewReader(data))
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(406)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) RegisterOpenAPIV3VersionedService(servePath string, handler common.PathHandlerByGroupVersion) error {
|
||||
handler.Handle(servePath, http.HandlerFunc(o.HandleDiscovery))
|
||||
handler.HandlePrefix(servePath+"/", http.HandlerFunc(o.HandleGroupVersion))
|
||||
return nil
|
||||
}
|
25
e2e/vendor/k8s.io/kube-openapi/pkg/internal/flags.go
generated
vendored
Normal file
25
e2e/vendor/k8s.io/kube-openapi/pkg/internal/flags.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
// Used by tests to selectively disable experimental JSON unmarshaler
|
||||
var UseOptimizedJSONUnmarshaling bool = true
|
||||
var UseOptimizedJSONUnmarshalingV3 bool = true
|
||||
|
||||
// Used by tests to selectively disable experimental JSON marshaler
|
||||
var UseOptimizedJSONMarshaling bool = true
|
||||
var UseOptimizedJSONMarshalingV3 bool = true
|
65
e2e/vendor/k8s.io/kube-openapi/pkg/internal/serialization.go
generated
vendored
Normal file
65
e2e/vendor/k8s.io/kube-openapi/pkg/internal/serialization.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2023 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 internal
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/jsonreference"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// DeterministicMarshal calls the jsonv2 library with the deterministic
|
||||
// flag in order to have stable marshaling.
|
||||
func DeterministicMarshal(in any) ([]byte, error) {
|
||||
return jsonv2.MarshalOptions{Deterministic: true}.Marshal(jsonv2.EncodeOptions{}, in)
|
||||
}
|
||||
|
||||
// JSONRefFromMap populates a json reference object if the map v contains a $ref key.
|
||||
func JSONRefFromMap(jsonRef *jsonreference.Ref, v map[string]interface{}) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if vv, ok := v["$ref"]; ok {
|
||||
if str, ok := vv.(string); ok {
|
||||
ref, err := jsonreference.New(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*jsonRef = ref
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SanitizeExtensions sanitizes the input map such that non extension
|
||||
// keys (non x-*, X-*) keys are dropped from the map. Returns the new
|
||||
// modified map, or nil if the map is now empty.
|
||||
func SanitizeExtensions(e map[string]interface{}) map[string]interface{} {
|
||||
for k := range e {
|
||||
if !IsExtensionKey(k) {
|
||||
delete(e, k)
|
||||
}
|
||||
}
|
||||
if len(e) == 0 {
|
||||
e = nil
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// IsExtensionKey returns true if the input string is of format x-* or X-*
|
||||
func IsExtensionKey(k string) bool {
|
||||
return len(k) > 1 && (k[0] == 'x' || k[0] == 'X') && k[1] == '-'
|
||||
}
|
3
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/AUTHORS
generated
vendored
Normal file
3
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
3
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/CONTRIBUTORS
generated
vendored
Normal file
3
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
27
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/LICENSE
generated
vendored
Normal file
27
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2020 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
321
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/README.md
generated
vendored
Normal file
321
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/README.md
generated
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
# JSON Serialization (v2)
|
||||
|
||||
[](https://pkg.go.dev/github.com/go-json-experiment/json)
|
||||
[](https://github.com/go-json-experiment/json/actions)
|
||||
|
||||
This module hosts an experimental implementation of v2 `encoding/json`.
|
||||
The API is unstable and breaking changes will regularly be made.
|
||||
Do not depend on this in publicly available modules.
|
||||
|
||||
## Goals and objectives
|
||||
|
||||
* **Mostly backwards compatible:** If possible, v2 should aim to be _mostly_
|
||||
compatible with v1 in terms of both API and default behavior to ease migration.
|
||||
For example, the `Marshal` and `Unmarshal` functions are the most widely used
|
||||
declarations in the v1 package. It seems sensible for equivalent functionality
|
||||
in v2 to be named the same and have the same signature.
|
||||
Behaviorally, we should aim for 95% to 99% backwards compatibility.
|
||||
We do not aim for 100% compatibility since we want the freedom to break
|
||||
certain behaviors that are now considered to have been a mistake.
|
||||
We may provide options that can bring the v2 implementation to 100% compatibility,
|
||||
but it will not be the default.
|
||||
|
||||
* **More flexible:** There is a
|
||||
[long list of feature requests](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+encoding%2Fjson+in%3Atitle).
|
||||
We should aim to provide the most flexible features that addresses most usages.
|
||||
We do not want to over fit the v2 API to handle every possible use case.
|
||||
Ideally, the features provided should be orthogonal in nature such that
|
||||
any combination of features results in as few surprising edge cases as possible.
|
||||
|
||||
* **More performant:** JSON serialization is widely used and any bit of extra
|
||||
performance gains will be greatly appreciated. Some rarely used behaviors of v1
|
||||
may be dropped in favor of better performance. For example,
|
||||
despite `Encoder` and `Decoder` operating on an `io.Writer` and `io.Reader`,
|
||||
they do not operate in a truly streaming manner,
|
||||
leading to a loss in performance. The v2 implementation should aim to be truly
|
||||
streaming by default (see [#33714](https://golang.org/issue/33714)).
|
||||
|
||||
* **Easy to use (hard to misuse):** The v2 API should aim to make
|
||||
the common case easy and the less common case at least possible.
|
||||
The API should avoid behavior that goes contrary to user expectation,
|
||||
which may result in subtle bugs (see [#36225](https://golang.org/issue/36225)).
|
||||
|
||||
* **v1 and v2 maintainability:** Since the v1 implementation must stay forever,
|
||||
it would be beneficial if v1 could be implemented under the hood with v2,
|
||||
allowing for less maintenance burden in the future. This probably implies that
|
||||
behavioral changes in v2 relative to v1 need to be exposed as options.
|
||||
|
||||
* **Avoid unsafe:** Standard library packages generally avoid the use of
|
||||
package `unsafe` even if it could provide a performance boost.
|
||||
We aim to preserve this property.
|
||||
|
||||
## Expectations
|
||||
|
||||
While this module aims to possibly be the v2 implementation of `encoding/json`,
|
||||
there is no guarantee that this outcome will occur. As with any major change
|
||||
to the Go standard library, this will eventually go through the
|
||||
[Go proposal process](https://github.com/golang/proposal#readme).
|
||||
At the present moment, this is still in the design and experimentation phase
|
||||
and is not ready for a formal proposal.
|
||||
|
||||
There are several possible outcomes from this experiment:
|
||||
1. We determine that a v2 `encoding/json` would not provide sufficient benefit
|
||||
over the existing v1 `encoding/json` package. Thus, we abandon this effort.
|
||||
2. We propose a v2 `encoding/json` design, but it is rejected in favor of some
|
||||
other design that is considered superior.
|
||||
3. We propose a v2 `encoding/json` design, but rather than adding an entirely
|
||||
new v2 `encoding/json` package, we decide to merge its functionality into
|
||||
the existing v1 `encoding/json` package.
|
||||
4. We propose a v2 `encoding/json` design and it is accepted, resulting in
|
||||
its addition to the standard library.
|
||||
5. Some other unforeseen outcome (among the infinite number of possibilities).
|
||||
|
||||
## Development
|
||||
|
||||
This module is primarily developed by
|
||||
[@dsnet](https://github.com/dsnet),
|
||||
[@mvdan](https://github.com/mvdan), and
|
||||
[@johanbrandhorst](https://github.com/johanbrandhorst)
|
||||
with feedback provided by
|
||||
[@rogpeppe](https://github.com/rogpeppe),
|
||||
[@ChrisHines](https://github.com/ChrisHines), and
|
||||
[@rsc](https://github.com/rsc).
|
||||
|
||||
Discussion about semantics occur semi-regularly, where a
|
||||
[record of past meetings can be found here](https://docs.google.com/document/d/1rovrOTd-wTawGMPPlPuKhwXaYBg9VszTXR9AQQL5LfI/edit?usp=sharing).
|
||||
|
||||
## Design overview
|
||||
|
||||
This package aims to provide a clean separation between syntax and semantics.
|
||||
Syntax deals with the structural representation of JSON (as specified in
|
||||
[RFC 4627](https://tools.ietf.org/html/rfc4627),
|
||||
[RFC 7159](https://tools.ietf.org/html/rfc7159),
|
||||
[RFC 7493](https://tools.ietf.org/html/rfc7493),
|
||||
[RFC 8259](https://tools.ietf.org/html/rfc8259), and
|
||||
[RFC 8785](https://tools.ietf.org/html/rfc8785)).
|
||||
Semantics deals with the meaning of syntactic data as usable application data.
|
||||
|
||||
The `Encoder` and `Decoder` types are streaming tokenizers concerned with the
|
||||
packing or parsing of JSON data. They operate on `Token` and `RawValue` types
|
||||
which represent the common data structures that are representable in JSON.
|
||||
`Encoder` and `Decoder` do not aim to provide any interpretation of the data.
|
||||
|
||||
Functions like `Marshal`, `MarshalFull`, `MarshalNext`, `Unmarshal`,
|
||||
`UnmarshalFull`, and `UnmarshalNext` provide semantic meaning by correlating
|
||||
any arbitrary Go type with some JSON representation of that type (as stored in
|
||||
data types like `[]byte`, `io.Writer`, `io.Reader`, `Encoder`, or `Decoder`).
|
||||
|
||||

|
||||
|
||||
This diagram provides a high-level overview of the v2 `json` package.
|
||||
Purple blocks represent types, while blue blocks represent functions or methods.
|
||||
The arrows and their direction represent the approximate flow of data.
|
||||
The bottom half of the diagram contains functionality that is only concerned
|
||||
with syntax, while the upper half contains functionality that assigns
|
||||
semantic meaning to syntactic data handled by the bottom half.
|
||||
|
||||
In contrast to v1 `encoding/json`, options are represented as separate types
|
||||
rather than being setter methods on the `Encoder` or `Decoder` types.
|
||||
|
||||
## Behavior changes
|
||||
|
||||
The v2 `json` package changes the default behavior of `Marshal` and `Unmarshal`
|
||||
relative to the v1 `json` package to be more sensible.
|
||||
Some of these behavior changes have options and workarounds to opt into
|
||||
behavior similar to what v1 provided.
|
||||
|
||||
This table shows an overview of the changes:
|
||||
|
||||
| v1 | v2 | Details |
|
||||
| -- | -- | ------- |
|
||||
| JSON object members are unmarshaled into a Go struct using a **case-insensitive name match**. | JSON object members are unmarshaled into a Go struct using a **case-sensitive name match**. | [CaseSensitivity](/diff_test.go#:~:text=TestCaseSensitivity) |
|
||||
| When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value is an empty Go value**, which is defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value would encode as an empty JSON value**, which is defined as a JSON null, or an empty JSON string, object, or array. | [OmitEmptyOption](/diff_test.go#:~:text=TestOmitEmptyOption) |
|
||||
| The `string` option **does affect** Go bools. | The `string` option **does not affect** Go bools. | [StringOption](/diff_test.go#:~:text=TestStringOption) |
|
||||
| The `string` option **does not recursively affect** sub-values of the Go field value. | The `string` option **does recursively affect** sub-values of the Go field value. | [StringOption](/diff_test.go#:~:text=TestStringOption) |
|
||||
| The `string` option **sometimes accepts** a JSON null escaped within a JSON string. | The `string` option **never accepts** a JSON null escaped within a JSON string. | [StringOption](/diff_test.go#:~:text=TestStringOption) |
|
||||
| A nil Go slice is marshaled as a **JSON null**. | A nil Go slice is marshaled as an **empty JSON array**. | [NilSlicesAndMaps](/diff_test.go#:~:text=TestNilSlicesAndMaps) |
|
||||
| A nil Go map is marshaled as a **JSON null**. | A nil Go map is marshaled as an **empty JSON object**. | [NilSlicesAndMaps](/diff_test.go#:~:text=TestNilSlicesAndMaps) |
|
||||
| A Go array may be unmarshaled from a **JSON array of any length**. | A Go array must be unmarshaled from a **JSON array of the same length**. | [Arrays](/diff_test.go#:~:text=Arrays) |
|
||||
| A Go byte array is represented as a **JSON array of JSON numbers**. | A Go byte array is represented as a **Base64-encoded JSON string**. | [ByteArrays](/diff_test.go#:~:text=TestByteArrays) |
|
||||
| `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **inconsistently called**. | `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **consistently called**. | [PointerReceiver](/diff_test.go#:~:text=TestPointerReceiver) |
|
||||
| A Go map is marshaled in a **deterministic order**. | A Go map is marshaled in a **non-deterministic order**. | [MapDeterminism](/diff_test.go#:~:text=TestMapDeterminism) |
|
||||
| JSON strings are encoded **with HTML-specific characters being escaped**. | JSON strings are encoded **without any characters being escaped** (unless necessary). | [EscapeHTML](/diff_test.go#:~:text=TestEscapeHTML) |
|
||||
| When marshaling, invalid UTF-8 within a Go string **are silently replaced**. | When marshaling, invalid UTF-8 within a Go string **results in an error**. | [InvalidUTF8](/diff_test.go#:~:text=TestInvalidUTF8) |
|
||||
| When unmarshaling, invalid UTF-8 within a JSON string **are silently replaced**. | When unmarshaling, invalid UTF-8 within a JSON string **results in an error**. | [InvalidUTF8](/diff_test.go#:~:text=TestInvalidUTF8) |
|
||||
| When marshaling, **an error does not occur** if the output JSON value contains objects with duplicate names. | When marshaling, **an error does occur** if the output JSON value contains objects with duplicate names. | [DuplicateNames](/diff_test.go#:~:text=TestDuplicateNames) |
|
||||
| When unmarshaling, **an error does not occur** if the input JSON value contains objects with duplicate names. | When unmarshaling, **an error does occur** if the input JSON value contains objects with duplicate names. | [DuplicateNames](/diff_test.go#:~:text=TestDuplicateNames) |
|
||||
| Unmarshaling a JSON null into a non-empty Go value **inconsistently clears the value or does nothing**. | Unmarshaling a JSON null into a non-empty Go value **always clears the value**. | [MergeNull](/diff_test.go#:~:text=TestMergeNull) |
|
||||
| Unmarshaling a JSON value into a non-empty Go value **follows inconsistent and bizarre behavior**. | Unmarshaling a JSON value into a non-empty Go value **always merges if the input is an object, and otherwise replaces**. | [MergeComposite](/diff_test.go#:~:text=TestMergeComposite) |
|
||||
| A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` is represented as a **JSON string containing the formatted duration (e.g., "1h2m3.456s")**. | [TimeDurations](/diff_test.go#:~:text=TestTimeDurations) |
|
||||
| Unmarshaling a JSON number into a Go float beyond its representation **results in an error**. | Unmarshaling a JSON number into a Go float beyond its representation **uses the closest representable value (e.g., ±`math.MaxFloat`)**. | [MaxFloats](/diff_test.go#:~:text=TestMaxFloats) |
|
||||
| A Go struct with only unexported fields **can be serialized**. | A Go struct with only unexported fields **cannot be serialized**. | [EmptyStructs](/diff_test.go#:~:text=TestEmptyStructs) |
|
||||
| A Go struct that embeds an unexported struct type **can sometimes be serialized**. | A Go struct that embeds an unexported struct type **cannot be serialized**. | [EmbedUnexported](/diff_test.go#:~:text=TestEmbedUnexported) |
|
||||
|
||||
See [diff_test.go](/diff_test.go) for details about every change.
|
||||
|
||||
## Performance
|
||||
|
||||
One of the goals of the v2 module is to be more performant than v1.
|
||||
|
||||
Each of the charts below show the performance across
|
||||
several different JSON implementations:
|
||||
|
||||
* `JSONv1` is `encoding/json` at `v1.18.2`
|
||||
* `JSONv2` is `github.com/go-json-experiment/json` at `v0.0.0-20220524042235-dd8be80fc4a7`
|
||||
* `JSONIterator` is `github.com/json-iterator/go` at `v1.1.12`
|
||||
* `SegmentJSON` is `github.com/segmentio/encoding/json` at `v0.3.5`
|
||||
* `GoJSON` is `github.com/goccy/go-json` at `v0.9.7`
|
||||
* `SonicJSON` is `github.com/bytedance/sonic` at `v1.3.0`
|
||||
|
||||
Benchmarks were run across various datasets:
|
||||
|
||||
* `CanadaGeometry` is a GeoJSON (RFC 7946) representation of Canada.
|
||||
It contains many JSON arrays of arrays of two-element arrays of numbers.
|
||||
* `CITMCatalog` contains many JSON objects using numeric names.
|
||||
* `SyntheaFHIR` is sample JSON data from the healthcare industry.
|
||||
It contains many nested JSON objects with mostly string values,
|
||||
where the set of unique string values is relatively small.
|
||||
* `TwitterStatus` is the JSON response from the Twitter API.
|
||||
It contains a mix of all different JSON kinds, where string values
|
||||
are a mix of both single-byte ASCII and multi-byte Unicode.
|
||||
* `GolangSource` is a simple tree representing the Go source code.
|
||||
It contains many nested JSON objects, each with the same schema.
|
||||
* `StringUnicode` contains many strings with multi-byte Unicode runes.
|
||||
|
||||
All of the implementations other than `JSONv1` and `JSONv2` make
|
||||
extensive use of `unsafe`. As such, we expect those to generally be faster,
|
||||
but at the cost of memory and type safety. `SonicJSON` goes a step even further
|
||||
and uses just-in-time compilation to generate machine code specialized
|
||||
for the Go type being marshaled or unmarshaled.
|
||||
Also, `SonicJSON` does not validate JSON strings for valid UTF-8,
|
||||
and so gains a notable performance boost on datasets with multi-byte Unicode.
|
||||
Benchmarks are performed based on the default marshal and unmarshal behavior
|
||||
of each package. Note that `JSONv2` aims to be safe and correct by default,
|
||||
which may not be the most performant strategy.
|
||||
|
||||
`JSONv2` has several semantic changes relative to `JSONv1` that
|
||||
impacts performance:
|
||||
|
||||
1. When marshaling, `JSONv2` no longer sorts the keys of a Go map.
|
||||
This will improve performance.
|
||||
2. When marshaling or unmarshaling, `JSONv2` always checks
|
||||
to make sure JSON object names are unique.
|
||||
This will hurt performance, but is more correct.
|
||||
3. When marshaling or unmarshaling, `JSONv2` always
|
||||
shallow copies the underlying value for a Go interface and
|
||||
shallow copies the key and value for entries in a Go map.
|
||||
This is done to keep the value as addressable so that `JSONv2` can
|
||||
call methods and functions that operate on a pointer receiver.
|
||||
This will hurt performance, but is more correct.
|
||||
|
||||
All of the charts are unit-less since the values are normalized
|
||||
relative to `JSONv1`, which is why `JSONv1` always has a value of 1.
|
||||
A lower value is better (i.e., runs faster).
|
||||
|
||||
Benchmarks were performed on an AMD Ryzen 9 5900X.
|
||||
|
||||
The code for the benchmarks is located at
|
||||
https://github.com/go-json-experiment/jsonbench.
|
||||
|
||||
### Marshal Performance
|
||||
|
||||
#### Concrete types
|
||||
|
||||

|
||||
|
||||
* This compares marshal performance when serializing
|
||||
[from concrete types](/testdata_test.go).
|
||||
* The `JSONv1` implementation is close to optimal (without the use of `unsafe`).
|
||||
* Relative to `JSONv1`, `JSONv2` is generally as fast or slightly faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is up to 1.3x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is up to 1.8x slower.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 2.0x slower.
|
||||
* Relative to `SonicJSON`, `JSONv2` is about 1.8x to 3.2x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* For `JSONv1` and `JSONv2`, marshaling from concrete types is
|
||||
mostly limited by the performance of Go reflection.
|
||||
|
||||
#### Interface types
|
||||
|
||||

|
||||
|
||||
* This compares marshal performance when serializing from
|
||||
`any`, `map[string]any`, and `[]any` types.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 1.5x to 4.2x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is about 1.1x to 2.4x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is about 1.2x to 1.8x faster.
|
||||
* Relative to `GoJSON`, `JSONv2` is about 1.1x to 2.5x faster.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 1.5x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* `JSONv2` is faster than the alternatives.
|
||||
One advantange is because it does not sort the keys for a `map[string]any`,
|
||||
while alternatives (except `SonicJSON` and `JSONIterator`) do sort the keys.
|
||||
|
||||
#### RawValue types
|
||||
|
||||

|
||||
|
||||
* This compares performance when marshaling from a `json.RawValue`.
|
||||
This mostly exercises the underlying encoder and
|
||||
hides the cost of Go reflection.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 3.5x to 7.8x faster.
|
||||
* `JSONIterator` is blazingly fast because
|
||||
[it does not validate whether the raw value is valid](https://go.dev/play/p/bun9IXQCKRe)
|
||||
and simply copies it to the output.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is about 1.5x to 2.7x faster.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 2.2x faster.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 1.5x faster.
|
||||
* Aside from `JSONIterator`, `JSONv2` is generally the fastest.
|
||||
|
||||
### Unmarshal Performance
|
||||
|
||||
#### Concrete types
|
||||
|
||||

|
||||
|
||||
* This compares unmarshal performance when deserializing
|
||||
[into concrete types](/testdata_test.go).
|
||||
* Relative to `JSONv1`, `JSONv2` is about 1.8x to 5.7x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is about 1.1x to 1.6x slower.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is up to 2.5x slower.
|
||||
* Relative to `GoJSON`, `JSONv2` is about 1.4x to 2.1x slower.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 4.0x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* For `JSONv1` and `JSONv2`, unmarshaling into concrete types is
|
||||
mostly limited by the performance of Go reflection.
|
||||
|
||||
#### Interface types
|
||||
|
||||

|
||||
|
||||
* This compares unmarshal performance when deserializing into
|
||||
`any`, `map[string]any`, and `[]any` types.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 1.tx to 4.3x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is up to 1.5x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is about 1.5 to 3.7x faster.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 1.3x faster.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 1.5x slower
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* Aside from `SonicJSON`, `JSONv2` is generally just as fast
|
||||
or faster than all the alternatives.
|
||||
|
||||
#### RawValue types
|
||||
|
||||

|
||||
|
||||
* This compares performance when unmarshaling into a `json.RawValue`.
|
||||
This mostly exercises the underlying decoder and
|
||||
hides away most of the cost of Go reflection.
|
||||
* Relative to `JSONv1`, `JSONv2` is about 8.3x to 17.0x faster.
|
||||
* Relative to `JSONIterator`, `JSONv2` is up to 2.0x faster.
|
||||
* Relative to `SegmentJSON`, `JSONv2` is up to 1.6x faster or 1.7x slower.
|
||||
* Relative to `GoJSON`, `JSONv2` is up to 1.9x faster or 2.1x slower.
|
||||
* Relative to `SonicJSON`, `JSONv2` is up to 2.0x faster
|
||||
(ignoring `StringUnicode` since `SonicJSON` does not validate UTF-8).
|
||||
* `JSONv1` takes a
|
||||
[lexical scanning approach](https://talks.golang.org/2011/lex.slide#1),
|
||||
which performs a virtual function call for every byte of input.
|
||||
In contrast, `JSONv2` makes heavy use of iterative and linear parsing logic
|
||||
(with extra complexity to resume parsing when encountering segmented buffers).
|
||||
* `JSONv2` is comparable to the alternatives that use `unsafe`.
|
||||
Generally it is faster, but sometimes it is slower.
|
513
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal.go
generated
vendored
Normal file
513
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal.go
generated
vendored
Normal file
@ -0,0 +1,513 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MarshalOptions configures how Go data is serialized as JSON data.
|
||||
// The zero value is equivalent to the default marshal settings.
|
||||
type MarshalOptions struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
// Marshalers is a list of type-specific marshalers to use.
|
||||
Marshalers *Marshalers
|
||||
|
||||
// StringifyNumbers specifies that numeric Go types should be serialized
|
||||
// as a JSON string containing the equivalent JSON number value.
|
||||
//
|
||||
// According to RFC 8259, section 6, a JSON implementation may choose to
|
||||
// limit the representation of a JSON number to an IEEE 754 binary64 value.
|
||||
// This may cause decoders to lose precision for int64 and uint64 types.
|
||||
// Escaping JSON numbers as a JSON string preserves the exact precision.
|
||||
StringifyNumbers bool
|
||||
|
||||
// DiscardUnknownMembers specifies that marshaling should ignore any
|
||||
// JSON object members stored in Go struct fields dedicated to storing
|
||||
// unknown JSON object members.
|
||||
DiscardUnknownMembers bool
|
||||
|
||||
// Deterministic specifies that the same input value will be serialized
|
||||
// as the exact same output bytes. Different processes of
|
||||
// the same program will serialize equal values to the same bytes,
|
||||
// but different versions of the same program are not guaranteed
|
||||
// to produce the exact same sequence of bytes.
|
||||
Deterministic bool
|
||||
|
||||
// formatDepth is the depth at which we respect the format flag.
|
||||
formatDepth int
|
||||
// format is custom formatting for the value at the specified depth.
|
||||
format string
|
||||
}
|
||||
|
||||
// Marshal serializes a Go value as a []byte with default options.
|
||||
// It is a thin wrapper over MarshalOptions.Marshal.
|
||||
func Marshal(in any) (out []byte, err error) {
|
||||
return MarshalOptions{}.Marshal(EncodeOptions{}, in)
|
||||
}
|
||||
|
||||
// MarshalFull serializes a Go value into an io.Writer with default options.
|
||||
// It is a thin wrapper over MarshalOptions.MarshalFull.
|
||||
func MarshalFull(out io.Writer, in any) error {
|
||||
return MarshalOptions{}.MarshalFull(EncodeOptions{}, out, in)
|
||||
}
|
||||
|
||||
// Marshal serializes a Go value as a []byte according to the provided
|
||||
// marshal and encode options. It does not terminate the output with a newline.
|
||||
// See MarshalNext for details about the conversion of a Go value into JSON.
|
||||
func (mo MarshalOptions) Marshal(eo EncodeOptions, in any) (out []byte, err error) {
|
||||
enc := getBufferedEncoder(eo)
|
||||
defer putBufferedEncoder(enc)
|
||||
enc.options.omitTopLevelNewline = true
|
||||
err = mo.MarshalNext(enc, in)
|
||||
// TODO(https://go.dev/issue/45038): Use bytes.Clone.
|
||||
return append([]byte(nil), enc.buf...), err
|
||||
}
|
||||
|
||||
// MarshalFull serializes a Go value into an io.Writer according to the provided
|
||||
// marshal and encode options. It does not terminate the output with a newline.
|
||||
// See MarshalNext for details about the conversion of a Go value into JSON.
|
||||
func (mo MarshalOptions) MarshalFull(eo EncodeOptions, out io.Writer, in any) error {
|
||||
enc := getStreamingEncoder(out, eo)
|
||||
defer putStreamingEncoder(enc)
|
||||
enc.options.omitTopLevelNewline = true
|
||||
err := mo.MarshalNext(enc, in)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalNext encodes a Go value as the next JSON value according to
|
||||
// the provided marshal options.
|
||||
//
|
||||
// Type-specific marshal functions and methods take precedence
|
||||
// over the default representation of a value.
|
||||
// Functions or methods that operate on *T are only called when encoding
|
||||
// a value of type T (by taking its address) or a non-nil value of *T.
|
||||
// MarshalNext ensures that a value is always addressable
|
||||
// (by boxing it on the heap if necessary) so that
|
||||
// these functions and methods can be consistently called. For performance,
|
||||
// it is recommended that MarshalNext be passed a non-nil pointer to the value.
|
||||
//
|
||||
// The input value is encoded as JSON according the following rules:
|
||||
//
|
||||
// - If any type-specific functions in MarshalOptions.Marshalers match
|
||||
// the value type, then those functions are called to encode the value.
|
||||
// If all applicable functions return SkipFunc,
|
||||
// then the value is encoded according to subsequent rules.
|
||||
//
|
||||
// - If the value type implements MarshalerV2,
|
||||
// then the MarshalNextJSON method is called to encode the value.
|
||||
//
|
||||
// - If the value type implements MarshalerV1,
|
||||
// then the MarshalJSON method is called to encode the value.
|
||||
//
|
||||
// - If the value type implements encoding.TextMarshaler,
|
||||
// then the MarshalText method is called to encode the value and
|
||||
// subsequently encode its result as a JSON string.
|
||||
//
|
||||
// - Otherwise, the value is encoded according to the value's type
|
||||
// as described in detail below.
|
||||
//
|
||||
// Most Go types have a default JSON representation.
|
||||
// Certain types support specialized formatting according to
|
||||
// a format flag optionally specified in the Go struct tag
|
||||
// for the struct field that contains the current value
|
||||
// (see the “JSON Representation of Go structs” section for more details).
|
||||
//
|
||||
// The representation of each type is as follows:
|
||||
//
|
||||
// - A Go boolean is encoded as a JSON boolean (e.g., true or false).
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go string is encoded as a JSON string.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go []byte or [N]byte is encoded as a JSON string containing
|
||||
// the binary value encoded using RFC 4648.
|
||||
// If the format is "base64" or unspecified, then this uses RFC 4648, section 4.
|
||||
// If the format is "base64url", then this uses RFC 4648, section 5.
|
||||
// If the format is "base32", then this uses RFC 4648, section 6.
|
||||
// If the format is "base32hex", then this uses RFC 4648, section 7.
|
||||
// If the format is "base16" or "hex", then this uses RFC 4648, section 8.
|
||||
// If the format is "array", then the bytes value is encoded as a JSON array
|
||||
// where each byte is recursively JSON-encoded as each JSON array element.
|
||||
//
|
||||
// - A Go integer is encoded as a JSON number without fractions or exponents.
|
||||
// If MarshalOptions.StringifyNumbers is specified, then the JSON number is
|
||||
// encoded within a JSON string. It does not support any custom format
|
||||
// flags.
|
||||
//
|
||||
// - A Go float is encoded as a JSON number.
|
||||
// If MarshalOptions.StringifyNumbers is specified,
|
||||
// then the JSON number is encoded within a JSON string.
|
||||
// If the format is "nonfinite", then NaN, +Inf, and -Inf are encoded as
|
||||
// the JSON strings "NaN", "Infinity", and "-Infinity", respectively.
|
||||
// Otherwise, the presence of non-finite numbers results in a SemanticError.
|
||||
//
|
||||
// - A Go map is encoded as a JSON object, where each Go map key and value
|
||||
// is recursively encoded as a name and value pair in the JSON object.
|
||||
// The Go map key must encode as a JSON string, otherwise this results
|
||||
// in a SemanticError. When encoding keys, MarshalOptions.StringifyNumbers
|
||||
// is automatically applied so that numeric keys encode as JSON strings.
|
||||
// The Go map is traversed in a non-deterministic order.
|
||||
// For deterministic encoding, consider using RawValue.Canonicalize.
|
||||
// If the format is "emitnull", then a nil map is encoded as a JSON null.
|
||||
// Otherwise by default, a nil map is encoded as an empty JSON object.
|
||||
//
|
||||
// - A Go struct is encoded as a JSON object.
|
||||
// See the “JSON Representation of Go structs” section
|
||||
// in the package-level documentation for more details.
|
||||
//
|
||||
// - A Go slice is encoded as a JSON array, where each Go slice element
|
||||
// is recursively JSON-encoded as the elements of the JSON array.
|
||||
// If the format is "emitnull", then a nil slice is encoded as a JSON null.
|
||||
// Otherwise by default, a nil slice is encoded as an empty JSON array.
|
||||
//
|
||||
// - A Go array is encoded as a JSON array, where each Go array element
|
||||
// is recursively JSON-encoded as the elements of the JSON array.
|
||||
// The JSON array length is always identical to the Go array length.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go pointer is encoded as a JSON null if nil, otherwise it is
|
||||
// the recursively JSON-encoded representation of the underlying value.
|
||||
// Format flags are forwarded to the encoding of the underlying value.
|
||||
//
|
||||
// - A Go interface is encoded as a JSON null if nil, otherwise it is
|
||||
// the recursively JSON-encoded representation of the underlying value.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go time.Time is encoded as a JSON string containing the timestamp
|
||||
// formatted in RFC 3339 with nanosecond resolution.
|
||||
// If the format matches one of the format constants declared
|
||||
// in the time package (e.g., RFC1123), then that format is used.
|
||||
// Otherwise, the format is used as-is with time.Time.Format if non-empty.
|
||||
//
|
||||
// - A Go time.Duration is encoded as a JSON string containing the duration
|
||||
// formatted according to time.Duration.String.
|
||||
// If the format is "nanos", it is encoded as a JSON number
|
||||
// containing the number of nanoseconds in the duration.
|
||||
//
|
||||
// - All other Go types (e.g., complex numbers, channels, and functions)
|
||||
// have no default representation and result in a SemanticError.
|
||||
//
|
||||
// JSON cannot represent cyclic data structures and
|
||||
// MarshalNext does not handle them.
|
||||
// Passing cyclic structures will result in an error.
|
||||
func (mo MarshalOptions) MarshalNext(out *Encoder, in any) error {
|
||||
v := reflect.ValueOf(in)
|
||||
if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) {
|
||||
return out.WriteToken(Null)
|
||||
}
|
||||
// Shallow copy non-pointer values to obtain an addressable value.
|
||||
// It is beneficial to performance to always pass pointers to avoid this.
|
||||
if v.Kind() != reflect.Pointer {
|
||||
v2 := reflect.New(v.Type())
|
||||
v2.Elem().Set(v)
|
||||
v = v2
|
||||
}
|
||||
va := addressableValue{v.Elem()} // dereferenced pointer is always addressable
|
||||
t := va.Type()
|
||||
|
||||
// Lookup and call the marshal function for this type.
|
||||
marshal := lookupArshaler(t).marshal
|
||||
if mo.Marshalers != nil {
|
||||
marshal, _ = mo.Marshalers.lookup(marshal, t)
|
||||
}
|
||||
if err := marshal(mo, out, va); err != nil {
|
||||
if !out.options.AllowDuplicateNames {
|
||||
out.tokens.invalidateDisabledNamespaces()
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalOptions configures how JSON data is deserialized as Go data.
|
||||
// The zero value is equivalent to the default unmarshal settings.
|
||||
type UnmarshalOptions struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
// Unmarshalers is a list of type-specific unmarshalers to use.
|
||||
Unmarshalers *Unmarshalers
|
||||
|
||||
// StringifyNumbers specifies that numeric Go types can be deserialized
|
||||
// from either a JSON number or a JSON string containing a JSON number
|
||||
// without any surrounding whitespace.
|
||||
StringifyNumbers bool
|
||||
|
||||
// RejectUnknownMembers specifies that unknown members should be rejected
|
||||
// when unmarshaling a JSON object, regardless of whether there is a field
|
||||
// to store unknown members.
|
||||
RejectUnknownMembers bool
|
||||
|
||||
// formatDepth is the depth at which we respect the format flag.
|
||||
formatDepth int
|
||||
// format is custom formatting for the value at the specified depth.
|
||||
format string
|
||||
}
|
||||
|
||||
// Unmarshal deserializes a Go value from a []byte with default options.
|
||||
// It is a thin wrapper over UnmarshalOptions.Unmarshal.
|
||||
func Unmarshal(in []byte, out any) error {
|
||||
return UnmarshalOptions{}.Unmarshal(DecodeOptions{}, in, out)
|
||||
}
|
||||
|
||||
// UnmarshalFull deserializes a Go value from an io.Reader with default options.
|
||||
// It is a thin wrapper over UnmarshalOptions.UnmarshalFull.
|
||||
func UnmarshalFull(in io.Reader, out any) error {
|
||||
return UnmarshalOptions{}.UnmarshalFull(DecodeOptions{}, in, out)
|
||||
}
|
||||
|
||||
// Unmarshal deserializes a Go value from a []byte according to the
|
||||
// provided unmarshal and decode options. The output must be a non-nil pointer.
|
||||
// The input must be a single JSON value with optional whitespace interspersed.
|
||||
// See UnmarshalNext for details about the conversion of JSON into a Go value.
|
||||
func (uo UnmarshalOptions) Unmarshal(do DecodeOptions, in []byte, out any) error {
|
||||
dec := getBufferedDecoder(in, do)
|
||||
defer putBufferedDecoder(dec)
|
||||
return uo.unmarshalFull(dec, out)
|
||||
}
|
||||
|
||||
// UnmarshalFull deserializes a Go value from an io.Reader according to the
|
||||
// provided unmarshal and decode options. The output must be a non-nil pointer.
|
||||
// The input must be a single JSON value with optional whitespace interspersed.
|
||||
// It consumes the entirety of io.Reader until io.EOF is encountered.
|
||||
// See UnmarshalNext for details about the conversion of JSON into a Go value.
|
||||
func (uo UnmarshalOptions) UnmarshalFull(do DecodeOptions, in io.Reader, out any) error {
|
||||
dec := getStreamingDecoder(in, do)
|
||||
defer putStreamingDecoder(dec)
|
||||
return uo.unmarshalFull(dec, out)
|
||||
}
|
||||
func (uo UnmarshalOptions) unmarshalFull(in *Decoder, out any) error {
|
||||
switch err := uo.UnmarshalNext(in, out); err {
|
||||
case nil:
|
||||
return in.checkEOF()
|
||||
case io.EOF:
|
||||
return io.ErrUnexpectedEOF
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalNext decodes the next JSON value into a Go value according to
|
||||
// the provided unmarshal options. The output must be a non-nil pointer.
|
||||
//
|
||||
// Type-specific unmarshal functions and methods take precedence
|
||||
// over the default representation of a value.
|
||||
// Functions or methods that operate on *T are only called when decoding
|
||||
// a value of type T (by taking its address) or a non-nil value of *T.
|
||||
// UnmarshalNext ensures that a value is always addressable
|
||||
// (by boxing it on the heap if necessary) so that
|
||||
// these functions and methods can be consistently called.
|
||||
//
|
||||
// The input is decoded into the output according the following rules:
|
||||
//
|
||||
// - If any type-specific functions in UnmarshalOptions.Unmarshalers match
|
||||
// the value type, then those functions are called to decode the JSON
|
||||
// value. If all applicable functions return SkipFunc,
|
||||
// then the input is decoded according to subsequent rules.
|
||||
//
|
||||
// - If the value type implements UnmarshalerV2,
|
||||
// then the UnmarshalNextJSON method is called to decode the JSON value.
|
||||
//
|
||||
// - If the value type implements UnmarshalerV1,
|
||||
// then the UnmarshalJSON method is called to decode the JSON value.
|
||||
//
|
||||
// - If the value type implements encoding.TextUnmarshaler,
|
||||
// then the input is decoded as a JSON string and
|
||||
// the UnmarshalText method is called with the decoded string value.
|
||||
// This fails with a SemanticError if the input is not a JSON string.
|
||||
//
|
||||
// - Otherwise, the JSON value is decoded according to the value's type
|
||||
// as described in detail below.
|
||||
//
|
||||
// Most Go types have a default JSON representation.
|
||||
// Certain types support specialized formatting according to
|
||||
// a format flag optionally specified in the Go struct tag
|
||||
// for the struct field that contains the current value
|
||||
// (see the “JSON Representation of Go structs” section for more details).
|
||||
// A JSON null may be decoded into every supported Go value where
|
||||
// it is equivalent to storing the zero value of the Go value.
|
||||
// If the input JSON kind is not handled by the current Go value type,
|
||||
// then this fails with a SemanticError. Unless otherwise specified,
|
||||
// the decoded value replaces any pre-existing value.
|
||||
//
|
||||
// The representation of each type is as follows:
|
||||
//
|
||||
// - A Go boolean is decoded from a JSON boolean (e.g., true or false).
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go string is decoded from a JSON string.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go []byte or [N]byte is decoded from a JSON string
|
||||
// containing the binary value encoded using RFC 4648.
|
||||
// If the format is "base64" or unspecified, then this uses RFC 4648, section 4.
|
||||
// If the format is "base64url", then this uses RFC 4648, section 5.
|
||||
// If the format is "base32", then this uses RFC 4648, section 6.
|
||||
// If the format is "base32hex", then this uses RFC 4648, section 7.
|
||||
// If the format is "base16" or "hex", then this uses RFC 4648, section 8.
|
||||
// If the format is "array", then the Go slice or array is decoded from a
|
||||
// JSON array where each JSON element is recursively decoded for each byte.
|
||||
// When decoding into a non-nil []byte, the slice length is reset to zero
|
||||
// and the decoded input is appended to it.
|
||||
// When decoding into a [N]byte, the input must decode to exactly N bytes,
|
||||
// otherwise it fails with a SemanticError.
|
||||
//
|
||||
// - A Go integer is decoded from a JSON number.
|
||||
// It may also be decoded from a JSON string containing a JSON number
|
||||
// if UnmarshalOptions.StringifyNumbers is specified.
|
||||
// It fails with a SemanticError if the JSON number
|
||||
// has a fractional or exponent component.
|
||||
// It also fails if it overflows the representation of the Go integer type.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go float is decoded from a JSON number.
|
||||
// It may also be decoded from a JSON string containing a JSON number
|
||||
// if UnmarshalOptions.StringifyNumbers is specified.
|
||||
// The JSON number is parsed as the closest representable Go float value.
|
||||
// If the format is "nonfinite", then the JSON strings
|
||||
// "NaN", "Infinity", and "-Infinity" are decoded as NaN, +Inf, and -Inf.
|
||||
// Otherwise, the presence of such strings results in a SemanticError.
|
||||
//
|
||||
// - A Go map is decoded from a JSON object,
|
||||
// where each JSON object name and value pair is recursively decoded
|
||||
// as the Go map key and value. When decoding keys,
|
||||
// UnmarshalOptions.StringifyNumbers is automatically applied so that
|
||||
// numeric keys can decode from JSON strings. Maps are not cleared.
|
||||
// If the Go map is nil, then a new map is allocated to decode into.
|
||||
// If the decoded key matches an existing Go map entry, the entry value
|
||||
// is reused by decoding the JSON object value into it.
|
||||
// The only supported format is "emitnull" and has no effect when decoding.
|
||||
//
|
||||
// - A Go struct is decoded from a JSON object.
|
||||
// See the “JSON Representation of Go structs” section
|
||||
// in the package-level documentation for more details.
|
||||
//
|
||||
// - A Go slice is decoded from a JSON array, where each JSON element
|
||||
// is recursively decoded and appended to the Go slice.
|
||||
// Before appending into a Go slice, a new slice is allocated if it is nil,
|
||||
// otherwise the slice length is reset to zero.
|
||||
// The only supported format is "emitnull" and has no effect when decoding.
|
||||
//
|
||||
// - A Go array is decoded from a JSON array, where each JSON array element
|
||||
// is recursively decoded as each corresponding Go array element.
|
||||
// Each Go array element is zeroed before decoding into it.
|
||||
// It fails with a SemanticError if the JSON array does not contain
|
||||
// the exact same number of elements as the Go array.
|
||||
// It does not support any custom format flags.
|
||||
//
|
||||
// - A Go pointer is decoded based on the JSON kind and underlying Go type.
|
||||
// If the input is a JSON null, then this stores a nil pointer.
|
||||
// Otherwise, it allocates a new underlying value if the pointer is nil,
|
||||
// and recursively JSON decodes into the underlying value.
|
||||
// Format flags are forwarded to the decoding of the underlying type.
|
||||
//
|
||||
// - A Go interface is decoded based on the JSON kind and underlying Go type.
|
||||
// If the input is a JSON null, then this stores a nil interface value.
|
||||
// Otherwise, a nil interface value of an empty interface type is initialized
|
||||
// with a zero Go bool, string, float64, map[string]any, or []any if the
|
||||
// input is a JSON boolean, string, number, object, or array, respectively.
|
||||
// If the interface value is still nil, then this fails with a SemanticError
|
||||
// since decoding could not determine an appropriate Go type to decode into.
|
||||
// For example, unmarshaling into a nil io.Reader fails since
|
||||
// there is no concrete type to populate the interface value with.
|
||||
// Otherwise an underlying value exists and it recursively decodes
|
||||
// the JSON input into it. It does not support any custom format flags.
|
||||
//
|
||||
// - A Go time.Time is decoded from a JSON string containing the time
|
||||
// formatted in RFC 3339 with nanosecond resolution.
|
||||
// If the format matches one of the format constants declared in
|
||||
// the time package (e.g., RFC1123), then that format is used for parsing.
|
||||
// Otherwise, the format is used as-is with time.Time.Parse if non-empty.
|
||||
//
|
||||
// - A Go time.Duration is decoded from a JSON string by
|
||||
// passing the decoded string to time.ParseDuration.
|
||||
// If the format is "nanos", it is instead decoded from a JSON number
|
||||
// containing the number of nanoseconds in the duration.
|
||||
//
|
||||
// - All other Go types (e.g., complex numbers, channels, and functions)
|
||||
// have no default representation and result in a SemanticError.
|
||||
//
|
||||
// In general, unmarshaling follows merge semantics (similar to RFC 7396)
|
||||
// where the decoded Go value replaces the destination value
|
||||
// for any JSON kind other than an object.
|
||||
// For JSON objects, the input object is merged into the destination value
|
||||
// where matching object members recursively apply merge semantics.
|
||||
func (uo UnmarshalOptions) UnmarshalNext(in *Decoder, out any) error {
|
||||
v := reflect.ValueOf(out)
|
||||
if !v.IsValid() || v.Kind() != reflect.Pointer || v.IsNil() {
|
||||
var t reflect.Type
|
||||
if v.IsValid() {
|
||||
t = v.Type()
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
}
|
||||
err := errors.New("value must be passed as a non-nil pointer reference")
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
va := addressableValue{v.Elem()} // dereferenced pointer is always addressable
|
||||
t := va.Type()
|
||||
|
||||
// Lookup and call the unmarshal function for this type.
|
||||
unmarshal := lookupArshaler(t).unmarshal
|
||||
if uo.Unmarshalers != nil {
|
||||
unmarshal, _ = uo.Unmarshalers.lookup(unmarshal, t)
|
||||
}
|
||||
if err := unmarshal(uo, in, va); err != nil {
|
||||
if !in.options.AllowDuplicateNames {
|
||||
in.tokens.invalidateDisabledNamespaces()
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addressableValue is a reflect.Value that is guaranteed to be addressable
|
||||
// such that calling the Addr and Set methods do not panic.
|
||||
//
|
||||
// There is no compile magic that enforces this property,
|
||||
// but rather the need to construct this type makes it easier to examine each
|
||||
// construction site to ensure that this property is upheld.
|
||||
type addressableValue struct{ reflect.Value }
|
||||
|
||||
// newAddressableValue constructs a new addressable value of type t.
|
||||
func newAddressableValue(t reflect.Type) addressableValue {
|
||||
return addressableValue{reflect.New(t).Elem()}
|
||||
}
|
||||
|
||||
// All marshal and unmarshal behavior is implemented using these signatures.
|
||||
type (
|
||||
marshaler = func(MarshalOptions, *Encoder, addressableValue) error
|
||||
unmarshaler = func(UnmarshalOptions, *Decoder, addressableValue) error
|
||||
)
|
||||
|
||||
type arshaler struct {
|
||||
marshal marshaler
|
||||
unmarshal unmarshaler
|
||||
nonDefault bool
|
||||
}
|
||||
|
||||
var lookupArshalerCache sync.Map // map[reflect.Type]*arshaler
|
||||
|
||||
func lookupArshaler(t reflect.Type) *arshaler {
|
||||
if v, ok := lookupArshalerCache.Load(t); ok {
|
||||
return v.(*arshaler)
|
||||
}
|
||||
|
||||
fncs := makeDefaultArshaler(t)
|
||||
fncs = makeMethodArshaler(fncs, t)
|
||||
fncs = makeTimeArshaler(fncs, t)
|
||||
|
||||
// Use the last stored so that duplicate arshalers can be garbage collected.
|
||||
v, _ := lookupArshalerCache.LoadOrStore(t, fncs)
|
||||
return v.(*arshaler)
|
||||
}
|
238
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_any.go
generated
vendored
Normal file
238
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_any.go
generated
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import "reflect"
|
||||
|
||||
// This files contains an optimized marshal and unmarshal implementation
|
||||
// for the any type. This type is often used when the Go program has
|
||||
// no knowledge of the JSON schema. This is a common enough occurrence
|
||||
// to justify the complexity of adding logic for this.
|
||||
|
||||
func marshalValueAny(mo MarshalOptions, enc *Encoder, val any) error {
|
||||
switch val := val.(type) {
|
||||
case nil:
|
||||
return enc.WriteToken(Null)
|
||||
case bool:
|
||||
return enc.WriteToken(Bool(val))
|
||||
case string:
|
||||
return enc.WriteToken(String(val))
|
||||
case float64:
|
||||
return enc.WriteToken(Float(val))
|
||||
case map[string]any:
|
||||
return marshalObjectAny(mo, enc, val)
|
||||
case []any:
|
||||
return marshalArrayAny(mo, enc, val)
|
||||
default:
|
||||
v := newAddressableValue(reflect.TypeOf(val))
|
||||
v.Set(reflect.ValueOf(val))
|
||||
marshal := lookupArshaler(v.Type()).marshal
|
||||
if mo.Marshalers != nil {
|
||||
marshal, _ = mo.Marshalers.lookup(marshal, v.Type())
|
||||
}
|
||||
return marshal(mo, enc, v)
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalValueAny(uo UnmarshalOptions, dec *Decoder) (any, error) {
|
||||
switch k := dec.PeekKind(); k {
|
||||
case '{':
|
||||
return unmarshalObjectAny(uo, dec)
|
||||
case '[':
|
||||
return unmarshalArrayAny(uo, dec)
|
||||
default:
|
||||
var flags valueFlags
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val.Kind() {
|
||||
case 'n':
|
||||
return nil, nil
|
||||
case 'f':
|
||||
return false, nil
|
||||
case 't':
|
||||
return true, nil
|
||||
case '"':
|
||||
val = unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
if dec.stringCache == nil {
|
||||
dec.stringCache = new(stringCache)
|
||||
}
|
||||
return dec.stringCache.make(val), nil
|
||||
case '0':
|
||||
fv, _ := parseFloat(val, 64) // ignore error since readValue guarantees val is valid
|
||||
return fv, nil
|
||||
default:
|
||||
panic("BUG: invalid kind: " + k.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func marshalObjectAny(mo MarshalOptions, enc *Encoder, obj map[string]any) error {
|
||||
// Check for cycles.
|
||||
if enc.tokens.depth() > startDetectingCyclesAfter {
|
||||
v := reflect.ValueOf(obj)
|
||||
if err := enc.seenPointers.visit(v); err != nil {
|
||||
return err
|
||||
}
|
||||
defer enc.seenPointers.leave(v)
|
||||
}
|
||||
|
||||
// Optimize for marshaling an empty map without any preceding whitespace.
|
||||
if len(obj) == 0 && !enc.options.multiline && !enc.tokens.last.needObjectName() {
|
||||
enc.buf = enc.tokens.mayAppendDelim(enc.buf, '{')
|
||||
enc.buf = append(enc.buf, "{}"...)
|
||||
enc.tokens.last.increment()
|
||||
if enc.needFlush() {
|
||||
return enc.flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(ObjectStart); err != nil {
|
||||
return err
|
||||
}
|
||||
// A Go map guarantees that each entry has a unique key
|
||||
// The only possibility of duplicates is due to invalid UTF-8.
|
||||
if !enc.options.AllowInvalidUTF8 {
|
||||
enc.tokens.last.disableNamespace()
|
||||
}
|
||||
if !mo.Deterministic || len(obj) <= 1 {
|
||||
for name, val := range obj {
|
||||
if err := enc.WriteToken(String(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := marshalValueAny(mo, enc, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
names := getStrings(len(obj))
|
||||
var i int
|
||||
for name := range obj {
|
||||
(*names)[i] = name
|
||||
i++
|
||||
}
|
||||
names.Sort()
|
||||
for _, name := range *names {
|
||||
if err := enc.WriteToken(String(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := marshalValueAny(mo, enc, obj[name]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
putStrings(names)
|
||||
}
|
||||
if err := enc.WriteToken(ObjectEnd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalObjectAny(uo UnmarshalOptions, dec *Decoder) (map[string]any, error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k := tok.Kind()
|
||||
switch k {
|
||||
case 'n':
|
||||
return nil, nil
|
||||
case '{':
|
||||
obj := make(map[string]any)
|
||||
// A Go map guarantees that each entry has a unique key
|
||||
// The only possibility of duplicates is due to invalid UTF-8.
|
||||
if !dec.options.AllowInvalidUTF8 {
|
||||
dec.tokens.last.disableNamespace()
|
||||
}
|
||||
for dec.PeekKind() != '}' {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
name := tok.String()
|
||||
|
||||
// Manually check for duplicate names.
|
||||
if _, ok := obj[name]; ok {
|
||||
name := dec.previousBuffer()
|
||||
err := &SyntacticError{str: "duplicate name " + string(name) + " in object"}
|
||||
return obj, err.withOffset(dec.InputOffset() - int64(len(name)))
|
||||
}
|
||||
|
||||
val, err := unmarshalValueAny(uo, dec)
|
||||
obj[name] = val
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
}
|
||||
if _, err := dec.ReadToken(); err != nil {
|
||||
return obj, err
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: mapStringAnyType}
|
||||
}
|
||||
|
||||
func marshalArrayAny(mo MarshalOptions, enc *Encoder, arr []any) error {
|
||||
// Check for cycles.
|
||||
if enc.tokens.depth() > startDetectingCyclesAfter {
|
||||
v := reflect.ValueOf(arr)
|
||||
if err := enc.seenPointers.visit(v); err != nil {
|
||||
return err
|
||||
}
|
||||
defer enc.seenPointers.leave(v)
|
||||
}
|
||||
|
||||
// Optimize for marshaling an empty slice without any preceding whitespace.
|
||||
if len(arr) == 0 && !enc.options.multiline && !enc.tokens.last.needObjectName() {
|
||||
enc.buf = enc.tokens.mayAppendDelim(enc.buf, '[')
|
||||
enc.buf = append(enc.buf, "[]"...)
|
||||
enc.tokens.last.increment()
|
||||
if enc.needFlush() {
|
||||
return enc.flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(ArrayStart); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, val := range arr {
|
||||
if err := marshalValueAny(mo, enc, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := enc.WriteToken(ArrayEnd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalArrayAny(uo UnmarshalOptions, dec *Decoder) ([]any, error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k := tok.Kind()
|
||||
switch k {
|
||||
case 'n':
|
||||
return nil, nil
|
||||
case '[':
|
||||
arr := []any{}
|
||||
for dec.PeekKind() != ']' {
|
||||
val, err := unmarshalValueAny(uo, dec)
|
||||
arr = append(arr, val)
|
||||
if err != nil {
|
||||
return arr, err
|
||||
}
|
||||
}
|
||||
if _, err := dec.ReadToken(); err != nil {
|
||||
return arr, err
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: sliceAnyType}
|
||||
}
|
1485
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_default.go
generated
vendored
Normal file
1485
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_default.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
387
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_funcs.go
generated
vendored
Normal file
387
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_funcs.go
generated
vendored
Normal file
@ -0,0 +1,387 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SkipFunc may be returned by MarshalFuncV2 and UnmarshalFuncV2 functions.
|
||||
//
|
||||
// Any function that returns SkipFunc must not cause observable side effects
|
||||
// on the provided Encoder or Decoder. For example, it is permissible to call
|
||||
// Decoder.PeekKind, but not permissible to call Decoder.ReadToken or
|
||||
// Encoder.WriteToken since such methods mutate the state.
|
||||
const SkipFunc = jsonError("skip function")
|
||||
|
||||
// Marshalers is a list of functions that may override the marshal behavior
|
||||
// of specific types. Populate MarshalOptions.Marshalers to use it.
|
||||
// A nil *Marshalers is equivalent to an empty list.
|
||||
type Marshalers = typedMarshalers
|
||||
|
||||
// NewMarshalers constructs a flattened list of marshal functions.
|
||||
// If multiple functions in the list are applicable for a value of a given type,
|
||||
// then those earlier in the list take precedence over those that come later.
|
||||
// If a function returns SkipFunc, then the next applicable function is called,
|
||||
// otherwise the default marshaling behavior is used.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// m1 := NewMarshalers(f1, f2)
|
||||
// m2 := NewMarshalers(f0, m1, f3) // equivalent to m3
|
||||
// m3 := NewMarshalers(f0, f1, f2, f3) // equivalent to m2
|
||||
func NewMarshalers(ms ...*Marshalers) *Marshalers {
|
||||
return newMarshalers(ms...)
|
||||
}
|
||||
|
||||
// Unmarshalers is a list of functions that may override the unmarshal behavior
|
||||
// of specific types. Populate UnmarshalOptions.Unmarshalers to use it.
|
||||
// A nil *Unmarshalers is equivalent to an empty list.
|
||||
type Unmarshalers = typedUnmarshalers
|
||||
|
||||
// NewUnmarshalers constructs a flattened list of unmarshal functions.
|
||||
// If multiple functions in the list are applicable for a value of a given type,
|
||||
// then those earlier in the list take precedence over those that come later.
|
||||
// If a function returns SkipFunc, then the next applicable function is called,
|
||||
// otherwise the default unmarshaling behavior is used.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// u1 := NewUnmarshalers(f1, f2)
|
||||
// u2 := NewUnmarshalers(f0, u1, f3) // equivalent to u3
|
||||
// u3 := NewUnmarshalers(f0, f1, f2, f3) // equivalent to u2
|
||||
func NewUnmarshalers(us ...*Unmarshalers) *Unmarshalers {
|
||||
return newUnmarshalers(us...)
|
||||
}
|
||||
|
||||
type typedMarshalers = typedArshalers[MarshalOptions, Encoder]
|
||||
type typedUnmarshalers = typedArshalers[UnmarshalOptions, Decoder]
|
||||
type typedArshalers[Options, Coder any] struct {
|
||||
nonComparable
|
||||
|
||||
fncVals []typedArshaler[Options, Coder]
|
||||
fncCache sync.Map // map[reflect.Type]arshaler
|
||||
|
||||
// fromAny reports whether any of Go types used to represent arbitrary JSON
|
||||
// (i.e., any, bool, string, float64, map[string]any, or []any) matches
|
||||
// any of the provided type-specific arshalers.
|
||||
//
|
||||
// This bit of information is needed in arshal_default.go to determine
|
||||
// whether to use the specialized logic in arshal_any.go to handle
|
||||
// the any interface type. The logic in arshal_any.go does not support
|
||||
// type-specific arshal functions, so we must avoid using that logic
|
||||
// if this is true.
|
||||
fromAny bool
|
||||
}
|
||||
type typedMarshaler = typedArshaler[MarshalOptions, Encoder]
|
||||
type typedUnmarshaler = typedArshaler[UnmarshalOptions, Decoder]
|
||||
type typedArshaler[Options, Coder any] struct {
|
||||
typ reflect.Type
|
||||
fnc func(Options, *Coder, addressableValue) error
|
||||
maySkip bool
|
||||
}
|
||||
|
||||
func newMarshalers(ms ...*Marshalers) *Marshalers { return newTypedArshalers(ms...) }
|
||||
func newUnmarshalers(us ...*Unmarshalers) *Unmarshalers { return newTypedArshalers(us...) }
|
||||
func newTypedArshalers[Options, Coder any](as ...*typedArshalers[Options, Coder]) *typedArshalers[Options, Coder] {
|
||||
var a typedArshalers[Options, Coder]
|
||||
for _, a2 := range as {
|
||||
if a2 != nil {
|
||||
a.fncVals = append(a.fncVals, a2.fncVals...)
|
||||
a.fromAny = a.fromAny || a2.fromAny
|
||||
}
|
||||
}
|
||||
if len(a.fncVals) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a *typedArshalers[Options, Coder]) lookup(fnc func(Options, *Coder, addressableValue) error, t reflect.Type) (func(Options, *Coder, addressableValue) error, bool) {
|
||||
if a == nil {
|
||||
return fnc, false
|
||||
}
|
||||
if v, ok := a.fncCache.Load(t); ok {
|
||||
if v == nil {
|
||||
return fnc, false
|
||||
}
|
||||
return v.(func(Options, *Coder, addressableValue) error), true
|
||||
}
|
||||
|
||||
// Collect a list of arshalers that can be called for this type.
|
||||
// This list may be longer than 1 since some arshalers can be skipped.
|
||||
var fncs []func(Options, *Coder, addressableValue) error
|
||||
for _, fncVal := range a.fncVals {
|
||||
if !castableTo(t, fncVal.typ) {
|
||||
continue
|
||||
}
|
||||
fncs = append(fncs, fncVal.fnc)
|
||||
if !fncVal.maySkip {
|
||||
break // subsequent arshalers will never be called
|
||||
}
|
||||
}
|
||||
|
||||
if len(fncs) == 0 {
|
||||
a.fncCache.Store(t, nil) // nil to indicate that no funcs found
|
||||
return fnc, false
|
||||
}
|
||||
|
||||
// Construct an arshaler that may call every applicable arshaler.
|
||||
fncDefault := fnc
|
||||
fnc = func(o Options, c *Coder, v addressableValue) error {
|
||||
for _, fnc := range fncs {
|
||||
if err := fnc(o, c, v); err != SkipFunc {
|
||||
return err // may be nil or non-nil
|
||||
}
|
||||
}
|
||||
return fncDefault(o, c, v)
|
||||
}
|
||||
|
||||
// Use the first stored so duplicate work can be garbage collected.
|
||||
v, _ := a.fncCache.LoadOrStore(t, fnc)
|
||||
return v.(func(Options, *Coder, addressableValue) error), true
|
||||
}
|
||||
|
||||
// MarshalFuncV1 constructs a type-specific marshaler that
|
||||
// specifies how to marshal values of type T.
|
||||
// T can be any type except a named pointer.
|
||||
// The function is always provided with a non-nil pointer value
|
||||
// if T is an interface or pointer type.
|
||||
//
|
||||
// The function must marshal exactly one JSON value.
|
||||
// The value of T must not be retained outside the function call.
|
||||
// It may not return SkipFunc.
|
||||
func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, true)
|
||||
typFnc := typedMarshaler{
|
||||
typ: t,
|
||||
fnc: func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
val, err := fn(va.castTo(t).Interface().(T))
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal function of type func(T) ([]byte, error)")
|
||||
// TODO: Avoid wrapping semantic errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: RawValue(val).Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// MarshalFuncV2 constructs a type-specific marshaler that
|
||||
// specifies how to marshal values of type T.
|
||||
// T can be any type except a named pointer.
|
||||
// The function is always provided with a non-nil pointer value
|
||||
// if T is an interface or pointer type.
|
||||
//
|
||||
// The function must marshal exactly one JSON value by calling write methods
|
||||
// on the provided encoder. It may return SkipFunc such that marshaling can
|
||||
// move on to the next marshal function. However, no mutable method calls may
|
||||
// be called on the encoder if SkipFunc is returned.
|
||||
// The pointer to Encoder and the value of T must not be retained
|
||||
// outside the function call.
|
||||
func MarshalFuncV2[T any](fn func(MarshalOptions, *Encoder, T) error) *Marshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, true)
|
||||
typFnc := typedMarshaler{
|
||||
typ: t,
|
||||
fnc: func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
prevDepth, prevLength := enc.tokens.depthLength()
|
||||
err := fn(mo, enc, va.castTo(t).Interface().(T))
|
||||
currDepth, currLength := enc.tokens.depthLength()
|
||||
if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) {
|
||||
err = errors.New("must write exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
if err == SkipFunc {
|
||||
if prevDepth == currDepth && prevLength == currLength {
|
||||
return SkipFunc
|
||||
}
|
||||
err = errors.New("must not write any JSON tokens when skipping")
|
||||
}
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
maySkip: true,
|
||||
}
|
||||
return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// UnmarshalFuncV1 constructs a type-specific unmarshaler that
|
||||
// specifies how to unmarshal values of type T.
|
||||
// T must be an unnamed pointer or an interface type.
|
||||
// The function is always provided with a non-nil pointer value.
|
||||
//
|
||||
// The function must unmarshal exactly one JSON value.
|
||||
// The input []byte must not be mutated.
|
||||
// The input []byte and value T must not be retained outside the function call.
|
||||
// It may not return SkipFunc.
|
||||
func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, false)
|
||||
typFnc := typedUnmarshaler{
|
||||
typ: t,
|
||||
fnc: func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
val, err := dec.ReadValue()
|
||||
if err != nil {
|
||||
return err // must be a syntactic or I/O error
|
||||
}
|
||||
err = fn(val, va.castTo(t).Interface().(T))
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal function of type func([]byte, T) error")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// UnmarshalFuncV2 constructs a type-specific unmarshaler that
|
||||
// specifies how to unmarshal values of type T.
|
||||
// T must be an unnamed pointer or an interface type.
|
||||
// The function is always provided with a non-nil pointer value.
|
||||
//
|
||||
// The function must unmarshal exactly one JSON value by calling read methods
|
||||
// on the provided decoder. It may return SkipFunc such that unmarshaling can
|
||||
// move on to the next unmarshal function. However, no mutable method calls may
|
||||
// be called on the decoder if SkipFunc is returned.
|
||||
// The pointer to Decoder and the value of T must not be retained
|
||||
// outside the function call.
|
||||
func UnmarshalFuncV2[T any](fn func(UnmarshalOptions, *Decoder, T) error) *Unmarshalers {
|
||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
||||
assertCastableTo(t, false)
|
||||
typFnc := typedUnmarshaler{
|
||||
typ: t,
|
||||
fnc: func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
prevDepth, prevLength := dec.tokens.depthLength()
|
||||
err := fn(uo, dec, va.castTo(t).Interface().(T))
|
||||
currDepth, currLength := dec.tokens.depthLength()
|
||||
if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) {
|
||||
err = errors.New("must read exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
if err == SkipFunc {
|
||||
if prevDepth == currDepth && prevLength == currLength {
|
||||
return SkipFunc
|
||||
}
|
||||
err = errors.New("must not read any JSON tokens when skipping")
|
||||
}
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
maySkip: true,
|
||||
}
|
||||
return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)}
|
||||
}
|
||||
|
||||
// assertCastableTo asserts that "to" is a valid type to be casted to.
|
||||
// These are the Go types that type-specific arshalers may operate upon.
|
||||
//
|
||||
// Let AllTypes be the universal set of all possible Go types.
|
||||
// This function generally asserts that:
|
||||
//
|
||||
// len([from for from in AllTypes if castableTo(from, to)]) > 0
|
||||
//
|
||||
// otherwise it panics.
|
||||
//
|
||||
// As a special-case if marshal is false, then we forbid any non-pointer or
|
||||
// non-interface type since it is almost always a bug trying to unmarshal
|
||||
// into something where the end-user caller did not pass in an addressable value
|
||||
// since they will not observe the mutations.
|
||||
func assertCastableTo(to reflect.Type, marshal bool) {
|
||||
switch to.Kind() {
|
||||
case reflect.Interface:
|
||||
return
|
||||
case reflect.Pointer:
|
||||
// Only allow unnamed pointers to be consistent with the fact that
|
||||
// taking the address of a value produces an unnamed pointer type.
|
||||
if to.Name() == "" {
|
||||
return
|
||||
}
|
||||
default:
|
||||
// Technically, non-pointer types are permissible for unmarshal.
|
||||
// However, they are often a bug since the receiver would be immutable.
|
||||
// Thus, only allow them for marshaling.
|
||||
if marshal {
|
||||
return
|
||||
}
|
||||
}
|
||||
if marshal {
|
||||
panic(fmt.Sprintf("input type %v must be an interface type, an unnamed pointer type, or a non-pointer type", to))
|
||||
} else {
|
||||
panic(fmt.Sprintf("input type %v must be an interface type or an unnamed pointer type", to))
|
||||
}
|
||||
}
|
||||
|
||||
// castableTo checks whether values of type "from" can be casted to type "to".
|
||||
// Nil pointer or interface "from" values are never considered castable.
|
||||
//
|
||||
// This function must be kept in sync with addressableValue.castTo.
|
||||
func castableTo(from, to reflect.Type) bool {
|
||||
switch to.Kind() {
|
||||
case reflect.Interface:
|
||||
// TODO: This breaks when ordinary interfaces can have type sets
|
||||
// since interfaces now exist where only the value form of a type (T)
|
||||
// implements the interface, but not the pointer variant (*T).
|
||||
// See https://go.dev/issue/45346.
|
||||
return reflect.PointerTo(from).Implements(to)
|
||||
case reflect.Pointer:
|
||||
// Common case for unmarshaling.
|
||||
// From must be a concrete or interface type.
|
||||
return reflect.PointerTo(from) == to
|
||||
default:
|
||||
// Common case for marshaling.
|
||||
// From must be a concrete type.
|
||||
return from == to
|
||||
}
|
||||
}
|
||||
|
||||
// castTo casts va to the specified type.
|
||||
// If the type is an interface, then the underlying type will always
|
||||
// be a non-nil pointer to a concrete type.
|
||||
//
|
||||
// Requirement: castableTo(va.Type(), to) must hold.
|
||||
func (va addressableValue) castTo(to reflect.Type) reflect.Value {
|
||||
switch to.Kind() {
|
||||
case reflect.Interface:
|
||||
return va.Addr().Convert(to)
|
||||
case reflect.Pointer:
|
||||
return va.Addr()
|
||||
default:
|
||||
return va.Value
|
||||
}
|
||||
}
|
||||
|
||||
// castableToFromAny reports whether "to" can be casted to from any
|
||||
// of the dynamic types used to represent arbitrary JSON.
|
||||
func castableToFromAny(to reflect.Type) bool {
|
||||
for _, from := range []reflect.Type{anyType, boolType, stringType, float64Type, mapStringAnyType, sliceAnyType} {
|
||||
if castableTo(from, to) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func wrapSkipFunc(err error, what string) error {
|
||||
if err == SkipFunc {
|
||||
return errors.New(what + " cannot be skipped")
|
||||
}
|
||||
return err
|
||||
}
|
213
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_inlined.go
generated
vendored
Normal file
213
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_inlined.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// This package supports "inlining" a Go struct field, where the contents
|
||||
// of the serialized field (which must be a JSON object) are treated as if
|
||||
// they are part of the parent Go struct (which represents a JSON object).
|
||||
//
|
||||
// Generally, inlined fields are of a Go struct type, where the fields of the
|
||||
// nested struct are virtually hoisted up to the parent struct using rules
|
||||
// similar to how Go embedding works (but operating within the JSON namespace).
|
||||
//
|
||||
// However, inlined fields may also be of a Go map type with a string key
|
||||
// or a RawValue. Such inlined fields are called "fallback" fields since they
|
||||
// represent any arbitrary JSON object member. Explicitly named fields take
|
||||
// precedence over the inlined fallback. Only one inlined fallback is allowed.
|
||||
|
||||
var rawValueType = reflect.TypeOf((*RawValue)(nil)).Elem()
|
||||
|
||||
// marshalInlinedFallbackAll marshals all the members in an inlined fallback.
|
||||
func marshalInlinedFallbackAll(mo MarshalOptions, enc *Encoder, va addressableValue, f *structField, insertUnquotedName func([]byte) bool) error {
|
||||
v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable
|
||||
if len(f.index) > 1 {
|
||||
v = v.fieldByIndex(f.index[1:], false)
|
||||
if !v.IsValid() {
|
||||
return nil // implies a nil inlined field
|
||||
}
|
||||
}
|
||||
v = v.indirect(false)
|
||||
if !v.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Type() == rawValueType {
|
||||
b := v.Interface().(RawValue)
|
||||
if len(b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
|
||||
return nil
|
||||
}
|
||||
|
||||
dec := getBufferedDecoder(b, DecodeOptions{AllowDuplicateNames: true, AllowInvalidUTF8: true})
|
||||
defer putBufferedDecoder(dec)
|
||||
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if tok.Kind() != '{' {
|
||||
err := errors.New("inlined raw value must be a JSON object")
|
||||
return &SemanticError{action: "marshal", JSONKind: tok.Kind(), GoType: rawValueType, Err: err}
|
||||
}
|
||||
for dec.PeekKind() != '}' {
|
||||
// Parse the JSON object name.
|
||||
var flags valueFlags
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if insertUnquotedName != nil {
|
||||
name := unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
if !insertUnquotedName(name) {
|
||||
return &SyntacticError{str: "duplicate name " + string(val) + " in object"}
|
||||
}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the JSON object value.
|
||||
val, err = dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := dec.ReadToken(); err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
if err := dec.checkEOF(); err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
m := v // must be a map[string]V
|
||||
n := m.Len()
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
mk := newAddressableValue(stringType)
|
||||
mv := newAddressableValue(m.Type().Elem())
|
||||
marshalKey := func(mk addressableValue) error {
|
||||
b, err := appendString(enc.UnusedBuffer(), mk.String(), !enc.options.AllowInvalidUTF8, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if insertUnquotedName != nil {
|
||||
isVerbatim := bytes.IndexByte(b, '\\') < 0
|
||||
name := unescapeStringMayCopy(b, isVerbatim)
|
||||
if !insertUnquotedName(name) {
|
||||
return &SyntacticError{str: "duplicate name " + string(b) + " in object"}
|
||||
}
|
||||
}
|
||||
return enc.WriteValue(b)
|
||||
}
|
||||
marshalVal := f.fncs.marshal
|
||||
if mo.Marshalers != nil {
|
||||
marshalVal, _ = mo.Marshalers.lookup(marshalVal, mv.Type())
|
||||
}
|
||||
if !mo.Deterministic || n <= 1 {
|
||||
for iter := m.MapRange(); iter.Next(); {
|
||||
mk.SetIterKey(iter)
|
||||
if err := marshalKey(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
mv.Set(iter.Value())
|
||||
if err := marshalVal(mo, enc, mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
names := getStrings(n)
|
||||
for i, iter := 0, m.Value.MapRange(); i < n && iter.Next(); i++ {
|
||||
mk.SetIterKey(iter)
|
||||
(*names)[i] = mk.String()
|
||||
}
|
||||
names.Sort()
|
||||
for _, name := range *names {
|
||||
mk.SetString(name)
|
||||
if err := marshalKey(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(https://go.dev/issue/57061): Use mv.SetMapIndexOf.
|
||||
mv.Set(m.MapIndex(mk.Value))
|
||||
if err := marshalVal(mo, enc, mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
putStrings(names)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback.
|
||||
func unmarshalInlinedFallbackNext(uo UnmarshalOptions, dec *Decoder, va addressableValue, f *structField, quotedName, unquotedName []byte) error {
|
||||
v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable
|
||||
if len(f.index) > 1 {
|
||||
v = v.fieldByIndex(f.index[1:], true)
|
||||
}
|
||||
v = v.indirect(true)
|
||||
|
||||
if v.Type() == rawValueType {
|
||||
b := v.Addr().Interface().(*RawValue)
|
||||
if len(*b) == 0 { // TODO: Should this be nil? What if it were all whitespace?
|
||||
*b = append(*b, '{')
|
||||
} else {
|
||||
*b = trimSuffixWhitespace(*b)
|
||||
if hasSuffixByte(*b, '}') {
|
||||
// TODO: When merging into an object for the first time,
|
||||
// should we verify that it is valid?
|
||||
*b = trimSuffixByte(*b, '}')
|
||||
*b = trimSuffixWhitespace(*b)
|
||||
if !hasSuffixByte(*b, ',') && !hasSuffixByte(*b, '{') {
|
||||
*b = append(*b, ',')
|
||||
}
|
||||
} else {
|
||||
err := errors.New("inlined raw value must be a JSON object")
|
||||
return &SemanticError{action: "unmarshal", GoType: rawValueType, Err: err}
|
||||
}
|
||||
}
|
||||
*b = append(*b, quotedName...)
|
||||
*b = append(*b, ':')
|
||||
rawValue, err := dec.ReadValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b = append(*b, rawValue...)
|
||||
*b = append(*b, '}')
|
||||
return nil
|
||||
} else {
|
||||
name := string(unquotedName) // TODO: Intern this?
|
||||
|
||||
m := v // must be a map[string]V
|
||||
if m.IsNil() {
|
||||
m.Set(reflect.MakeMap(m.Type()))
|
||||
}
|
||||
mk := reflect.ValueOf(name)
|
||||
mv := newAddressableValue(v.Type().Elem()) // TODO: Cache across calls?
|
||||
if v2 := m.MapIndex(mk); v2.IsValid() {
|
||||
mv.Set(v2)
|
||||
}
|
||||
|
||||
unmarshal := f.fncs.unmarshal
|
||||
if uo.Unmarshalers != nil {
|
||||
unmarshal, _ = uo.Unmarshalers.lookup(unmarshal, mv.Type())
|
||||
}
|
||||
err := unmarshal(uo, dec, mv)
|
||||
m.SetMapIndex(mk, mv.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
229
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_methods.go
generated
vendored
Normal file
229
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_methods.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Interfaces for custom serialization.
|
||||
var (
|
||||
jsonMarshalerV1Type = reflect.TypeOf((*MarshalerV1)(nil)).Elem()
|
||||
jsonMarshalerV2Type = reflect.TypeOf((*MarshalerV2)(nil)).Elem()
|
||||
jsonUnmarshalerV1Type = reflect.TypeOf((*UnmarshalerV1)(nil)).Elem()
|
||||
jsonUnmarshalerV2Type = reflect.TypeOf((*UnmarshalerV2)(nil)).Elem()
|
||||
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
// MarshalerV1 is implemented by types that can marshal themselves.
|
||||
// It is recommended that types implement MarshalerV2 unless the implementation
|
||||
// is trying to avoid a hard dependency on the "jsontext" package.
|
||||
//
|
||||
// It is recommended that implementations return a buffer that is safe
|
||||
// for the caller to retain and potentially mutate.
|
||||
type MarshalerV1 interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
}
|
||||
|
||||
// MarshalerV2 is implemented by types that can marshal themselves.
|
||||
// It is recommended that types implement MarshalerV2 instead of MarshalerV1
|
||||
// since this is both more performant and flexible.
|
||||
// If a type implements both MarshalerV1 and MarshalerV2,
|
||||
// then MarshalerV2 takes precedence. In such a case, both implementations
|
||||
// should aim to have equivalent behavior for the default marshal options.
|
||||
//
|
||||
// The implementation must write only one JSON value to the Encoder and
|
||||
// must not retain the pointer to Encoder.
|
||||
type MarshalerV2 interface {
|
||||
MarshalNextJSON(MarshalOptions, *Encoder) error
|
||||
|
||||
// TODO: Should users call the MarshalOptions.MarshalNext method or
|
||||
// should/can they call this method directly? Does it matter?
|
||||
}
|
||||
|
||||
// UnmarshalerV1 is implemented by types that can unmarshal themselves.
|
||||
// It is recommended that types implement UnmarshalerV2 unless
|
||||
// the implementation is trying to avoid a hard dependency on this package.
|
||||
//
|
||||
// The input can be assumed to be a valid encoding of a JSON value
|
||||
// if called from unmarshal functionality in this package.
|
||||
// UnmarshalJSON must copy the JSON data if it is retained after returning.
|
||||
// It is recommended that UnmarshalJSON implement merge semantics when
|
||||
// unmarshaling into a pre-populated value.
|
||||
//
|
||||
// Implementations must not retain or mutate the input []byte.
|
||||
type UnmarshalerV1 interface {
|
||||
UnmarshalJSON([]byte) error
|
||||
}
|
||||
|
||||
// UnmarshalerV2 is implemented by types that can unmarshal themselves.
|
||||
// It is recommended that types implement UnmarshalerV2 instead of UnmarshalerV1
|
||||
// since this is both more performant and flexible.
|
||||
// If a type implements both UnmarshalerV1 and UnmarshalerV2,
|
||||
// then UnmarshalerV2 takes precedence. In such a case, both implementations
|
||||
// should aim to have equivalent behavior for the default unmarshal options.
|
||||
//
|
||||
// The implementation must read only one JSON value from the Decoder.
|
||||
// It is recommended that UnmarshalNextJSON implement merge semantics when
|
||||
// unmarshaling into a pre-populated value.
|
||||
//
|
||||
// Implementations must not retain the pointer to Decoder.
|
||||
type UnmarshalerV2 interface {
|
||||
UnmarshalNextJSON(UnmarshalOptions, *Decoder) error
|
||||
|
||||
// TODO: Should users call the UnmarshalOptions.UnmarshalNext method or
|
||||
// should/can they call this method directly? Does it matter?
|
||||
}
|
||||
|
||||
func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler {
|
||||
// Avoid injecting method arshaler on the pointer or interface version
|
||||
// to avoid ever calling the method on a nil pointer or interface receiver.
|
||||
// Let it be injected on the value receiver (which is always addressable).
|
||||
if t.Kind() == reflect.Pointer || t.Kind() == reflect.Interface {
|
||||
return fncs
|
||||
}
|
||||
|
||||
// Handle custom marshaler.
|
||||
switch which, needAddr := implementsWhich(t, jsonMarshalerV2Type, jsonMarshalerV1Type, textMarshalerType); which {
|
||||
case jsonMarshalerV2Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
prevDepth, prevLength := enc.tokens.depthLength()
|
||||
err := va.addrWhen(needAddr).Interface().(MarshalerV2).MarshalNextJSON(mo, enc)
|
||||
currDepth, currLength := enc.tokens.depthLength()
|
||||
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
|
||||
err = errors.New("must write exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal method")
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case jsonMarshalerV1Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
marshaler := va.addrWhen(needAddr).Interface().(MarshalerV1)
|
||||
val, err := marshaler.MarshalJSON()
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal method")
|
||||
// TODO: Avoid wrapping semantic errors.
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
// TODO: Avoid wrapping semantic or I/O errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: RawValue(val).Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case textMarshalerType:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
marshaler := va.addrWhen(needAddr).Interface().(encoding.TextMarshaler)
|
||||
s, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "marshal method")
|
||||
// TODO: Avoid wrapping semantic errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err}
|
||||
}
|
||||
val := enc.UnusedBuffer()
|
||||
val, err = appendString(val, string(s), true, nil)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err}
|
||||
}
|
||||
if err := enc.WriteValue(val); err != nil {
|
||||
// TODO: Avoid wrapping syntactic or I/O errors.
|
||||
return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Handle custom unmarshaler.
|
||||
switch which, needAddr := implementsWhich(t, jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType); which {
|
||||
case jsonUnmarshalerV2Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
prevDepth, prevLength := dec.tokens.depthLength()
|
||||
err := va.addrWhen(needAddr).Interface().(UnmarshalerV2).UnmarshalNextJSON(uo, dec)
|
||||
currDepth, currLength := dec.tokens.depthLength()
|
||||
if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil {
|
||||
err = errors.New("must read exactly one JSON value")
|
||||
}
|
||||
if err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal method")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case jsonUnmarshalerV1Type:
|
||||
fncs.nonDefault = true
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
val, err := dec.ReadValue()
|
||||
if err != nil {
|
||||
return err // must be a syntactic or I/O error
|
||||
}
|
||||
unmarshaler := va.addrWhen(needAddr).Interface().(UnmarshalerV1)
|
||||
if err := unmarshaler.UnmarshalJSON(val); err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal method")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case textUnmarshalerType:
|
||||
fncs.nonDefault = true
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
var flags valueFlags
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return err // must be a syntactic or I/O error
|
||||
}
|
||||
if val.Kind() != '"' {
|
||||
err = errors.New("JSON value must be string type")
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
s := unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
unmarshaler := va.addrWhen(needAddr).Interface().(encoding.TextUnmarshaler)
|
||||
if err := unmarshaler.UnmarshalText(s); err != nil {
|
||||
err = wrapSkipFunc(err, "unmarshal method")
|
||||
// TODO: Avoid wrapping semantic, syntactic, or I/O errors.
|
||||
return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fncs
|
||||
}
|
||||
|
||||
// implementsWhich is like t.Implements(ifaceType) for a list of interfaces,
|
||||
// but checks whether either t or reflect.PointerTo(t) implements the interface.
|
||||
// It returns the first interface type that matches and whether a value of t
|
||||
// needs to be addressed first before it implements the interface.
|
||||
func implementsWhich(t reflect.Type, ifaceTypes ...reflect.Type) (which reflect.Type, needAddr bool) {
|
||||
for _, ifaceType := range ifaceTypes {
|
||||
switch {
|
||||
case t.Implements(ifaceType):
|
||||
return ifaceType, false
|
||||
case reflect.PointerTo(t).Implements(ifaceType):
|
||||
return ifaceType, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// addrWhen returns va.Addr if addr is specified, otherwise it returns itself.
|
||||
func (va addressableValue) addrWhen(addr bool) reflect.Value {
|
||||
if addr {
|
||||
return va.Addr()
|
||||
}
|
||||
return va.Value
|
||||
}
|
241
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_time.go
generated
vendored
Normal file
241
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/arshal_time.go
generated
vendored
Normal file
@ -0,0 +1,241 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
timeDurationType = reflect.TypeOf((*time.Duration)(nil)).Elem()
|
||||
timeTimeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
)
|
||||
|
||||
func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler {
|
||||
// Ideally, time types would implement MarshalerV2 and UnmarshalerV2,
|
||||
// but that would incur a dependency on package json from package time.
|
||||
// Given how widely used time is, it is more acceptable that we incur a
|
||||
// dependency on time from json.
|
||||
//
|
||||
// Injecting the arshaling functionality like this will not be identical
|
||||
// to actually declaring methods on the time types since embedding of the
|
||||
// time types will not be able to forward this functionality.
|
||||
switch t {
|
||||
case timeDurationType:
|
||||
fncs.nonDefault = true
|
||||
marshalNanos := fncs.marshal
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
if mo.format != "" && mo.formatDepth == enc.tokens.depth() {
|
||||
if mo.format == "nanos" {
|
||||
mo.format = ""
|
||||
return marshalNanos(mo, enc, va)
|
||||
} else {
|
||||
return newInvalidFormatError("marshal", t, mo.format)
|
||||
}
|
||||
}
|
||||
|
||||
td := va.Interface().(time.Duration)
|
||||
b := enc.UnusedBuffer()
|
||||
b = append(b, '"')
|
||||
b = append(b, td.String()...) // never contains special characters
|
||||
b = append(b, '"')
|
||||
return enc.WriteValue(b)
|
||||
}
|
||||
unmarshalNanos := fncs.unmarshal
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
// TODO: Should there be a flag that specifies that we can unmarshal
|
||||
// from either form since there would be no ambiguity?
|
||||
if uo.format != "" && uo.formatDepth == dec.tokens.depth() {
|
||||
if uo.format == "nanos" {
|
||||
uo.format = ""
|
||||
return unmarshalNanos(uo, dec, va)
|
||||
} else {
|
||||
return newInvalidFormatError("unmarshal", t, uo.format)
|
||||
}
|
||||
}
|
||||
|
||||
var flags valueFlags
|
||||
td := va.Addr().Interface().(*time.Duration)
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch k := val.Kind(); k {
|
||||
case 'n':
|
||||
*td = time.Duration(0)
|
||||
return nil
|
||||
case '"':
|
||||
val = unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
td2, err := time.ParseDuration(string(val))
|
||||
if err != nil {
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err}
|
||||
}
|
||||
*td = td2
|
||||
return nil
|
||||
default:
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t}
|
||||
}
|
||||
}
|
||||
case timeTimeType:
|
||||
fncs.nonDefault = true
|
||||
fncs.marshal = func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
|
||||
format := time.RFC3339Nano
|
||||
isRFC3339 := true
|
||||
if mo.format != "" && mo.formatDepth == enc.tokens.depth() {
|
||||
var err error
|
||||
format, isRFC3339, err = checkTimeFormat(mo.format)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
tt := va.Interface().(time.Time)
|
||||
b := enc.UnusedBuffer()
|
||||
b = append(b, '"')
|
||||
b = tt.AppendFormat(b, format)
|
||||
b = append(b, '"')
|
||||
if isRFC3339 {
|
||||
// Not all Go timestamps can be represented as valid RFC 3339.
|
||||
// Explicitly check for these edge cases.
|
||||
// See https://go.dev/issue/4556 and https://go.dev/issue/54580.
|
||||
var err error
|
||||
switch b := b[len(`"`) : len(b)-len(`"`)]; {
|
||||
case b[len("9999")] != '-': // year must be exactly 4 digits wide
|
||||
err = errors.New("year outside of range [0,9999]")
|
||||
case b[len(b)-1] != 'Z':
|
||||
c := b[len(b)-len("Z07:00")]
|
||||
if ('0' <= c && c <= '9') || parseDec2(b[len(b)-len("07:00"):]) >= 24 {
|
||||
err = errors.New("timezone hour outside of range [0,23]")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return &SemanticError{action: "marshal", GoType: t, Err: err}
|
||||
}
|
||||
return enc.WriteValue(b) // RFC 3339 never needs JSON escaping
|
||||
}
|
||||
// The format may contain special characters that need escaping.
|
||||
// Verify that the result is a valid JSON string (common case),
|
||||
// otherwise escape the string correctly (slower case).
|
||||
if consumeSimpleString(b) != len(b) {
|
||||
b, _ = appendString(nil, string(b[len(`"`):len(b)-len(`"`)]), true, nil)
|
||||
}
|
||||
return enc.WriteValue(b)
|
||||
}
|
||||
fncs.unmarshal = func(uo UnmarshalOptions, dec *Decoder, va addressableValue) error {
|
||||
format := time.RFC3339
|
||||
isRFC3339 := true
|
||||
if uo.format != "" && uo.formatDepth == dec.tokens.depth() {
|
||||
var err error
|
||||
format, isRFC3339, err = checkTimeFormat(uo.format)
|
||||
if err != nil {
|
||||
return &SemanticError{action: "unmarshal", GoType: t, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
var flags valueFlags
|
||||
tt := va.Addr().Interface().(*time.Time)
|
||||
val, err := dec.readValue(&flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k := val.Kind()
|
||||
switch k {
|
||||
case 'n':
|
||||
*tt = time.Time{}
|
||||
return nil
|
||||
case '"':
|
||||
val = unescapeStringMayCopy(val, flags.isVerbatim())
|
||||
tt2, err := time.Parse(format, string(val))
|
||||
if isRFC3339 && err == nil {
|
||||
// TODO(https://go.dev/issue/54580): RFC 3339 specifies
|
||||
// the exact grammar of a valid timestamp. However,
|
||||
// the parsing functionality in "time" is too loose and
|
||||
// incorrectly accepts invalid timestamps as valid.
|
||||
// Remove these manual checks when "time" checks it for us.
|
||||
newParseError := func(layout, value, layoutElem, valueElem, message string) error {
|
||||
return &time.ParseError{Layout: layout, Value: value, LayoutElem: layoutElem, ValueElem: valueElem, Message: message}
|
||||
}
|
||||
switch {
|
||||
case val[len("2006-01-02T")+1] == ':': // hour must be two digits
|
||||
err = newParseError(format, string(val), "15", string(val[len("2006-01-02T"):][:1]), "")
|
||||
case val[len("2006-01-02T15:04:05")] == ',': // sub-second separator must be a period
|
||||
err = newParseError(format, string(val), ".", ",", "")
|
||||
case val[len(val)-1] != 'Z':
|
||||
switch {
|
||||
case parseDec2(val[len(val)-len("07:00"):]) >= 24: // timezone hour must be in range
|
||||
err = newParseError(format, string(val), "Z07:00", string(val[len(val)-len("Z07:00"):]), ": timezone hour out of range")
|
||||
case parseDec2(val[len(val)-len("00"):]) >= 60: // timezone minute must be in range
|
||||
err = newParseError(format, string(val), "Z07:00", string(val[len(val)-len("Z07:00"):]), ": timezone minute out of range")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err}
|
||||
}
|
||||
*tt = tt2
|
||||
return nil
|
||||
default:
|
||||
return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fncs
|
||||
}
|
||||
|
||||
func checkTimeFormat(format string) (string, bool, error) {
|
||||
// We assume that an exported constant in the time package will
|
||||
// always start with an uppercase ASCII letter.
|
||||
if len(format) > 0 && 'A' <= format[0] && format[0] <= 'Z' {
|
||||
switch format {
|
||||
case "ANSIC":
|
||||
return time.ANSIC, false, nil
|
||||
case "UnixDate":
|
||||
return time.UnixDate, false, nil
|
||||
case "RubyDate":
|
||||
return time.RubyDate, false, nil
|
||||
case "RFC822":
|
||||
return time.RFC822, false, nil
|
||||
case "RFC822Z":
|
||||
return time.RFC822Z, false, nil
|
||||
case "RFC850":
|
||||
return time.RFC850, false, nil
|
||||
case "RFC1123":
|
||||
return time.RFC1123, false, nil
|
||||
case "RFC1123Z":
|
||||
return time.RFC1123Z, false, nil
|
||||
case "RFC3339":
|
||||
return time.RFC3339, true, nil
|
||||
case "RFC3339Nano":
|
||||
return time.RFC3339Nano, true, nil
|
||||
case "Kitchen":
|
||||
return time.Kitchen, false, nil
|
||||
case "Stamp":
|
||||
return time.Stamp, false, nil
|
||||
case "StampMilli":
|
||||
return time.StampMilli, false, nil
|
||||
case "StampMicro":
|
||||
return time.StampMicro, false, nil
|
||||
case "StampNano":
|
||||
return time.StampNano, false, nil
|
||||
default:
|
||||
// Reject any format that is an exported Go identifier in case
|
||||
// new format constants are added to the time package.
|
||||
if strings.TrimFunc(format, isLetterOrDigit) == "" {
|
||||
return "", false, fmt.Errorf("undefined format layout: %v", format)
|
||||
}
|
||||
}
|
||||
}
|
||||
return format, false, nil
|
||||
}
|
||||
|
||||
// parseDec2 parses b as an unsigned, base-10, 2-digit number.
|
||||
// It panics if len(b) < 2. The result is undefined if digits are not base-10.
|
||||
func parseDec2(b []byte) byte {
|
||||
return 10*(b[0]-'0') + (b[1] - '0')
|
||||
}
|
1655
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/decode.go
generated
vendored
Normal file
1655
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/decode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
182
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/doc.go
generated
vendored
Normal file
182
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/doc.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package json implements serialization of JSON
|
||||
// as specified in RFC 4627, RFC 7159, RFC 7493, RFC 8259, and RFC 8785.
|
||||
// JSON is a simple data interchange format that can represent
|
||||
// primitive data types such as booleans, strings, and numbers,
|
||||
// in addition to structured data types such as objects and arrays.
|
||||
//
|
||||
// # Terminology
|
||||
//
|
||||
// This package uses the terms "encode" and "decode" for syntactic functionality
|
||||
// that is concerned with processing JSON based on its grammar, and
|
||||
// uses the terms "marshal" and "unmarshal" for semantic functionality
|
||||
// that determines the meaning of JSON values as Go values and vice-versa.
|
||||
// It aims to provide a clear distinction between functionality that
|
||||
// is purely concerned with encoding versus that of marshaling.
|
||||
// For example, one can directly encode a stream of JSON tokens without
|
||||
// needing to marshal a concrete Go value representing them.
|
||||
// Similarly, one can decode a stream of JSON tokens without
|
||||
// needing to unmarshal them into a concrete Go value.
|
||||
//
|
||||
// This package uses JSON terminology when discussing JSON, which may differ
|
||||
// from related concepts in Go or elsewhere in computing literature.
|
||||
//
|
||||
// - A JSON "object" refers to an unordered collection of name/value members.
|
||||
// - A JSON "array" refers to an ordered sequence of elements.
|
||||
// - A JSON "value" refers to either a literal (i.e., null, false, or true),
|
||||
// string, number, object, or array.
|
||||
//
|
||||
// See RFC 8259 for more information.
|
||||
//
|
||||
// # Specifications
|
||||
//
|
||||
// Relevant specifications include RFC 4627, RFC 7159, RFC 7493, RFC 8259,
|
||||
// and RFC 8785. Each RFC is generally a stricter subset of another RFC.
|
||||
// In increasing order of strictness:
|
||||
//
|
||||
// - RFC 4627 and RFC 7159 do not require (but recommend) the use of UTF-8
|
||||
// and also do not require (but recommend) that object names be unique.
|
||||
// - RFC 8259 requires the use of UTF-8,
|
||||
// but does not require (but recommends) that object names be unique.
|
||||
// - RFC 7493 requires the use of UTF-8
|
||||
// and also requires that object names be unique.
|
||||
// - RFC 8785 defines a canonical representation. It requires the use of UTF-8
|
||||
// and also requires that object names be unique and in a specific ordering.
|
||||
// It specifies exactly how strings and numbers must be formatted.
|
||||
//
|
||||
// The primary difference between RFC 4627 and RFC 7159 is that the former
|
||||
// restricted top-level values to only JSON objects and arrays, while
|
||||
// RFC 7159 and subsequent RFCs permit top-level values to additionally be
|
||||
// JSON nulls, booleans, strings, or numbers.
|
||||
//
|
||||
// By default, this package operates on RFC 7493, but can be configured
|
||||
// to operate according to the other RFC specifications.
|
||||
// RFC 7493 is a stricter subset of RFC 8259 and fully compliant with it.
|
||||
// In particular, it makes specific choices about behavior that RFC 8259
|
||||
// leaves as undefined in order to ensure greater interoperability.
|
||||
//
|
||||
// # JSON Representation of Go structs
|
||||
//
|
||||
// A Go struct is naturally represented as a JSON object,
|
||||
// where each Go struct field corresponds with a JSON object member.
|
||||
// When marshaling, all Go struct fields are recursively encoded in depth-first
|
||||
// order as JSON object members except those that are ignored or omitted.
|
||||
// When unmarshaling, JSON object members are recursively decoded
|
||||
// into the corresponding Go struct fields.
|
||||
// Object members that do not match any struct fields,
|
||||
// also known as “unknown members”, are ignored by default or rejected
|
||||
// if UnmarshalOptions.RejectUnknownMembers is specified.
|
||||
//
|
||||
// The representation of each struct field can be customized in the
|
||||
// "json" struct field tag, where the tag is a comma separated list of options.
|
||||
// As a special case, if the entire tag is `json:"-"`,
|
||||
// then the field is ignored with regard to its JSON representation.
|
||||
//
|
||||
// The first option is the JSON object name override for the Go struct field.
|
||||
// If the name is not specified, then the Go struct field name
|
||||
// is used as the JSON object name. JSON names containing commas or quotes,
|
||||
// or names identical to "" or "-", can be specified using
|
||||
// a single-quoted string literal, where the syntax is identical to
|
||||
// the Go grammar for a double-quoted string literal,
|
||||
// but instead uses single quotes as the delimiters.
|
||||
// By default, unmarshaling uses case-sensitive matching to identify
|
||||
// the Go struct field associated with a JSON object name.
|
||||
//
|
||||
// After the name, the following tag options are supported:
|
||||
//
|
||||
// - omitzero: When marshaling, the "omitzero" option specifies that
|
||||
// the struct field should be omitted if the field value is zero
|
||||
// as determined by the "IsZero() bool" method if present,
|
||||
// otherwise based on whether the field is the zero Go value.
|
||||
// This option has no effect when unmarshaling.
|
||||
//
|
||||
// - omitempty: When marshaling, the "omitempty" option specifies that
|
||||
// the struct field should be omitted if the field value would have been
|
||||
// encoded as a JSON null, empty string, empty object, or empty array.
|
||||
// This option has no effect when unmarshaling.
|
||||
//
|
||||
// - string: The "string" option specifies that
|
||||
// MarshalOptions.StringifyNumbers and UnmarshalOptions.StringifyNumbers
|
||||
// be set when marshaling or unmarshaling a struct field value.
|
||||
// This causes numeric types to be encoded as a JSON number
|
||||
// within a JSON string, and to be decoded from either a JSON number or
|
||||
// a JSON string containing a JSON number.
|
||||
// This extra level of encoding is often necessary since
|
||||
// many JSON parsers cannot precisely represent 64-bit integers.
|
||||
//
|
||||
// - nocase: When unmarshaling, the "nocase" option specifies that
|
||||
// if the JSON object name does not exactly match the JSON name
|
||||
// for any of the struct fields, then it attempts to match the struct field
|
||||
// using a case-insensitive match that also ignores dashes and underscores.
|
||||
// If multiple fields match, the first declared field in breadth-first order
|
||||
// takes precedence. This option has no effect when marshaling.
|
||||
//
|
||||
// - inline: The "inline" option specifies that
|
||||
// the JSON representable content of this field type is to be promoted
|
||||
// as if they were specified in the parent struct.
|
||||
// It is the JSON equivalent of Go struct embedding.
|
||||
// A Go embedded field is implicitly inlined unless an explicit JSON name
|
||||
// is specified. The inlined field must be a Go struct
|
||||
// (that does not implement any JSON methods), RawValue, map[string]T,
|
||||
// or an unnamed pointer to such types. When marshaling,
|
||||
// inlined fields from a pointer type are omitted if it is nil.
|
||||
// Inlined fields of type RawValue and map[string]T are called
|
||||
// “inlined fallbacks” as they can represent all possible
|
||||
// JSON object members not directly handled by the parent struct.
|
||||
// Only one inlined fallback field may be specified in a struct,
|
||||
// while many non-fallback fields may be specified. This option
|
||||
// must not be specified with any other option (including the JSON name).
|
||||
//
|
||||
// - unknown: The "unknown" option is a specialized variant
|
||||
// of the inlined fallback to indicate that this Go struct field
|
||||
// contains any number of unknown JSON object members. The field type
|
||||
// must be a RawValue, map[string]T, or an unnamed pointer to such types.
|
||||
// If MarshalOptions.DiscardUnknownMembers is specified when marshaling,
|
||||
// the contents of this field are ignored.
|
||||
// If UnmarshalOptions.RejectUnknownMembers is specified when unmarshaling,
|
||||
// any unknown object members are rejected regardless of whether
|
||||
// an inlined fallback with the "unknown" option exists. This option
|
||||
// must not be specified with any other option (including the JSON name).
|
||||
//
|
||||
// - format: The "format" option specifies a format flag
|
||||
// used to specialize the formatting of the field value.
|
||||
// The option is a key-value pair specified as "format:value" where
|
||||
// the value must be either a literal consisting of letters and numbers
|
||||
// (e.g., "format:RFC3339") or a single-quoted string literal
|
||||
// (e.g., "format:'2006-01-02'"). The interpretation of the format flag
|
||||
// is determined by the struct field type.
|
||||
//
|
||||
// The "omitzero" and "omitempty" options are mostly semantically identical.
|
||||
// The former is defined in terms of the Go type system,
|
||||
// while the latter in terms of the JSON type system.
|
||||
// Consequently they behave differently in some circumstances.
|
||||
// For example, only a nil slice or map is omitted under "omitzero", while
|
||||
// an empty slice or map is omitted under "omitempty" regardless of nilness.
|
||||
// The "omitzero" option is useful for types with a well-defined zero value
|
||||
// (e.g., netip.Addr) or have an IsZero method (e.g., time.Time).
|
||||
//
|
||||
// Every Go struct corresponds to a list of JSON representable fields
|
||||
// which is constructed by performing a breadth-first search over
|
||||
// all struct fields (excluding unexported or ignored fields),
|
||||
// where the search recursively descends into inlined structs.
|
||||
// The set of non-inlined fields in a struct must have unique JSON names.
|
||||
// If multiple fields all have the same JSON name, then the one
|
||||
// at shallowest depth takes precedence and the other fields at deeper depths
|
||||
// are excluded from the list of JSON representable fields.
|
||||
// If multiple fields at the shallowest depth have the same JSON name,
|
||||
// then all of those fields are excluded from the list. This is analogous to
|
||||
// Go visibility rules for struct field selection with embedded struct types.
|
||||
//
|
||||
// Marshaling or unmarshaling a non-empty struct
|
||||
// without any JSON representable fields results in a SemanticError.
|
||||
// Unexported fields must not have any `json` tags except for `json:"-"`.
|
||||
package json
|
||||
|
||||
// requireKeyedLiterals can be embedded in a struct to require keyed literals.
|
||||
type requireKeyedLiterals struct{}
|
||||
|
||||
// nonComparable can be embedded in a struct to prevent comparability.
|
||||
type nonComparable [0]func()
|
1170
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/encode.go
generated
vendored
Normal file
1170
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/encode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
183
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/errors.go
generated
vendored
Normal file
183
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/errors.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const errorPrefix = "json: "
|
||||
|
||||
// Error matches errors returned by this package according to errors.Is.
|
||||
const Error = jsonError("json error")
|
||||
|
||||
type jsonError string
|
||||
|
||||
func (e jsonError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
func (e jsonError) Is(target error) bool {
|
||||
return e == target || target == Error
|
||||
}
|
||||
|
||||
type ioError struct {
|
||||
action string // either "read" or "write"
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *ioError) Error() string {
|
||||
return errorPrefix + e.action + " error: " + e.err.Error()
|
||||
}
|
||||
func (e *ioError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
func (e *ioError) Is(target error) bool {
|
||||
return e == target || target == Error || errors.Is(e.err, target)
|
||||
}
|
||||
|
||||
// SemanticError describes an error determining the meaning
|
||||
// of JSON data as Go data or vice-versa.
|
||||
//
|
||||
// The contents of this error as produced by this package may change over time.
|
||||
type SemanticError struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
action string // either "marshal" or "unmarshal"
|
||||
|
||||
// ByteOffset indicates that an error occurred after this byte offset.
|
||||
ByteOffset int64
|
||||
// JSONPointer indicates that an error occurred within this JSON value
|
||||
// as indicated using the JSON Pointer notation (see RFC 6901).
|
||||
JSONPointer string
|
||||
|
||||
// JSONKind is the JSON kind that could not be handled.
|
||||
JSONKind Kind // may be zero if unknown
|
||||
// GoType is the Go type that could not be handled.
|
||||
GoType reflect.Type // may be nil if unknown
|
||||
|
||||
// Err is the underlying error.
|
||||
Err error // may be nil
|
||||
}
|
||||
|
||||
func (e *SemanticError) Error() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(errorPrefix)
|
||||
|
||||
// Hyrum-proof the error message by deliberately switching between
|
||||
// two equivalent renderings of the same error message.
|
||||
// The randomization is tied to the Hyrum-proofing already applied
|
||||
// on map iteration in Go.
|
||||
for phrase := range map[string]struct{}{"cannot": {}, "unable to": {}} {
|
||||
sb.WriteString(phrase)
|
||||
break // use whichever phrase we get in the first iteration
|
||||
}
|
||||
|
||||
// Format action.
|
||||
var preposition string
|
||||
switch e.action {
|
||||
case "marshal":
|
||||
sb.WriteString(" marshal")
|
||||
preposition = " from"
|
||||
case "unmarshal":
|
||||
sb.WriteString(" unmarshal")
|
||||
preposition = " into"
|
||||
default:
|
||||
sb.WriteString(" handle")
|
||||
preposition = " with"
|
||||
}
|
||||
|
||||
// Format JSON kind.
|
||||
var omitPreposition bool
|
||||
switch e.JSONKind {
|
||||
case 'n':
|
||||
sb.WriteString(" JSON null")
|
||||
case 'f', 't':
|
||||
sb.WriteString(" JSON boolean")
|
||||
case '"':
|
||||
sb.WriteString(" JSON string")
|
||||
case '0':
|
||||
sb.WriteString(" JSON number")
|
||||
case '{', '}':
|
||||
sb.WriteString(" JSON object")
|
||||
case '[', ']':
|
||||
sb.WriteString(" JSON array")
|
||||
default:
|
||||
omitPreposition = true
|
||||
}
|
||||
|
||||
// Format Go type.
|
||||
if e.GoType != nil {
|
||||
if !omitPreposition {
|
||||
sb.WriteString(preposition)
|
||||
}
|
||||
sb.WriteString(" Go value of type ")
|
||||
sb.WriteString(e.GoType.String())
|
||||
}
|
||||
|
||||
// Format where.
|
||||
switch {
|
||||
case e.JSONPointer != "":
|
||||
sb.WriteString(" within JSON value at ")
|
||||
sb.WriteString(strconv.Quote(e.JSONPointer))
|
||||
case e.ByteOffset > 0:
|
||||
sb.WriteString(" after byte offset ")
|
||||
sb.WriteString(strconv.FormatInt(e.ByteOffset, 10))
|
||||
}
|
||||
|
||||
// Format underlying error.
|
||||
if e.Err != nil {
|
||||
sb.WriteString(": ")
|
||||
sb.WriteString(e.Err.Error())
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
func (e *SemanticError) Is(target error) bool {
|
||||
return e == target || target == Error || errors.Is(e.Err, target)
|
||||
}
|
||||
func (e *SemanticError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// SyntacticError is a description of a syntactic error that occurred when
|
||||
// encoding or decoding JSON according to the grammar.
|
||||
//
|
||||
// The contents of this error as produced by this package may change over time.
|
||||
type SyntacticError struct {
|
||||
requireKeyedLiterals
|
||||
nonComparable
|
||||
|
||||
// ByteOffset indicates that an error occurred after this byte offset.
|
||||
ByteOffset int64
|
||||
str string
|
||||
}
|
||||
|
||||
func (e *SyntacticError) Error() string {
|
||||
return errorPrefix + e.str
|
||||
}
|
||||
func (e *SyntacticError) Is(target error) bool {
|
||||
return e == target || target == Error
|
||||
}
|
||||
func (e *SyntacticError) withOffset(pos int64) error {
|
||||
return &SyntacticError{ByteOffset: pos, str: e.str}
|
||||
}
|
||||
|
||||
func newInvalidCharacterError(prefix []byte, where string) *SyntacticError {
|
||||
what := quoteRune(prefix)
|
||||
return &SyntacticError{str: "invalid character " + what + " " + where}
|
||||
}
|
||||
|
||||
func quoteRune(b []byte) string {
|
||||
r, n := utf8.DecodeRune(b)
|
||||
if r == utf8.RuneError && n == 1 {
|
||||
return `'\x` + strconv.FormatUint(uint64(b[0]), 16) + `'`
|
||||
}
|
||||
return strconv.QuoteRune(r)
|
||||
}
|
509
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fields.go
generated
vendored
Normal file
509
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fields.go
generated
vendored
Normal file
@ -0,0 +1,509 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var errIgnoredField = errors.New("ignored field")
|
||||
|
||||
type isZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
|
||||
|
||||
type structFields struct {
|
||||
flattened []structField // listed in depth-first ordering
|
||||
byActualName map[string]*structField
|
||||
byFoldedName map[string][]*structField
|
||||
inlinedFallback *structField
|
||||
}
|
||||
|
||||
type structField struct {
|
||||
id int // unique numeric ID in breadth-first ordering
|
||||
index []int // index into a struct according to reflect.Type.FieldByIndex
|
||||
typ reflect.Type
|
||||
fncs *arshaler
|
||||
isZero func(addressableValue) bool
|
||||
isEmpty func(addressableValue) bool
|
||||
fieldOptions
|
||||
}
|
||||
|
||||
func makeStructFields(root reflect.Type) (structFields, *SemanticError) {
|
||||
var fs structFields
|
||||
fs.byActualName = make(map[string]*structField, root.NumField())
|
||||
fs.byFoldedName = make(map[string][]*structField, root.NumField())
|
||||
|
||||
// ambiguous is a sentinel value to indicate that at least two fields
|
||||
// at the same depth have the same name, and thus cancel each other out.
|
||||
// This follows the same rules as selecting a field on embedded structs
|
||||
// where the shallowest field takes precedence. If more than one field
|
||||
// exists at the shallowest depth, then the selection is illegal.
|
||||
// See https://go.dev/ref/spec#Selectors.
|
||||
ambiguous := new(structField)
|
||||
|
||||
// Setup a queue for a breath-first search.
|
||||
var queueIndex int
|
||||
type queueEntry struct {
|
||||
typ reflect.Type
|
||||
index []int
|
||||
visitChildren bool // whether to recursively visit inlined field in this struct
|
||||
}
|
||||
queue := []queueEntry{{root, nil, true}}
|
||||
seen := map[reflect.Type]bool{root: true}
|
||||
|
||||
// Perform a breadth-first search over all reachable fields.
|
||||
// This ensures that len(f.index) will be monotonically increasing.
|
||||
for queueIndex < len(queue) {
|
||||
qe := queue[queueIndex]
|
||||
queueIndex++
|
||||
|
||||
t := qe.typ
|
||||
inlinedFallbackIndex := -1 // index of last inlined fallback field in current struct
|
||||
namesIndex := make(map[string]int) // index of each field with a given JSON object name in current struct
|
||||
var hasAnyJSONTag bool // whether any Go struct field has a `json` tag
|
||||
var hasAnyJSONField bool // whether any JSON serializable fields exist in current struct
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
sf := t.Field(i)
|
||||
_, hasTag := sf.Tag.Lookup("json")
|
||||
hasAnyJSONTag = hasAnyJSONTag || hasTag
|
||||
options, err := parseFieldOptions(sf)
|
||||
if err != nil {
|
||||
if err == errIgnoredField {
|
||||
continue
|
||||
}
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
hasAnyJSONField = true
|
||||
f := structField{
|
||||
// Allocate a new slice (len=N+1) to hold both
|
||||
// the parent index (len=N) and the current index (len=1).
|
||||
// Do this to avoid clobbering the memory of the parent index.
|
||||
index: append(append(make([]int, 0, len(qe.index)+1), qe.index...), i),
|
||||
typ: sf.Type,
|
||||
fieldOptions: options,
|
||||
}
|
||||
if sf.Anonymous && !f.hasName {
|
||||
f.inline = true // implied by use of Go embedding without an explicit name
|
||||
}
|
||||
if f.inline || f.unknown {
|
||||
// Handle an inlined field that serializes to/from
|
||||
// zero or more JSON object members.
|
||||
|
||||
if f.inline && f.unknown {
|
||||
err := fmt.Errorf("Go struct field %s cannot have both `inline` and `unknown` specified", sf.Name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
switch f.fieldOptions {
|
||||
case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true}:
|
||||
case fieldOptions{name: f.name, quotedName: f.quotedName, unknown: true}:
|
||||
default:
|
||||
err := fmt.Errorf("Go struct field %s cannot have any options other than `inline` or `unknown` specified", sf.Name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
|
||||
// Unwrap one level of pointer indirection similar to how Go
|
||||
// only allows embedding either T or *T, but not **T.
|
||||
tf := f.typ
|
||||
if tf.Kind() == reflect.Pointer && tf.Name() == "" {
|
||||
tf = tf.Elem()
|
||||
}
|
||||
// Reject any types with custom serialization otherwise
|
||||
// it becomes impossible to know what sub-fields to inline.
|
||||
if which, _ := implementsWhich(tf,
|
||||
jsonMarshalerV2Type, jsonMarshalerV1Type, textMarshalerType,
|
||||
jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType,
|
||||
); which != nil && tf != rawValueType {
|
||||
err := fmt.Errorf("inlined Go struct field %s of type %s must not implement JSON marshal or unmarshal methods", sf.Name, tf)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
|
||||
// Handle an inlined field that serializes to/from
|
||||
// a finite number of JSON object members backed by a Go struct.
|
||||
if tf.Kind() == reflect.Struct {
|
||||
if f.unknown {
|
||||
err := fmt.Errorf("inlined Go struct field %s of type %s with `unknown` tag must be a Go map of string key or a json.RawValue", sf.Name, tf)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
if qe.visitChildren {
|
||||
queue = append(queue, queueEntry{tf, f.index, !seen[tf]})
|
||||
}
|
||||
seen[tf] = true
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle an inlined field that serializes to/from any number of
|
||||
// JSON object members back by a Go map or RawValue.
|
||||
switch {
|
||||
case tf == rawValueType:
|
||||
f.fncs = nil // specially handled in arshal_inlined.go
|
||||
case tf.Kind() == reflect.Map && tf.Key() == stringType:
|
||||
f.fncs = lookupArshaler(tf.Elem())
|
||||
default:
|
||||
err := fmt.Errorf("inlined Go struct field %s of type %s must be a Go struct, Go map of string key, or json.RawValue", sf.Name, tf)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
|
||||
// Reject multiple inlined fallback fields within the same struct.
|
||||
if inlinedFallbackIndex >= 0 {
|
||||
err := fmt.Errorf("inlined Go struct fields %s and %s cannot both be a Go map or json.RawValue", t.Field(inlinedFallbackIndex).Name, sf.Name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
inlinedFallbackIndex = i
|
||||
|
||||
// Multiple inlined fallback fields across different structs
|
||||
// follow the same precedence rules as Go struct embedding.
|
||||
if fs.inlinedFallback == nil {
|
||||
fs.inlinedFallback = &f // store first occurrence at lowest depth
|
||||
} else if len(fs.inlinedFallback.index) == len(f.index) {
|
||||
fs.inlinedFallback = ambiguous // at least two occurrences at same depth
|
||||
}
|
||||
} else {
|
||||
// Handle normal Go struct field that serializes to/from
|
||||
// a single JSON object member.
|
||||
|
||||
// Provide a function that uses a type's IsZero method.
|
||||
switch {
|
||||
case sf.Type.Kind() == reflect.Interface && sf.Type.Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool {
|
||||
// Avoid panics calling IsZero on a nil interface or
|
||||
// non-nil interface with nil pointer.
|
||||
return va.IsNil() || (va.Elem().Kind() == reflect.Pointer && va.Elem().IsNil()) || va.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
case sf.Type.Kind() == reflect.Pointer && sf.Type.Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool {
|
||||
// Avoid panics calling IsZero on nil pointer.
|
||||
return va.IsNil() || va.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
case sf.Type.Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool { return va.Interface().(isZeroer).IsZero() }
|
||||
case reflect.PointerTo(sf.Type).Implements(isZeroerType):
|
||||
f.isZero = func(va addressableValue) bool { return va.Addr().Interface().(isZeroer).IsZero() }
|
||||
}
|
||||
|
||||
// Provide a function that can determine whether the value would
|
||||
// serialize as an empty JSON value.
|
||||
switch sf.Type.Kind() {
|
||||
case reflect.String, reflect.Map, reflect.Array, reflect.Slice:
|
||||
f.isEmpty = func(va addressableValue) bool { return va.Len() == 0 }
|
||||
case reflect.Pointer, reflect.Interface:
|
||||
f.isEmpty = func(va addressableValue) bool { return va.IsNil() }
|
||||
}
|
||||
|
||||
f.id = len(fs.flattened)
|
||||
f.fncs = lookupArshaler(sf.Type)
|
||||
fs.flattened = append(fs.flattened, f)
|
||||
|
||||
// Reject user-specified names with invalid UTF-8.
|
||||
if !utf8.ValidString(f.name) {
|
||||
err := fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, f.name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
// Reject multiple fields with same name within the same struct.
|
||||
if j, ok := namesIndex[f.name]; ok {
|
||||
err := fmt.Errorf("Go struct fields %s and %s conflict over JSON object name %q", t.Field(j).Name, sf.Name, f.name)
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
namesIndex[f.name] = i
|
||||
|
||||
// Multiple fields of the same name across different structs
|
||||
// follow the same precedence rules as Go struct embedding.
|
||||
if f2 := fs.byActualName[f.name]; f2 == nil {
|
||||
fs.byActualName[f.name] = &fs.flattened[len(fs.flattened)-1] // store first occurrence at lowest depth
|
||||
} else if len(f2.index) == len(f.index) {
|
||||
fs.byActualName[f.name] = ambiguous // at least two occurrences at same depth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: New users to the json package are occasionally surprised that
|
||||
// unexported fields are ignored. This occurs by necessity due to our
|
||||
// inability to directly introspect such fields with Go reflection
|
||||
// without the use of unsafe.
|
||||
//
|
||||
// To reduce friction here, refuse to serialize any Go struct that
|
||||
// has no JSON serializable fields, has at least one Go struct field,
|
||||
// and does not have any `json` tags present. For example,
|
||||
// errors returned by errors.New would fail to serialize.
|
||||
isEmptyStruct := t.NumField() == 0
|
||||
if !isEmptyStruct && !hasAnyJSONTag && !hasAnyJSONField {
|
||||
err := errors.New("Go struct has no exported fields")
|
||||
return structFields{}, &SemanticError{GoType: t, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all fields that are duplicates.
|
||||
// This may move elements forward to fill the holes from removed fields.
|
||||
var n int
|
||||
for _, f := range fs.flattened {
|
||||
switch f2 := fs.byActualName[f.name]; {
|
||||
case f2 == ambiguous:
|
||||
delete(fs.byActualName, f.name)
|
||||
case f2 == nil:
|
||||
continue // may be nil due to previous delete
|
||||
// TODO(https://go.dev/issue/45955): Use slices.Equal.
|
||||
case reflect.DeepEqual(f.index, f2.index):
|
||||
f.id = n
|
||||
fs.flattened[n] = f
|
||||
fs.byActualName[f.name] = &fs.flattened[n] // fix pointer to new location
|
||||
n++
|
||||
}
|
||||
}
|
||||
fs.flattened = fs.flattened[:n]
|
||||
if fs.inlinedFallback == ambiguous {
|
||||
fs.inlinedFallback = nil
|
||||
}
|
||||
if len(fs.flattened) != len(fs.byActualName) {
|
||||
panic(fmt.Sprintf("BUG: flattened list of fields mismatches fields mapped by name: %d != %d", len(fs.flattened), len(fs.byActualName)))
|
||||
}
|
||||
|
||||
// Sort the fields according to a depth-first ordering.
|
||||
// This operation will cause pointers in byActualName to become incorrect,
|
||||
// which we will correct in another loop shortly thereafter.
|
||||
sort.Slice(fs.flattened, func(i, j int) bool {
|
||||
si := fs.flattened[i].index
|
||||
sj := fs.flattened[j].index
|
||||
for len(si) > 0 && len(sj) > 0 {
|
||||
switch {
|
||||
case si[0] < sj[0]:
|
||||
return true
|
||||
case si[0] > sj[0]:
|
||||
return false
|
||||
default:
|
||||
si = si[1:]
|
||||
sj = sj[1:]
|
||||
}
|
||||
}
|
||||
return len(si) < len(sj)
|
||||
})
|
||||
|
||||
// Recompute the mapping of fields in the byActualName map.
|
||||
// Pre-fold all names so that we can lookup folded names quickly.
|
||||
for i, f := range fs.flattened {
|
||||
foldedName := string(foldName([]byte(f.name)))
|
||||
fs.byActualName[f.name] = &fs.flattened[i]
|
||||
fs.byFoldedName[foldedName] = append(fs.byFoldedName[foldedName], &fs.flattened[i])
|
||||
}
|
||||
for foldedName, fields := range fs.byFoldedName {
|
||||
if len(fields) > 1 {
|
||||
// The precedence order for conflicting nocase names
|
||||
// is by breadth-first order, rather than depth-first order.
|
||||
sort.Slice(fields, func(i, j int) bool {
|
||||
return fields[i].id < fields[j].id
|
||||
})
|
||||
fs.byFoldedName[foldedName] = fields
|
||||
}
|
||||
}
|
||||
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
type fieldOptions struct {
|
||||
name string
|
||||
quotedName string // quoted name per RFC 8785, section 3.2.2.2.
|
||||
hasName bool
|
||||
nocase bool
|
||||
inline bool
|
||||
unknown bool
|
||||
omitzero bool
|
||||
omitempty bool
|
||||
string bool
|
||||
format string
|
||||
}
|
||||
|
||||
// parseFieldOptions parses the `json` tag in a Go struct field as
|
||||
// a structured set of options configuring parameters such as
|
||||
// the JSON member name and other features.
|
||||
// As a special case, it returns errIgnoredField if the field is ignored.
|
||||
func parseFieldOptions(sf reflect.StructField) (out fieldOptions, err error) {
|
||||
tag, hasTag := sf.Tag.Lookup("json")
|
||||
|
||||
// Check whether this field is explicitly ignored.
|
||||
if tag == "-" {
|
||||
return fieldOptions{}, errIgnoredField
|
||||
}
|
||||
|
||||
// Check whether this field is unexported.
|
||||
if !sf.IsExported() {
|
||||
// In contrast to v1, v2 no longer forwards exported fields from
|
||||
// embedded fields of unexported types since Go reflection does not
|
||||
// allow the same set of operations that are available in normal cases
|
||||
// of purely exported fields.
|
||||
// See https://go.dev/issue/21357 and https://go.dev/issue/24153.
|
||||
if sf.Anonymous {
|
||||
return fieldOptions{}, fmt.Errorf("embedded Go struct field %s of an unexported type must be explicitly ignored with a `json:\"-\"` tag", sf.Type.Name())
|
||||
}
|
||||
// Tag options specified on an unexported field suggests user error.
|
||||
if hasTag {
|
||||
return fieldOptions{}, fmt.Errorf("unexported Go struct field %s cannot have non-ignored `json:%q` tag", sf.Name, tag)
|
||||
}
|
||||
return fieldOptions{}, errIgnoredField
|
||||
}
|
||||
|
||||
// Determine the JSON member name for this Go field. A user-specified name
|
||||
// may be provided as either an identifier or a single-quoted string.
|
||||
// The single-quoted string allows arbitrary characters in the name.
|
||||
// See https://go.dev/issue/2718 and https://go.dev/issue/3546.
|
||||
out.name = sf.Name // always starts with an uppercase character
|
||||
if len(tag) > 0 && !strings.HasPrefix(tag, ",") {
|
||||
// For better compatibility with v1, accept almost any unescaped name.
|
||||
n := len(tag) - len(strings.TrimLeftFunc(tag, func(r rune) bool {
|
||||
return !strings.ContainsRune(",\\'\"`", r) // reserve comma, backslash, and quotes
|
||||
}))
|
||||
opt := tag[:n]
|
||||
if n == 0 {
|
||||
// Allow a single quoted string for arbitrary names.
|
||||
opt, n, err = consumeTagOption(tag)
|
||||
if err != nil {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err)
|
||||
}
|
||||
}
|
||||
out.hasName = true
|
||||
out.name = opt
|
||||
tag = tag[n:]
|
||||
}
|
||||
b, _ := appendString(nil, out.name, false, nil)
|
||||
out.quotedName = string(b)
|
||||
|
||||
// Handle any additional tag options (if any).
|
||||
var wasFormat bool
|
||||
seenOpts := make(map[string]bool)
|
||||
for len(tag) > 0 {
|
||||
// Consume comma delimiter.
|
||||
if tag[0] != ',' {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid character %q before next option (expecting ',')", sf.Name, tag[0])
|
||||
}
|
||||
tag = tag[len(","):]
|
||||
if len(tag) == 0 {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid trailing ',' character", sf.Name)
|
||||
}
|
||||
|
||||
// Consume and process the tag option.
|
||||
opt, n, err := consumeTagOption(tag)
|
||||
if err != nil {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err)
|
||||
}
|
||||
rawOpt := tag[:n]
|
||||
tag = tag[n:]
|
||||
switch {
|
||||
case wasFormat:
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has `format` tag option that was not specified last", sf.Name)
|
||||
case strings.HasPrefix(rawOpt, "'") && strings.TrimFunc(opt, isLetterOrDigit) == "":
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `%s` tag option; specify `%s` instead", sf.Name, rawOpt, opt)
|
||||
}
|
||||
switch opt {
|
||||
case "nocase":
|
||||
out.nocase = true
|
||||
case "inline":
|
||||
out.inline = true
|
||||
case "unknown":
|
||||
out.unknown = true
|
||||
case "omitzero":
|
||||
out.omitzero = true
|
||||
case "omitempty":
|
||||
out.omitempty = true
|
||||
case "string":
|
||||
out.string = true
|
||||
case "format":
|
||||
if !strings.HasPrefix(tag, ":") {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s is missing value for `format` tag option", sf.Name)
|
||||
}
|
||||
tag = tag[len(":"):]
|
||||
opt, n, err := consumeTagOption(tag)
|
||||
if err != nil {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has malformed value for `format` tag option: %v", sf.Name, err)
|
||||
}
|
||||
tag = tag[n:]
|
||||
out.format = opt
|
||||
wasFormat = true
|
||||
default:
|
||||
// Reject keys that resemble one of the supported options.
|
||||
// This catches invalid mutants such as "omitEmpty" or "omit_empty".
|
||||
normOpt := strings.ReplaceAll(strings.ToLower(opt), "_", "")
|
||||
switch normOpt {
|
||||
case "nocase", "inline", "unknown", "omitzero", "omitempty", "string", "format":
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has invalid appearance of `%s` tag option; specify `%s` instead", sf.Name, opt, normOpt)
|
||||
}
|
||||
|
||||
// NOTE: Everything else is ignored. This does not mean it is
|
||||
// forward compatible to insert arbitrary tag options since
|
||||
// a future version of this package may understand that tag.
|
||||
}
|
||||
|
||||
// Reject duplicates.
|
||||
if seenOpts[opt] {
|
||||
return fieldOptions{}, fmt.Errorf("Go struct field %s has duplicate appearance of `%s` tag option", sf.Name, rawOpt)
|
||||
}
|
||||
seenOpts[opt] = true
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func consumeTagOption(in string) (string, int, error) {
|
||||
switch r, _ := utf8.DecodeRuneInString(in); {
|
||||
// Option as a Go identifier.
|
||||
case r == '_' || unicode.IsLetter(r):
|
||||
n := len(in) - len(strings.TrimLeftFunc(in, isLetterOrDigit))
|
||||
return in[:n], n, nil
|
||||
// Option as a single-quoted string.
|
||||
case r == '\'':
|
||||
// The grammar is nearly identical to a double-quoted Go string literal,
|
||||
// but uses single quotes as the terminators. The reason for a custom
|
||||
// grammar is because both backtick and double quotes cannot be used
|
||||
// verbatim in a struct tag.
|
||||
//
|
||||
// Convert a single-quoted string to a double-quote string and rely on
|
||||
// strconv.Unquote to handle the rest.
|
||||
var inEscape bool
|
||||
b := []byte{'"'}
|
||||
n := len(`'`)
|
||||
for len(in) > n {
|
||||
r, rn := utf8.DecodeRuneInString(in[n:])
|
||||
switch {
|
||||
case inEscape:
|
||||
if r == '\'' {
|
||||
b = b[:len(b)-1] // remove escape character: `\'` => `'`
|
||||
}
|
||||
inEscape = false
|
||||
case r == '\\':
|
||||
inEscape = true
|
||||
case r == '"':
|
||||
b = append(b, '\\') // insert escape character: `"` => `\"`
|
||||
case r == '\'':
|
||||
b = append(b, '"')
|
||||
n += len(`'`)
|
||||
out, err := strconv.Unquote(string(b))
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("invalid single-quoted string: %s", in[:n])
|
||||
}
|
||||
return out, n, nil
|
||||
}
|
||||
b = append(b, in[n:][:rn]...)
|
||||
n += rn
|
||||
}
|
||||
if n > 10 {
|
||||
n = 10 // limit the amount of context printed in the error
|
||||
}
|
||||
return "", 0, fmt.Errorf("single-quoted string not terminated: %s...", in[:n])
|
||||
case len(in) == 0:
|
||||
return "", 0, io.ErrUnexpectedEOF
|
||||
default:
|
||||
return "", 0, fmt.Errorf("invalid character %q at start of option (expecting Unicode letter or single quote)", r)
|
||||
}
|
||||
}
|
||||
|
||||
func isLetterOrDigit(r rune) bool {
|
||||
return r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r)
|
||||
}
|
56
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fold.go
generated
vendored
Normal file
56
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/fold.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// foldName returns a folded string such that foldName(x) == foldName(y)
|
||||
// is similar to strings.EqualFold(x, y), but ignores underscore and dashes.
|
||||
// This allows foldName to match common naming conventions.
|
||||
func foldName(in []byte) []byte {
|
||||
// This is inlinable to take advantage of "function outlining".
|
||||
// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
|
||||
var arr [32]byte // large enough for most JSON names
|
||||
return appendFoldedName(arr[:0], in)
|
||||
}
|
||||
func appendFoldedName(out, in []byte) []byte {
|
||||
for i := 0; i < len(in); {
|
||||
// Handle single-byte ASCII.
|
||||
if c := in[i]; c < utf8.RuneSelf {
|
||||
if c != '_' && c != '-' {
|
||||
if 'a' <= c && c <= 'z' {
|
||||
c -= 'a' - 'A'
|
||||
}
|
||||
out = append(out, c)
|
||||
}
|
||||
i++
|
||||
continue
|
||||
}
|
||||
// Handle multi-byte Unicode.
|
||||
r, n := utf8.DecodeRune(in[i:])
|
||||
out = utf8.AppendRune(out, foldRune(r))
|
||||
i += n
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// foldRune is a variation on unicode.SimpleFold that returns the same rune
|
||||
// for all runes in the same fold set.
|
||||
//
|
||||
// Invariant:
|
||||
//
|
||||
// foldRune(x) == foldRune(y) ⇔ strings.EqualFold(string(x), string(y))
|
||||
func foldRune(r rune) rune {
|
||||
for {
|
||||
r2 := unicode.SimpleFold(r)
|
||||
if r2 <= r {
|
||||
return r2 // smallest character in the fold set
|
||||
}
|
||||
r = r2
|
||||
}
|
||||
}
|
86
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/intern.go
generated
vendored
Normal file
86
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/intern.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// stringCache is a cache for strings converted from a []byte.
|
||||
type stringCache [256]string // 256*unsafe.Sizeof(string("")) => 4KiB
|
||||
|
||||
// make returns the string form of b.
|
||||
// It returns a pre-allocated string from c if present, otherwise
|
||||
// it allocates a new string, inserts it into the cache, and returns it.
|
||||
func (c *stringCache) make(b []byte) string {
|
||||
const (
|
||||
minCachedLen = 2 // single byte strings are already interned by the runtime
|
||||
maxCachedLen = 256 // large enough for UUIDs, IPv6 addresses, SHA-256 checksums, etc.
|
||||
)
|
||||
if c == nil || len(b) < minCachedLen || len(b) > maxCachedLen {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Compute a hash from the fixed-width prefix and suffix of the string.
|
||||
// This ensures hashing a string is a constant time operation.
|
||||
var h uint32
|
||||
switch {
|
||||
case len(b) >= 8:
|
||||
lo := binary.LittleEndian.Uint64(b[:8])
|
||||
hi := binary.LittleEndian.Uint64(b[len(b)-8:])
|
||||
h = hash64(uint32(lo), uint32(lo>>32)) ^ hash64(uint32(hi), uint32(hi>>32))
|
||||
case len(b) >= 4:
|
||||
lo := binary.LittleEndian.Uint32(b[:4])
|
||||
hi := binary.LittleEndian.Uint32(b[len(b)-4:])
|
||||
h = hash64(lo, hi)
|
||||
case len(b) >= 2:
|
||||
lo := binary.LittleEndian.Uint16(b[:2])
|
||||
hi := binary.LittleEndian.Uint16(b[len(b)-2:])
|
||||
h = hash64(uint32(lo), uint32(hi))
|
||||
}
|
||||
|
||||
// Check the cache for the string.
|
||||
i := h % uint32(len(*c))
|
||||
if s := (*c)[i]; s == string(b) {
|
||||
return s
|
||||
}
|
||||
s := string(b)
|
||||
(*c)[i] = s
|
||||
return s
|
||||
}
|
||||
|
||||
// hash64 returns the hash of two uint32s as a single uint32.
|
||||
func hash64(lo, hi uint32) uint32 {
|
||||
// If avalanche=true, this is identical to XXH32 hash on a 8B string:
|
||||
// var b [8]byte
|
||||
// binary.LittleEndian.PutUint32(b[:4], lo)
|
||||
// binary.LittleEndian.PutUint32(b[4:], hi)
|
||||
// return xxhash.Sum32(b[:])
|
||||
const (
|
||||
prime1 = 0x9e3779b1
|
||||
prime2 = 0x85ebca77
|
||||
prime3 = 0xc2b2ae3d
|
||||
prime4 = 0x27d4eb2f
|
||||
prime5 = 0x165667b1
|
||||
)
|
||||
h := prime5 + uint32(8)
|
||||
h += lo * prime3
|
||||
h = bits.RotateLeft32(h, 17) * prime4
|
||||
h += hi * prime3
|
||||
h = bits.RotateLeft32(h, 17) * prime4
|
||||
// Skip final mix (avalanche) step of XXH32 for performance reasons.
|
||||
// Empirical testing shows that the improvements in unbiased distribution
|
||||
// does not outweigh the extra cost in computational complexity.
|
||||
const avalanche = false
|
||||
if avalanche {
|
||||
h ^= h >> 15
|
||||
h *= prime2
|
||||
h ^= h >> 13
|
||||
h *= prime3
|
||||
h ^= h >> 16
|
||||
}
|
||||
return h
|
||||
}
|
182
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/pools.go
generated
vendored
Normal file
182
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/pools.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/bits"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TODO(https://go.dev/issue/47657): Use sync.PoolOf.
|
||||
|
||||
var (
|
||||
// This owns the internal buffer since there is no io.Writer to output to.
|
||||
// Since the buffer can get arbitrarily large in normal usage,
|
||||
// there is statistical tracking logic to determine whether to recycle
|
||||
// the internal buffer or not based on a history of utilization.
|
||||
bufferedEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }}
|
||||
|
||||
// This owns the internal buffer, but it is only used to temporarily store
|
||||
// buffered JSON before flushing it to the underlying io.Writer.
|
||||
// In a sufficiently efficient streaming mode, we do not expect the buffer
|
||||
// to grow arbitrarily large. Thus, we avoid recycling large buffers.
|
||||
streamingEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }}
|
||||
|
||||
// This does not own the internal buffer since
|
||||
// it is taken directly from the provided bytes.Buffer.
|
||||
bytesBufferEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }}
|
||||
)
|
||||
|
||||
// bufferStatistics is statistics to track buffer utilization.
|
||||
// It is used to determine whether to recycle a buffer or not
|
||||
// to avoid https://go.dev/issue/23199.
|
||||
type bufferStatistics struct {
|
||||
strikes int // number of times the buffer was under-utilized
|
||||
prevLen int // length of previous buffer
|
||||
}
|
||||
|
||||
func getBufferedEncoder(o EncodeOptions) *Encoder {
|
||||
e := bufferedEncoderPool.Get().(*Encoder)
|
||||
if e.buf == nil {
|
||||
// Round up to nearest 2ⁿ to make best use of malloc size classes.
|
||||
// See runtime/sizeclasses.go on Go1.15.
|
||||
// Logical OR with 63 to ensure 64 as the minimum buffer size.
|
||||
n := 1 << bits.Len(uint(e.bufStats.prevLen|63))
|
||||
e.buf = make([]byte, 0, n)
|
||||
}
|
||||
e.reset(e.buf[:0], nil, o)
|
||||
return e
|
||||
}
|
||||
func putBufferedEncoder(e *Encoder) {
|
||||
// Recycle large buffers only if sufficiently utilized.
|
||||
// If a buffer is under-utilized enough times sequentially,
|
||||
// then it is discarded, ensuring that a single large buffer
|
||||
// won't be kept alive by a continuous stream of small usages.
|
||||
//
|
||||
// The worst case utilization is computed as:
|
||||
// MIN_UTILIZATION_THRESHOLD / (1 + MAX_NUM_STRIKES)
|
||||
//
|
||||
// For the constants chosen below, this is (25%)/(1+4) ⇒ 5%.
|
||||
// This may seem low, but it ensures a lower bound on
|
||||
// the absolute worst-case utilization. Without this check,
|
||||
// this would be theoretically 0%, which is infinitely worse.
|
||||
//
|
||||
// See https://go.dev/issue/27735.
|
||||
switch {
|
||||
case cap(e.buf) <= 4<<10: // always recycle buffers smaller than 4KiB
|
||||
e.bufStats.strikes = 0
|
||||
case cap(e.buf)/4 <= len(e.buf): // at least 25% utilization
|
||||
e.bufStats.strikes = 0
|
||||
case e.bufStats.strikes < 4: // at most 4 strikes
|
||||
e.bufStats.strikes++
|
||||
default: // discard the buffer; too large and too often under-utilized
|
||||
e.bufStats.strikes = 0
|
||||
e.bufStats.prevLen = len(e.buf) // heuristic for size to allocate next time
|
||||
e.buf = nil
|
||||
}
|
||||
bufferedEncoderPool.Put(e)
|
||||
}
|
||||
|
||||
func getStreamingEncoder(w io.Writer, o EncodeOptions) *Encoder {
|
||||
if _, ok := w.(*bytes.Buffer); ok {
|
||||
e := bytesBufferEncoderPool.Get().(*Encoder)
|
||||
e.reset(nil, w, o) // buffer taken from bytes.Buffer
|
||||
return e
|
||||
} else {
|
||||
e := streamingEncoderPool.Get().(*Encoder)
|
||||
e.reset(e.buf[:0], w, o) // preserve existing buffer
|
||||
return e
|
||||
}
|
||||
}
|
||||
func putStreamingEncoder(e *Encoder) {
|
||||
if _, ok := e.wr.(*bytes.Buffer); ok {
|
||||
bytesBufferEncoderPool.Put(e)
|
||||
} else {
|
||||
if cap(e.buf) > 64<<10 {
|
||||
e.buf = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
streamingEncoderPool.Put(e)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// This does not own the internal buffer since it is externally provided.
|
||||
bufferedDecoderPool = &sync.Pool{New: func() any { return new(Decoder) }}
|
||||
|
||||
// This owns the internal buffer, but it is only used to temporarily store
|
||||
// buffered JSON fetched from the underlying io.Reader.
|
||||
// In a sufficiently efficient streaming mode, we do not expect the buffer
|
||||
// to grow arbitrarily large. Thus, we avoid recycling large buffers.
|
||||
streamingDecoderPool = &sync.Pool{New: func() any { return new(Decoder) }}
|
||||
|
||||
// This does not own the internal buffer since
|
||||
// it is taken directly from the provided bytes.Buffer.
|
||||
bytesBufferDecoderPool = bufferedDecoderPool
|
||||
)
|
||||
|
||||
func getBufferedDecoder(b []byte, o DecodeOptions) *Decoder {
|
||||
d := bufferedDecoderPool.Get().(*Decoder)
|
||||
d.reset(b, nil, o)
|
||||
return d
|
||||
}
|
||||
func putBufferedDecoder(d *Decoder) {
|
||||
bufferedDecoderPool.Put(d)
|
||||
}
|
||||
|
||||
func getStreamingDecoder(r io.Reader, o DecodeOptions) *Decoder {
|
||||
if _, ok := r.(*bytes.Buffer); ok {
|
||||
d := bytesBufferDecoderPool.Get().(*Decoder)
|
||||
d.reset(nil, r, o) // buffer taken from bytes.Buffer
|
||||
return d
|
||||
} else {
|
||||
d := streamingDecoderPool.Get().(*Decoder)
|
||||
d.reset(d.buf[:0], r, o) // preserve existing buffer
|
||||
return d
|
||||
}
|
||||
}
|
||||
func putStreamingDecoder(d *Decoder) {
|
||||
if _, ok := d.rd.(*bytes.Buffer); ok {
|
||||
bytesBufferDecoderPool.Put(d)
|
||||
} else {
|
||||
if cap(d.buf) > 64<<10 {
|
||||
d.buf = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
streamingDecoderPool.Put(d)
|
||||
}
|
||||
}
|
||||
|
||||
var stringsPools = &sync.Pool{New: func() any { return new(stringSlice) }}
|
||||
|
||||
type stringSlice []string
|
||||
|
||||
// getStrings returns a non-nil pointer to a slice with length n.
|
||||
func getStrings(n int) *stringSlice {
|
||||
s := stringsPools.Get().(*stringSlice)
|
||||
if cap(*s) < n {
|
||||
*s = make([]string, n)
|
||||
}
|
||||
*s = (*s)[:n]
|
||||
return s
|
||||
}
|
||||
|
||||
func putStrings(s *stringSlice) {
|
||||
if cap(*s) > 1<<10 {
|
||||
*s = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
stringsPools.Put(s)
|
||||
}
|
||||
|
||||
// Sort sorts the string slice according to RFC 8785, section 3.2.3.
|
||||
func (ss *stringSlice) Sort() {
|
||||
// TODO(https://go.dev/issue/47619): Use slices.SortFunc instead.
|
||||
sort.Sort(ss)
|
||||
}
|
||||
|
||||
func (ss *stringSlice) Len() int { return len(*ss) }
|
||||
func (ss *stringSlice) Less(i, j int) bool { return lessUTF16((*ss)[i], (*ss)[j]) }
|
||||
func (ss *stringSlice) Swap(i, j int) { (*ss)[i], (*ss)[j] = (*ss)[j], (*ss)[i] }
|
747
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/state.go
generated
vendored
Normal file
747
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/state.go
generated
vendored
Normal file
@ -0,0 +1,747 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
errMissingName = &SyntacticError{str: "missing string for object name"}
|
||||
errMissingColon = &SyntacticError{str: "missing character ':' after object name"}
|
||||
errMissingValue = &SyntacticError{str: "missing value after object name"}
|
||||
errMissingComma = &SyntacticError{str: "missing character ',' after object or array value"}
|
||||
errMismatchDelim = &SyntacticError{str: "mismatching structural token for object or array"}
|
||||
)
|
||||
|
||||
const errInvalidNamespace = jsonError("object namespace is in an invalid state")
|
||||
|
||||
type state struct {
|
||||
// tokens validates whether the next token kind is valid.
|
||||
tokens stateMachine
|
||||
|
||||
// names is a stack of object names.
|
||||
// Not used if AllowDuplicateNames is true.
|
||||
names objectNameStack
|
||||
|
||||
// namespaces is a stack of object namespaces.
|
||||
// For performance reasons, Encoder or Decoder may not update this
|
||||
// if Marshal or Unmarshal is able to track names in a more efficient way.
|
||||
// See makeMapArshaler and makeStructArshaler.
|
||||
// Not used if AllowDuplicateNames is true.
|
||||
namespaces objectNamespaceStack
|
||||
}
|
||||
|
||||
func (s *state) reset() {
|
||||
s.tokens.reset()
|
||||
s.names.reset()
|
||||
s.namespaces.reset()
|
||||
}
|
||||
|
||||
// appendStackPointer appends a JSON Pointer (RFC 6901) to the current value.
|
||||
// The returned pointer is only accurate if s.names is populated,
|
||||
// otherwise it uses the numeric index as the object member name.
|
||||
//
|
||||
// Invariant: Must call s.names.copyQuotedBuffer beforehand.
|
||||
func (s state) appendStackPointer(b []byte) []byte {
|
||||
var objectDepth int
|
||||
for i := 1; i < s.tokens.depth(); i++ {
|
||||
e := s.tokens.index(i)
|
||||
if e.length() == 0 {
|
||||
break // empty object or array
|
||||
}
|
||||
b = append(b, '/')
|
||||
switch {
|
||||
case e.isObject():
|
||||
if objectDepth < s.names.length() {
|
||||
for _, c := range s.names.getUnquoted(objectDepth) {
|
||||
// Per RFC 6901, section 3, escape '~' and '/' characters.
|
||||
switch c {
|
||||
case '~':
|
||||
b = append(b, "~0"...)
|
||||
case '/':
|
||||
b = append(b, "~1"...)
|
||||
default:
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Since the names stack is unpopulated, the name is unknown.
|
||||
// As a best-effort replacement, use the numeric member index.
|
||||
// While inaccurate, it produces a syntactically valid pointer.
|
||||
b = strconv.AppendUint(b, uint64((e.length()-1)/2), 10)
|
||||
}
|
||||
objectDepth++
|
||||
case e.isArray():
|
||||
b = strconv.AppendUint(b, uint64(e.length()-1), 10)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// stateMachine is a push-down automaton that validates whether
|
||||
// a sequence of tokens is valid or not according to the JSON grammar.
|
||||
// It is useful for both encoding and decoding.
|
||||
//
|
||||
// It is a stack where each entry represents a nested JSON object or array.
|
||||
// The stack has a minimum depth of 1 where the first level is a
|
||||
// virtual JSON array to handle a stream of top-level JSON values.
|
||||
// The top-level virtual JSON array is special in that it doesn't require commas
|
||||
// between each JSON value.
|
||||
//
|
||||
// For performance, most methods are carefully written to be inlineable.
|
||||
// The zero value is a valid state machine ready for use.
|
||||
type stateMachine struct {
|
||||
stack []stateEntry
|
||||
last stateEntry
|
||||
}
|
||||
|
||||
// reset resets the state machine.
|
||||
// The machine always starts with a minimum depth of 1.
|
||||
func (m *stateMachine) reset() {
|
||||
m.stack = m.stack[:0]
|
||||
if cap(m.stack) > 1<<10 {
|
||||
m.stack = nil
|
||||
}
|
||||
m.last = stateTypeArray
|
||||
}
|
||||
|
||||
// depth is the current nested depth of JSON objects and arrays.
|
||||
// It is one-indexed (i.e., top-level values have a depth of 1).
|
||||
func (m stateMachine) depth() int {
|
||||
return len(m.stack) + 1
|
||||
}
|
||||
|
||||
// index returns a reference to the ith entry.
|
||||
// It is only valid until the next push method call.
|
||||
func (m *stateMachine) index(i int) *stateEntry {
|
||||
if i == len(m.stack) {
|
||||
return &m.last
|
||||
}
|
||||
return &m.stack[i]
|
||||
}
|
||||
|
||||
// depthLength reports the current nested depth and
|
||||
// the length of the last JSON object or array.
|
||||
func (m stateMachine) depthLength() (int, int) {
|
||||
return m.depth(), m.last.length()
|
||||
}
|
||||
|
||||
// appendLiteral appends a JSON literal as the next token in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) appendLiteral() error {
|
||||
switch {
|
||||
case m.last.needObjectName():
|
||||
return errMissingName
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// appendString appends a JSON string as the next token in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) appendString() error {
|
||||
switch {
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// appendNumber appends a JSON number as the next token in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) appendNumber() error {
|
||||
return m.appendLiteral()
|
||||
}
|
||||
|
||||
// pushObject appends a JSON start object token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) pushObject() error {
|
||||
switch {
|
||||
case m.last.needObjectName():
|
||||
return errMissingName
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
m.stack = append(m.stack, m.last)
|
||||
m.last = stateTypeObject
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// popObject appends a JSON end object token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) popObject() error {
|
||||
switch {
|
||||
case !m.last.isObject():
|
||||
return errMismatchDelim
|
||||
case m.last.needObjectValue():
|
||||
return errMissingValue
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last = m.stack[len(m.stack)-1]
|
||||
m.stack = m.stack[:len(m.stack)-1]
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// pushArray appends a JSON start array token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) pushArray() error {
|
||||
switch {
|
||||
case m.last.needObjectName():
|
||||
return errMissingName
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last.increment()
|
||||
m.stack = append(m.stack, m.last)
|
||||
m.last = stateTypeArray
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// popArray appends a JSON end array token as next in the sequence.
|
||||
// If an error is returned, the state is not mutated.
|
||||
func (m *stateMachine) popArray() error {
|
||||
switch {
|
||||
case !m.last.isArray() || len(m.stack) == 0: // forbid popping top-level virtual JSON array
|
||||
return errMismatchDelim
|
||||
case !m.last.isValidNamespace():
|
||||
return errInvalidNamespace
|
||||
default:
|
||||
m.last = m.stack[len(m.stack)-1]
|
||||
m.stack = m.stack[:len(m.stack)-1]
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// needIndent reports whether indent whitespace should be injected.
|
||||
// A zero value means that no whitespace should be injected.
|
||||
// A positive value means '\n', indentPrefix, and (n-1) copies of indentBody
|
||||
// should be appended to the output immediately before the next token.
|
||||
func (m stateMachine) needIndent(next Kind) (n int) {
|
||||
willEnd := next == '}' || next == ']'
|
||||
switch {
|
||||
case m.depth() == 1:
|
||||
return 0 // top-level values are never indented
|
||||
case m.last.length() == 0 && willEnd:
|
||||
return 0 // an empty object or array is never indented
|
||||
case m.last.length() == 0 || m.last.needImplicitComma(next):
|
||||
return m.depth()
|
||||
case willEnd:
|
||||
return m.depth() - 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// mayAppendDelim appends a colon or comma that may precede the next token.
|
||||
func (m stateMachine) mayAppendDelim(b []byte, next Kind) []byte {
|
||||
switch {
|
||||
case m.last.needImplicitColon():
|
||||
return append(b, ':')
|
||||
case m.last.needImplicitComma(next) && len(m.stack) != 0: // comma not needed for top-level values
|
||||
return append(b, ',')
|
||||
default:
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
// needDelim reports whether a colon or comma token should be implicitly emitted
|
||||
// before the next token of the specified kind.
|
||||
// A zero value means no delimiter should be emitted.
|
||||
func (m stateMachine) needDelim(next Kind) (delim byte) {
|
||||
switch {
|
||||
case m.last.needImplicitColon():
|
||||
return ':'
|
||||
case m.last.needImplicitComma(next) && len(m.stack) != 0: // comma not needed for top-level values
|
||||
return ','
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// checkDelim reports whether the specified delimiter should be there given
|
||||
// the kind of the next token that appears immediately afterwards.
|
||||
func (m stateMachine) checkDelim(delim byte, next Kind) error {
|
||||
switch needDelim := m.needDelim(next); {
|
||||
case needDelim == delim:
|
||||
return nil
|
||||
case needDelim == ':':
|
||||
return errMissingColon
|
||||
case needDelim == ',':
|
||||
return errMissingComma
|
||||
default:
|
||||
return newInvalidCharacterError([]byte{delim}, "before next token")
|
||||
}
|
||||
}
|
||||
|
||||
// invalidateDisabledNamespaces marks all disabled namespaces as invalid.
|
||||
//
|
||||
// For efficiency, Marshal and Unmarshal may disable namespaces since there are
|
||||
// more efficient ways to track duplicate names. However, if an error occurs,
|
||||
// the namespaces in Encoder or Decoder will be left in an inconsistent state.
|
||||
// Mark the namespaces as invalid so that future method calls on
|
||||
// Encoder or Decoder will return an error.
|
||||
func (m *stateMachine) invalidateDisabledNamespaces() {
|
||||
for i := 0; i < m.depth(); i++ {
|
||||
e := m.index(i)
|
||||
if !e.isActiveNamespace() {
|
||||
e.invalidateNamespace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stateEntry encodes several artifacts within a single unsigned integer:
|
||||
// - whether this represents a JSON object or array,
|
||||
// - whether this object should check for duplicate names, and
|
||||
// - how many elements are in this JSON object or array.
|
||||
type stateEntry uint64
|
||||
|
||||
const (
|
||||
// The type mask (1 bit) records whether this is a JSON object or array.
|
||||
stateTypeMask stateEntry = 0x8000_0000_0000_0000
|
||||
stateTypeObject stateEntry = 0x8000_0000_0000_0000
|
||||
stateTypeArray stateEntry = 0x0000_0000_0000_0000
|
||||
|
||||
// The name check mask (2 bit) records whether to update
|
||||
// the namespaces for the current JSON object and
|
||||
// whether the namespace is valid.
|
||||
stateNamespaceMask stateEntry = 0x6000_0000_0000_0000
|
||||
stateDisableNamespace stateEntry = 0x4000_0000_0000_0000
|
||||
stateInvalidNamespace stateEntry = 0x2000_0000_0000_0000
|
||||
|
||||
// The count mask (61 bits) records the number of elements.
|
||||
stateCountMask stateEntry = 0x1fff_ffff_ffff_ffff
|
||||
stateCountLSBMask stateEntry = 0x0000_0000_0000_0001
|
||||
stateCountOdd stateEntry = 0x0000_0000_0000_0001
|
||||
stateCountEven stateEntry = 0x0000_0000_0000_0000
|
||||
)
|
||||
|
||||
// length reports the number of elements in the JSON object or array.
|
||||
// Each name and value in an object entry is treated as a separate element.
|
||||
func (e stateEntry) length() int {
|
||||
return int(e & stateCountMask)
|
||||
}
|
||||
|
||||
// isObject reports whether this is a JSON object.
|
||||
func (e stateEntry) isObject() bool {
|
||||
return e&stateTypeMask == stateTypeObject
|
||||
}
|
||||
|
||||
// isArray reports whether this is a JSON array.
|
||||
func (e stateEntry) isArray() bool {
|
||||
return e&stateTypeMask == stateTypeArray
|
||||
}
|
||||
|
||||
// needObjectName reports whether the next token must be a JSON string,
|
||||
// which is necessary for JSON object names.
|
||||
func (e stateEntry) needObjectName() bool {
|
||||
return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountEven
|
||||
}
|
||||
|
||||
// needImplicitColon reports whether an colon should occur next,
|
||||
// which always occurs after JSON object names.
|
||||
func (e stateEntry) needImplicitColon() bool {
|
||||
return e.needObjectValue()
|
||||
}
|
||||
|
||||
// needObjectValue reports whether the next token must be a JSON value,
|
||||
// which is necessary after every JSON object name.
|
||||
func (e stateEntry) needObjectValue() bool {
|
||||
return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountOdd
|
||||
}
|
||||
|
||||
// needImplicitComma reports whether an comma should occur next,
|
||||
// which always occurs after a value in a JSON object or array
|
||||
// before the next value (or name).
|
||||
func (e stateEntry) needImplicitComma(next Kind) bool {
|
||||
return !e.needObjectValue() && e.length() > 0 && next != '}' && next != ']'
|
||||
}
|
||||
|
||||
// increment increments the number of elements for the current object or array.
|
||||
// This assumes that overflow won't practically be an issue since
|
||||
// 1<<bits.OnesCount(stateCountMask) is sufficiently large.
|
||||
func (e *stateEntry) increment() {
|
||||
(*e)++
|
||||
}
|
||||
|
||||
// decrement decrements the number of elements for the current object or array.
|
||||
// It is the callers responsibility to ensure that e.length > 0.
|
||||
func (e *stateEntry) decrement() {
|
||||
(*e)--
|
||||
}
|
||||
|
||||
// disableNamespace disables the JSON object namespace such that the
|
||||
// Encoder or Decoder no longer updates the namespace.
|
||||
func (e *stateEntry) disableNamespace() {
|
||||
*e |= stateDisableNamespace
|
||||
}
|
||||
|
||||
// isActiveNamespace reports whether the JSON object namespace is actively
|
||||
// being updated and used for duplicate name checks.
|
||||
func (e stateEntry) isActiveNamespace() bool {
|
||||
return e&(stateDisableNamespace) == 0
|
||||
}
|
||||
|
||||
// invalidateNamespace marks the JSON object namespace as being invalid.
|
||||
func (e *stateEntry) invalidateNamespace() {
|
||||
*e |= stateInvalidNamespace
|
||||
}
|
||||
|
||||
// isValidNamespace reports whether the JSON object namespace is valid.
|
||||
func (e stateEntry) isValidNamespace() bool {
|
||||
return e&(stateInvalidNamespace) == 0
|
||||
}
|
||||
|
||||
// objectNameStack is a stack of names when descending into a JSON object.
|
||||
// In contrast to objectNamespaceStack, this only has to remember a single name
|
||||
// per JSON object.
|
||||
//
|
||||
// This data structure may contain offsets to encodeBuffer or decodeBuffer.
|
||||
// It violates clean abstraction of layers, but is significantly more efficient.
|
||||
// This ensures that popping and pushing in the common case is a trivial
|
||||
// push/pop of an offset integer.
|
||||
//
|
||||
// The zero value is an empty names stack ready for use.
|
||||
type objectNameStack struct {
|
||||
// offsets is a stack of offsets for each name.
|
||||
// A non-negative offset is the ending offset into the local names buffer.
|
||||
// A negative offset is the bit-wise inverse of a starting offset into
|
||||
// a remote buffer (e.g., encodeBuffer or decodeBuffer).
|
||||
// A math.MinInt offset at the end implies that the last object is empty.
|
||||
// Invariant: Positive offsets always occur before negative offsets.
|
||||
offsets []int
|
||||
// unquotedNames is a back-to-back concatenation of names.
|
||||
unquotedNames []byte
|
||||
}
|
||||
|
||||
func (ns *objectNameStack) reset() {
|
||||
ns.offsets = ns.offsets[:0]
|
||||
ns.unquotedNames = ns.unquotedNames[:0]
|
||||
if cap(ns.offsets) > 1<<6 {
|
||||
ns.offsets = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
if cap(ns.unquotedNames) > 1<<10 {
|
||||
ns.unquotedNames = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *objectNameStack) length() int {
|
||||
return len(ns.offsets)
|
||||
}
|
||||
|
||||
// getUnquoted retrieves the ith unquoted name in the namespace.
|
||||
// It returns an empty string if the last object is empty.
|
||||
//
|
||||
// Invariant: Must call copyQuotedBuffer beforehand.
|
||||
func (ns *objectNameStack) getUnquoted(i int) []byte {
|
||||
ns.ensureCopiedBuffer()
|
||||
if i == 0 {
|
||||
return ns.unquotedNames[:ns.offsets[0]]
|
||||
} else {
|
||||
return ns.unquotedNames[ns.offsets[i-1]:ns.offsets[i-0]]
|
||||
}
|
||||
}
|
||||
|
||||
// invalidOffset indicates that the last JSON object currently has no name.
|
||||
const invalidOffset = math.MinInt
|
||||
|
||||
// push descends into a nested JSON object.
|
||||
func (ns *objectNameStack) push() {
|
||||
ns.offsets = append(ns.offsets, invalidOffset)
|
||||
}
|
||||
|
||||
// replaceLastQuotedOffset replaces the last name with the starting offset
|
||||
// to the quoted name in some remote buffer. All offsets provided must be
|
||||
// relative to the same buffer until copyQuotedBuffer is called.
|
||||
func (ns *objectNameStack) replaceLastQuotedOffset(i int) {
|
||||
// Use bit-wise inversion instead of naive multiplication by -1 to avoid
|
||||
// ambiguity regarding zero (which is a valid offset into the names field).
|
||||
// Bit-wise inversion is mathematically equivalent to -i-1,
|
||||
// such that 0 becomes -1, 1 becomes -2, and so forth.
|
||||
// This ensures that remote offsets are always negative.
|
||||
ns.offsets[len(ns.offsets)-1] = ^i
|
||||
}
|
||||
|
||||
// replaceLastUnquotedName replaces the last name with the provided name.
|
||||
//
|
||||
// Invariant: Must call copyQuotedBuffer beforehand.
|
||||
func (ns *objectNameStack) replaceLastUnquotedName(s string) {
|
||||
ns.ensureCopiedBuffer()
|
||||
var startOffset int
|
||||
if len(ns.offsets) > 1 {
|
||||
startOffset = ns.offsets[len(ns.offsets)-2]
|
||||
}
|
||||
ns.unquotedNames = append(ns.unquotedNames[:startOffset], s...)
|
||||
ns.offsets[len(ns.offsets)-1] = len(ns.unquotedNames)
|
||||
}
|
||||
|
||||
// clearLast removes any name in the last JSON object.
|
||||
// It is semantically equivalent to ns.push followed by ns.pop.
|
||||
func (ns *objectNameStack) clearLast() {
|
||||
ns.offsets[len(ns.offsets)-1] = invalidOffset
|
||||
}
|
||||
|
||||
// pop ascends out of a nested JSON object.
|
||||
func (ns *objectNameStack) pop() {
|
||||
ns.offsets = ns.offsets[:len(ns.offsets)-1]
|
||||
}
|
||||
|
||||
// copyQuotedBuffer copies names from the remote buffer into the local names
|
||||
// buffer so that there are no more offset references into the remote buffer.
|
||||
// This allows the remote buffer to change contents without affecting
|
||||
// the names that this data structure is trying to remember.
|
||||
func (ns *objectNameStack) copyQuotedBuffer(b []byte) {
|
||||
// Find the first negative offset.
|
||||
var i int
|
||||
for i = len(ns.offsets) - 1; i >= 0 && ns.offsets[i] < 0; i-- {
|
||||
continue
|
||||
}
|
||||
|
||||
// Copy each name from the remote buffer into the local buffer.
|
||||
for i = i + 1; i < len(ns.offsets); i++ {
|
||||
if i == len(ns.offsets)-1 && ns.offsets[i] == invalidOffset {
|
||||
if i == 0 {
|
||||
ns.offsets[i] = 0
|
||||
} else {
|
||||
ns.offsets[i] = ns.offsets[i-1]
|
||||
}
|
||||
break // last JSON object had a push without any names
|
||||
}
|
||||
|
||||
// As a form of Hyrum proofing, we write an invalid character into the
|
||||
// buffer to make misuse of Decoder.ReadToken more obvious.
|
||||
// We need to undo that mutation here.
|
||||
quotedName := b[^ns.offsets[i]:]
|
||||
if quotedName[0] == invalidateBufferByte {
|
||||
quotedName[0] = '"'
|
||||
}
|
||||
|
||||
// Append the unquoted name to the local buffer.
|
||||
var startOffset int
|
||||
if i > 0 {
|
||||
startOffset = ns.offsets[i-1]
|
||||
}
|
||||
if n := consumeSimpleString(quotedName); n > 0 {
|
||||
ns.unquotedNames = append(ns.unquotedNames[:startOffset], quotedName[len(`"`):n-len(`"`)]...)
|
||||
} else {
|
||||
ns.unquotedNames, _ = unescapeString(ns.unquotedNames[:startOffset], quotedName)
|
||||
}
|
||||
ns.offsets[i] = len(ns.unquotedNames)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *objectNameStack) ensureCopiedBuffer() {
|
||||
if len(ns.offsets) > 0 && ns.offsets[len(ns.offsets)-1] < 0 {
|
||||
panic("BUG: copyQuotedBuffer not called beforehand")
|
||||
}
|
||||
}
|
||||
|
||||
// objectNamespaceStack is a stack of object namespaces.
|
||||
// This data structure assists in detecting duplicate names.
|
||||
type objectNamespaceStack []objectNamespace
|
||||
|
||||
// reset resets the object namespace stack.
|
||||
func (nss *objectNamespaceStack) reset() {
|
||||
if cap(*nss) > 1<<10 {
|
||||
*nss = nil
|
||||
}
|
||||
*nss = (*nss)[:0]
|
||||
}
|
||||
|
||||
// push starts a new namespace for a nested JSON object.
|
||||
func (nss *objectNamespaceStack) push() {
|
||||
if cap(*nss) > len(*nss) {
|
||||
*nss = (*nss)[:len(*nss)+1]
|
||||
nss.last().reset()
|
||||
} else {
|
||||
*nss = append(*nss, objectNamespace{})
|
||||
}
|
||||
}
|
||||
|
||||
// last returns a pointer to the last JSON object namespace.
|
||||
func (nss objectNamespaceStack) last() *objectNamespace {
|
||||
return &nss[len(nss)-1]
|
||||
}
|
||||
|
||||
// pop terminates the namespace for a nested JSON object.
|
||||
func (nss *objectNamespaceStack) pop() {
|
||||
*nss = (*nss)[:len(*nss)-1]
|
||||
}
|
||||
|
||||
// objectNamespace is the namespace for a JSON object.
|
||||
// In contrast to objectNameStack, this needs to remember a all names
|
||||
// per JSON object.
|
||||
//
|
||||
// The zero value is an empty namespace ready for use.
|
||||
type objectNamespace struct {
|
||||
// It relies on a linear search over all the names before switching
|
||||
// to use a Go map for direct lookup.
|
||||
|
||||
// endOffsets is a list of offsets to the end of each name in buffers.
|
||||
// The length of offsets is the number of names in the namespace.
|
||||
endOffsets []uint
|
||||
// allUnquotedNames is a back-to-back concatenation of every name in the namespace.
|
||||
allUnquotedNames []byte
|
||||
// mapNames is a Go map containing every name in the namespace.
|
||||
// Only valid if non-nil.
|
||||
mapNames map[string]struct{}
|
||||
}
|
||||
|
||||
// reset resets the namespace to be empty.
|
||||
func (ns *objectNamespace) reset() {
|
||||
ns.endOffsets = ns.endOffsets[:0]
|
||||
ns.allUnquotedNames = ns.allUnquotedNames[:0]
|
||||
ns.mapNames = nil
|
||||
if cap(ns.endOffsets) > 1<<6 {
|
||||
ns.endOffsets = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
if cap(ns.allUnquotedNames) > 1<<10 {
|
||||
ns.allUnquotedNames = nil // avoid pinning arbitrarily large amounts of memory
|
||||
}
|
||||
}
|
||||
|
||||
// length reports the number of names in the namespace.
|
||||
func (ns *objectNamespace) length() int {
|
||||
return len(ns.endOffsets)
|
||||
}
|
||||
|
||||
// getUnquoted retrieves the ith unquoted name in the namespace.
|
||||
func (ns *objectNamespace) getUnquoted(i int) []byte {
|
||||
if i == 0 {
|
||||
return ns.allUnquotedNames[:ns.endOffsets[0]]
|
||||
} else {
|
||||
return ns.allUnquotedNames[ns.endOffsets[i-1]:ns.endOffsets[i-0]]
|
||||
}
|
||||
}
|
||||
|
||||
// lastUnquoted retrieves the last name in the namespace.
|
||||
func (ns *objectNamespace) lastUnquoted() []byte {
|
||||
return ns.getUnquoted(ns.length() - 1)
|
||||
}
|
||||
|
||||
// insertQuoted inserts a name and reports whether it was inserted,
|
||||
// which only occurs if name is not already in the namespace.
|
||||
// The provided name must be a valid JSON string.
|
||||
func (ns *objectNamespace) insertQuoted(name []byte, isVerbatim bool) bool {
|
||||
if isVerbatim {
|
||||
name = name[len(`"`) : len(name)-len(`"`)]
|
||||
}
|
||||
return ns.insert(name, !isVerbatim)
|
||||
}
|
||||
func (ns *objectNamespace) insertUnquoted(name []byte) bool {
|
||||
return ns.insert(name, false)
|
||||
}
|
||||
func (ns *objectNamespace) insert(name []byte, quoted bool) bool {
|
||||
var allNames []byte
|
||||
if quoted {
|
||||
allNames, _ = unescapeString(ns.allUnquotedNames, name)
|
||||
} else {
|
||||
allNames = append(ns.allUnquotedNames, name...)
|
||||
}
|
||||
name = allNames[len(ns.allUnquotedNames):]
|
||||
|
||||
// Switch to a map if the buffer is too large for linear search.
|
||||
// This does not add the current name to the map.
|
||||
if ns.mapNames == nil && (ns.length() > 64 || len(ns.allUnquotedNames) > 1024) {
|
||||
ns.mapNames = make(map[string]struct{})
|
||||
var startOffset uint
|
||||
for _, endOffset := range ns.endOffsets {
|
||||
name := ns.allUnquotedNames[startOffset:endOffset]
|
||||
ns.mapNames[string(name)] = struct{}{} // allocates a new string
|
||||
startOffset = endOffset
|
||||
}
|
||||
}
|
||||
|
||||
if ns.mapNames == nil {
|
||||
// Perform linear search over the buffer to find matching names.
|
||||
// It provides O(n) lookup, but does not require any allocations.
|
||||
var startOffset uint
|
||||
for _, endOffset := range ns.endOffsets {
|
||||
if string(ns.allUnquotedNames[startOffset:endOffset]) == string(name) {
|
||||
return false
|
||||
}
|
||||
startOffset = endOffset
|
||||
}
|
||||
} else {
|
||||
// Use the map if it is populated.
|
||||
// It provides O(1) lookup, but requires a string allocation per name.
|
||||
if _, ok := ns.mapNames[string(name)]; ok {
|
||||
return false
|
||||
}
|
||||
ns.mapNames[string(name)] = struct{}{} // allocates a new string
|
||||
}
|
||||
|
||||
ns.allUnquotedNames = allNames
|
||||
ns.endOffsets = append(ns.endOffsets, uint(len(ns.allUnquotedNames)))
|
||||
return true
|
||||
}
|
||||
|
||||
// removeLast removes the last name in the namespace.
|
||||
func (ns *objectNamespace) removeLast() {
|
||||
if ns.mapNames != nil {
|
||||
delete(ns.mapNames, string(ns.lastUnquoted()))
|
||||
}
|
||||
if ns.length()-1 == 0 {
|
||||
ns.endOffsets = ns.endOffsets[:0]
|
||||
ns.allUnquotedNames = ns.allUnquotedNames[:0]
|
||||
} else {
|
||||
ns.endOffsets = ns.endOffsets[:ns.length()-1]
|
||||
ns.allUnquotedNames = ns.allUnquotedNames[:ns.endOffsets[ns.length()-1]]
|
||||
}
|
||||
}
|
||||
|
||||
type uintSet64 uint64
|
||||
|
||||
func (s uintSet64) has(i uint) bool { return s&(1<<i) > 0 }
|
||||
func (s *uintSet64) set(i uint) { *s |= 1 << i }
|
||||
|
||||
// uintSet is a set of unsigned integers.
|
||||
// It is optimized for most integers being close to zero.
|
||||
type uintSet struct {
|
||||
lo uintSet64
|
||||
hi []uintSet64
|
||||
}
|
||||
|
||||
// has reports whether i is in the set.
|
||||
func (s *uintSet) has(i uint) bool {
|
||||
if i < 64 {
|
||||
return s.lo.has(i)
|
||||
} else {
|
||||
i -= 64
|
||||
iHi, iLo := int(i/64), i%64
|
||||
return iHi < len(s.hi) && s.hi[iHi].has(iLo)
|
||||
}
|
||||
}
|
||||
|
||||
// insert inserts i into the set and reports whether it was the first insertion.
|
||||
func (s *uintSet) insert(i uint) bool {
|
||||
// TODO: Make this inlineable at least for the lower 64-bit case.
|
||||
if i < 64 {
|
||||
has := s.lo.has(i)
|
||||
s.lo.set(i)
|
||||
return !has
|
||||
} else {
|
||||
i -= 64
|
||||
iHi, iLo := int(i/64), i%64
|
||||
if iHi >= len(s.hi) {
|
||||
s.hi = append(s.hi, make([]uintSet64, iHi+1-len(s.hi))...)
|
||||
s.hi = s.hi[:cap(s.hi)]
|
||||
}
|
||||
has := s.hi[iHi].has(iLo)
|
||||
s.hi[iHi].set(iLo)
|
||||
return !has
|
||||
}
|
||||
}
|
522
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/token.go
generated
vendored
Normal file
522
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/token.go
generated
vendored
Normal file
@ -0,0 +1,522 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// NOTE: Token is analogous to v1 json.Token.
|
||||
|
||||
const (
|
||||
maxInt64 = math.MaxInt64
|
||||
minInt64 = math.MinInt64
|
||||
maxUint64 = math.MaxUint64
|
||||
minUint64 = 0 // for consistency and readability purposes
|
||||
|
||||
invalidTokenPanic = "invalid json.Token; it has been voided by a subsequent json.Decoder call"
|
||||
)
|
||||
|
||||
// Token represents a lexical JSON token, which may be one of the following:
|
||||
// - a JSON literal (i.e., null, true, or false)
|
||||
// - a JSON string (e.g., "hello, world!")
|
||||
// - a JSON number (e.g., 123.456)
|
||||
// - a start or end delimiter for a JSON object (i.e., { or } )
|
||||
// - a start or end delimiter for a JSON array (i.e., [ or ] )
|
||||
//
|
||||
// A Token cannot represent entire array or object values, while a RawValue can.
|
||||
// There is no Token to represent commas and colons since
|
||||
// these structural tokens can be inferred from the surrounding context.
|
||||
type Token struct {
|
||||
nonComparable
|
||||
|
||||
// Tokens can exist in either a "raw" or an "exact" form.
|
||||
// Tokens produced by the Decoder are in the "raw" form.
|
||||
// Tokens returned by constructors are usually in the "exact" form.
|
||||
// The Encoder accepts Tokens in either the "raw" or "exact" form.
|
||||
//
|
||||
// The following chart shows the possible values for each Token type:
|
||||
// ╔═════════════════╦════════════╤════════════╤════════════╗
|
||||
// ║ Token type ║ raw field │ str field │ num field ║
|
||||
// ╠═════════════════╬════════════╪════════════╪════════════╣
|
||||
// ║ null (raw) ║ "null" │ "" │ 0 ║
|
||||
// ║ false (raw) ║ "false" │ "" │ 0 ║
|
||||
// ║ true (raw) ║ "true" │ "" │ 0 ║
|
||||
// ║ string (raw) ║ non-empty │ "" │ offset ║
|
||||
// ║ string (string) ║ nil │ non-empty │ 0 ║
|
||||
// ║ number (raw) ║ non-empty │ "" │ offset ║
|
||||
// ║ number (float) ║ nil │ "f" │ non-zero ║
|
||||
// ║ number (int64) ║ nil │ "i" │ non-zero ║
|
||||
// ║ number (uint64) ║ nil │ "u" │ non-zero ║
|
||||
// ║ object (delim) ║ "{" or "}" │ "" │ 0 ║
|
||||
// ║ array (delim) ║ "[" or "]" │ "" │ 0 ║
|
||||
// ╚═════════════════╩════════════╧════════════╧════════════╝
|
||||
//
|
||||
// Notes:
|
||||
// - For tokens stored in "raw" form, the num field contains the
|
||||
// absolute offset determined by raw.previousOffsetStart().
|
||||
// The buffer itself is stored in raw.previousBuffer().
|
||||
// - JSON literals and structural characters are always in the "raw" form.
|
||||
// - JSON strings and numbers can be in either "raw" or "exact" forms.
|
||||
// - The exact zero value of JSON strings and numbers in the "exact" forms
|
||||
// have ambiguous representation. Thus, they are always represented
|
||||
// in the "raw" form.
|
||||
|
||||
// raw contains a reference to the raw decode buffer.
|
||||
// If non-nil, then its value takes precedence over str and num.
|
||||
// It is only valid if num == raw.previousOffsetStart().
|
||||
raw *decodeBuffer
|
||||
|
||||
// str is the unescaped JSON string if num is zero.
|
||||
// Otherwise, it is "f", "i", or "u" if num should be interpreted
|
||||
// as a float64, int64, or uint64, respectively.
|
||||
str string
|
||||
|
||||
// num is a float64, int64, or uint64 stored as a uint64 value.
|
||||
// It is non-zero for any JSON number in the "exact" form.
|
||||
num uint64
|
||||
}
|
||||
|
||||
// TODO: Does representing 1-byte delimiters as *decodeBuffer cause performance issues?
|
||||
|
||||
var (
|
||||
Null Token = rawToken("null")
|
||||
False Token = rawToken("false")
|
||||
True Token = rawToken("true")
|
||||
|
||||
ObjectStart Token = rawToken("{")
|
||||
ObjectEnd Token = rawToken("}")
|
||||
ArrayStart Token = rawToken("[")
|
||||
ArrayEnd Token = rawToken("]")
|
||||
|
||||
zeroString Token = rawToken(`""`)
|
||||
zeroNumber Token = rawToken(`0`)
|
||||
|
||||
nanString Token = String("NaN")
|
||||
pinfString Token = String("Infinity")
|
||||
ninfString Token = String("-Infinity")
|
||||
)
|
||||
|
||||
func rawToken(s string) Token {
|
||||
return Token{raw: &decodeBuffer{buf: []byte(s), prevStart: 0, prevEnd: len(s)}}
|
||||
}
|
||||
|
||||
// Bool constructs a Token representing a JSON boolean.
|
||||
func Bool(b bool) Token {
|
||||
if b {
|
||||
return True
|
||||
}
|
||||
return False
|
||||
}
|
||||
|
||||
// String constructs a Token representing a JSON string.
|
||||
// The provided string should contain valid UTF-8, otherwise invalid characters
|
||||
// may be mangled as the Unicode replacement character.
|
||||
func String(s string) Token {
|
||||
if len(s) == 0 {
|
||||
return zeroString
|
||||
}
|
||||
return Token{str: s}
|
||||
}
|
||||
|
||||
// Float constructs a Token representing a JSON number.
|
||||
// The values NaN, +Inf, and -Inf will be represented
|
||||
// as a JSON string with the values "NaN", "Infinity", and "-Infinity".
|
||||
func Float(n float64) Token {
|
||||
switch {
|
||||
case math.Float64bits(n) == 0:
|
||||
return zeroNumber
|
||||
case math.IsNaN(n):
|
||||
return nanString
|
||||
case math.IsInf(n, +1):
|
||||
return pinfString
|
||||
case math.IsInf(n, -1):
|
||||
return ninfString
|
||||
}
|
||||
return Token{str: "f", num: math.Float64bits(n)}
|
||||
}
|
||||
|
||||
// Int constructs a Token representing a JSON number from an int64.
|
||||
func Int(n int64) Token {
|
||||
if n == 0 {
|
||||
return zeroNumber
|
||||
}
|
||||
return Token{str: "i", num: uint64(n)}
|
||||
}
|
||||
|
||||
// Uint constructs a Token representing a JSON number from a uint64.
|
||||
func Uint(n uint64) Token {
|
||||
if n == 0 {
|
||||
return zeroNumber
|
||||
}
|
||||
return Token{str: "u", num: uint64(n)}
|
||||
}
|
||||
|
||||
// Clone makes a copy of the Token such that its value remains valid
|
||||
// even after a subsequent Decoder.Read call.
|
||||
func (t Token) Clone() Token {
|
||||
// TODO: Allow caller to avoid any allocations?
|
||||
if raw := t.raw; raw != nil {
|
||||
// Avoid copying globals.
|
||||
if t.raw.prevStart == 0 {
|
||||
switch t.raw {
|
||||
case Null.raw:
|
||||
return Null
|
||||
case False.raw:
|
||||
return False
|
||||
case True.raw:
|
||||
return True
|
||||
case ObjectStart.raw:
|
||||
return ObjectStart
|
||||
case ObjectEnd.raw:
|
||||
return ObjectEnd
|
||||
case ArrayStart.raw:
|
||||
return ArrayStart
|
||||
case ArrayEnd.raw:
|
||||
return ArrayEnd
|
||||
}
|
||||
}
|
||||
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
// TODO(https://go.dev/issue/45038): Use bytes.Clone.
|
||||
buf := append([]byte(nil), raw.previousBuffer()...)
|
||||
return Token{raw: &decodeBuffer{buf: buf, prevStart: 0, prevEnd: len(buf)}}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Bool returns the value for a JSON boolean.
|
||||
// It panics if the token kind is not a JSON boolean.
|
||||
func (t Token) Bool() bool {
|
||||
switch t.raw {
|
||||
case True.raw:
|
||||
return true
|
||||
case False.raw:
|
||||
return false
|
||||
default:
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
// appendString appends a JSON string to dst and returns it.
|
||||
// It panics if t is not a JSON string.
|
||||
func (t Token) appendString(dst []byte, validateUTF8, preserveRaw bool, escapeRune func(rune) bool) ([]byte, error) {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw string value.
|
||||
buf := raw.previousBuffer()
|
||||
if Kind(buf[0]) == '"' {
|
||||
if escapeRune == nil && consumeSimpleString(buf) == len(buf) {
|
||||
return append(dst, buf...), nil
|
||||
}
|
||||
dst, _, err := reformatString(dst, buf, validateUTF8, preserveRaw, escapeRune)
|
||||
return dst, err
|
||||
}
|
||||
} else if len(t.str) != 0 && t.num == 0 {
|
||||
// Handle exact string value.
|
||||
return appendString(dst, t.str, validateUTF8, escapeRune)
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// String returns the unescaped string value for a JSON string.
|
||||
// For other JSON kinds, this returns the raw JSON representation.
|
||||
func (t Token) String() string {
|
||||
// This is inlinable to take advantage of "function outlining".
|
||||
// This avoids an allocation for the string(b) conversion
|
||||
// if the caller does not use the string in an escaping manner.
|
||||
// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
|
||||
s, b := t.string()
|
||||
if len(b) > 0 {
|
||||
return string(b)
|
||||
}
|
||||
return s
|
||||
}
|
||||
func (t Token) string() (string, []byte) {
|
||||
if raw := t.raw; raw != nil {
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
buf := raw.previousBuffer()
|
||||
if buf[0] == '"' {
|
||||
// TODO: Preserve valueFlags in Token?
|
||||
isVerbatim := consumeSimpleString(buf) == len(buf)
|
||||
return "", unescapeStringMayCopy(buf, isVerbatim)
|
||||
}
|
||||
// Handle tokens that are not JSON strings for fmt.Stringer.
|
||||
return "", buf
|
||||
}
|
||||
if len(t.str) != 0 && t.num == 0 {
|
||||
return t.str, nil
|
||||
}
|
||||
// Handle tokens that are not JSON strings for fmt.Stringer.
|
||||
if t.num > 0 {
|
||||
switch t.str[0] {
|
||||
case 'f':
|
||||
return string(appendNumber(nil, math.Float64frombits(t.num), 64)), nil
|
||||
case 'i':
|
||||
return strconv.FormatInt(int64(t.num), 10), nil
|
||||
case 'u':
|
||||
return strconv.FormatUint(uint64(t.num), 10), nil
|
||||
}
|
||||
}
|
||||
return "<invalid json.Token>", nil
|
||||
}
|
||||
|
||||
// appendNumber appends a JSON number to dst and returns it.
|
||||
// It panics if t is not a JSON number.
|
||||
func (t Token) appendNumber(dst []byte, canonicalize bool) ([]byte, error) {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw number value.
|
||||
buf := raw.previousBuffer()
|
||||
if Kind(buf[0]).normalize() == '0' {
|
||||
if !canonicalize {
|
||||
return append(dst, buf...), nil
|
||||
}
|
||||
dst, _, err := reformatNumber(dst, buf, canonicalize)
|
||||
return dst, err
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact number value.
|
||||
switch t.str[0] {
|
||||
case 'f':
|
||||
return appendNumber(dst, math.Float64frombits(t.num), 64), nil
|
||||
case 'i':
|
||||
return strconv.AppendInt(dst, int64(t.num), 10), nil
|
||||
case 'u':
|
||||
return strconv.AppendUint(dst, uint64(t.num), 10), nil
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Float returns the floating-point value for a JSON number.
|
||||
// It returns a NaN, +Inf, or -Inf value for any JSON string
|
||||
// with the values "NaN", "Infinity", or "-Infinity".
|
||||
// It panics for all other cases.
|
||||
func (t Token) Float() float64 {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw number value.
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
buf := raw.previousBuffer()
|
||||
if Kind(buf[0]).normalize() == '0' {
|
||||
fv, _ := parseFloat(buf, 64)
|
||||
return fv
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact number value.
|
||||
switch t.str[0] {
|
||||
case 'f':
|
||||
return math.Float64frombits(t.num)
|
||||
case 'i':
|
||||
return float64(int64(t.num))
|
||||
case 'u':
|
||||
return float64(uint64(t.num))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle string values with "NaN", "Infinity", or "-Infinity".
|
||||
if t.Kind() == '"' {
|
||||
switch t.String() {
|
||||
case "NaN":
|
||||
return math.NaN()
|
||||
case "Infinity":
|
||||
return math.Inf(+1)
|
||||
case "-Infinity":
|
||||
return math.Inf(-1)
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Int returns the signed integer value for a JSON number.
|
||||
// The fractional component of any number is ignored (truncation toward zero).
|
||||
// Any number beyond the representation of an int64 will be saturated
|
||||
// to the closest representable value.
|
||||
// It panics if the token kind is not a JSON number.
|
||||
func (t Token) Int() int64 {
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw integer value.
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
neg := false
|
||||
buf := raw.previousBuffer()
|
||||
if len(buf) > 0 && buf[0] == '-' {
|
||||
neg, buf = true, buf[1:]
|
||||
}
|
||||
if numAbs, ok := parseDecUint(buf); ok {
|
||||
if neg {
|
||||
if numAbs > -minInt64 {
|
||||
return minInt64
|
||||
}
|
||||
return -1 * int64(numAbs)
|
||||
} else {
|
||||
if numAbs > +maxInt64 {
|
||||
return maxInt64
|
||||
}
|
||||
return +1 * int64(numAbs)
|
||||
}
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact integer value.
|
||||
switch t.str[0] {
|
||||
case 'i':
|
||||
return int64(t.num)
|
||||
case 'u':
|
||||
if t.num > maxInt64 {
|
||||
return maxInt64
|
||||
}
|
||||
return int64(t.num)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle JSON number that is a floating-point value.
|
||||
if t.Kind() == '0' {
|
||||
switch fv := t.Float(); {
|
||||
case fv >= maxInt64:
|
||||
return maxInt64
|
||||
case fv <= minInt64:
|
||||
return minInt64
|
||||
default:
|
||||
return int64(fv) // truncation toward zero
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Uint returns the unsigned integer value for a JSON number.
|
||||
// The fractional component of any number is ignored (truncation toward zero).
|
||||
// Any number beyond the representation of an uint64 will be saturated
|
||||
// to the closest representable value.
|
||||
// It panics if the token kind is not a JSON number.
|
||||
func (t Token) Uint() uint64 {
|
||||
// NOTE: This accessor returns 0 for any negative JSON number,
|
||||
// which might be surprising, but is at least consistent with the behavior
|
||||
// of saturating out-of-bounds numbers to the closest representable number.
|
||||
|
||||
if raw := t.raw; raw != nil {
|
||||
// Handle raw integer value.
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
neg := false
|
||||
buf := raw.previousBuffer()
|
||||
if len(buf) > 0 && buf[0] == '-' {
|
||||
neg, buf = true, buf[1:]
|
||||
}
|
||||
if num, ok := parseDecUint(buf); ok {
|
||||
if neg {
|
||||
return minUint64
|
||||
}
|
||||
return num
|
||||
}
|
||||
} else if t.num != 0 {
|
||||
// Handle exact integer value.
|
||||
switch t.str[0] {
|
||||
case 'u':
|
||||
return t.num
|
||||
case 'i':
|
||||
if int64(t.num) < minUint64 {
|
||||
return minUint64
|
||||
}
|
||||
return uint64(int64(t.num))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle JSON number that is a floating-point value.
|
||||
if t.Kind() == '0' {
|
||||
switch fv := t.Float(); {
|
||||
case fv >= maxUint64:
|
||||
return maxUint64
|
||||
case fv <= minUint64:
|
||||
return minUint64
|
||||
default:
|
||||
return uint64(fv) // truncation toward zero
|
||||
}
|
||||
}
|
||||
|
||||
panic("invalid JSON token kind: " + t.Kind().String())
|
||||
}
|
||||
|
||||
// Kind returns the token kind.
|
||||
func (t Token) Kind() Kind {
|
||||
switch {
|
||||
case t.raw != nil:
|
||||
raw := t.raw
|
||||
if uint64(raw.previousOffsetStart()) != t.num {
|
||||
panic(invalidTokenPanic)
|
||||
}
|
||||
return Kind(t.raw.buf[raw.prevStart]).normalize()
|
||||
case t.num != 0:
|
||||
return '0'
|
||||
case len(t.str) != 0:
|
||||
return '"'
|
||||
default:
|
||||
return invalidKind
|
||||
}
|
||||
}
|
||||
|
||||
// Kind represents each possible JSON token kind with a single byte,
|
||||
// which is conveniently the first byte of that kind's grammar
|
||||
// with the restriction that numbers always be represented with '0':
|
||||
//
|
||||
// - 'n': null
|
||||
// - 'f': false
|
||||
// - 't': true
|
||||
// - '"': string
|
||||
// - '0': number
|
||||
// - '{': object start
|
||||
// - '}': object end
|
||||
// - '[': array start
|
||||
// - ']': array end
|
||||
//
|
||||
// An invalid kind is usually represented using 0,
|
||||
// but may be non-zero due to invalid JSON data.
|
||||
type Kind byte
|
||||
|
||||
const invalidKind Kind = 0
|
||||
|
||||
// String prints the kind in a humanly readable fashion.
|
||||
func (k Kind) String() string {
|
||||
switch k {
|
||||
case 'n':
|
||||
return "null"
|
||||
case 'f':
|
||||
return "false"
|
||||
case 't':
|
||||
return "true"
|
||||
case '"':
|
||||
return "string"
|
||||
case '0':
|
||||
return "number"
|
||||
case '{':
|
||||
return "{"
|
||||
case '}':
|
||||
return "}"
|
||||
case '[':
|
||||
return "["
|
||||
case ']':
|
||||
return "]"
|
||||
default:
|
||||
return "<invalid json.Kind: " + quoteRune([]byte{byte(k)}) + ">"
|
||||
}
|
||||
}
|
||||
|
||||
// normalize coalesces all possible starting characters of a number as just '0'.
|
||||
func (k Kind) normalize() Kind {
|
||||
if k == '-' || ('0' <= k && k <= '9') {
|
||||
return '0'
|
||||
}
|
||||
return k
|
||||
}
|
381
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/value.go
generated
vendored
Normal file
381
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/value.go
generated
vendored
Normal file
@ -0,0 +1,381 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"sort"
|
||||
"sync"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// NOTE: RawValue is analogous to v1 json.RawMessage.
|
||||
|
||||
// RawValue represents a single raw JSON value, which may be one of the following:
|
||||
// - a JSON literal (i.e., null, true, or false)
|
||||
// - a JSON string (e.g., "hello, world!")
|
||||
// - a JSON number (e.g., 123.456)
|
||||
// - an entire JSON object (e.g., {"fizz":"buzz"} )
|
||||
// - an entire JSON array (e.g., [1,2,3] )
|
||||
//
|
||||
// RawValue can represent entire array or object values, while Token cannot.
|
||||
// RawValue may contain leading and/or trailing whitespace.
|
||||
type RawValue []byte
|
||||
|
||||
// Clone returns a copy of v.
|
||||
func (v RawValue) Clone() RawValue {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return append(RawValue{}, v...)
|
||||
}
|
||||
|
||||
// String returns the string formatting of v.
|
||||
func (v RawValue) String() string {
|
||||
if v == nil {
|
||||
return "null"
|
||||
}
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// IsValid reports whether the raw JSON value is syntactically valid
|
||||
// according to RFC 7493.
|
||||
//
|
||||
// It verifies whether the input is properly encoded as UTF-8,
|
||||
// that escape sequences within strings decode to valid Unicode codepoints, and
|
||||
// that all names in each object are unique.
|
||||
// It does not verify whether numbers are representable within the limits
|
||||
// of any common numeric type (e.g., float64, int64, or uint64).
|
||||
func (v RawValue) IsValid() bool {
|
||||
d := getBufferedDecoder(v, DecodeOptions{})
|
||||
defer putBufferedDecoder(d)
|
||||
_, errVal := d.ReadValue()
|
||||
_, errEOF := d.ReadToken()
|
||||
return errVal == nil && errEOF == io.EOF
|
||||
}
|
||||
|
||||
// Compact removes all whitespace from the raw JSON value.
|
||||
//
|
||||
// It does not reformat JSON strings to use any other representation.
|
||||
// It is guaranteed to succeed if the input is valid.
|
||||
// If the value is already compacted, then the buffer is not mutated.
|
||||
func (v *RawValue) Compact() error {
|
||||
return v.reformat(false, false, "", "")
|
||||
}
|
||||
|
||||
// Indent reformats the whitespace in the raw JSON value so that each element
|
||||
// in a JSON object or array begins on a new, indented line beginning with
|
||||
// prefix followed by one or more copies of indent according to the nesting.
|
||||
// The value does not begin with the prefix nor any indention,
|
||||
// to make it easier to embed inside other formatted JSON data.
|
||||
//
|
||||
// It does not reformat JSON strings to use any other representation.
|
||||
// It is guaranteed to succeed if the input is valid.
|
||||
// If the value is already indented properly, then the buffer is not mutated.
|
||||
func (v *RawValue) Indent(prefix, indent string) error {
|
||||
return v.reformat(false, true, prefix, indent)
|
||||
}
|
||||
|
||||
// Canonicalize canonicalizes the raw JSON value according to the
|
||||
// JSON Canonicalization Scheme (JCS) as defined by RFC 8785
|
||||
// where it produces a stable representation of a JSON value.
|
||||
//
|
||||
// The output stability is dependent on the stability of the application data
|
||||
// (see RFC 8785, Appendix E). It cannot produce stable output from
|
||||
// fundamentally unstable input. For example, if the JSON value
|
||||
// contains ephemeral data (e.g., a frequently changing timestamp),
|
||||
// then the value is still unstable regardless of whether this is called.
|
||||
//
|
||||
// Note that JCS treats all JSON numbers as IEEE 754 double precision numbers.
|
||||
// Any numbers with precision beyond what is representable by that form
|
||||
// will lose their precision when canonicalized. For example, integer values
|
||||
// beyond ±2⁵³ will lose their precision. It is recommended that
|
||||
// int64 and uint64 data types be represented as a JSON string.
|
||||
//
|
||||
// It is guaranteed to succeed if the input is valid.
|
||||
// If the value is already canonicalized, then the buffer is not mutated.
|
||||
func (v *RawValue) Canonicalize() error {
|
||||
return v.reformat(true, false, "", "")
|
||||
}
|
||||
|
||||
// TODO: Instead of implementing the v1 Marshaler/Unmarshaler,
|
||||
// consider implementing the v2 versions instead.
|
||||
|
||||
// MarshalJSON returns v as the JSON encoding of v.
|
||||
// It returns the stored value as the raw JSON output without any validation.
|
||||
// If v is nil, then this returns a JSON null.
|
||||
func (v RawValue) MarshalJSON() ([]byte, error) {
|
||||
// NOTE: This matches the behavior of v1 json.RawMessage.MarshalJSON.
|
||||
if v == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets v as the JSON encoding of b.
|
||||
// It stores a copy of the provided raw JSON input without any validation.
|
||||
func (v *RawValue) UnmarshalJSON(b []byte) error {
|
||||
// NOTE: This matches the behavior of v1 json.RawMessage.UnmarshalJSON.
|
||||
if v == nil {
|
||||
return errors.New("json.RawValue: UnmarshalJSON on nil pointer")
|
||||
}
|
||||
*v = append((*v)[:0], b...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kind returns the starting token kind.
|
||||
// For a valid value, this will never include '}' or ']'.
|
||||
func (v RawValue) Kind() Kind {
|
||||
if v := v[consumeWhitespace(v):]; len(v) > 0 {
|
||||
return Kind(v[0]).normalize()
|
||||
}
|
||||
return invalidKind
|
||||
}
|
||||
|
||||
func (v *RawValue) reformat(canonical, multiline bool, prefix, indent string) error {
|
||||
var eo EncodeOptions
|
||||
if canonical {
|
||||
eo.AllowInvalidUTF8 = false // per RFC 8785, section 3.2.4
|
||||
eo.AllowDuplicateNames = false // per RFC 8785, section 3.1
|
||||
eo.canonicalizeNumbers = true // per RFC 8785, section 3.2.2.3
|
||||
eo.EscapeRune = nil // per RFC 8785, section 3.2.2.2
|
||||
eo.multiline = false // per RFC 8785, section 3.2.1
|
||||
} else {
|
||||
if s := trimLeftSpaceTab(prefix); len(s) > 0 {
|
||||
panic("json: invalid character " + quoteRune([]byte(s)) + " in indent prefix")
|
||||
}
|
||||
if s := trimLeftSpaceTab(indent); len(s) > 0 {
|
||||
panic("json: invalid character " + quoteRune([]byte(s)) + " in indent")
|
||||
}
|
||||
eo.AllowInvalidUTF8 = true
|
||||
eo.AllowDuplicateNames = true
|
||||
eo.preserveRawStrings = true
|
||||
eo.multiline = multiline // in case indent is empty
|
||||
eo.IndentPrefix = prefix
|
||||
eo.Indent = indent
|
||||
}
|
||||
eo.omitTopLevelNewline = true
|
||||
|
||||
// Write the entire value to reformat all tokens and whitespace.
|
||||
e := getBufferedEncoder(eo)
|
||||
defer putBufferedEncoder(e)
|
||||
if err := e.WriteValue(*v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// For canonical output, we may need to reorder object members.
|
||||
if canonical {
|
||||
// Obtain a buffered encoder just to use its internal buffer as
|
||||
// a scratch buffer in reorderObjects for reordering object members.
|
||||
e2 := getBufferedEncoder(EncodeOptions{})
|
||||
defer putBufferedEncoder(e2)
|
||||
|
||||
// Disable redundant checks performed earlier during encoding.
|
||||
d := getBufferedDecoder(e.buf, DecodeOptions{AllowInvalidUTF8: true, AllowDuplicateNames: true})
|
||||
defer putBufferedDecoder(d)
|
||||
reorderObjects(d, &e2.buf) // per RFC 8785, section 3.2.3
|
||||
}
|
||||
|
||||
// Store the result back into the value if different.
|
||||
if !bytes.Equal(*v, e.buf) {
|
||||
*v = append((*v)[:0], e.buf...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func trimLeftSpaceTab(s string) string {
|
||||
for i, r := range s {
|
||||
switch r {
|
||||
case ' ', '\t':
|
||||
default:
|
||||
return s[i:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type memberName struct {
|
||||
// name is the unescaped name.
|
||||
name []byte
|
||||
// before and after are byte offsets into Decoder.buf that represents
|
||||
// the entire name/value pair. It may contain leading commas.
|
||||
before, after int64
|
||||
}
|
||||
|
||||
var memberNamePool = sync.Pool{New: func() any { return new(memberNames) }}
|
||||
|
||||
func getMemberNames() *memberNames {
|
||||
ns := memberNamePool.Get().(*memberNames)
|
||||
*ns = (*ns)[:0]
|
||||
return ns
|
||||
}
|
||||
func putMemberNames(ns *memberNames) {
|
||||
if cap(*ns) < 1<<10 {
|
||||
for i := range *ns {
|
||||
(*ns)[i] = memberName{} // avoid pinning name
|
||||
}
|
||||
memberNamePool.Put(ns)
|
||||
}
|
||||
}
|
||||
|
||||
type memberNames []memberName
|
||||
|
||||
func (m *memberNames) Len() int { return len(*m) }
|
||||
func (m *memberNames) Less(i, j int) bool { return lessUTF16((*m)[i].name, (*m)[j].name) }
|
||||
func (m *memberNames) Swap(i, j int) { (*m)[i], (*m)[j] = (*m)[j], (*m)[i] }
|
||||
|
||||
// reorderObjects recursively reorders all object members in place
|
||||
// according to the ordering specified in RFC 8785, section 3.2.3.
|
||||
//
|
||||
// Pre-conditions:
|
||||
// - The value is valid (i.e., no decoder errors should ever occur).
|
||||
// - The value is compact (i.e., no whitespace is present).
|
||||
// - Initial call is provided a Decoder reading from the start of v.
|
||||
//
|
||||
// Post-conditions:
|
||||
// - Exactly one JSON value is read from the Decoder.
|
||||
// - All fully-parsed JSON objects are reordered by directly moving
|
||||
// the members in the value buffer.
|
||||
//
|
||||
// The runtime is approximately O(n·log(n)) + O(m·log(m)),
|
||||
// where n is len(v) and m is the total number of object members.
|
||||
func reorderObjects(d *Decoder, scratch *[]byte) {
|
||||
switch tok, _ := d.ReadToken(); tok.Kind() {
|
||||
case '{':
|
||||
// Iterate and collect the name and offsets for every object member.
|
||||
members := getMemberNames()
|
||||
defer putMemberNames(members)
|
||||
var prevName []byte
|
||||
isSorted := true
|
||||
|
||||
beforeBody := d.InputOffset() // offset after '{'
|
||||
for d.PeekKind() != '}' {
|
||||
beforeName := d.InputOffset()
|
||||
var flags valueFlags
|
||||
name, _ := d.readValue(&flags)
|
||||
name = unescapeStringMayCopy(name, flags.isVerbatim())
|
||||
reorderObjects(d, scratch)
|
||||
afterValue := d.InputOffset()
|
||||
|
||||
if isSorted && len(*members) > 0 {
|
||||
isSorted = lessUTF16(prevName, []byte(name))
|
||||
}
|
||||
*members = append(*members, memberName{name, beforeName, afterValue})
|
||||
prevName = name
|
||||
}
|
||||
afterBody := d.InputOffset() // offset before '}'
|
||||
d.ReadToken()
|
||||
|
||||
// Sort the members; return early if it's already sorted.
|
||||
if isSorted {
|
||||
return
|
||||
}
|
||||
// TODO(https://go.dev/issue/47619): Use slices.Sort.
|
||||
sort.Sort(members)
|
||||
|
||||
// Append the reordered members to a new buffer,
|
||||
// then copy the reordered members back over the original members.
|
||||
// Avoid swapping in place since each member may be a different size
|
||||
// where moving a member over a smaller member may corrupt the data
|
||||
// for subsequent members before they have been moved.
|
||||
//
|
||||
// The following invariant must hold:
|
||||
// sum([m.after-m.before for m in members]) == afterBody-beforeBody
|
||||
sorted := (*scratch)[:0]
|
||||
for i, member := range *members {
|
||||
if d.buf[member.before] == ',' {
|
||||
member.before++ // trim leading comma
|
||||
}
|
||||
sorted = append(sorted, d.buf[member.before:member.after]...)
|
||||
if i < len(*members)-1 {
|
||||
sorted = append(sorted, ',') // append trailing comma
|
||||
}
|
||||
}
|
||||
if int(afterBody-beforeBody) != len(sorted) {
|
||||
panic("BUG: length invariant violated")
|
||||
}
|
||||
copy(d.buf[beforeBody:afterBody], sorted)
|
||||
|
||||
// Update scratch buffer to the largest amount ever used.
|
||||
if len(sorted) > len(*scratch) {
|
||||
*scratch = sorted
|
||||
}
|
||||
case '[':
|
||||
for d.PeekKind() != ']' {
|
||||
reorderObjects(d, scratch)
|
||||
}
|
||||
d.ReadToken()
|
||||
}
|
||||
}
|
||||
|
||||
// lessUTF16 reports whether x is lexicographically less than y according
|
||||
// to the UTF-16 codepoints of the UTF-8 encoded input strings.
|
||||
// This implements the ordering specified in RFC 8785, section 3.2.3.
|
||||
// The inputs must be valid UTF-8, otherwise this may panic.
|
||||
func lessUTF16[Bytes []byte | string](x, y Bytes) bool {
|
||||
// NOTE: This is an optimized, allocation-free implementation
|
||||
// of lessUTF16Simple in fuzz_test.go. FuzzLessUTF16 verifies that the
|
||||
// two implementations agree on the result of comparing any two strings.
|
||||
|
||||
isUTF16Self := func(r rune) bool {
|
||||
return ('\u0000' <= r && r <= '\uD7FF') || ('\uE000' <= r && r <= '\uFFFF')
|
||||
}
|
||||
|
||||
var invalidUTF8 bool
|
||||
x0, y0 := x, y
|
||||
for {
|
||||
if len(x) == 0 || len(y) == 0 {
|
||||
if len(x) == len(y) && invalidUTF8 {
|
||||
return string(x0) < string(y0)
|
||||
}
|
||||
return len(x) < len(y)
|
||||
}
|
||||
|
||||
// ASCII fast-path.
|
||||
if x[0] < utf8.RuneSelf || y[0] < utf8.RuneSelf {
|
||||
if x[0] != y[0] {
|
||||
return x[0] < y[0]
|
||||
}
|
||||
x, y = x[1:], y[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode next pair of runes as UTF-8.
|
||||
// TODO(https://go.dev/issue/56948): Use a generic implementation
|
||||
// of utf8.DecodeRune, or rely on a compiler optimization to statically
|
||||
// hide the cost of a type switch (https://go.dev/issue/57072).
|
||||
var rx, ry rune
|
||||
var nx, ny int
|
||||
switch any(x).(type) {
|
||||
case string:
|
||||
rx, nx = utf8.DecodeRuneInString(string(x))
|
||||
ry, ny = utf8.DecodeRuneInString(string(y))
|
||||
case []byte:
|
||||
rx, nx = utf8.DecodeRune([]byte(x))
|
||||
ry, ny = utf8.DecodeRune([]byte(y))
|
||||
}
|
||||
|
||||
selfx := isUTF16Self(rx)
|
||||
selfy := isUTF16Self(ry)
|
||||
switch {
|
||||
// The x rune is a single UTF-16 codepoint, while
|
||||
// the y rune is a surrogate pair of UTF-16 codepoints.
|
||||
case selfx && !selfy:
|
||||
ry, _ = utf16.EncodeRune(ry)
|
||||
// The y rune is a single UTF-16 codepoint, while
|
||||
// the x rune is a surrogate pair of UTF-16 codepoints.
|
||||
case selfy && !selfx:
|
||||
rx, _ = utf16.EncodeRune(rx)
|
||||
}
|
||||
if rx != ry {
|
||||
return rx < ry
|
||||
}
|
||||
invalidUTF8 = invalidUTF8 || (rx == utf8.RuneError && nx == 1) || (ry == utf8.RuneError && ny == 1)
|
||||
x, y = x[nx:], y[ny:]
|
||||
}
|
||||
}
|
21
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/govalidator/LICENSE
generated
vendored
Normal file
21
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/govalidator/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Alex Saskevich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
26
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/govalidator/patterns.go
generated
vendored
Normal file
26
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/govalidator/patterns.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
package govalidator
|
||||
|
||||
import "regexp"
|
||||
|
||||
// Basic regular expressions for validating strings
|
||||
const (
|
||||
CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$"
|
||||
ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$"
|
||||
ISBN13 string = "^(?:[0-9]{13})$"
|
||||
Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
|
||||
RGBcolor string = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$"
|
||||
Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
|
||||
SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
|
||||
Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$"
|
||||
)
|
||||
|
||||
var (
|
||||
rxCreditCard = regexp.MustCompile(CreditCard)
|
||||
rxInt = regexp.MustCompile(Int)
|
||||
rxISBN10 = regexp.MustCompile(ISBN10)
|
||||
rxISBN13 = regexp.MustCompile(ISBN13)
|
||||
rxHexcolor = regexp.MustCompile(Hexcolor)
|
||||
rxRGBcolor = regexp.MustCompile(RGBcolor)
|
||||
rxBase64 = regexp.MustCompile(Base64)
|
||||
rxSSN = regexp.MustCompile(SSN)
|
||||
)
|
181
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/govalidator/validator.go
generated
vendored
Normal file
181
e2e/vendor/k8s.io/kube-openapi/pkg/internal/third_party/govalidator/validator.go
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
// Package govalidator is package of validators and sanitizers for strings, structs and collections.
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
notNumberRegexp = regexp.MustCompile("[^0-9]+")
|
||||
whiteSpacesAndMinus = regexp.MustCompile(`[\s-]+`)
|
||||
)
|
||||
|
||||
// IsRequestURI check if the string rawurl, assuming
|
||||
// it was received in an HTTP request, is an
|
||||
// absolute URI or an absolute path.
|
||||
func IsRequestURI(rawurl string) bool {
|
||||
_, err := url.ParseRequestURI(rawurl)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsHexcolor check if the string is a hexadecimal color.
|
||||
func IsHexcolor(str string) bool {
|
||||
return rxHexcolor.MatchString(str)
|
||||
}
|
||||
|
||||
// IsRGBcolor check if the string is a valid RGB color in form rgb(RRR, GGG, BBB).
|
||||
func IsRGBcolor(str string) bool {
|
||||
return rxRGBcolor.MatchString(str)
|
||||
}
|
||||
|
||||
// IsCreditCard check if the string is a credit card.
|
||||
func IsCreditCard(str string) bool {
|
||||
sanitized := notNumberRegexp.ReplaceAllString(str, "")
|
||||
if !rxCreditCard.MatchString(sanitized) {
|
||||
return false
|
||||
}
|
||||
var sum int64
|
||||
var digit string
|
||||
var tmpNum int64
|
||||
var shouldDouble bool
|
||||
for i := len(sanitized) - 1; i >= 0; i-- {
|
||||
digit = sanitized[i:(i + 1)]
|
||||
tmpNum, _ = ToInt(digit)
|
||||
if shouldDouble {
|
||||
tmpNum *= 2
|
||||
if tmpNum >= 10 {
|
||||
sum += (tmpNum % 10) + 1
|
||||
} else {
|
||||
sum += tmpNum
|
||||
}
|
||||
} else {
|
||||
sum += tmpNum
|
||||
}
|
||||
shouldDouble = !shouldDouble
|
||||
}
|
||||
|
||||
return sum%10 == 0
|
||||
}
|
||||
|
||||
// IsISBN10 check if the string is an ISBN version 10.
|
||||
func IsISBN10(str string) bool {
|
||||
return IsISBN(str, 10)
|
||||
}
|
||||
|
||||
// IsISBN13 check if the string is an ISBN version 13.
|
||||
func IsISBN13(str string) bool {
|
||||
return IsISBN(str, 13)
|
||||
}
|
||||
|
||||
// IsISBN check if the string is an ISBN (version 10 or 13).
|
||||
// If version value is not equal to 10 or 13, it will be check both variants.
|
||||
func IsISBN(str string, version int) bool {
|
||||
sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "")
|
||||
var checksum int32
|
||||
var i int32
|
||||
if version == 10 {
|
||||
if !rxISBN10.MatchString(sanitized) {
|
||||
return false
|
||||
}
|
||||
for i = 0; i < 9; i++ {
|
||||
checksum += (i + 1) * int32(sanitized[i]-'0')
|
||||
}
|
||||
if sanitized[9] == 'X' {
|
||||
checksum += 10 * 10
|
||||
} else {
|
||||
checksum += 10 * int32(sanitized[9]-'0')
|
||||
}
|
||||
if checksum%11 == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else if version == 13 {
|
||||
if !rxISBN13.MatchString(sanitized) {
|
||||
return false
|
||||
}
|
||||
factor := []int32{1, 3}
|
||||
for i = 0; i < 12; i++ {
|
||||
checksum += factor[i%2] * int32(sanitized[i]-'0')
|
||||
}
|
||||
return (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0
|
||||
}
|
||||
return IsISBN(str, 10) || IsISBN(str, 13)
|
||||
}
|
||||
|
||||
// IsBase64 check if a string is base64 encoded.
|
||||
func IsBase64(str string) bool {
|
||||
return rxBase64.MatchString(str)
|
||||
}
|
||||
|
||||
// IsIPv6 check if the string is an IP version 6.
|
||||
func IsIPv6(str string) bool {
|
||||
ip := net.ParseIP(str)
|
||||
return ip != nil && strings.Contains(str, ":")
|
||||
}
|
||||
|
||||
// IsMAC check if a string is valid MAC address.
|
||||
// Possible MAC formats:
|
||||
// 01:23:45:67:89:ab
|
||||
// 01:23:45:67:89:ab:cd:ef
|
||||
// 01-23-45-67-89-ab
|
||||
// 01-23-45-67-89-ab-cd-ef
|
||||
// 0123.4567.89ab
|
||||
// 0123.4567.89ab.cdef
|
||||
func IsMAC(str string) bool {
|
||||
_, err := net.ParseMAC(str)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsSSN will validate the given string as a U.S. Social Security Number
|
||||
func IsSSN(str string) bool {
|
||||
if str == "" || len(str) != 11 {
|
||||
return false
|
||||
}
|
||||
return rxSSN.MatchString(str)
|
||||
}
|
||||
|
||||
// ToInt convert the input string or any int type to an integer type 64, or 0 if the input is not an integer.
|
||||
func ToInt(value interface{}) (res int64, err error) {
|
||||
val := reflect.ValueOf(value)
|
||||
|
||||
switch value.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
res = val.Int()
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
res = int64(val.Uint())
|
||||
case string:
|
||||
if IsInt(val.String()) {
|
||||
res, err = strconv.ParseInt(val.String(), 0, 64)
|
||||
if err != nil {
|
||||
res = 0
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("math: square root of negative number %g", value)
|
||||
res = 0
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("math: square root of negative number %g", value)
|
||||
res = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsInt check if the string is an integer. Empty string is valid.
|
||||
func IsInt(str string) bool {
|
||||
if IsNull(str) {
|
||||
return true
|
||||
}
|
||||
return rxInt.MatchString(str)
|
||||
}
|
||||
|
||||
// IsNull check if the string is null.
|
||||
func IsNull(str string) bool {
|
||||
return len(str) == 0
|
||||
}
|
260
e2e/vendor/k8s.io/kube-openapi/pkg/schemaconv/openapi.go
generated
vendored
Normal file
260
e2e/vendor/k8s.io/kube-openapi/pkg/schemaconv/openapi.go
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
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 schemaconv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
)
|
||||
|
||||
// ToSchemaFromOpenAPI converts a directory of OpenAPI schemas to an smd Schema.
|
||||
// - models: a map from definition name to OpenAPI V3 structural schema for each definition.
|
||||
// Key in map is used to resolve references in the schema.
|
||||
// - preserveUnknownFields: flag indicating whether unknown fields in all schemas should be preserved.
|
||||
// - returns: nil and an error if there is a parse error, or if schema does not satisfy a
|
||||
// required structural schema invariant for conversion. If no error, returns
|
||||
// a new smd schema.
|
||||
//
|
||||
// Schema should be validated as structural before using with this function, or
|
||||
// there may be information lost.
|
||||
func ToSchemaFromOpenAPI(models map[string]*spec.Schema, preserveUnknownFields bool) (*schema.Schema, error) {
|
||||
c := convert{
|
||||
preserveUnknownFields: preserveUnknownFields,
|
||||
output: &schema.Schema{},
|
||||
}
|
||||
|
||||
for name, spec := range models {
|
||||
// Skip/Ignore top-level references
|
||||
if len(spec.Ref.String()) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var a schema.Atom
|
||||
|
||||
// Hard-coded schemas for now as proto_models implementation functions.
|
||||
// https://github.com/kubernetes/kube-openapi/issues/364
|
||||
if name == quantityResource {
|
||||
a = schema.Atom{
|
||||
Scalar: untypedDef.Atom.Scalar,
|
||||
}
|
||||
} else if name == rawExtensionResource {
|
||||
a = untypedDef.Atom
|
||||
} else {
|
||||
c2 := c.push(name, &a)
|
||||
c2.visitSpec(spec)
|
||||
c.pop(c2)
|
||||
}
|
||||
|
||||
c.insertTypeDef(name, a)
|
||||
}
|
||||
|
||||
if len(c.errorMessages) > 0 {
|
||||
return nil, errors.New(strings.Join(c.errorMessages, "\n"))
|
||||
}
|
||||
|
||||
c.addCommonTypes()
|
||||
return c.output, nil
|
||||
}
|
||||
|
||||
func (c *convert) visitSpec(m *spec.Schema) {
|
||||
// Check if this schema opts its descendants into preserve-unknown-fields
|
||||
if p, ok := m.Extensions["x-kubernetes-preserve-unknown-fields"]; ok && p == true {
|
||||
c.preserveUnknownFields = true
|
||||
}
|
||||
a := c.top()
|
||||
*a = c.parseSchema(m)
|
||||
}
|
||||
|
||||
func (c *convert) parseSchema(m *spec.Schema) schema.Atom {
|
||||
// k8s-generated OpenAPI specs have historically used only one value for
|
||||
// type and starting with OpenAPIV3 it is only allowed to be
|
||||
// a single string.
|
||||
typ := ""
|
||||
if len(m.Type) > 0 {
|
||||
typ = m.Type[0]
|
||||
}
|
||||
|
||||
// Structural Schemas produced by kubernetes follow very specific rules which
|
||||
// we can use to infer the SMD type:
|
||||
switch typ {
|
||||
case "":
|
||||
// According to Swagger docs:
|
||||
// https://swagger.io/docs/specification/data-models/data-types/#any
|
||||
//
|
||||
// If no type is specified, it is equivalent to accepting any type.
|
||||
return schema.Atom{
|
||||
Scalar: ptr(schema.Scalar("untyped")),
|
||||
List: c.parseList(m),
|
||||
Map: c.parseObject(m),
|
||||
}
|
||||
|
||||
case "object":
|
||||
return schema.Atom{
|
||||
Map: c.parseObject(m),
|
||||
}
|
||||
case "array":
|
||||
return schema.Atom{
|
||||
List: c.parseList(m),
|
||||
}
|
||||
case "integer", "boolean", "number", "string":
|
||||
return convertPrimitive(typ, m.Format)
|
||||
default:
|
||||
c.reportError("unrecognized type: '%v'", typ)
|
||||
return schema.Atom{
|
||||
Scalar: ptr(schema.Scalar("untyped")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) makeOpenAPIRef(specSchema *spec.Schema) schema.TypeRef {
|
||||
refString := specSchema.Ref.String()
|
||||
|
||||
// Special-case handling for $ref stored inside a single-element allOf
|
||||
if len(refString) == 0 && len(specSchema.AllOf) == 1 && len(specSchema.AllOf[0].Ref.String()) > 0 {
|
||||
refString = specSchema.AllOf[0].Ref.String()
|
||||
}
|
||||
|
||||
if _, n := path.Split(refString); len(n) > 0 {
|
||||
//!TODO: Refactor the field ElementRelationship override
|
||||
// we can generate the types with overrides ahead of time rather than
|
||||
// requiring the hacky runtime support
|
||||
// (could just create a normalized key struct containing all customizations
|
||||
// to deduplicate)
|
||||
mapRelationship, err := getMapElementRelationship(specSchema.Extensions)
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
|
||||
if len(mapRelationship) > 0 {
|
||||
return schema.TypeRef{
|
||||
NamedType: &n,
|
||||
ElementRelationship: &mapRelationship,
|
||||
}
|
||||
}
|
||||
|
||||
return schema.TypeRef{
|
||||
NamedType: &n,
|
||||
}
|
||||
|
||||
}
|
||||
var inlined schema.Atom
|
||||
|
||||
// compute the type inline
|
||||
c2 := c.push("inlined in "+c.currentName, &inlined)
|
||||
c2.preserveUnknownFields = c.preserveUnknownFields
|
||||
c2.visitSpec(specSchema)
|
||||
c.pop(c2)
|
||||
|
||||
return schema.TypeRef{
|
||||
Inlined: inlined,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) parseObject(s *spec.Schema) *schema.Map {
|
||||
var fields []schema.StructField
|
||||
for name, member := range s.Properties {
|
||||
fields = append(fields, schema.StructField{
|
||||
Name: name,
|
||||
Type: c.makeOpenAPIRef(&member),
|
||||
Default: member.Default,
|
||||
})
|
||||
}
|
||||
|
||||
// AdditionalProperties informs the schema of any "unknown" keys
|
||||
// Unknown keys are enforced by the ElementType field.
|
||||
elementType := func() schema.TypeRef {
|
||||
if s.AdditionalProperties == nil {
|
||||
// According to openAPI spec, an object without properties and without
|
||||
// additionalProperties is assumed to be a free-form object.
|
||||
if c.preserveUnknownFields || len(s.Properties) == 0 {
|
||||
return schema.TypeRef{
|
||||
NamedType: &deducedName,
|
||||
}
|
||||
}
|
||||
|
||||
// If properties are specified, do not implicitly allow unknown
|
||||
// fields
|
||||
return schema.TypeRef{}
|
||||
} else if s.AdditionalProperties.Schema != nil {
|
||||
// Unknown fields use the referred schema
|
||||
return c.makeOpenAPIRef(s.AdditionalProperties.Schema)
|
||||
|
||||
} else if s.AdditionalProperties.Allows {
|
||||
// A boolean instead of a schema was provided. Deduce the
|
||||
// type from the value provided at runtime.
|
||||
return schema.TypeRef{
|
||||
NamedType: &deducedName,
|
||||
}
|
||||
} else {
|
||||
// Additional Properties are explicitly disallowed by the user.
|
||||
// Ensure element type is empty.
|
||||
return schema.TypeRef{}
|
||||
}
|
||||
}()
|
||||
|
||||
relationship, err := getMapElementRelationship(s.Extensions)
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
|
||||
return &schema.Map{
|
||||
Fields: fields,
|
||||
ElementRelationship: relationship,
|
||||
ElementType: elementType,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) parseList(s *spec.Schema) *schema.List {
|
||||
relationship, mapKeys, err := getListElementRelationship(s.Extensions)
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
elementType := func() schema.TypeRef {
|
||||
if s.Items != nil {
|
||||
if s.Items.Schema == nil || s.Items.Len() != 1 {
|
||||
c.reportError("structural schema arrays must have exactly one member subtype")
|
||||
return schema.TypeRef{
|
||||
NamedType: &deducedName,
|
||||
}
|
||||
}
|
||||
|
||||
subSchema := s.Items.Schema
|
||||
if subSchema == nil {
|
||||
subSchema = &s.Items.Schemas[0]
|
||||
}
|
||||
return c.makeOpenAPIRef(subSchema)
|
||||
} else if len(s.Type) > 0 && len(s.Type[0]) > 0 {
|
||||
c.reportError("`items` must be specified on arrays")
|
||||
}
|
||||
|
||||
// A list with no items specified is treated as "untyped".
|
||||
return schema.TypeRef{
|
||||
NamedType: &untypedName,
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
return &schema.List{
|
||||
ElementRelationship: relationship,
|
||||
Keys: mapKeys,
|
||||
ElementType: elementType,
|
||||
}
|
||||
}
|
178
e2e/vendor/k8s.io/kube-openapi/pkg/schemaconv/proto_models.go
generated
vendored
Normal file
178
e2e/vendor/k8s.io/kube-openapi/pkg/schemaconv/proto_models.go
generated
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
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 schemaconv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
)
|
||||
|
||||
// ToSchema converts openapi definitions into a schema suitable for structured
|
||||
// merge (i.e. kubectl apply v2).
|
||||
func ToSchema(models proto.Models) (*schema.Schema, error) {
|
||||
return ToSchemaWithPreserveUnknownFields(models, false)
|
||||
}
|
||||
|
||||
// ToSchemaWithPreserveUnknownFields converts openapi definitions into a schema suitable for structured
|
||||
// merge (i.e. kubectl apply v2), it will preserve unknown fields if specified.
|
||||
func ToSchemaWithPreserveUnknownFields(models proto.Models, preserveUnknownFields bool) (*schema.Schema, error) {
|
||||
c := convert{
|
||||
preserveUnknownFields: preserveUnknownFields,
|
||||
output: &schema.Schema{},
|
||||
}
|
||||
for _, name := range models.ListModels() {
|
||||
model := models.LookupModel(name)
|
||||
|
||||
var a schema.Atom
|
||||
c2 := c.push(name, &a)
|
||||
model.Accept(c2)
|
||||
c.pop(c2)
|
||||
|
||||
c.insertTypeDef(name, a)
|
||||
}
|
||||
|
||||
if len(c.errorMessages) > 0 {
|
||||
return nil, errors.New(strings.Join(c.errorMessages, "\n"))
|
||||
}
|
||||
|
||||
c.addCommonTypes()
|
||||
return c.output, nil
|
||||
}
|
||||
|
||||
func (c *convert) makeRef(model proto.Schema, preserveUnknownFields bool) schema.TypeRef {
|
||||
var tr schema.TypeRef
|
||||
if r, ok := model.(*proto.Ref); ok {
|
||||
if r.Reference() == "io.k8s.apimachinery.pkg.runtime.RawExtension" {
|
||||
return schema.TypeRef{
|
||||
NamedType: &untypedName,
|
||||
}
|
||||
}
|
||||
// reference a named type
|
||||
_, n := path.Split(r.Reference())
|
||||
tr.NamedType = &n
|
||||
|
||||
mapRelationship, err := getMapElementRelationship(model.GetExtensions())
|
||||
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
|
||||
// empty string means unset.
|
||||
if len(mapRelationship) > 0 {
|
||||
tr.ElementRelationship = &mapRelationship
|
||||
}
|
||||
} else {
|
||||
// compute the type inline
|
||||
c2 := c.push("inlined in "+c.currentName, &tr.Inlined)
|
||||
c2.preserveUnknownFields = preserveUnknownFields
|
||||
model.Accept(c2)
|
||||
c.pop(c2)
|
||||
|
||||
if tr == (schema.TypeRef{}) {
|
||||
// emit warning?
|
||||
tr.NamedType = &untypedName
|
||||
}
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
func (c *convert) VisitKind(k *proto.Kind) {
|
||||
preserveUnknownFields := c.preserveUnknownFields
|
||||
if p, ok := k.GetExtensions()["x-kubernetes-preserve-unknown-fields"]; ok && p == true {
|
||||
preserveUnknownFields = true
|
||||
}
|
||||
|
||||
a := c.top()
|
||||
a.Map = &schema.Map{}
|
||||
for _, name := range k.FieldOrder {
|
||||
member := k.Fields[name]
|
||||
tr := c.makeRef(member, preserveUnknownFields)
|
||||
a.Map.Fields = append(a.Map.Fields, schema.StructField{
|
||||
Name: name,
|
||||
Type: tr,
|
||||
Default: member.GetDefault(),
|
||||
})
|
||||
}
|
||||
|
||||
unions, err := makeUnions(k.GetExtensions())
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
return
|
||||
}
|
||||
// TODO: We should check that the fields and discriminator
|
||||
// specified in the union are actual fields in the struct.
|
||||
a.Map.Unions = unions
|
||||
|
||||
if preserveUnknownFields {
|
||||
a.Map.ElementType = schema.TypeRef{
|
||||
NamedType: &deducedName,
|
||||
}
|
||||
}
|
||||
|
||||
a.Map.ElementRelationship, err = getMapElementRelationship(k.GetExtensions())
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) VisitArray(a *proto.Array) {
|
||||
relationship, mapKeys, err := getListElementRelationship(a.GetExtensions())
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
|
||||
atom := c.top()
|
||||
atom.List = &schema.List{
|
||||
ElementType: c.makeRef(a.SubType, c.preserveUnknownFields),
|
||||
ElementRelationship: relationship,
|
||||
Keys: mapKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) VisitMap(m *proto.Map) {
|
||||
relationship, err := getMapElementRelationship(m.GetExtensions())
|
||||
if err != nil {
|
||||
c.reportError(err.Error())
|
||||
}
|
||||
|
||||
a := c.top()
|
||||
a.Map = &schema.Map{
|
||||
ElementType: c.makeRef(m.SubType, c.preserveUnknownFields),
|
||||
ElementRelationship: relationship,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) VisitPrimitive(p *proto.Primitive) {
|
||||
a := c.top()
|
||||
if c.currentName == quantityResource {
|
||||
a.Scalar = ptr(schema.Scalar("untyped"))
|
||||
} else {
|
||||
*a = convertPrimitive(p.Type, p.Format)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) VisitArbitrary(a *proto.Arbitrary) {
|
||||
*c.top() = deducedDef.Atom
|
||||
}
|
||||
|
||||
func (c *convert) VisitReference(proto.Reference) {
|
||||
// Do nothing, we handle references specially
|
||||
}
|
334
e2e/vendor/k8s.io/kube-openapi/pkg/schemaconv/smd.go
generated
vendored
Normal file
334
e2e/vendor/k8s.io/kube-openapi/pkg/schemaconv/smd.go
generated
vendored
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
Copyright 2017 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 schemaconv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
quantityResource = "io.k8s.apimachinery.pkg.api.resource.Quantity"
|
||||
rawExtensionResource = "io.k8s.apimachinery.pkg.runtime.RawExtension"
|
||||
)
|
||||
|
||||
type convert struct {
|
||||
preserveUnknownFields bool
|
||||
output *schema.Schema
|
||||
|
||||
currentName string
|
||||
current *schema.Atom
|
||||
errorMessages []string
|
||||
}
|
||||
|
||||
func (c *convert) push(name string, a *schema.Atom) *convert {
|
||||
return &convert{
|
||||
preserveUnknownFields: c.preserveUnknownFields,
|
||||
output: c.output,
|
||||
currentName: name,
|
||||
current: a,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) top() *schema.Atom { return c.current }
|
||||
|
||||
func (c *convert) pop(c2 *convert) {
|
||||
c.errorMessages = append(c.errorMessages, c2.errorMessages...)
|
||||
}
|
||||
|
||||
func (c *convert) reportError(format string, args ...interface{}) {
|
||||
c.errorMessages = append(c.errorMessages,
|
||||
c.currentName+": "+fmt.Sprintf(format, args...),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *convert) insertTypeDef(name string, atom schema.Atom) {
|
||||
def := schema.TypeDef{
|
||||
Name: name,
|
||||
Atom: atom,
|
||||
}
|
||||
if def.Atom == (schema.Atom{}) {
|
||||
// This could happen if there were a top-level reference.
|
||||
return
|
||||
}
|
||||
c.output.Types = append(c.output.Types, def)
|
||||
}
|
||||
|
||||
func (c *convert) addCommonTypes() {
|
||||
c.output.Types = append(c.output.Types, untypedDef)
|
||||
c.output.Types = append(c.output.Types, deducedDef)
|
||||
}
|
||||
|
||||
var untypedName string = "__untyped_atomic_"
|
||||
|
||||
var untypedDef schema.TypeDef = schema.TypeDef{
|
||||
Name: untypedName,
|
||||
Atom: schema.Atom{
|
||||
Scalar: ptr(schema.Scalar("untyped")),
|
||||
List: &schema.List{
|
||||
ElementType: schema.TypeRef{
|
||||
NamedType: &untypedName,
|
||||
},
|
||||
ElementRelationship: schema.Atomic,
|
||||
},
|
||||
Map: &schema.Map{
|
||||
ElementType: schema.TypeRef{
|
||||
NamedType: &untypedName,
|
||||
},
|
||||
ElementRelationship: schema.Atomic,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var deducedName string = "__untyped_deduced_"
|
||||
|
||||
var deducedDef schema.TypeDef = schema.TypeDef{
|
||||
Name: deducedName,
|
||||
Atom: schema.Atom{
|
||||
Scalar: ptr(schema.Scalar("untyped")),
|
||||
List: &schema.List{
|
||||
ElementType: schema.TypeRef{
|
||||
NamedType: &untypedName,
|
||||
},
|
||||
ElementRelationship: schema.Atomic,
|
||||
},
|
||||
Map: &schema.Map{
|
||||
ElementType: schema.TypeRef{
|
||||
NamedType: &deducedName,
|
||||
},
|
||||
ElementRelationship: schema.Separable,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func makeUnions(extensions map[string]interface{}) ([]schema.Union, error) {
|
||||
schemaUnions := []schema.Union{}
|
||||
if iunions, ok := extensions["x-kubernetes-unions"]; ok {
|
||||
unions, ok := iunions.([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"x-kubernetes-unions" should be a list, got %#v`, unions)
|
||||
}
|
||||
for _, iunion := range unions {
|
||||
union, ok := iunion.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"x-kubernetes-unions" items should be a map of string to unions, got %#v`, iunion)
|
||||
}
|
||||
unionMap := map[string]interface{}{}
|
||||
for k, v := range union {
|
||||
key, ok := k.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"x-kubernetes-unions" has non-string key: %#v`, k)
|
||||
}
|
||||
unionMap[key] = v
|
||||
}
|
||||
schemaUnion, err := makeUnion(unionMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
schemaUnions = append(schemaUnions, schemaUnion)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we have no overlap between unions
|
||||
fs := map[string]struct{}{}
|
||||
for _, u := range schemaUnions {
|
||||
if u.Discriminator != nil {
|
||||
if _, ok := fs[*u.Discriminator]; ok {
|
||||
return nil, fmt.Errorf("%v field appears multiple times in unions", *u.Discriminator)
|
||||
}
|
||||
fs[*u.Discriminator] = struct{}{}
|
||||
}
|
||||
for _, f := range u.Fields {
|
||||
if _, ok := fs[f.FieldName]; ok {
|
||||
return nil, fmt.Errorf("%v field appears multiple times in unions", f.FieldName)
|
||||
}
|
||||
fs[f.FieldName] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return schemaUnions, nil
|
||||
}
|
||||
|
||||
func makeUnion(extensions map[string]interface{}) (schema.Union, error) {
|
||||
union := schema.Union{
|
||||
Fields: []schema.UnionField{},
|
||||
}
|
||||
|
||||
if idiscriminator, ok := extensions["discriminator"]; ok {
|
||||
discriminator, ok := idiscriminator.(string)
|
||||
if !ok {
|
||||
return schema.Union{}, fmt.Errorf(`"discriminator" must be a string, got: %#v`, idiscriminator)
|
||||
}
|
||||
union.Discriminator = &discriminator
|
||||
}
|
||||
|
||||
if ifields, ok := extensions["fields-to-discriminateBy"]; ok {
|
||||
fields, ok := ifields.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
return schema.Union{}, fmt.Errorf(`"fields-to-discriminateBy" must be a map[string]string, got: %#v`, ifields)
|
||||
}
|
||||
// Needs sorted keys by field.
|
||||
keys := []string{}
|
||||
for ifield := range fields {
|
||||
field, ok := ifield.(string)
|
||||
if !ok {
|
||||
return schema.Union{}, fmt.Errorf(`"fields-to-discriminateBy": field must be a string, got: %#v`, ifield)
|
||||
}
|
||||
keys = append(keys, field)
|
||||
|
||||
}
|
||||
sort.Strings(keys)
|
||||
reverseMap := map[string]struct{}{}
|
||||
for _, field := range keys {
|
||||
value := fields[field]
|
||||
discriminated, ok := value.(string)
|
||||
if !ok {
|
||||
return schema.Union{}, fmt.Errorf(`"fields-to-discriminateBy"/%v: value must be a string, got: %#v`, field, value)
|
||||
}
|
||||
union.Fields = append(union.Fields, schema.UnionField{
|
||||
FieldName: field,
|
||||
DiscriminatorValue: discriminated,
|
||||
})
|
||||
|
||||
// Check that we don't have the same discriminateBy multiple times.
|
||||
if _, ok := reverseMap[discriminated]; ok {
|
||||
return schema.Union{}, fmt.Errorf("Multiple fields have the same discriminated name: %v", discriminated)
|
||||
}
|
||||
reverseMap[discriminated] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return union, nil
|
||||
}
|
||||
|
||||
func toStringSlice(o interface{}) (out []string, ok bool) {
|
||||
switch t := o.(type) {
|
||||
case []interface{}:
|
||||
for _, v := range t {
|
||||
switch vt := v.(type) {
|
||||
case string:
|
||||
out = append(out, vt)
|
||||
}
|
||||
}
|
||||
return out, true
|
||||
case []string:
|
||||
return t, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func ptr(s schema.Scalar) *schema.Scalar { return &s }
|
||||
|
||||
// Basic conversion functions to convert OpenAPI schema definitions to
|
||||
// SMD Schema atoms
|
||||
func convertPrimitive(typ string, format string) (a schema.Atom) {
|
||||
switch typ {
|
||||
case "integer":
|
||||
a.Scalar = ptr(schema.Numeric)
|
||||
case "number":
|
||||
a.Scalar = ptr(schema.Numeric)
|
||||
case "string":
|
||||
switch format {
|
||||
case "":
|
||||
a.Scalar = ptr(schema.String)
|
||||
case "byte":
|
||||
// byte really means []byte and is encoded as a string.
|
||||
a.Scalar = ptr(schema.String)
|
||||
case "int-or-string":
|
||||
a.Scalar = ptr(schema.Scalar("untyped"))
|
||||
case "date-time":
|
||||
a.Scalar = ptr(schema.Scalar("untyped"))
|
||||
default:
|
||||
a.Scalar = ptr(schema.Scalar("untyped"))
|
||||
}
|
||||
case "boolean":
|
||||
a.Scalar = ptr(schema.Boolean)
|
||||
default:
|
||||
a.Scalar = ptr(schema.Scalar("untyped"))
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func getListElementRelationship(ext map[string]any) (schema.ElementRelationship, []string, error) {
|
||||
if val, ok := ext["x-kubernetes-list-type"]; ok {
|
||||
switch val {
|
||||
case "atomic":
|
||||
return schema.Atomic, nil, nil
|
||||
case "set":
|
||||
return schema.Associative, nil, nil
|
||||
case "map":
|
||||
keys, ok := ext["x-kubernetes-list-map-keys"]
|
||||
|
||||
if !ok {
|
||||
return schema.Associative, nil, fmt.Errorf("missing map keys")
|
||||
}
|
||||
|
||||
keyNames, ok := toStringSlice(keys)
|
||||
if !ok {
|
||||
return schema.Associative, nil, fmt.Errorf("uninterpreted map keys: %#v", keys)
|
||||
}
|
||||
|
||||
return schema.Associative, keyNames, nil
|
||||
default:
|
||||
return schema.Atomic, nil, fmt.Errorf("unknown list type %v", val)
|
||||
}
|
||||
} else if val, ok := ext["x-kubernetes-patch-strategy"]; ok {
|
||||
switch val {
|
||||
case "merge", "merge,retainKeys":
|
||||
if key, ok := ext["x-kubernetes-patch-merge-key"]; ok {
|
||||
keyName, ok := key.(string)
|
||||
|
||||
if !ok {
|
||||
return schema.Associative, nil, fmt.Errorf("uninterpreted merge key: %#v", key)
|
||||
}
|
||||
|
||||
return schema.Associative, []string{keyName}, nil
|
||||
}
|
||||
// It's not an error for x-kubernetes-patch-merge-key to be absent,
|
||||
// it means it's a set
|
||||
return schema.Associative, nil, nil
|
||||
case "retainKeys":
|
||||
return schema.Atomic, nil, nil
|
||||
default:
|
||||
return schema.Atomic, nil, fmt.Errorf("unknown patch strategy %v", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Treat as atomic by default
|
||||
return schema.Atomic, nil, nil
|
||||
}
|
||||
|
||||
// Returns map element relationship if specified, or empty string if unspecified
|
||||
func getMapElementRelationship(ext map[string]any) (schema.ElementRelationship, error) {
|
||||
val, ok := ext["x-kubernetes-map-type"]
|
||||
if !ok {
|
||||
// unset Map element relationship
|
||||
return "", nil
|
||||
}
|
||||
|
||||
switch val {
|
||||
case "atomic":
|
||||
return schema.Atomic, nil
|
||||
case "granular":
|
||||
return schema.Separable, nil
|
||||
default:
|
||||
return "", fmt.Errorf("unknown map type %v", val)
|
||||
}
|
||||
}
|
519
e2e/vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go
generated
vendored
Normal file
519
e2e/vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go
generated
vendored
Normal file
@ -0,0 +1,519 @@
|
||||
/*
|
||||
Copyright 2017 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 schemamutation
|
||||
|
||||
import (
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Walker runs callback functions on all references of an OpenAPI spec,
|
||||
// replacing the values when visiting corresponding types.
|
||||
type Walker struct {
|
||||
// SchemaCallback will be called on each schema, taking the original schema,
|
||||
// and before any other callbacks of the Walker.
|
||||
// If the schema needs to be mutated, DO NOT mutate it in-place,
|
||||
// always create a copy, mutate, and return it.
|
||||
SchemaCallback func(schema *spec.Schema) *spec.Schema
|
||||
|
||||
// RefCallback will be called on each ref.
|
||||
// If the ref needs to be mutated, DO NOT mutate it in-place,
|
||||
// always create a copy, mutate, and return it.
|
||||
RefCallback func(ref *spec.Ref) *spec.Ref
|
||||
}
|
||||
|
||||
type SchemaCallbackFunc func(schema *spec.Schema) *spec.Schema
|
||||
type RefCallbackFunc func(ref *spec.Ref) *spec.Ref
|
||||
|
||||
var SchemaCallBackNoop SchemaCallbackFunc = func(schema *spec.Schema) *spec.Schema {
|
||||
return schema
|
||||
}
|
||||
var RefCallbackNoop RefCallbackFunc = func(ref *spec.Ref) *spec.Ref {
|
||||
return ref
|
||||
}
|
||||
|
||||
// ReplaceReferences rewrites the references without mutating the input.
|
||||
// The output might share data with the input.
|
||||
func ReplaceReferences(walkRef func(ref *spec.Ref) *spec.Ref, sp *spec.Swagger) *spec.Swagger {
|
||||
walker := &Walker{RefCallback: walkRef, SchemaCallback: SchemaCallBackNoop}
|
||||
return walker.WalkRoot(sp)
|
||||
}
|
||||
|
||||
func (w *Walker) WalkSchema(schema *spec.Schema) *spec.Schema {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = &spec.Schema{}
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
|
||||
// Always run callback on the whole schema first
|
||||
// so that SchemaCallback can take the original schema as input.
|
||||
schema = w.SchemaCallback(schema)
|
||||
|
||||
if r := w.RefCallback(&schema.Ref); r != &schema.Ref {
|
||||
clone()
|
||||
schema.Ref = *r
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range schema.Definitions {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
schema.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
schema.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
propertiesCloned := false
|
||||
for k, v := range schema.Properties {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !propertiesCloned {
|
||||
propertiesCloned = true
|
||||
clone()
|
||||
schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
|
||||
for k2, v2 := range orig.Properties {
|
||||
schema.Properties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Properties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
patternPropertiesCloned := false
|
||||
for k, v := range schema.PatternProperties {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !patternPropertiesCloned {
|
||||
patternPropertiesCloned = true
|
||||
clone()
|
||||
schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
|
||||
for k2, v2 := range orig.PatternProperties {
|
||||
schema.PatternProperties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.PatternProperties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
allOfCloned := false
|
||||
for i := range schema.AllOf {
|
||||
if s := w.WalkSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
|
||||
if !allOfCloned {
|
||||
allOfCloned = true
|
||||
clone()
|
||||
schema.AllOf = make([]spec.Schema, len(orig.AllOf))
|
||||
copy(schema.AllOf, orig.AllOf)
|
||||
}
|
||||
schema.AllOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
anyOfCloned := false
|
||||
for i := range schema.AnyOf {
|
||||
if s := w.WalkSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
|
||||
if !anyOfCloned {
|
||||
anyOfCloned = true
|
||||
clone()
|
||||
schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
|
||||
copy(schema.AnyOf, orig.AnyOf)
|
||||
}
|
||||
schema.AnyOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
oneOfCloned := false
|
||||
for i := range schema.OneOf {
|
||||
if s := w.WalkSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
|
||||
if !oneOfCloned {
|
||||
oneOfCloned = true
|
||||
clone()
|
||||
schema.OneOf = make([]spec.Schema, len(orig.OneOf))
|
||||
copy(schema.OneOf, orig.OneOf)
|
||||
}
|
||||
schema.OneOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Not != nil {
|
||||
if s := w.WalkSchema(schema.Not); s != schema.Not {
|
||||
clone()
|
||||
schema.Not = s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
if s := w.WalkSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
|
||||
clone()
|
||||
schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
if s := w.WalkSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
|
||||
clone()
|
||||
schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
if s := w.WalkSchema(schema.Items.Schema); s != schema.Items.Schema {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{Schema: s}
|
||||
}
|
||||
} else {
|
||||
itemsCloned := false
|
||||
for i := range schema.Items.Schemas {
|
||||
if s := w.WalkSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
|
||||
if !itemsCloned {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{
|
||||
Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
|
||||
}
|
||||
itemsCloned = true
|
||||
copy(schema.Items.Schemas, orig.Items.Schemas)
|
||||
}
|
||||
schema.Items.Schemas[i] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
func (w *Walker) walkParameter(param *spec.Parameter) *spec.Parameter {
|
||||
if param == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := param
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
param = &spec.Parameter{}
|
||||
*param = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.RefCallback(¶m.Ref); r != ¶m.Ref {
|
||||
clone()
|
||||
param.Ref = *r
|
||||
}
|
||||
if s := w.WalkSchema(param.Schema); s != param.Schema {
|
||||
clone()
|
||||
param.Schema = s
|
||||
}
|
||||
if param.Items != nil {
|
||||
if r := w.RefCallback(¶m.Items.Ref); r != ¶m.Items.Ref {
|
||||
param.Items.Ref = *r
|
||||
}
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
|
||||
func (w *Walker) walkParameters(params []spec.Parameter) ([]spec.Parameter, bool) {
|
||||
if params == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
orig := params
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
params = make([]spec.Parameter, len(params))
|
||||
copy(params, orig)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range params {
|
||||
if s := w.walkParameter(¶ms[i]); s != ¶ms[i] {
|
||||
clone()
|
||||
params[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
return params, cloned
|
||||
}
|
||||
|
||||
func (w *Walker) walkResponse(resp *spec.Response) *spec.Response {
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := resp
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
resp = &spec.Response{}
|
||||
*resp = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.RefCallback(&resp.Ref); r != &resp.Ref {
|
||||
clone()
|
||||
resp.Ref = *r
|
||||
}
|
||||
if s := w.WalkSchema(resp.Schema); s != resp.Schema {
|
||||
clone()
|
||||
resp.Schema = s
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (w *Walker) walkResponses(resps *spec.Responses) *spec.Responses {
|
||||
if resps == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := resps
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
resps = &spec.Responses{}
|
||||
*resps = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.walkResponse(resps.ResponsesProps.Default); r != resps.ResponsesProps.Default {
|
||||
clone()
|
||||
resps.Default = r
|
||||
}
|
||||
|
||||
responsesCloned := false
|
||||
for k, v := range resps.ResponsesProps.StatusCodeResponses {
|
||||
if r := w.walkResponse(&v); r != &v {
|
||||
if !responsesCloned {
|
||||
responsesCloned = true
|
||||
clone()
|
||||
resps.ResponsesProps.StatusCodeResponses = make(map[int]spec.Response, len(orig.StatusCodeResponses))
|
||||
for k2, v2 := range orig.StatusCodeResponses {
|
||||
resps.ResponsesProps.StatusCodeResponses[k2] = v2
|
||||
}
|
||||
}
|
||||
resps.ResponsesProps.StatusCodeResponses[k] = *r
|
||||
}
|
||||
}
|
||||
|
||||
return resps
|
||||
}
|
||||
|
||||
func (w *Walker) walkOperation(op *spec.Operation) *spec.Operation {
|
||||
if op == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := op
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
op = &spec.Operation{}
|
||||
*op = *orig
|
||||
}
|
||||
}
|
||||
|
||||
parametersCloned := false
|
||||
for i := range op.Parameters {
|
||||
if s := w.walkParameter(&op.Parameters[i]); s != &op.Parameters[i] {
|
||||
if !parametersCloned {
|
||||
parametersCloned = true
|
||||
clone()
|
||||
op.Parameters = make([]spec.Parameter, len(orig.Parameters))
|
||||
copy(op.Parameters, orig.Parameters)
|
||||
}
|
||||
op.Parameters[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.walkResponses(op.Responses); r != op.Responses {
|
||||
clone()
|
||||
op.Responses = r
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
func (w *Walker) walkPathItem(pathItem *spec.PathItem) *spec.PathItem {
|
||||
if pathItem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := pathItem
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
pathItem = &spec.PathItem{}
|
||||
*pathItem = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if p, changed := w.walkParameters(pathItem.Parameters); changed {
|
||||
clone()
|
||||
pathItem.Parameters = p
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Get); op != pathItem.Get {
|
||||
clone()
|
||||
pathItem.Get = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Head); op != pathItem.Head {
|
||||
clone()
|
||||
pathItem.Head = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Delete); op != pathItem.Delete {
|
||||
clone()
|
||||
pathItem.Delete = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Options); op != pathItem.Options {
|
||||
clone()
|
||||
pathItem.Options = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Patch); op != pathItem.Patch {
|
||||
clone()
|
||||
pathItem.Patch = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Post); op != pathItem.Post {
|
||||
clone()
|
||||
pathItem.Post = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Put); op != pathItem.Put {
|
||||
clone()
|
||||
pathItem.Put = op
|
||||
}
|
||||
|
||||
return pathItem
|
||||
}
|
||||
|
||||
func (w *Walker) walkPaths(paths *spec.Paths) *spec.Paths {
|
||||
if paths == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := paths
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
paths = &spec.Paths{}
|
||||
*paths = *orig
|
||||
}
|
||||
}
|
||||
|
||||
pathsCloned := false
|
||||
for k, v := range paths.Paths {
|
||||
if p := w.walkPathItem(&v); p != &v {
|
||||
if !pathsCloned {
|
||||
pathsCloned = true
|
||||
clone()
|
||||
paths.Paths = make(map[string]spec.PathItem, len(orig.Paths))
|
||||
for k2, v2 := range orig.Paths {
|
||||
paths.Paths[k2] = v2
|
||||
}
|
||||
}
|
||||
paths.Paths[k] = *p
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
func (w *Walker) WalkRoot(swagger *spec.Swagger) *spec.Swagger {
|
||||
if swagger == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := swagger
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
swagger = &spec.Swagger{}
|
||||
*swagger = *orig
|
||||
}
|
||||
}
|
||||
|
||||
parametersCloned := false
|
||||
for k, v := range swagger.Parameters {
|
||||
if p := w.walkParameter(&v); p != &v {
|
||||
if !parametersCloned {
|
||||
parametersCloned = true
|
||||
clone()
|
||||
swagger.Parameters = make(map[string]spec.Parameter, len(orig.Parameters))
|
||||
for k2, v2 := range orig.Parameters {
|
||||
swagger.Parameters[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Parameters[k] = *p
|
||||
}
|
||||
}
|
||||
|
||||
responsesCloned := false
|
||||
for k, v := range swagger.Responses {
|
||||
if r := w.walkResponse(&v); r != &v {
|
||||
if !responsesCloned {
|
||||
responsesCloned = true
|
||||
clone()
|
||||
swagger.Responses = make(map[string]spec.Response, len(orig.Responses))
|
||||
for k2, v2 := range orig.Responses {
|
||||
swagger.Responses[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Responses[k] = *r
|
||||
}
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range swagger.Definitions {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
swagger.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
swagger.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if swagger.Paths != nil {
|
||||
if p := w.walkPaths(swagger.Paths); p != swagger.Paths {
|
||||
clone()
|
||||
swagger.Paths = p
|
||||
}
|
||||
}
|
||||
|
||||
return swagger
|
||||
}
|
47
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/component.go
generated
vendored
Normal file
47
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/component.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
// Components holds a set of reusable objects for different aspects of the OAS.
|
||||
// All objects defined within the components object will have no effect on the API
|
||||
// unless they are explicitly referenced from properties outside the components object.
|
||||
//
|
||||
// more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject
|
||||
type Components struct {
|
||||
// Schemas holds reusable Schema Objects
|
||||
Schemas map[string]*spec.Schema `json:"schemas,omitempty"`
|
||||
// SecuritySchemes holds reusable Security Scheme Objects, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
|
||||
SecuritySchemes SecuritySchemes `json:"securitySchemes,omitempty"`
|
||||
// Responses holds reusable Responses Objects
|
||||
Responses map[string]*Response `json:"responses,omitempty"`
|
||||
// Parameters holds reusable Parameters Objects
|
||||
Parameters map[string]*Parameter `json:"parameters,omitempty"`
|
||||
// Example holds reusable Example objects
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
// RequestBodies holds reusable Request Body objects
|
||||
RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty"`
|
||||
// Links is a map of operations links that can be followed from the response
|
||||
Links map[string]*Link `json:"links,omitempty"`
|
||||
// Headers holds a maps of a headers name to its definition
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
// all fields are defined at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject
|
||||
}
|
||||
|
||||
// SecuritySchemes holds reusable Security Scheme Objects, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
|
||||
type SecuritySchemes map[string]*SecurityScheme
|
105
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go
generated
vendored
Normal file
105
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
type Encoding struct {
|
||||
EncodingProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Encoding as JSON
|
||||
func (e *Encoding) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(e)
|
||||
}
|
||||
b1, err := json.Marshal(e.EncodingProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(e.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (e *Encoding) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
EncodingProps encodingPropsOmitZero `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(e.Extensions)
|
||||
x.EncodingProps = encodingPropsOmitZero(e.EncodingProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (e *Encoding) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, e)
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.EncodingProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoding) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
EncodingProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
e.EncodingProps = x.EncodingProps
|
||||
return nil
|
||||
}
|
||||
|
||||
type EncodingProps struct {
|
||||
// Content Type for encoding a specific property
|
||||
ContentType string `json:"contentType,omitempty"`
|
||||
// A map allowing additional information to be provided as headers
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
// Describes how a specific property value will be serialized depending on its type
|
||||
Style string `json:"style,omitempty"`
|
||||
// When this is true, property values of type array or object generate separate parameters for each value of the array, or key-value-pair of the map. For other types of properties this property has no effect
|
||||
Explode bool `json:"explode,omitempty"`
|
||||
// AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986
|
||||
AllowReserved bool `json:"allowReserved,omitempty"`
|
||||
}
|
||||
|
||||
type encodingPropsOmitZero struct {
|
||||
ContentType string `json:"contentType,omitempty"`
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
Style string `json:"style,omitempty"`
|
||||
Explode bool `json:"explode,omitzero"`
|
||||
AllowReserved bool `json:"allowReserved,omitzero"`
|
||||
}
|
110
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/example.go
generated
vendored
Normal file
110
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/example.go
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Example https://swagger.io/specification/#example-object
|
||||
|
||||
type Example struct {
|
||||
spec.Refable
|
||||
ExampleProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode RequestBody as JSON
|
||||
func (e *Example) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(e)
|
||||
}
|
||||
b1, err := json.Marshal(e.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(e.ExampleProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(e.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
func (e *Example) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
ExampleProps `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Ref = e.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(e.Extensions)
|
||||
x.ExampleProps = e.ExampleProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (e *Example) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, e)
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.ExampleProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Example) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
ExampleProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&e.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
e.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
e.ExampleProps = x.ExampleProps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExampleProps struct {
|
||||
// Summary holds a short description of the example
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Description holds a long description of the example
|
||||
Description string `json:"description,omitempty"`
|
||||
// Embedded literal example.
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
// A URL that points to the literal example. This provides the capability to reference examples that cannot easily be included in JSON or YAML documents.
|
||||
ExternalValue string `json:"externalValue,omitempty"`
|
||||
}
|
90
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go
generated
vendored
Normal file
90
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
type ExternalDocumentation struct {
|
||||
ExternalDocumentationProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
type ExternalDocumentationProps struct {
|
||||
// Description is a short description of the target documentation. CommonMark syntax MAY be used for rich text representation.
|
||||
Description string `json:"description,omitempty"`
|
||||
// URL is the URL for the target documentation.
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (e *ExternalDocumentation) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(e)
|
||||
}
|
||||
b1, err := json.Marshal(e.ExternalDocumentationProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(e.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (e *ExternalDocumentation) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
ExternalDocumentationProps `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(e.Extensions)
|
||||
x.ExternalDocumentationProps = e.ExternalDocumentationProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (e *ExternalDocumentation) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, e)
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.ExternalDocumentationProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &e.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ExternalDocumentation) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
ExternalDocumentationProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
e.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
e.ExternalDocumentationProps = x.ExternalDocumentationProps
|
||||
return nil
|
||||
}
|
281
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go
generated
vendored
Normal file
281
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,281 @@
|
||||
package spec3
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// refChance is the chance that a particular component will use a $ref
|
||||
// instead of fuzzed. Expressed as a fraction 1/n, currently there is
|
||||
// a 1/3 chance that a ref will be used.
|
||||
const refChance = 3
|
||||
|
||||
const alphaNumChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
func randAlphanumString() string {
|
||||
arr := make([]string, rand.Intn(10)+5)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
arr[i] = string(alphaNumChars[rand.Intn(len(alphaNumChars))])
|
||||
}
|
||||
return strings.Join(arr, "")
|
||||
}
|
||||
|
||||
var OpenAPIV3FuzzFuncs []interface{} = []interface{}{
|
||||
func(s *string, c fuzz.Continue) {
|
||||
// All OpenAPI V3 map keys must follow the corresponding
|
||||
// regex. Note that this restricts the range for all other
|
||||
// string values as well.
|
||||
str := randAlphanumString()
|
||||
*s = str
|
||||
},
|
||||
func(o *OpenAPI, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(o)
|
||||
o.Version = "3.0.0"
|
||||
for i, val := range o.SecurityRequirement {
|
||||
if val == nil {
|
||||
o.SecurityRequirement[i] = make(map[string][]string)
|
||||
}
|
||||
|
||||
for k, v := range val {
|
||||
if v == nil {
|
||||
val[k] = make([]string, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
func(r *interface{}, c fuzz.Continue) {
|
||||
switch c.Intn(3) {
|
||||
case 0:
|
||||
*r = nil
|
||||
case 1:
|
||||
n := c.RandString() + "x"
|
||||
*r = n
|
||||
case 2:
|
||||
n := c.Float64()
|
||||
*r = n
|
||||
}
|
||||
},
|
||||
func(v **spec.Info, c fuzz.Continue) {
|
||||
// Info is never nil
|
||||
*v = &spec.Info{}
|
||||
c.FuzzNoCustom(*v)
|
||||
(*v).Title = c.RandString() + "x"
|
||||
},
|
||||
func(v *Paths, c fuzz.Continue) {
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
num := c.Intn(5)
|
||||
if num > 0 {
|
||||
v.Paths = make(map[string]*Path)
|
||||
}
|
||||
for i := 0; i < num; i++ {
|
||||
val := Path{}
|
||||
c.Fuzz(&val)
|
||||
v.Paths["/"+c.RandString()] = &val
|
||||
}
|
||||
},
|
||||
func(v *SecurityScheme, c fuzz.Continue) {
|
||||
if c.Intn(refChance) == 0 {
|
||||
c.Fuzz(&v.Refable)
|
||||
return
|
||||
}
|
||||
switch c.Intn(4) {
|
||||
case 0:
|
||||
v.Type = "apiKey"
|
||||
v.Name = c.RandString() + "x"
|
||||
switch c.Intn(3) {
|
||||
case 0:
|
||||
v.In = "query"
|
||||
case 1:
|
||||
v.In = "header"
|
||||
case 2:
|
||||
v.In = "cookie"
|
||||
}
|
||||
case 1:
|
||||
v.Type = "http"
|
||||
case 2:
|
||||
v.Type = "oauth2"
|
||||
v.Flows = make(map[string]*OAuthFlow)
|
||||
flow := OAuthFlow{}
|
||||
flow.AuthorizationUrl = c.RandString() + "x"
|
||||
v.Flows["implicit"] = &flow
|
||||
flow.Scopes = make(map[string]string)
|
||||
flow.Scopes["foo"] = "bar"
|
||||
case 3:
|
||||
v.Type = "openIdConnect"
|
||||
v.OpenIdConnectUrl = "https://" + c.RandString()
|
||||
}
|
||||
v.Scheme = "basic"
|
||||
},
|
||||
func(v *spec.Ref, c fuzz.Continue) {
|
||||
switch c.Intn(7) {
|
||||
case 0:
|
||||
*v = spec.MustCreateRef("#/components/schemas/" + randAlphanumString())
|
||||
case 1:
|
||||
*v = spec.MustCreateRef("#/components/responses/" + randAlphanumString())
|
||||
case 2:
|
||||
*v = spec.MustCreateRef("#/components/headers/" + randAlphanumString())
|
||||
case 3:
|
||||
*v = spec.MustCreateRef("#/components/securitySchemes/" + randAlphanumString())
|
||||
case 5:
|
||||
*v = spec.MustCreateRef("#/components/parameters/" + randAlphanumString())
|
||||
case 6:
|
||||
*v = spec.MustCreateRef("#/components/requestBodies/" + randAlphanumString())
|
||||
}
|
||||
},
|
||||
func(v *Parameter, c fuzz.Continue) {
|
||||
if c.Intn(refChance) == 0 {
|
||||
c.Fuzz(&v.Refable)
|
||||
return
|
||||
}
|
||||
c.Fuzz(&v.ParameterProps)
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
|
||||
switch c.Intn(3) {
|
||||
case 0:
|
||||
// Header param
|
||||
v.In = "query"
|
||||
case 1:
|
||||
v.In = "header"
|
||||
case 2:
|
||||
v.In = "cookie"
|
||||
}
|
||||
},
|
||||
func(v *RequestBody, c fuzz.Continue) {
|
||||
if c.Intn(refChance) == 0 {
|
||||
c.Fuzz(&v.Refable)
|
||||
return
|
||||
}
|
||||
c.Fuzz(&v.RequestBodyProps)
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
},
|
||||
func(v *Header, c fuzz.Continue) {
|
||||
if c.Intn(refChance) == 0 {
|
||||
c.Fuzz(&v.Refable)
|
||||
return
|
||||
}
|
||||
c.Fuzz(&v.HeaderProps)
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
},
|
||||
func(v *ResponsesProps, c fuzz.Continue) {
|
||||
c.Fuzz(&v.Default)
|
||||
n := c.Intn(5)
|
||||
for i := 0; i < n; i++ {
|
||||
r2 := Response{}
|
||||
c.Fuzz(&r2)
|
||||
// HTTP Status code in 100-599 Range
|
||||
code := c.Intn(500) + 100
|
||||
v.StatusCodeResponses = make(map[int]*Response)
|
||||
v.StatusCodeResponses[code] = &r2
|
||||
}
|
||||
},
|
||||
func(v *Response, c fuzz.Continue) {
|
||||
if c.Intn(refChance) == 0 {
|
||||
c.Fuzz(&v.Refable)
|
||||
return
|
||||
}
|
||||
c.Fuzz(&v.ResponseProps)
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
},
|
||||
func(v *Operation, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(v)
|
||||
// Do not fuzz null values into the array.
|
||||
for i, val := range v.SecurityRequirement {
|
||||
if val == nil {
|
||||
v.SecurityRequirement[i] = make(map[string][]string)
|
||||
}
|
||||
|
||||
for k, v := range val {
|
||||
if v == nil {
|
||||
val[k] = make([]string, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
func(v *spec.Extensions, c fuzz.Continue) {
|
||||
numChildren := c.Intn(5)
|
||||
for i := 0; i < numChildren; i++ {
|
||||
if *v == nil {
|
||||
*v = spec.Extensions{}
|
||||
}
|
||||
(*v)["x-"+c.RandString()] = c.RandString()
|
||||
}
|
||||
},
|
||||
func(v *spec.ExternalDocumentation, c fuzz.Continue) {
|
||||
c.Fuzz(&v.Description)
|
||||
v.URL = "https://" + randAlphanumString()
|
||||
},
|
||||
func(v *spec.SchemaURL, c fuzz.Continue) {
|
||||
*v = spec.SchemaURL("https://" + randAlphanumString())
|
||||
},
|
||||
func(v *spec.SchemaOrBool, c fuzz.Continue) {
|
||||
*v = spec.SchemaOrBool{}
|
||||
|
||||
if c.RandBool() {
|
||||
v.Allows = c.RandBool()
|
||||
} else {
|
||||
v.Schema = &spec.Schema{}
|
||||
v.Allows = true
|
||||
c.Fuzz(&v.Schema)
|
||||
}
|
||||
},
|
||||
func(v *spec.SchemaOrArray, c fuzz.Continue) {
|
||||
*v = spec.SchemaOrArray{}
|
||||
if c.RandBool() {
|
||||
schema := spec.Schema{}
|
||||
c.Fuzz(&schema)
|
||||
v.Schema = &schema
|
||||
} else {
|
||||
v.Schemas = []spec.Schema{}
|
||||
numChildren := c.Intn(5)
|
||||
for i := 0; i < numChildren; i++ {
|
||||
schema := spec.Schema{}
|
||||
c.Fuzz(&schema)
|
||||
v.Schemas = append(v.Schemas, schema)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
func(v *spec.SchemaOrStringArray, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
*v = spec.SchemaOrStringArray{}
|
||||
if c.RandBool() {
|
||||
c.Fuzz(&v.Property)
|
||||
} else {
|
||||
c.Fuzz(&v.Schema)
|
||||
}
|
||||
}
|
||||
},
|
||||
func(v *spec.Schema, c fuzz.Continue) {
|
||||
if c.Intn(refChance) == 0 {
|
||||
c.Fuzz(&v.Ref)
|
||||
return
|
||||
}
|
||||
if c.RandBool() {
|
||||
// file schema
|
||||
c.Fuzz(&v.Default)
|
||||
c.Fuzz(&v.Description)
|
||||
c.Fuzz(&v.Example)
|
||||
c.Fuzz(&v.ExternalDocs)
|
||||
|
||||
c.Fuzz(&v.Format)
|
||||
c.Fuzz(&v.ReadOnly)
|
||||
c.Fuzz(&v.Required)
|
||||
c.Fuzz(&v.Title)
|
||||
v.Type = spec.StringOrArray{"file"}
|
||||
|
||||
} else {
|
||||
// normal schema
|
||||
c.Fuzz(&v.SchemaProps)
|
||||
c.Fuzz(&v.SwaggerSchemaProps)
|
||||
c.Fuzz(&v.VendorExtensible)
|
||||
c.Fuzz(&v.ExtraProps)
|
||||
}
|
||||
|
||||
},
|
||||
}
|
142
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/header.go
generated
vendored
Normal file
142
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/header.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Header a struct that describes a single operation parameter, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around HeaderProps to make it referable and extensible
|
||||
type Header struct {
|
||||
spec.Refable
|
||||
HeaderProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Header as JSON
|
||||
func (h *Header) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(h)
|
||||
}
|
||||
b1, err := json.Marshal(h.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(h.HeaderProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(h.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (h *Header) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
HeaderProps headerPropsOmitZero `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Ref = h.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(h.Extensions)
|
||||
x.HeaderProps = headerPropsOmitZero(h.HeaderProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, h)
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.HeaderProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Header) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
HeaderProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&h.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
h.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
h.HeaderProps = x.HeaderProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// HeaderProps a struct that describes a header object
|
||||
type HeaderProps struct {
|
||||
// Description holds a brief description of the parameter
|
||||
Description string `json:"description,omitempty"`
|
||||
// Required determines whether this parameter is mandatory
|
||||
Required bool `json:"required,omitempty"`
|
||||
// Deprecated declares this operation to be deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// AllowEmptyValue sets the ability to pass empty-valued parameters
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||
// Style describes how the parameter value will be serialized depending on the type of the parameter value
|
||||
Style string `json:"style,omitempty"`
|
||||
// Explode when true, parameter values of type array or object generate separate parameters for each value of the array or key-value pair of the map
|
||||
Explode bool `json:"explode,omitempty"`
|
||||
// AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986
|
||||
AllowReserved bool `json:"allowReserved,omitempty"`
|
||||
// Schema holds the schema defining the type used for the parameter
|
||||
Schema *spec.Schema `json:"schema,omitempty"`
|
||||
// Content holds a map containing the representations for the parameter
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Example of the header
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
// Examples of the header
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type headerPropsOmitZero struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Required bool `json:"required,omitzero"`
|
||||
Deprecated bool `json:"deprecated,omitzero"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitzero"`
|
||||
Style string `json:"style,omitempty"`
|
||||
Explode bool `json:"explode,omitzero"`
|
||||
AllowReserved bool `json:"allowReserved,omitzero"`
|
||||
Schema *spec.Schema `json:"schema,omitzero"`
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
}
|
106
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go
generated
vendored
Normal file
106
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// MediaType a struct that allows you to specify content format, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#mediaTypeObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around MediaTypeProps to make it referable and extensible
|
||||
type MediaType struct {
|
||||
MediaTypeProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode MediaType as JSON
|
||||
func (m *MediaType) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(m)
|
||||
}
|
||||
b1, err := json.Marshal(m.MediaTypeProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(m.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (e *MediaType) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
MediaTypeProps mediaTypePropsOmitZero `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(e.Extensions)
|
||||
x.MediaTypeProps = mediaTypePropsOmitZero(e.MediaTypeProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (m *MediaType) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, m)
|
||||
}
|
||||
if err := json.Unmarshal(data, &m.MediaTypeProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &m.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MediaType) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
MediaTypeProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
m.MediaTypeProps = x.MediaTypeProps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MediaTypeProps a struct that allows you to specify content format, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#mediaTypeObject
|
||||
type MediaTypeProps struct {
|
||||
// Schema holds the schema defining the type used for the media type
|
||||
Schema *spec.Schema `json:"schema,omitempty"`
|
||||
// Example of the media type
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
// Examples of the media type. Each example object should match the media type and specific schema if present
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
// A map between a property name and its encoding information. The key, being the property name, MUST exist in the schema as a property. The encoding object SHALL only apply to requestBody objects when the media type is multipart or application/x-www-form-urlencoded
|
||||
Encoding map[string]*Encoding `json:"encoding,omitempty"`
|
||||
}
|
||||
|
||||
type mediaTypePropsOmitZero struct {
|
||||
Schema *spec.Schema `json:"schema,omitzero"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
Encoding map[string]*Encoding `json:"encoding,omitempty"`
|
||||
}
|
124
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go
generated
vendored
Normal file
124
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Operation describes a single API operation on a path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operationObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around OperationProps to make it referable and extensible
|
||||
type Operation struct {
|
||||
OperationProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Operation as JSON
|
||||
func (o *Operation) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(o)
|
||||
}
|
||||
b1, err := json.Marshal(o.OperationProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(o.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (o *Operation) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
OperationProps operationPropsOmitZero `json:",inline"`
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(o.Extensions)
|
||||
x.OperationProps = operationPropsOmitZero(o.OperationProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (o *Operation) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, o)
|
||||
}
|
||||
if err := json.Unmarshal(data, &o.OperationProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &o.VendorExtensible)
|
||||
}
|
||||
|
||||
func (o *Operation) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
OperationProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
o.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
o.OperationProps = x.OperationProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// OperationProps describes a single API operation on a path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operationObject
|
||||
type OperationProps struct {
|
||||
// Tags holds a list of tags for API documentation control
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Summary holds a short summary of what the operation does
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Description holds a verbose explanation of the operation behavior
|
||||
Description string `json:"description,omitempty"`
|
||||
// ExternalDocs holds additional external documentation for this operation
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
// OperationId holds a unique string used to identify the operation
|
||||
OperationId string `json:"operationId,omitempty"`
|
||||
// Parameters a list of parameters that are applicable for this operation
|
||||
Parameters []*Parameter `json:"parameters,omitempty"`
|
||||
// RequestBody holds the request body applicable for this operation
|
||||
RequestBody *RequestBody `json:"requestBody,omitempty"`
|
||||
// Responses holds the list of possible responses as they are returned from executing this operation
|
||||
Responses *Responses `json:"responses,omitempty"`
|
||||
// Deprecated declares this operation to be deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// SecurityRequirement holds a declaration of which security mechanisms can be used for this operation
|
||||
SecurityRequirement []map[string][]string `json:"security,omitempty"`
|
||||
// Servers contains an alternative server array to service this operation
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
}
|
||||
|
||||
type operationPropsOmitZero struct {
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"`
|
||||
OperationId string `json:"operationId,omitempty"`
|
||||
Parameters []*Parameter `json:"parameters,omitempty"`
|
||||
RequestBody *RequestBody `json:"requestBody,omitzero"`
|
||||
Responses *Responses `json:"responses,omitzero"`
|
||||
Deprecated bool `json:"deprecated,omitzero"`
|
||||
SecurityRequirement []map[string][]string `json:"security,omitempty"`
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
}
|
147
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go
generated
vendored
Normal file
147
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Parameter a struct that describes a single operation parameter, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around ParameterProps to make it referable and extensible
|
||||
type Parameter struct {
|
||||
spec.Refable
|
||||
ParameterProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Parameter as JSON
|
||||
func (p *Parameter) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(p)
|
||||
}
|
||||
b1, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.ParameterProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (p *Parameter) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
ParameterProps parameterPropsOmitZero `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Ref = p.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(p.Extensions)
|
||||
x.ParameterProps = parameterPropsOmitZero(p.ParameterProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (p *Parameter) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.ParameterProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parameter) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
ParameterProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&p.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
p.ParameterProps = x.ParameterProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParameterProps a struct that describes a single operation parameter, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject
|
||||
type ParameterProps struct {
|
||||
// Name holds the name of the parameter
|
||||
Name string `json:"name,omitempty"`
|
||||
// In holds the location of the parameter
|
||||
In string `json:"in,omitempty"`
|
||||
// Description holds a brief description of the parameter
|
||||
Description string `json:"description,omitempty"`
|
||||
// Required determines whether this parameter is mandatory
|
||||
Required bool `json:"required,omitempty"`
|
||||
// Deprecated declares this operation to be deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// AllowEmptyValue sets the ability to pass empty-valued parameters
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||
// Style describes how the parameter value will be serialized depending on the type of the parameter value
|
||||
Style string `json:"style,omitempty"`
|
||||
// Explode when true, parameter values of type array or object generate separate parameters for each value of the array or key-value pair of the map
|
||||
Explode bool `json:"explode,omitempty"`
|
||||
// AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986
|
||||
AllowReserved bool `json:"allowReserved,omitempty"`
|
||||
// Schema holds the schema defining the type used for the parameter
|
||||
Schema *spec.Schema `json:"schema,omitempty"`
|
||||
// Content holds a map containing the representations for the parameter
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Example of the parameter's potential value
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
// Examples of the parameter's potential value. Each example SHOULD contain a value in the correct format as specified in the parameter encoding
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
}
|
||||
|
||||
type parameterPropsOmitZero struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
In string `json:"in,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Required bool `json:"required,omitzero"`
|
||||
Deprecated bool `json:"deprecated,omitzero"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitzero"`
|
||||
Style string `json:"style,omitempty"`
|
||||
Explode bool `json:"explode,omitzero"`
|
||||
AllowReserved bool `json:"allowReserved,omitzero"`
|
||||
Schema *spec.Schema `json:"schema,omitzero"`
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
Examples map[string]*Example `json:"examples,omitempty"`
|
||||
}
|
263
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/path.go
generated
vendored
Normal file
263
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/path.go
generated
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Paths describes the available paths and operations for the API, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathsObject
|
||||
type Paths struct {
|
||||
Paths map[string]*Path
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Paths as JSON
|
||||
func (p *Paths) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(p)
|
||||
}
|
||||
b1, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pths := make(map[string]*Path)
|
||||
for k, v := range p.Paths {
|
||||
if strings.HasPrefix(k, "/") {
|
||||
pths[k] = v
|
||||
}
|
||||
}
|
||||
b2, err := json.Marshal(pths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
|
||||
func (p *Paths) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
m := make(map[string]any, len(p.Extensions)+len(p.Paths))
|
||||
for k, v := range p.Extensions {
|
||||
if internal.IsExtensionKey(k) {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range p.Paths {
|
||||
if strings.HasPrefix(k, "/") {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
return opts.MarshalNext(enc, m)
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *Paths) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range res {
|
||||
if strings.HasPrefix(strings.ToLower(k), "x-") {
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]interface{})
|
||||
}
|
||||
var d interface{}
|
||||
if err := json.Unmarshal(v, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions[k] = d
|
||||
}
|
||||
if strings.HasPrefix(k, "/") {
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]*Path)
|
||||
}
|
||||
var pi *Path
|
||||
if err := json.Unmarshal(v, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Paths[k] = pi
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Paths) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch k := tok.Kind(); k {
|
||||
case 'n':
|
||||
*p = Paths{}
|
||||
return nil
|
||||
case '{':
|
||||
for {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tok.Kind() == '}' {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch k := tok.String(); {
|
||||
case internal.IsExtensionKey(k):
|
||||
var ext any
|
||||
if err := opts.UnmarshalNext(dec, &ext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]any)
|
||||
}
|
||||
p.Extensions[k] = ext
|
||||
case len(k) > 0 && k[0] == '/':
|
||||
pi := Path{}
|
||||
if err := opts.UnmarshalNext(dec, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]*Path)
|
||||
}
|
||||
p.Paths[k] = &pi
|
||||
default:
|
||||
_, err := dec.ReadValue() // skip value
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown JSON kind: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
// Path describes the operations available on a single path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around PathProps to make it referable and extensible
|
||||
type Path struct {
|
||||
spec.Refable
|
||||
PathProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Path as JSON
|
||||
func (p *Path) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(p)
|
||||
}
|
||||
b1, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.PathProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (p *Path) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
spec.Extensions
|
||||
PathProps
|
||||
}
|
||||
x.Ref = p.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(p.Extensions)
|
||||
x.PathProps = p.PathProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (p *Path) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.PathProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Path) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
PathProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&p.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
p.PathProps = x.PathProps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PathProps describes the operations available on a single path, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject
|
||||
type PathProps struct {
|
||||
// Summary holds a summary for all operations in this path
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Description holds a description for all operations in this path
|
||||
Description string `json:"description,omitempty"`
|
||||
// Get defines GET operation
|
||||
Get *Operation `json:"get,omitempty"`
|
||||
// Put defines PUT operation
|
||||
Put *Operation `json:"put,omitempty"`
|
||||
// Post defines POST operation
|
||||
Post *Operation `json:"post,omitempty"`
|
||||
// Delete defines DELETE operation
|
||||
Delete *Operation `json:"delete,omitempty"`
|
||||
// Options defines OPTIONS operation
|
||||
Options *Operation `json:"options,omitempty"`
|
||||
// Head defines HEAD operation
|
||||
Head *Operation `json:"head,omitempty"`
|
||||
// Patch defines PATCH operation
|
||||
Patch *Operation `json:"patch,omitempty"`
|
||||
// Trace defines TRACE operation
|
||||
Trace *Operation `json:"trace,omitempty"`
|
||||
// Servers is an alternative server array to service all operations in this path
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
// Parameters a list of parameters that are applicable for this operation
|
||||
Parameters []*Parameter `json:"parameters,omitempty"`
|
||||
}
|
115
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go
generated
vendored
Normal file
115
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// RequestBody describes a single request body, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#requestBodyObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around RequestBodyProps to make it referable and extensible
|
||||
type RequestBody struct {
|
||||
spec.Refable
|
||||
RequestBodyProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode RequestBody as JSON
|
||||
func (r *RequestBody) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(r)
|
||||
}
|
||||
b1, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.RequestBodyProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r *RequestBody) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
RequestBodyProps requestBodyPropsOmitZero `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Ref = r.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(r.Extensions)
|
||||
x.RequestBodyProps = requestBodyPropsOmitZero(r.RequestBodyProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (r *RequestBody) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.RequestBodyProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequestBodyProps describes a single request body, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#requestBodyObject
|
||||
type RequestBodyProps struct {
|
||||
// Description holds a brief description of the request body
|
||||
Description string `json:"description,omitempty"`
|
||||
// Content is the content of the request body. The key is a media type or media type range and the value describes it
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Required determines if the request body is required in the request
|
||||
Required bool `json:"required,omitempty"`
|
||||
}
|
||||
|
||||
type requestBodyPropsOmitZero struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
Required bool `json:"required,omitzero"`
|
||||
}
|
||||
|
||||
func (r *RequestBody) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
RequestBodyProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&r.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
r.RequestBodyProps = x.RequestBodyProps
|
||||
return nil
|
||||
}
|
362
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/response.go
generated
vendored
Normal file
362
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/response.go
generated
vendored
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Responses holds the list of possible responses as they are returned from executing this operation
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around ResponsesProps to make it referable and extensible
|
||||
type Responses struct {
|
||||
ResponsesProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (r *Responses) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(r)
|
||||
}
|
||||
b1, err := json.Marshal(r.ResponsesProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (r Responses) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
type ArbitraryKeys map[string]interface{}
|
||||
var x struct {
|
||||
ArbitraryKeys
|
||||
Default *Response `json:"default,omitzero"`
|
||||
}
|
||||
x.ArbitraryKeys = make(map[string]any, len(r.Extensions)+len(r.StatusCodeResponses))
|
||||
for k, v := range r.Extensions {
|
||||
if internal.IsExtensionKey(k) {
|
||||
x.ArbitraryKeys[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range r.StatusCodeResponses {
|
||||
x.ArbitraryKeys[strconv.Itoa(k)] = v
|
||||
}
|
||||
x.Default = r.Default
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (r *Responses) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResponsesProps holds the list of possible responses as they are returned from executing this operation
|
||||
type ResponsesProps struct {
|
||||
// Default holds the documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses
|
||||
Default *Response `json:"-"`
|
||||
// StatusCodeResponses holds a map of any HTTP status code to the response definition
|
||||
StatusCodeResponses map[int]*Response `json:"-"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode ResponsesProps as JSON
|
||||
func (r ResponsesProps) MarshalJSON() ([]byte, error) {
|
||||
toser := map[string]*Response{}
|
||||
if r.Default != nil {
|
||||
toser["default"] = r.Default
|
||||
}
|
||||
for k, v := range r.StatusCodeResponses {
|
||||
toser[strconv.Itoa(k)] = v
|
||||
}
|
||||
return json.Marshal(toser)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals responses from JSON
|
||||
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
if v, ok := res["default"]; ok {
|
||||
value := Response{}
|
||||
if err := json.Unmarshal(v, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Default = &value
|
||||
delete(res, "default")
|
||||
}
|
||||
for k, v := range res {
|
||||
// Take all integral keys
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]*Response{}
|
||||
}
|
||||
value := Response{}
|
||||
if err := json.Unmarshal(v, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
r.StatusCodeResponses[nk] = &value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Responses) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) (err error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch k := tok.Kind(); k {
|
||||
case 'n':
|
||||
*r = Responses{}
|
||||
return nil
|
||||
case '{':
|
||||
for {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() == '}' {
|
||||
return nil
|
||||
}
|
||||
switch k := tok.String(); {
|
||||
case internal.IsExtensionKey(k):
|
||||
var ext any
|
||||
if err := opts.UnmarshalNext(dec, &ext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.Extensions == nil {
|
||||
r.Extensions = make(map[string]any)
|
||||
}
|
||||
r.Extensions[k] = ext
|
||||
case k == "default":
|
||||
resp := Response{}
|
||||
if err := opts.UnmarshalNext(dec, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
r.ResponsesProps.Default = &resp
|
||||
default:
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
resp := Response{}
|
||||
if err := opts.UnmarshalNext(dec, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]*Response{}
|
||||
}
|
||||
r.StatusCodeResponses[nk] = &resp
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown JSON kind: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
// Response describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
|
||||
//
|
||||
// Note that this struct is actually a thin wrapper around ResponseProps to make it referable and extensible
|
||||
type Response struct {
|
||||
spec.Refable
|
||||
ResponseProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Response as JSON
|
||||
func (r *Response) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(r)
|
||||
}
|
||||
b1, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.ResponseProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r Response) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
spec.Extensions
|
||||
ResponseProps `json:",inline"`
|
||||
}
|
||||
x.Ref = r.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(r.Extensions)
|
||||
x.ResponseProps = r.ResponseProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Response) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
ResponseProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&r.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
r.ResponseProps = x.ResponseProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResponseProps describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
|
||||
type ResponseProps struct {
|
||||
// Description holds a short description of the response
|
||||
Description string `json:"description,omitempty"`
|
||||
// Headers holds a maps of a headers name to its definition
|
||||
Headers map[string]*Header `json:"headers,omitempty"`
|
||||
// Content holds a map containing descriptions of potential response payloads
|
||||
Content map[string]*MediaType `json:"content,omitempty"`
|
||||
// Links is a map of operations links that can be followed from the response
|
||||
Links map[string]*Link `json:"links,omitempty"`
|
||||
}
|
||||
|
||||
// Link represents a possible design-time link for a response, more at https://swagger.io/specification/#link-object
|
||||
type Link struct {
|
||||
spec.Refable
|
||||
LinkProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Link as JSON
|
||||
func (r *Link) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(r)
|
||||
}
|
||||
b1, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.LinkProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r *Link) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
spec.Extensions
|
||||
LinkProps `json:",inline"`
|
||||
}
|
||||
x.Ref = r.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(r.Extensions)
|
||||
x.LinkProps = r.LinkProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (r *Link) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.LinkProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Link) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
LinkProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := internal.JSONRefFromMap(&l.Ref.Ref, x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
l.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
l.LinkProps = x.LinkProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// LinkProps describes a single response from an API Operation, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject
|
||||
type LinkProps struct {
|
||||
// OperationId is the name of an existing, resolvable OAS operation
|
||||
OperationId string `json:"operationId,omitempty"`
|
||||
// Parameters is a map representing parameters to pass to an operation as specified with operationId or identified via operationRef
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
// Description holds a description of the link
|
||||
Description string `json:"description,omitempty"`
|
||||
// RequestBody is a literal value or expresion to use as a request body when calling the target operation
|
||||
RequestBody interface{} `json:"requestBody,omitempty"`
|
||||
// Server holds a server object used by the target operation
|
||||
Server *Server `json:"server,omitempty"`
|
||||
}
|
135
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go
generated
vendored
Normal file
135
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// SecurityScheme defines reusable Security Scheme Object, more at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject
|
||||
type SecurityScheme struct {
|
||||
spec.Refable
|
||||
SecuritySchemeProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode SecurityScheme as JSON
|
||||
func (s *SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
b1, err := json.Marshal(s.SecuritySchemeProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(s.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (s *SecurityScheme) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
SecuritySchemeProps `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Ref = s.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(s.Extensions)
|
||||
x.SecuritySchemeProps = s.SecuritySchemeProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &s.Refable)
|
||||
}
|
||||
|
||||
// SecuritySchemeProps defines a security scheme that can be used by the operations
|
||||
type SecuritySchemeProps struct {
|
||||
// Type of the security scheme
|
||||
Type string `json:"type,omitempty"`
|
||||
// Description holds a short description for security scheme
|
||||
Description string `json:"description,omitempty"`
|
||||
// Name holds the name of the header, query or cookie parameter to be used
|
||||
Name string `json:"name,omitempty"`
|
||||
// In holds the location of the API key
|
||||
In string `json:"in,omitempty"`
|
||||
// Scheme holds the name of the HTTP Authorization scheme to be used in the Authorization header
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
// BearerFormat holds a hint to the client to identify how the bearer token is formatted
|
||||
BearerFormat string `json:"bearerFormat,omitempty"`
|
||||
// Flows contains configuration information for the flow types supported.
|
||||
Flows map[string]*OAuthFlow `json:"flows,omitempty"`
|
||||
// OpenIdConnectUrl holds an url to discover OAuth2 configuration values from
|
||||
OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty"`
|
||||
}
|
||||
|
||||
// OAuthFlow contains configuration information for the flow types supported.
|
||||
type OAuthFlow struct {
|
||||
OAuthFlowProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode OAuthFlow as JSON
|
||||
func (o *OAuthFlow) MarshalJSON() ([]byte, error) {
|
||||
b1, err := json.Marshal(o.OAuthFlowProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(o.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (o *OAuthFlow) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &o.OAuthFlowProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &o.VendorExtensible)
|
||||
}
|
||||
|
||||
// OAuthFlowProps holds configuration details for a supported OAuth Flow
|
||||
type OAuthFlowProps struct {
|
||||
// AuthorizationUrl hold the authorization URL to be used for this flow
|
||||
AuthorizationUrl string `json:"authorizationUrl,omitempty"`
|
||||
// TokenUrl holds the token URL to be used for this flow
|
||||
TokenUrl string `json:"tokenUrl,omitempty"`
|
||||
// RefreshUrl holds the URL to be used for obtaining refresh tokens
|
||||
RefreshUrl string `json:"refreshUrl,omitempty"`
|
||||
// Scopes holds the available scopes for the OAuth2 security scheme
|
||||
Scopes map[string]string `json:"scopes,omitempty"`
|
||||
}
|
161
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/server.go
generated
vendored
Normal file
161
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/server.go
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
ServerProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
type ServerProps struct {
|
||||
// Description is a short description of the target documentation. CommonMark syntax MAY be used for rich text representation.
|
||||
Description string `json:"description,omitempty"`
|
||||
// URL is the URL for the target documentation.
|
||||
URL string `json:"url"`
|
||||
// Variables contains a map between a variable name and its value. The value is used for substitution in the server's URL templeate
|
||||
Variables map[string]*ServerVariable `json:"variables,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (s *Server) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
b1, err := json.Marshal(s.ServerProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (s *Server) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
ServerProps `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(s.Extensions)
|
||||
x.ServerProps = s.ServerProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (s *Server) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &s.ServerProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
ServerProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
s.ServerProps = x.ServerProps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerVariable struct {
|
||||
ServerVariableProps
|
||||
spec.VendorExtensible
|
||||
}
|
||||
|
||||
type ServerVariableProps struct {
|
||||
// Enum is an enumeration of string values to be used if the substitution options are from a limited set
|
||||
Enum []string `json:"enum,omitempty"`
|
||||
// Default is the default value to use for substitution, which SHALL be sent if an alternate value is not supplied
|
||||
Default string `json:"default"`
|
||||
// Description is a description for the server variable
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom marshal function that knows how to encode Responses as JSON
|
||||
func (s *ServerVariable) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
b1, err := json.Marshal(s.ServerVariableProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (s *ServerVariable) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
ServerVariableProps `json:",inline"`
|
||||
spec.Extensions
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(s.Extensions)
|
||||
x.ServerVariableProps = s.ServerVariableProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
func (s *ServerVariable) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.ServerVariableProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerVariable) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
spec.Extensions
|
||||
ServerVariableProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
s.ServerVariableProps = x.ServerVariableProps
|
||||
|
||||
return nil
|
||||
}
|
75
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go
generated
vendored
Normal file
75
e2e/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright 2021 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 spec3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// OpenAPI is an object that describes an API and conforms to the OpenAPI Specification.
|
||||
type OpenAPI struct {
|
||||
// Version represents the semantic version number of the OpenAPI Specification that this document uses
|
||||
Version string `json:"openapi"`
|
||||
// Info provides metadata about the API
|
||||
Info *spec.Info `json:"info"`
|
||||
// Paths holds the available target and operations for the API
|
||||
Paths *Paths `json:"paths,omitempty"`
|
||||
// Servers is an array of Server objects which provide connectivity information to a target server
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
// Components hold various schemas for the specification
|
||||
Components *Components `json:"components,omitempty"`
|
||||
// SecurityRequirement holds a declaration of which security mechanisms can be used across the API
|
||||
SecurityRequirement []map[string][]string `json:"security,omitempty"`
|
||||
// ExternalDocs holds additional external documentation
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
func (o *OpenAPI) UnmarshalJSON(data []byte) error {
|
||||
type OpenAPIWithNoFunctions OpenAPI
|
||||
p := (*OpenAPIWithNoFunctions)(o)
|
||||
if internal.UseOptimizedJSONUnmarshalingV3 {
|
||||
return jsonv2.Unmarshal(data, &p)
|
||||
}
|
||||
return json.Unmarshal(data, &p)
|
||||
}
|
||||
|
||||
func (o *OpenAPI) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshalingV3 {
|
||||
return internal.DeterministicMarshal(o)
|
||||
}
|
||||
type OpenAPIWithNoFunctions OpenAPI
|
||||
p := (*OpenAPIWithNoFunctions)(o)
|
||||
return json.Marshal(&p)
|
||||
}
|
||||
|
||||
func (o *OpenAPI) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
type OpenAPIOmitZero struct {
|
||||
Version string `json:"openapi"`
|
||||
Info *spec.Info `json:"info"`
|
||||
Paths *Paths `json:"paths,omitzero"`
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
Components *Components `json:"components,omitzero"`
|
||||
SecurityRequirement []map[string][]string `json:"security,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"`
|
||||
}
|
||||
x := (*OpenAPIOmitZero)(o)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
2
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/OWNERS
generated
vendored
Normal file
2
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/OWNERS
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
approvers:
|
||||
- apelisse
|
19
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/doc.go
generated
vendored
Normal file
19
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2017 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 proto is a collection of libraries for parsing and indexing the type definitions.
|
||||
// The openapi spec contains the object model definitions and extensions metadata.
|
||||
package proto
|
362
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go
generated
vendored
Normal file
362
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go
generated
vendored
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
Copyright 2017 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 proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
openapi_v2 "github.com/google/gnostic-models/openapiv2"
|
||||
yaml "sigs.k8s.io/yaml/goyaml.v2"
|
||||
)
|
||||
|
||||
func newSchemaError(path *Path, format string, a ...interface{}) error {
|
||||
err := fmt.Sprintf(format, a...)
|
||||
if path.Len() == 0 {
|
||||
return fmt.Errorf("SchemaError: %v", err)
|
||||
}
|
||||
return fmt.Errorf("SchemaError(%v): %v", path, err)
|
||||
}
|
||||
|
||||
// VendorExtensionToMap converts openapi VendorExtension to a map.
|
||||
func VendorExtensionToMap(e []*openapi_v2.NamedAny) map[string]interface{} {
|
||||
values := map[string]interface{}{}
|
||||
|
||||
for _, na := range e {
|
||||
if na.GetName() == "" || na.GetValue() == nil {
|
||||
continue
|
||||
}
|
||||
if na.GetValue().GetYaml() == "" {
|
||||
continue
|
||||
}
|
||||
var value interface{}
|
||||
err := yaml.Unmarshal([]byte(na.GetValue().GetYaml()), &value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
values[na.GetName()] = value
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// Definitions is an implementation of `Models`. It looks for
|
||||
// models in an openapi Schema.
|
||||
type Definitions struct {
|
||||
models map[string]Schema
|
||||
}
|
||||
|
||||
var _ Models = &Definitions{}
|
||||
|
||||
// NewOpenAPIData creates a new `Models` out of the openapi document.
|
||||
func NewOpenAPIData(doc *openapi_v2.Document) (Models, error) {
|
||||
definitions := Definitions{
|
||||
models: map[string]Schema{},
|
||||
}
|
||||
|
||||
// Save the list of all models first. This will allow us to
|
||||
// validate that we don't have any dangling reference.
|
||||
for _, namedSchema := range doc.GetDefinitions().GetAdditionalProperties() {
|
||||
definitions.models[namedSchema.GetName()] = nil
|
||||
}
|
||||
|
||||
// Now, parse each model. We can validate that references exists.
|
||||
for _, namedSchema := range doc.GetDefinitions().GetAdditionalProperties() {
|
||||
path := NewPath(namedSchema.GetName())
|
||||
schema, err := definitions.ParseSchema(namedSchema.GetValue(), &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
definitions.models[namedSchema.GetName()] = schema
|
||||
}
|
||||
|
||||
return &definitions, nil
|
||||
}
|
||||
|
||||
// We believe the schema is a reference, verify that and returns a new
|
||||
// Schema
|
||||
func (d *Definitions) parseReference(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
// TODO(wrong): a schema with a $ref can have properties. We can ignore them (would be incomplete), but we cannot return an error.
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
return nil, newSchemaError(path, "unallowed embedded type definition")
|
||||
}
|
||||
// TODO(wrong): a schema with a $ref can have a type. We can ignore it (would be incomplete), but we cannot return an error.
|
||||
if len(s.GetType().GetValue()) > 0 {
|
||||
return nil, newSchemaError(path, "definition reference can't have a type")
|
||||
}
|
||||
|
||||
// TODO(wrong): $refs outside of the definitions are completely valid. We can ignore them (would be incomplete), but we cannot return an error.
|
||||
if !strings.HasPrefix(s.GetXRef(), "#/definitions/") {
|
||||
return nil, newSchemaError(path, "unallowed reference to non-definition %q", s.GetXRef())
|
||||
}
|
||||
reference := strings.TrimPrefix(s.GetXRef(), "#/definitions/")
|
||||
if _, ok := d.models[reference]; !ok {
|
||||
return nil, newSchemaError(path, "unknown model in reference: %q", reference)
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ref{
|
||||
BaseSchema: base,
|
||||
reference: reference,
|
||||
definitions: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseDefault(def *openapi_v2.Any) (interface{}, error) {
|
||||
if def == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var i interface{}
|
||||
if err := yaml.Unmarshal([]byte(def.Yaml), &i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseBaseSchema(s *openapi_v2.Schema, path *Path) (BaseSchema, error) {
|
||||
def, err := parseDefault(s.GetDefault())
|
||||
if err != nil {
|
||||
return BaseSchema{}, err
|
||||
}
|
||||
return BaseSchema{
|
||||
Description: s.GetDescription(),
|
||||
Default: def,
|
||||
Extensions: VendorExtensionToMap(s.GetVendorExtension()),
|
||||
Path: *path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// We believe the schema is a map, verify and return a new schema
|
||||
func (d *Definitions) parseMap(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
}
|
||||
var sub Schema
|
||||
// TODO(incomplete): this misses the boolean case as AdditionalProperties is a bool+schema sum type.
|
||||
if s.GetAdditionalProperties().GetSchema() == nil {
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub = &Arbitrary{
|
||||
BaseSchema: base,
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
sub, err = d.ParseSchema(s.GetAdditionalProperties().GetSchema(), path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Map{
|
||||
BaseSchema: base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parsePrimitive(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
var t string
|
||||
if len(s.GetType().GetValue()) > 1 {
|
||||
return nil, newSchemaError(path, "primitive can't have more than 1 type")
|
||||
}
|
||||
if len(s.GetType().GetValue()) == 1 {
|
||||
t = s.GetType().GetValue()[0]
|
||||
}
|
||||
switch t {
|
||||
case String: // do nothing
|
||||
case Number: // do nothing
|
||||
case Integer: // do nothing
|
||||
case Boolean: // do nothing
|
||||
// TODO(wrong): this misses "null". Would skip the null case (would be incomplete), but we cannot return an error.
|
||||
default:
|
||||
return nil, newSchemaError(path, "Unknown primitive type: %q", t)
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Primitive{
|
||||
BaseSchema: base,
|
||||
Type: t,
|
||||
Format: s.GetFormat(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseArray(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if len(s.GetType().GetValue()) != 1 {
|
||||
return nil, newSchemaError(path, "array should have exactly one type")
|
||||
}
|
||||
if s.GetType().GetValue()[0] != array {
|
||||
return nil, newSchemaError(path, `array should have type "array"`)
|
||||
}
|
||||
if len(s.GetItems().GetSchema()) != 1 {
|
||||
// TODO(wrong): Items can have multiple elements. We can ignore Items then (would be incomplete), but we cannot return an error.
|
||||
// TODO(wrong): "type: array" witohut any items at all is completely valid.
|
||||
return nil, newSchemaError(path, "array should have exactly one sub-item")
|
||||
}
|
||||
sub, err := d.ParseSchema(s.GetItems().GetSchema()[0], path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Array{
|
||||
BaseSchema: base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseKind(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
}
|
||||
if s.GetProperties() == nil {
|
||||
return nil, newSchemaError(path, "object doesn't have properties")
|
||||
}
|
||||
|
||||
fields := map[string]Schema{}
|
||||
fieldOrder := []string{}
|
||||
|
||||
for _, namedSchema := range s.GetProperties().GetAdditionalProperties() {
|
||||
var err error
|
||||
name := namedSchema.GetName()
|
||||
path := path.FieldPath(name)
|
||||
fields[name], err = d.ParseSchema(namedSchema.GetValue(), &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldOrder = append(fieldOrder, name)
|
||||
}
|
||||
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Kind{
|
||||
BaseSchema: base,
|
||||
RequiredFields: s.GetRequired(),
|
||||
Fields: fields,
|
||||
FieldOrder: fieldOrder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseArbitrary(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
base, err := d.parseBaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Arbitrary{
|
||||
BaseSchema: base,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseSchema creates a walkable Schema from an openapi schema. While
|
||||
// this function is public, it doesn't leak through the interface.
|
||||
func (d *Definitions) ParseSchema(s *openapi_v2.Schema, path *Path) (Schema, error) {
|
||||
if s.GetXRef() != "" {
|
||||
// TODO(incomplete): ignoring the rest of s is wrong. As long as there are no conflict, everything from s must be considered
|
||||
// Reference: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#path-item-object
|
||||
return d.parseReference(s, path)
|
||||
}
|
||||
objectTypes := s.GetType().GetValue()
|
||||
switch len(objectTypes) {
|
||||
case 0:
|
||||
// in the OpenAPI schema served by older k8s versions, object definitions created from structs did not include
|
||||
// the type:object property (they only included the "properties" property), so we need to handle this case
|
||||
// TODO: validate that we ever published empty, non-nil properties. JSON roundtripping nils them.
|
||||
if s.GetProperties() != nil {
|
||||
// TODO(wrong): when verifying a non-object later against this, it will be rejected as invalid type.
|
||||
// TODO(CRD validation schema publishing): we have to filter properties (empty or not) if type=object is not given
|
||||
return d.parseKind(s, path)
|
||||
} else {
|
||||
// Definition has no type and no properties. Treat it as an arbitrary value
|
||||
// TODO(incomplete): what if it has additionalProperties=false or patternProperties?
|
||||
// ANSWER: parseArbitrary is less strict than it has to be with patternProperties (which is ignored). So this is correct (of course not complete).
|
||||
return d.parseArbitrary(s, path)
|
||||
}
|
||||
case 1:
|
||||
t := objectTypes[0]
|
||||
switch t {
|
||||
case object:
|
||||
if s.GetProperties() != nil {
|
||||
return d.parseKind(s, path)
|
||||
} else {
|
||||
return d.parseMap(s, path)
|
||||
}
|
||||
case array:
|
||||
return d.parseArray(s, path)
|
||||
}
|
||||
return d.parsePrimitive(s, path)
|
||||
default:
|
||||
// the OpenAPI generator never generates (nor it ever did in the past) OpenAPI type definitions with multiple types
|
||||
// TODO(wrong): this is rejecting a completely valid OpenAPI spec
|
||||
// TODO(CRD validation schema publishing): filter these out
|
||||
return nil, newSchemaError(path, "definitions with multiple types aren't supported")
|
||||
}
|
||||
}
|
||||
|
||||
// LookupModel is public through the interface of Models. It
|
||||
// returns a visitable schema from the given model name.
|
||||
func (d *Definitions) LookupModel(model string) Schema {
|
||||
return d.models[model]
|
||||
}
|
||||
|
||||
func (d *Definitions) ListModels() []string {
|
||||
models := []string{}
|
||||
|
||||
for model := range d.models {
|
||||
models = append(models, model)
|
||||
}
|
||||
|
||||
sort.Strings(models)
|
||||
return models
|
||||
}
|
||||
|
||||
type Ref struct {
|
||||
BaseSchema
|
||||
|
||||
reference string
|
||||
definitions *Definitions
|
||||
}
|
||||
|
||||
var _ Reference = &Ref{}
|
||||
|
||||
func (r *Ref) Reference() string {
|
||||
return r.reference
|
||||
}
|
||||
|
||||
func (r *Ref) SubSchema() Schema {
|
||||
return r.definitions.models[r.reference]
|
||||
}
|
||||
|
||||
func (r *Ref) Accept(v SchemaVisitor) {
|
||||
v.VisitReference(r)
|
||||
}
|
||||
|
||||
func (r *Ref) GetName() string {
|
||||
return fmt.Sprintf("Reference to %q", r.reference)
|
||||
}
|
324
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go
generated
vendored
Normal file
324
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go
generated
vendored
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
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 proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
openapi_v3 "github.com/google/gnostic-models/openapiv3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Temporary parse implementation to be used until gnostic->kube-openapi conversion
|
||||
// is possible.
|
||||
func NewOpenAPIV3Data(doc *openapi_v3.Document) (Models, error) {
|
||||
definitions := Definitions{
|
||||
models: map[string]Schema{},
|
||||
}
|
||||
|
||||
schemas := doc.GetComponents().GetSchemas()
|
||||
if schemas == nil {
|
||||
return &definitions, nil
|
||||
}
|
||||
|
||||
// Save the list of all models first. This will allow us to
|
||||
// validate that we don't have any dangling reference.
|
||||
for _, namedSchema := range schemas.GetAdditionalProperties() {
|
||||
definitions.models[namedSchema.GetName()] = nil
|
||||
}
|
||||
|
||||
// Now, parse each model. We can validate that references exists.
|
||||
for _, namedSchema := range schemas.GetAdditionalProperties() {
|
||||
path := NewPath(namedSchema.GetName())
|
||||
val := namedSchema.GetValue()
|
||||
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if schema, err := definitions.ParseV3SchemaOrReference(namedSchema.GetValue(), &path); err != nil {
|
||||
return nil, err
|
||||
} else if schema != nil {
|
||||
// Schema may be nil if we hit incompleteness in the conversion,
|
||||
// but not a fatal error
|
||||
definitions.models[namedSchema.GetName()] = schema
|
||||
}
|
||||
}
|
||||
|
||||
return &definitions, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) ParseV3SchemaReference(s *openapi_v3.Reference, path *Path) (Schema, error) {
|
||||
base := &BaseSchema{
|
||||
Description: s.Description,
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(s.GetXRef(), "#/components/schemas") {
|
||||
// Only resolve references to components/schemas. We may add support
|
||||
// later for other in-spec paths, but otherwise treat unrecognized
|
||||
// refs as arbitrary/unknown values.
|
||||
return &Arbitrary{
|
||||
BaseSchema: *base,
|
||||
}, nil
|
||||
}
|
||||
|
||||
reference := strings.TrimPrefix(s.GetXRef(), "#/components/schemas/")
|
||||
if _, ok := d.models[reference]; !ok {
|
||||
return nil, newSchemaError(path, "unknown model in reference: %q", reference)
|
||||
}
|
||||
|
||||
return &Ref{
|
||||
BaseSchema: BaseSchema{
|
||||
Description: s.Description,
|
||||
},
|
||||
reference: reference,
|
||||
definitions: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) ParseV3SchemaOrReference(s *openapi_v3.SchemaOrReference, path *Path) (Schema, error) {
|
||||
var schema Schema
|
||||
var err error
|
||||
|
||||
switch v := s.GetOneof().(type) {
|
||||
case *openapi_v3.SchemaOrReference_Reference:
|
||||
// Any references stored in #!/components/... are bound to refer
|
||||
// to external documents. This API does not support such a
|
||||
// feature.
|
||||
//
|
||||
// In the weird case that this is a reference to a schema that is
|
||||
// not external, we attempt to parse anyway
|
||||
schema, err = d.ParseV3SchemaReference(v.Reference, path)
|
||||
case *openapi_v3.SchemaOrReference_Schema:
|
||||
schema, err = d.ParseSchemaV3(v.Schema, path)
|
||||
default:
|
||||
panic("unexpected type")
|
||||
}
|
||||
|
||||
return schema, err
|
||||
}
|
||||
|
||||
// ParseSchema creates a walkable Schema from an openapi v3 schema. While
|
||||
// this function is public, it doesn't leak through the interface.
|
||||
func (d *Definitions) ParseSchemaV3(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
switch s.GetType() {
|
||||
case object:
|
||||
for _, extension := range s.GetSpecificationExtension() {
|
||||
if extension.Name == "x-kubernetes-group-version-kind" {
|
||||
// Objects with x-kubernetes-group-version-kind are always top
|
||||
// level types.
|
||||
return d.parseV3Kind(s, path)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
return d.parseV3Kind(s, path)
|
||||
}
|
||||
return d.parseV3Map(s, path)
|
||||
case array:
|
||||
return d.parseV3Array(s, path)
|
||||
case String, Number, Integer, Boolean:
|
||||
return d.parseV3Primitive(s, path)
|
||||
default:
|
||||
return d.parseV3Arbitrary(s, path)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Kind(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
if s.GetType() != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
} else if s.GetProperties() == nil {
|
||||
return nil, newSchemaError(path, "object doesn't have properties")
|
||||
}
|
||||
|
||||
fields := map[string]Schema{}
|
||||
fieldOrder := []string{}
|
||||
|
||||
for _, namedSchema := range s.GetProperties().GetAdditionalProperties() {
|
||||
var err error
|
||||
name := namedSchema.GetName()
|
||||
path := path.FieldPath(name)
|
||||
fields[name], err = d.ParseV3SchemaOrReference(namedSchema.GetValue(), &path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldOrder = append(fieldOrder, name)
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Kind{
|
||||
BaseSchema: *base,
|
||||
RequiredFields: s.GetRequired(),
|
||||
Fields: fields,
|
||||
FieldOrder: fieldOrder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Arbitrary(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Arbitrary{
|
||||
BaseSchema: *base,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Primitive(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
switch s.GetType() {
|
||||
case String: // do nothing
|
||||
case Number: // do nothing
|
||||
case Integer: // do nothing
|
||||
case Boolean: // do nothing
|
||||
default:
|
||||
// Unsupported primitive type. Treat as arbitrary type
|
||||
return d.parseV3Arbitrary(s, path)
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Primitive{
|
||||
BaseSchema: *base,
|
||||
Type: s.GetType(),
|
||||
Format: s.GetFormat(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3Array(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
if s.GetType() != array {
|
||||
return nil, newSchemaError(path, `array should have type "array"`)
|
||||
} else if len(s.GetItems().GetSchemaOrReference()) != 1 {
|
||||
// This array can have multiple types in it (or no types at all)
|
||||
// This is not supported by this conversion.
|
||||
// Just return an arbitrary type
|
||||
return d.parseV3Arbitrary(s, path)
|
||||
}
|
||||
|
||||
sub, err := d.ParseV3SchemaOrReference(s.GetItems().GetSchemaOrReference()[0], path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Array{
|
||||
BaseSchema: *base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// We believe the schema is a map, verify and return a new schema
|
||||
func (d *Definitions) parseV3Map(s *openapi_v3.Schema, path *Path) (Schema, error) {
|
||||
if s.GetType() != object {
|
||||
return nil, newSchemaError(path, "invalid object type")
|
||||
}
|
||||
var sub Schema
|
||||
|
||||
switch p := s.GetAdditionalProperties().GetOneof().(type) {
|
||||
case *openapi_v3.AdditionalPropertiesItem_Boolean:
|
||||
// What does this boolean even mean?
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub = &Arbitrary{
|
||||
BaseSchema: *base,
|
||||
}
|
||||
case *openapi_v3.AdditionalPropertiesItem_SchemaOrReference:
|
||||
if schema, err := d.ParseV3SchemaOrReference(p.SchemaOrReference, path); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
sub = schema
|
||||
}
|
||||
case nil:
|
||||
// no subtype?
|
||||
sub = &Arbitrary{}
|
||||
default:
|
||||
panic("unrecognized type " + reflect.TypeOf(p).Name())
|
||||
}
|
||||
|
||||
base, err := d.parseV3BaseSchema(s, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Map{
|
||||
BaseSchema: *base,
|
||||
SubType: sub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseV3Interface(def *yaml.Node) (interface{}, error) {
|
||||
if def == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var i interface{}
|
||||
if err := def.Decode(&i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (d *Definitions) parseV3BaseSchema(s *openapi_v3.Schema, path *Path) (*BaseSchema, error) {
|
||||
if s == nil {
|
||||
return nil, fmt.Errorf("cannot initialize BaseSchema from nil")
|
||||
}
|
||||
|
||||
def, err := parseV3Interface(s.GetDefault().ToRawInfo())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BaseSchema{
|
||||
Description: s.GetDescription(),
|
||||
Default: def,
|
||||
Extensions: SpecificationExtensionToMap(s.GetSpecificationExtension()),
|
||||
Path: *path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func SpecificationExtensionToMap(e []*openapi_v3.NamedAny) map[string]interface{} {
|
||||
values := map[string]interface{}{}
|
||||
|
||||
for _, na := range e {
|
||||
if na.GetName() == "" || na.GetValue() == nil {
|
||||
continue
|
||||
}
|
||||
if na.GetValue().GetYaml() == "" {
|
||||
continue
|
||||
}
|
||||
var value interface{}
|
||||
err := yaml.Unmarshal([]byte(na.GetValue().GetYaml()), &value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
values[na.GetName()] = value
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
285
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi.go
generated
vendored
Normal file
285
e2e/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi.go
generated
vendored
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
Copyright 2017 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 proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Defines openapi types.
|
||||
const (
|
||||
Integer = "integer"
|
||||
Number = "number"
|
||||
String = "string"
|
||||
Boolean = "boolean"
|
||||
|
||||
// These types are private as they should never leak, and are
|
||||
// represented by actual structs.
|
||||
array = "array"
|
||||
object = "object"
|
||||
)
|
||||
|
||||
// Models interface describe a model provider. They can give you the
|
||||
// schema for a specific model.
|
||||
type Models interface {
|
||||
LookupModel(string) Schema
|
||||
ListModels() []string
|
||||
}
|
||||
|
||||
// SchemaVisitor is an interface that you need to implement if you want
|
||||
// to "visit" an openapi schema. A dispatch on the Schema type will call
|
||||
// the appropriate function based on its actual type:
|
||||
// - Array is a list of one and only one given subtype
|
||||
// - Map is a map of string to one and only one given subtype
|
||||
// - Primitive can be string, integer, number and boolean.
|
||||
// - Kind is an object with specific fields mapping to specific types.
|
||||
// - Reference is a link to another definition.
|
||||
type SchemaVisitor interface {
|
||||
VisitArray(*Array)
|
||||
VisitMap(*Map)
|
||||
VisitPrimitive(*Primitive)
|
||||
VisitKind(*Kind)
|
||||
VisitReference(Reference)
|
||||
}
|
||||
|
||||
// SchemaVisitorArbitrary is an additional visitor interface which handles
|
||||
// arbitrary types. For backwards compatibility, it's a separate interface
|
||||
// which is checked for at runtime.
|
||||
type SchemaVisitorArbitrary interface {
|
||||
SchemaVisitor
|
||||
VisitArbitrary(*Arbitrary)
|
||||
}
|
||||
|
||||
// Schema is the base definition of an openapi type.
|
||||
type Schema interface {
|
||||
// Giving a visitor here will let you visit the actual type.
|
||||
Accept(SchemaVisitor)
|
||||
|
||||
// Pretty print the name of the type.
|
||||
GetName() string
|
||||
// Describes how to access this field.
|
||||
GetPath() *Path
|
||||
// Describes the field.
|
||||
GetDescription() string
|
||||
// Default for that schema.
|
||||
GetDefault() interface{}
|
||||
// Returns type extensions.
|
||||
GetExtensions() map[string]interface{}
|
||||
}
|
||||
|
||||
// Path helps us keep track of type paths
|
||||
type Path struct {
|
||||
parent *Path
|
||||
key string
|
||||
}
|
||||
|
||||
func NewPath(key string) Path {
|
||||
return Path{key: key}
|
||||
}
|
||||
|
||||
func (p *Path) Get() []string {
|
||||
if p == nil {
|
||||
return []string{}
|
||||
}
|
||||
if p.key == "" {
|
||||
return p.parent.Get()
|
||||
}
|
||||
return append(p.parent.Get(), p.key)
|
||||
}
|
||||
|
||||
func (p *Path) Len() int {
|
||||
return len(p.Get())
|
||||
}
|
||||
|
||||
func (p *Path) String() string {
|
||||
return strings.Join(p.Get(), "")
|
||||
}
|
||||
|
||||
// ArrayPath appends an array index and creates a new path
|
||||
func (p *Path) ArrayPath(i int) Path {
|
||||
return Path{
|
||||
parent: p,
|
||||
key: fmt.Sprintf("[%d]", i),
|
||||
}
|
||||
}
|
||||
|
||||
// FieldPath appends a field name and creates a new path
|
||||
func (p *Path) FieldPath(field string) Path {
|
||||
return Path{
|
||||
parent: p,
|
||||
key: fmt.Sprintf(".%s", field),
|
||||
}
|
||||
}
|
||||
|
||||
// BaseSchema holds data used by each types of schema.
|
||||
type BaseSchema struct {
|
||||
Description string
|
||||
Extensions map[string]interface{}
|
||||
Default interface{}
|
||||
|
||||
Path Path
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetDescription() string {
|
||||
return b.Description
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetExtensions() map[string]interface{} {
|
||||
return b.Extensions
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetDefault() interface{} {
|
||||
return b.Default
|
||||
}
|
||||
|
||||
func (b *BaseSchema) GetPath() *Path {
|
||||
return &b.Path
|
||||
}
|
||||
|
||||
// Array must have all its element of the same `SubType`.
|
||||
type Array struct {
|
||||
BaseSchema
|
||||
|
||||
SubType Schema
|
||||
}
|
||||
|
||||
var _ Schema = &Array{}
|
||||
|
||||
func (a *Array) Accept(v SchemaVisitor) {
|
||||
v.VisitArray(a)
|
||||
}
|
||||
|
||||
func (a *Array) GetName() string {
|
||||
return fmt.Sprintf("Array of %s", a.SubType.GetName())
|
||||
}
|
||||
|
||||
// Kind is a complex object. It can have multiple different
|
||||
// subtypes for each field, as defined in the `Fields` field. Mandatory
|
||||
// fields are listed in `RequiredFields`. The key of the object is
|
||||
// always of type `string`.
|
||||
type Kind struct {
|
||||
BaseSchema
|
||||
|
||||
// Lists names of required fields.
|
||||
RequiredFields []string
|
||||
// Maps field names to types.
|
||||
Fields map[string]Schema
|
||||
// FieldOrder reports the canonical order for the fields.
|
||||
FieldOrder []string
|
||||
}
|
||||
|
||||
var _ Schema = &Kind{}
|
||||
|
||||
func (k *Kind) Accept(v SchemaVisitor) {
|
||||
v.VisitKind(k)
|
||||
}
|
||||
|
||||
func (k *Kind) GetName() string {
|
||||
properties := []string{}
|
||||
for key := range k.Fields {
|
||||
properties = append(properties, key)
|
||||
}
|
||||
return fmt.Sprintf("Kind(%v)", properties)
|
||||
}
|
||||
|
||||
// IsRequired returns true if `field` is a required field for this type.
|
||||
func (k *Kind) IsRequired(field string) bool {
|
||||
for _, f := range k.RequiredFields {
|
||||
if f == field {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Keys returns a alphabetically sorted list of keys.
|
||||
func (k *Kind) Keys() []string {
|
||||
keys := make([]string, 0)
|
||||
for key := range k.Fields {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// Map is an object who values must all be of the same `SubType`.
|
||||
// The key of the object is always of type `string`.
|
||||
type Map struct {
|
||||
BaseSchema
|
||||
|
||||
SubType Schema
|
||||
}
|
||||
|
||||
var _ Schema = &Map{}
|
||||
|
||||
func (m *Map) Accept(v SchemaVisitor) {
|
||||
v.VisitMap(m)
|
||||
}
|
||||
|
||||
func (m *Map) GetName() string {
|
||||
return fmt.Sprintf("Map of %s", m.SubType.GetName())
|
||||
}
|
||||
|
||||
// Primitive is a literal. There can be multiple types of primitives,
|
||||
// and this subtype can be visited through the `subType` field.
|
||||
type Primitive struct {
|
||||
BaseSchema
|
||||
|
||||
// Type of a primitive must be one of: integer, number, string, boolean.
|
||||
Type string
|
||||
Format string
|
||||
}
|
||||
|
||||
var _ Schema = &Primitive{}
|
||||
|
||||
func (p *Primitive) Accept(v SchemaVisitor) {
|
||||
v.VisitPrimitive(p)
|
||||
}
|
||||
|
||||
func (p *Primitive) GetName() string {
|
||||
if p.Format == "" {
|
||||
return p.Type
|
||||
}
|
||||
return fmt.Sprintf("%s (%s)", p.Type, p.Format)
|
||||
}
|
||||
|
||||
// Arbitrary is a value of any type (primitive, object or array)
|
||||
type Arbitrary struct {
|
||||
BaseSchema
|
||||
}
|
||||
|
||||
var _ Schema = &Arbitrary{}
|
||||
|
||||
func (a *Arbitrary) Accept(v SchemaVisitor) {
|
||||
if visitor, ok := v.(SchemaVisitorArbitrary); ok {
|
||||
visitor.VisitArbitrary(a)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Arbitrary) GetName() string {
|
||||
return "Arbitrary value (primitive, object or array)"
|
||||
}
|
||||
|
||||
// Reference implementation depends on the type of document.
|
||||
type Reference interface {
|
||||
Schema
|
||||
|
||||
Reference() string
|
||||
SubSchema() Schema
|
||||
}
|
79
e2e/vendor/k8s.io/kube-openapi/pkg/util/trie.go
generated
vendored
Normal file
79
e2e/vendor/k8s.io/kube-openapi/pkg/util/trie.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2016 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 util
|
||||
|
||||
// A simple trie implementation with Add and HasPrefix methods only.
|
||||
type Trie struct {
|
||||
children map[byte]*Trie
|
||||
wordTail bool
|
||||
word string
|
||||
}
|
||||
|
||||
// NewTrie creates a Trie and add all strings in the provided list to it.
|
||||
func NewTrie(list []string) Trie {
|
||||
ret := Trie{
|
||||
children: make(map[byte]*Trie),
|
||||
wordTail: false,
|
||||
}
|
||||
for _, v := range list {
|
||||
ret.Add(v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Add adds a word to this trie
|
||||
func (t *Trie) Add(v string) {
|
||||
root := t
|
||||
for _, b := range []byte(v) {
|
||||
child, exists := root.children[b]
|
||||
if !exists {
|
||||
child = &Trie{
|
||||
children: make(map[byte]*Trie),
|
||||
wordTail: false,
|
||||
}
|
||||
root.children[b] = child
|
||||
}
|
||||
root = child
|
||||
}
|
||||
root.wordTail = true
|
||||
root.word = v
|
||||
}
|
||||
|
||||
// HasPrefix returns true of v has any of the prefixes stored in this trie.
|
||||
func (t *Trie) HasPrefix(v string) bool {
|
||||
_, has := t.GetPrefix(v)
|
||||
return has
|
||||
}
|
||||
|
||||
// GetPrefix is like HasPrefix but return the prefix in case of match or empty string otherwise.
|
||||
func (t *Trie) GetPrefix(v string) (string, bool) {
|
||||
root := t
|
||||
if root.wordTail {
|
||||
return root.word, true
|
||||
}
|
||||
for _, b := range []byte(v) {
|
||||
child, exists := root.children[b]
|
||||
if !exists {
|
||||
return "", false
|
||||
}
|
||||
if child.wordTail {
|
||||
return child.word, true
|
||||
}
|
||||
root = child
|
||||
}
|
||||
return "", false
|
||||
}
|
115
e2e/vendor/k8s.io/kube-openapi/pkg/util/util.go
generated
vendored
Normal file
115
e2e/vendor/k8s.io/kube-openapi/pkg/util/util.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright 2017 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 util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [DEPRECATED] ToCanonicalName converts Golang package/type canonical name into REST friendly OpenAPI name.
|
||||
// This method is deprecated because it has a misleading name. Please use ToRESTFriendlyName
|
||||
// instead
|
||||
//
|
||||
// NOTE: actually the "canonical name" in this method should be named "REST friendly OpenAPI name",
|
||||
// which is different from "canonical name" defined in GetCanonicalTypeName. The "canonical name" defined
|
||||
// in GetCanonicalTypeName means Go type names with full package path.
|
||||
//
|
||||
// Examples of REST friendly OpenAPI name:
|
||||
//
|
||||
// Input: k8s.io/api/core/v1.Pod
|
||||
// Output: io.k8s.api.core.v1.Pod
|
||||
//
|
||||
// Input: k8s.io/api/core/v1
|
||||
// Output: io.k8s.api.core.v1
|
||||
//
|
||||
// Input: csi.storage.k8s.io/v1alpha1.CSINodeInfo
|
||||
// Output: io.k8s.storage.csi.v1alpha1.CSINodeInfo
|
||||
func ToCanonicalName(name string) string {
|
||||
return ToRESTFriendlyName(name)
|
||||
}
|
||||
|
||||
// ToRESTFriendlyName converts Golang package/type canonical name into REST friendly OpenAPI name.
|
||||
//
|
||||
// Examples of REST friendly OpenAPI name:
|
||||
//
|
||||
// Input: k8s.io/api/core/v1.Pod
|
||||
// Output: io.k8s.api.core.v1.Pod
|
||||
//
|
||||
// Input: k8s.io/api/core/v1
|
||||
// Output: io.k8s.api.core.v1
|
||||
//
|
||||
// Input: csi.storage.k8s.io/v1alpha1.CSINodeInfo
|
||||
// Output: io.k8s.storage.csi.v1alpha1.CSINodeInfo
|
||||
func ToRESTFriendlyName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
parts := strings.Split(nameParts[0], ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
nameParts[0] = strings.Join(parts, ".")
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
// OpenAPICanonicalTypeNamer is an interface for models without Go type to seed model name.
|
||||
//
|
||||
// OpenAPI canonical names are Go type names with full package path, for uniquely indentifying
|
||||
// a model / Go type. If a Go type is vendored from another package, only the path after "/vendor/"
|
||||
// should be used. For custom resource definition (CRD), the canonical name is expected to be
|
||||
//
|
||||
// group/version.kind
|
||||
//
|
||||
// Examples of canonical name:
|
||||
//
|
||||
// Go type: k8s.io/kubernetes/pkg/apis/core.Pod
|
||||
// CRD: csi.storage.k8s.io/v1alpha1.CSINodeInfo
|
||||
//
|
||||
// Example for vendored Go type:
|
||||
//
|
||||
// Original full path: k8s.io/kubernetes/vendor/k8s.io/api/core/v1.Pod
|
||||
// Canonical name: k8s.io/api/core/v1.Pod
|
||||
//
|
||||
// Original full path: vendor/k8s.io/api/core/v1.Pod
|
||||
// Canonical name: k8s.io/api/core/v1.Pod
|
||||
type OpenAPICanonicalTypeNamer interface {
|
||||
OpenAPICanonicalTypeName() string
|
||||
}
|
||||
|
||||
// GetCanonicalTypeName will find the canonical type name of a sample object, removing
|
||||
// the "vendor" part of the path
|
||||
func GetCanonicalTypeName(model interface{}) string {
|
||||
if namer, ok := model.(OpenAPICanonicalTypeNamer); ok {
|
||||
return namer.OpenAPICanonicalTypeName()
|
||||
}
|
||||
t := reflect.TypeOf(model)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.PkgPath() == "" {
|
||||
return t.Name()
|
||||
}
|
||||
path := t.PkgPath()
|
||||
if strings.Contains(path, "/vendor/") {
|
||||
path = path[strings.Index(path, "/vendor/")+len("/vendor/"):]
|
||||
} else if strings.HasPrefix(path, "vendor/") {
|
||||
path = strings.TrimPrefix(path, "vendor/")
|
||||
}
|
||||
return path + "." + t.Name()
|
||||
}
|
2
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/.gitignore
generated
vendored
Normal file
2
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
secrets.yml
|
||||
coverage.out
|
202
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/LICENSE
generated
vendored
Normal file
202
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
46
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/api.go
generated
vendored
Normal file
46
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/api.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Error represents a error interface all swagger framework errors implement
|
||||
type Error interface {
|
||||
error
|
||||
Code() int32
|
||||
}
|
||||
|
||||
type apiError struct {
|
||||
code int32
|
||||
message string
|
||||
}
|
||||
|
||||
func (a *apiError) Error() string {
|
||||
return a.message
|
||||
}
|
||||
|
||||
func (a *apiError) Code() int32 {
|
||||
return a.code
|
||||
}
|
||||
|
||||
// New creates a new API error with a code and a message
|
||||
func New(code int32, message string, args ...interface{}) Error {
|
||||
if len(args) > 0 {
|
||||
return &apiError{code, fmt.Sprintf(message, args...)}
|
||||
}
|
||||
return &apiError{code, message}
|
||||
}
|
26
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/doc.go
generated
vendored
Normal file
26
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/doc.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors provides an Error interface and several concrete types
|
||||
implementing this interface to manage API errors and JSON-schema validation
|
||||
errors.
|
||||
|
||||
A middleware handler ServeError() is provided to serve the errors types
|
||||
it defines.
|
||||
|
||||
It is used throughout the various go-openapi toolkit libraries
|
||||
(https://github.com/go-openapi).
|
||||
*/
|
||||
package errors
|
44
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/headers.go
generated
vendored
Normal file
44
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/headers.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
// Validation represents a failure of a precondition
|
||||
type Validation struct {
|
||||
code int32
|
||||
Name string
|
||||
In string
|
||||
Value interface{}
|
||||
Valid interface{}
|
||||
message string
|
||||
Values []interface{}
|
||||
}
|
||||
|
||||
func (e *Validation) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// Code the error code
|
||||
func (e *Validation) Code() int32 {
|
||||
return e.code
|
||||
}
|
||||
|
||||
// ValidateName produces an error message name for an aliased property
|
||||
func (e *Validation) ValidateName(name string) *Validation {
|
||||
if e.Name == "" && name != "" {
|
||||
e.Name = name
|
||||
e.message = name + e.message
|
||||
}
|
||||
return e
|
||||
}
|
573
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/schema.go
generated
vendored
Normal file
573
e2e/vendor/k8s.io/kube-openapi/pkg/validation/errors/schema.go
generated
vendored
Normal file
@ -0,0 +1,573 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
invalidType = "%s is an invalid type name"
|
||||
typeFail = "%s in %s must be of type %s"
|
||||
typeFailWithData = "%s in %s must be of type %s: %q"
|
||||
typeFailWithError = "%s in %s must be of type %s, because: %s"
|
||||
requiredFail = "%s in %s is required"
|
||||
tooLongMessage = "%s in %s should be at most %d chars long"
|
||||
tooShortMessage = "%s in %s should be at least %d chars long"
|
||||
patternFail = "%s in %s should match '%s'"
|
||||
enumFail = "%s in %s should be one of %v"
|
||||
multipleOfFail = "%s in %s should be a multiple of %v"
|
||||
maxIncFail = "%s in %s should be less than or equal to %v"
|
||||
maxExcFail = "%s in %s should be less than %v"
|
||||
minIncFail = "%s in %s should be greater than or equal to %v"
|
||||
minExcFail = "%s in %s should be greater than %v"
|
||||
uniqueFail = "%s in %s shouldn't contain duplicates"
|
||||
maxItemsFail = "%s in %s should have at most %d items"
|
||||
minItemsFail = "%s in %s should have at least %d items"
|
||||
typeFailNoIn = "%s must be of type %s"
|
||||
typeFailWithDataNoIn = "%s must be of type %s: %q"
|
||||
typeFailWithErrorNoIn = "%s must be of type %s, because: %s"
|
||||
requiredFailNoIn = "%s is required"
|
||||
tooLongMessageNoIn = "%s should be at most %d chars long"
|
||||
tooShortMessageNoIn = "%s should be at least %d chars long"
|
||||
patternFailNoIn = "%s should match '%s'"
|
||||
enumFailNoIn = "%s should be one of %v"
|
||||
multipleOfFailNoIn = "%s should be a multiple of %v"
|
||||
maxIncFailNoIn = "%s should be less than or equal to %v"
|
||||
maxExcFailNoIn = "%s should be less than %v"
|
||||
minIncFailNoIn = "%s should be greater than or equal to %v"
|
||||
minExcFailNoIn = "%s should be greater than %v"
|
||||
uniqueFailNoIn = "%s shouldn't contain duplicates"
|
||||
maxItemsFailNoIn = "%s should have at most %d items"
|
||||
minItemsFailNoIn = "%s should have at least %d items"
|
||||
noAdditionalItems = "%s in %s can't have additional items"
|
||||
noAdditionalItemsNoIn = "%s can't have additional items"
|
||||
tooFewProperties = "%s in %s should have at least %d properties"
|
||||
tooFewPropertiesNoIn = "%s should have at least %d properties"
|
||||
tooManyProperties = "%s in %s should have at most %d properties"
|
||||
tooManyPropertiesNoIn = "%s should have at most %d properties"
|
||||
unallowedProperty = "%s.%s in %s is a forbidden property"
|
||||
unallowedPropertyNoIn = "%s.%s is a forbidden property"
|
||||
failedAllPatternProps = "%s.%s in %s failed all pattern properties"
|
||||
failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
|
||||
multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v"
|
||||
)
|
||||
|
||||
// All code responses can be used to differentiate errors for different handling
|
||||
// by the consuming program
|
||||
const (
|
||||
// CompositeErrorCode remains 422 for backwards-compatibility
|
||||
// and to separate it from validation errors with cause
|
||||
CompositeErrorCode = 422
|
||||
// InvalidTypeCode is used for any subclass of invalid types
|
||||
InvalidTypeCode = 600 + iota
|
||||
RequiredFailCode
|
||||
TooLongFailCode
|
||||
TooShortFailCode
|
||||
PatternFailCode
|
||||
EnumFailCode
|
||||
MultipleOfFailCode
|
||||
MaxFailCode
|
||||
MinFailCode
|
||||
UniqueFailCode
|
||||
MaxItemsFailCode
|
||||
MinItemsFailCode
|
||||
NoAdditionalItemsCode
|
||||
TooFewPropertiesCode
|
||||
TooManyPropertiesCode
|
||||
UnallowedPropertyCode
|
||||
FailedAllPatternPropsCode
|
||||
MultipleOfMustBePositiveCode
|
||||
)
|
||||
|
||||
// CompositeError is an error that groups several errors together
|
||||
type CompositeError struct {
|
||||
Errors []error
|
||||
code int32
|
||||
message string
|
||||
}
|
||||
|
||||
// Code for this error
|
||||
func (c *CompositeError) Code() int32 {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (c *CompositeError) Error() string {
|
||||
if len(c.Errors) > 0 {
|
||||
msgs := []string{c.message + ":"}
|
||||
for _, e := range c.Errors {
|
||||
msgs = append(msgs, e.Error())
|
||||
}
|
||||
return strings.Join(msgs, "\n")
|
||||
}
|
||||
return c.message
|
||||
}
|
||||
|
||||
// CompositeValidationError an error to wrap a bunch of other errors
|
||||
func CompositeValidationError(errors ...error) *CompositeError {
|
||||
return &CompositeError{
|
||||
code: CompositeErrorCode,
|
||||
Errors: append([]error{}, errors...),
|
||||
message: "validation failure list",
|
||||
}
|
||||
}
|
||||
|
||||
// FailedAllPatternProperties an error for when the property doesn't match a pattern
|
||||
func FailedAllPatternProperties(name, in, key string) *Validation {
|
||||
msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
|
||||
}
|
||||
return &Validation{
|
||||
code: FailedAllPatternPropsCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: key,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyNotAllowed an error for when the property doesn't match a pattern
|
||||
func PropertyNotAllowed(name, in, key string) *Validation {
|
||||
msg := fmt.Sprintf(unallowedProperty, name, key, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
|
||||
}
|
||||
return &Validation{
|
||||
code: UnallowedPropertyCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: key,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooFewProperties an error for an object with too few properties
|
||||
func TooFewProperties(name, in string, minProperties, size int64) *Validation {
|
||||
msg := fmt.Sprintf(tooFewProperties, name, in, minProperties)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooFewPropertiesNoIn, name, minProperties)
|
||||
}
|
||||
return &Validation{
|
||||
code: TooFewPropertiesCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: size,
|
||||
Valid: minProperties,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooManyProperties an error for an object with too many properties
|
||||
func TooManyProperties(name, in string, maxProperties, size int64) *Validation {
|
||||
msg := fmt.Sprintf(tooManyProperties, name, in, maxProperties)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooManyPropertiesNoIn, name, maxProperties)
|
||||
}
|
||||
return &Validation{
|
||||
code: TooManyPropertiesCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: size,
|
||||
Valid: maxProperties,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// AdditionalItemsNotAllowed an error for invalid additional items
|
||||
func AdditionalItemsNotAllowed(name, in string) *Validation {
|
||||
msg := fmt.Sprintf(noAdditionalItems, name, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
|
||||
}
|
||||
return &Validation{
|
||||
code: NoAdditionalItemsCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidCollectionFormat another flavor of invalid type error
|
||||
func InvalidCollectionFormat(name, in, format string) *Validation {
|
||||
return &Validation{
|
||||
code: InvalidTypeCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: format,
|
||||
message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidTypeName an error for when the type is invalid
|
||||
func InvalidTypeName(typeName string) *Validation {
|
||||
return &Validation{
|
||||
code: InvalidTypeCode,
|
||||
Value: typeName,
|
||||
message: fmt.Sprintf(invalidType, typeName),
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidType creates an error for when the type is invalid
|
||||
func InvalidType(name, in, typeName string, value interface{}) *Validation {
|
||||
var message string
|
||||
|
||||
if in != "" {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
|
||||
case error:
|
||||
message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
|
||||
default:
|
||||
message = fmt.Sprintf(typeFail, name, in, typeName)
|
||||
}
|
||||
} else {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
|
||||
case error:
|
||||
message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
|
||||
default:
|
||||
message = fmt.Sprintf(typeFailNoIn, name, typeName)
|
||||
}
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: InvalidTypeCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DuplicateItems error for when an array contains duplicates
|
||||
func DuplicateItems(name, in string) *Validation {
|
||||
msg := fmt.Sprintf(uniqueFail, name, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(uniqueFailNoIn, name)
|
||||
}
|
||||
return &Validation{
|
||||
code: UniqueFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooManyItems error for when an array contains too many items
|
||||
func TooManyItems(name, in string, max int64, value interface{}) *Validation {
|
||||
msg := fmt.Sprintf(maxItemsFail, name, in, max)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: MaxItemsFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Valid: max,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooFewItems error for when an array contains too few items
|
||||
func TooFewItems(name, in string, min int64, value interface{}) *Validation {
|
||||
msg := fmt.Sprintf(minItemsFail, name, in, min)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(minItemsFailNoIn, name, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinItemsFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Valid: min,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMaximumInt error for when maxinum validation fails
|
||||
func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interface{}) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := maxIncFailNoIn
|
||||
if exclusive {
|
||||
m = maxExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, max)
|
||||
} else {
|
||||
m := maxIncFail
|
||||
if exclusive {
|
||||
m = maxExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: MaxFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMaximumUint error for when maxinum validation fails
|
||||
func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value interface{}) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := maxIncFailNoIn
|
||||
if exclusive {
|
||||
m = maxExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, max)
|
||||
} else {
|
||||
m := maxIncFail
|
||||
if exclusive {
|
||||
m = maxExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: MaxFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMaximum error for when maxinum validation fails
|
||||
func ExceedsMaximum(name, in string, max float64, exclusive bool, value interface{}) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := maxIncFailNoIn
|
||||
if exclusive {
|
||||
m = maxExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, max)
|
||||
} else {
|
||||
m := maxIncFail
|
||||
if exclusive {
|
||||
m = maxExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: MaxFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMinimumInt error for when maxinum validation fails
|
||||
func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interface{}) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := minIncFailNoIn
|
||||
if exclusive {
|
||||
m = minExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, min)
|
||||
} else {
|
||||
m := minIncFail
|
||||
if exclusive {
|
||||
m = minExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMinimumUint error for when maxinum validation fails
|
||||
func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value interface{}) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := minIncFailNoIn
|
||||
if exclusive {
|
||||
m = minExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, min)
|
||||
} else {
|
||||
m := minIncFail
|
||||
if exclusive {
|
||||
m = minExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMinimum error for when maxinum validation fails
|
||||
func ExceedsMinimum(name, in string, min float64, exclusive bool, value interface{}) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := minIncFailNoIn
|
||||
if exclusive {
|
||||
m = minExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, min)
|
||||
} else {
|
||||
m := minIncFail
|
||||
if exclusive {
|
||||
m = minExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// NotMultipleOf error for when multiple of validation fails
|
||||
func NotMultipleOf(name, in string, multiple, value interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(multipleOfFailNoIn, name, multiple)
|
||||
} else {
|
||||
msg = fmt.Sprintf(multipleOfFail, name, in, multiple)
|
||||
}
|
||||
return &Validation{
|
||||
code: MultipleOfFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// EnumFail error for when an enum validation fails
|
||||
func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(enumFailNoIn, name, values)
|
||||
} else {
|
||||
msg = fmt.Sprintf(enumFail, name, in, values)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: EnumFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Values: values,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// Required error for when a value is missing
|
||||
func Required(name, in string) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(requiredFailNoIn, name)
|
||||
} else {
|
||||
msg = fmt.Sprintf(requiredFail, name, in)
|
||||
}
|
||||
return &Validation{
|
||||
code: RequiredFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooLong error for when a string is too long
|
||||
func TooLong(name, in string, max int64, value interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
|
||||
} else {
|
||||
msg = fmt.Sprintf(tooLongMessage, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: TooLongFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Valid: max,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooShort error for when a string is too short
|
||||
func TooShort(name, in string, min int64, value interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
|
||||
} else {
|
||||
msg = fmt.Sprintf(tooShortMessage, name, in, min)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: TooShortFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Valid: min,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// FailedPattern error for when a string fails a regex pattern match
|
||||
// the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
|
||||
func FailedPattern(name, in, pattern string, value interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(patternFailNoIn, name, pattern)
|
||||
} else {
|
||||
msg = fmt.Sprintf(patternFail, name, in, pattern)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: PatternFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// MultipleOfMustBePositive error for when a
|
||||
// multipleOf factor is negative
|
||||
func MultipleOfMustBePositive(name, in string, factor interface{}) *Validation {
|
||||
return &Validation{
|
||||
code: MultipleOfMustBePositiveCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: factor,
|
||||
message: fmt.Sprintf(multipleOfMustBePositive, name, factor),
|
||||
}
|
||||
}
|
2
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/.gitignore
generated
vendored
Normal file
2
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
secrets.yml
|
||||
coverage.out
|
202
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/LICENSE
generated
vendored
Normal file
202
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
24
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/contact_info.go
generated
vendored
Normal file
24
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/contact_info.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
// ContactInfo contact information for the exposed API.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#contactObject
|
||||
type ContactInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
}
|
24
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/external_docs.go
generated
vendored
Normal file
24
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/external_docs.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for
|
||||
// extended documentation.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#externalDocumentationObject
|
||||
type ExternalDocumentation struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
1517
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go
generated
vendored
Normal file
1517
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
118
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/header.go
generated
vendored
Normal file
118
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/header.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonArray = "array"
|
||||
)
|
||||
|
||||
// HeaderProps describes a response header
|
||||
type HeaderProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// Header describes a header for a response of the API
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#headerObject
|
||||
type Header struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
VendorExtensible
|
||||
HeaderProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (h Header) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(h)
|
||||
}
|
||||
b1, err := json.Marshal(h.CommonValidations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(h.SimpleSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(h.HeaderProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(h.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3, b4), nil
|
||||
}
|
||||
|
||||
func (h Header) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
CommonValidations commonValidationsOmitZero `json:",inline"`
|
||||
SimpleSchema simpleSchemaOmitZero `json:",inline"`
|
||||
Extensions
|
||||
HeaderProps
|
||||
}
|
||||
x.CommonValidations = commonValidationsOmitZero(h.CommonValidations)
|
||||
x.SimpleSchema = simpleSchemaOmitZero(h.SimpleSchema)
|
||||
x.Extensions = internal.SanitizeExtensions(h.Extensions)
|
||||
x.HeaderProps = h.HeaderProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this header from JSON
|
||||
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, h)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &h.CommonValidations); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.SimpleSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &h.HeaderProps)
|
||||
}
|
||||
|
||||
func (h *Header) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
Extensions
|
||||
HeaderProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.CommonValidations = x.CommonValidations
|
||||
h.SimpleSchema = x.SimpleSchema
|
||||
h.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
h.HeaderProps = x.HeaderProps
|
||||
|
||||
return nil
|
||||
}
|
219
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/info.go
generated
vendored
Normal file
219
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/info.go
generated
vendored
Normal file
@ -0,0 +1,219 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Extensions vendor specific extensions
|
||||
type Extensions map[string]interface{}
|
||||
|
||||
// Add adds a value to these extensions
|
||||
func (e Extensions) Add(key string, value interface{}) {
|
||||
realKey := strings.ToLower(key)
|
||||
e[realKey] = value
|
||||
}
|
||||
|
||||
// GetString gets a string value from the extensions
|
||||
func (e Extensions) GetString(key string) (string, bool) {
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
str, ok := v.(string)
|
||||
return str, ok
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// GetBool gets a string value from the extensions
|
||||
func (e Extensions) GetBool(key string) (bool, bool) {
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
str, ok := v.(bool)
|
||||
return str, ok
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// GetStringSlice gets a string value from the extensions
|
||||
func (e Extensions) GetStringSlice(key string) ([]string, bool) {
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
arr, isSlice := v.([]interface{})
|
||||
if !isSlice {
|
||||
return nil, false
|
||||
}
|
||||
var strs []string
|
||||
for _, iface := range arr {
|
||||
str, isString := iface.(string)
|
||||
if !isString {
|
||||
return nil, false
|
||||
}
|
||||
strs = append(strs, str)
|
||||
}
|
||||
return strs, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GetObject gets the object value from the extensions.
|
||||
// out must be a json serializable type; the json go struct
|
||||
// tags of out are used to populate it.
|
||||
func (e Extensions) GetObject(key string, out interface{}) error {
|
||||
// This json serialization/deserialization could be replaced with
|
||||
// an approach using reflection if the optimization becomes justified.
|
||||
if v, ok := e[strings.ToLower(key)]; ok {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(b, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Extensions) sanitizeWithExtra() (extra map[string]any) {
|
||||
for k, v := range e {
|
||||
if !internal.IsExtensionKey(k) {
|
||||
if extra == nil {
|
||||
extra = make(map[string]any)
|
||||
}
|
||||
extra[k] = v
|
||||
delete(e, k)
|
||||
}
|
||||
}
|
||||
return extra
|
||||
}
|
||||
|
||||
// VendorExtensible composition block.
|
||||
type VendorExtensible struct {
|
||||
Extensions Extensions
|
||||
}
|
||||
|
||||
// AddExtension adds an extension to this extensible object
|
||||
func (v *VendorExtensible) AddExtension(key string, value interface{}) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
if v.Extensions == nil {
|
||||
v.Extensions = make(map[string]interface{})
|
||||
}
|
||||
v.Extensions.Add(key, value)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the extensions to json
|
||||
func (v VendorExtensible) MarshalJSON() ([]byte, error) {
|
||||
toser := make(map[string]interface{})
|
||||
for k, v := range v.Extensions {
|
||||
lk := strings.ToLower(k)
|
||||
if strings.HasPrefix(lk, "x-") {
|
||||
toser[k] = v
|
||||
}
|
||||
}
|
||||
return json.Marshal(toser)
|
||||
}
|
||||
|
||||
// UnmarshalJSON for this extensible object
|
||||
func (v *VendorExtensible) UnmarshalJSON(data []byte) error {
|
||||
var d map[string]interface{}
|
||||
if err := json.Unmarshal(data, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, vv := range d {
|
||||
lk := strings.ToLower(k)
|
||||
if strings.HasPrefix(lk, "x-") {
|
||||
if v.Extensions == nil {
|
||||
v.Extensions = map[string]interface{}{}
|
||||
}
|
||||
v.Extensions[k] = vv
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InfoProps the properties for an info definition
|
||||
type InfoProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
TermsOfService string `json:"termsOfService,omitempty"`
|
||||
Contact *ContactInfo `json:"contact,omitempty"`
|
||||
License *License `json:"license,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// Info object provides metadata about the API.
|
||||
// The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#infoObject
|
||||
type Info struct {
|
||||
VendorExtensible
|
||||
InfoProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (i Info) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(i)
|
||||
}
|
||||
b1, err := json.Marshal(i.InfoProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(i.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (i Info) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
InfoProps
|
||||
}
|
||||
x.Extensions = i.Extensions
|
||||
x.InfoProps = i.InfoProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (i *Info) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, i)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &i.InfoProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &i.VendorExtensible)
|
||||
}
|
||||
|
||||
func (i *Info) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
InfoProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
i.InfoProps = x.InfoProps
|
||||
return nil
|
||||
}
|
180
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/items.go
generated
vendored
Normal file
180
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/items.go
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonRef = "$ref"
|
||||
)
|
||||
|
||||
// SimpleSchema describe swagger simple schemas for parameters and headers
|
||||
type SimpleSchema struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Nullable bool `json:"nullable,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Items *Items `json:"items,omitempty"`
|
||||
CollectionFormat string `json:"collectionFormat,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type simpleSchemaOmitZero struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Nullable bool `json:"nullable,omitzero"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Items *Items `json:"items,omitzero"`
|
||||
CollectionFormat string `json:"collectionFormat,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
// CommonValidations describe common JSON-schema validations
|
||||
type CommonValidations struct {
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||
MinLength *int64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||
MinItems *int64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||
Enum []interface{} `json:"enum,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type commonValidationsOmitZero struct {
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitzero"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitzero"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||
MinLength *int64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||
MinItems *int64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitzero"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||
Enum []interface{} `json:"enum,omitempty"`
|
||||
}
|
||||
|
||||
// Items a limited subset of JSON-Schema's items object.
|
||||
// It is used by parameter definitions that are not located in "body".
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#items-object
|
||||
type Items struct {
|
||||
Refable
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
VendorExtensible
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (i *Items) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, i)
|
||||
}
|
||||
|
||||
var validations CommonValidations
|
||||
if err := json.Unmarshal(data, &validations); err != nil {
|
||||
return err
|
||||
}
|
||||
var ref Refable
|
||||
if err := json.Unmarshal(data, &ref); err != nil {
|
||||
return err
|
||||
}
|
||||
var simpleSchema SimpleSchema
|
||||
if err := json.Unmarshal(data, &simpleSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
var vendorExtensible VendorExtensible
|
||||
if err := json.Unmarshal(data, &vendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Refable = ref
|
||||
i.CommonValidations = validations
|
||||
i.SimpleSchema = simpleSchema
|
||||
i.VendorExtensible = vendorExtensible
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Items) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
Extensions
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := i.Refable.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.CommonValidations = x.CommonValidations
|
||||
i.SimpleSchema = x.SimpleSchema
|
||||
i.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (i Items) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(i)
|
||||
}
|
||||
b1, err := json.Marshal(i.CommonValidations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(i.SimpleSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(i.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(i.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b4, b3, b1, b2), nil
|
||||
}
|
||||
|
||||
func (i Items) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
CommonValidations commonValidationsOmitZero `json:",inline"`
|
||||
SimpleSchema simpleSchemaOmitZero `json:",inline"`
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
Extensions
|
||||
}
|
||||
x.CommonValidations = commonValidationsOmitZero(i.CommonValidations)
|
||||
x.SimpleSchema = simpleSchemaOmitZero(i.SimpleSchema)
|
||||
x.Ref = i.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(i.Extensions)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
23
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/license.go
generated
vendored
Normal file
23
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/license.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
// License information for the exposed API.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#licenseObject
|
||||
type License struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
146
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/operation.go
generated
vendored
Normal file
146
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/operation.go
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// OperationProps describes an operation
|
||||
//
|
||||
// NOTES:
|
||||
// - schemes, when present must be from [http, https, ws, wss]: see validate
|
||||
// - Security is handled as a special case: see MarshalJSON function
|
||||
type OperationProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Schemes []string `json:"schemes,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
ID string `json:"operationId,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
Responses *Responses `json:"responses,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type operationPropsOmitZero struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Schemes []string `json:"schemes,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"`
|
||||
ID string `json:"operationId,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty,omitzero"`
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
Responses *Responses `json:"responses,omitzero"`
|
||||
}
|
||||
|
||||
// MarshalJSON takes care of serializing operation properties to JSON
|
||||
//
|
||||
// We use a custom marhaller here to handle a special cases related to
|
||||
// the Security field. We need to preserve zero length slice
|
||||
// while omitting the field when the value is nil/unset.
|
||||
func (op OperationProps) MarshalJSON() ([]byte, error) {
|
||||
type Alias OperationProps
|
||||
if op.Security == nil {
|
||||
return json.Marshal(&struct {
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
Security: op.Security,
|
||||
Alias: (*Alias)(&op),
|
||||
})
|
||||
}
|
||||
return json.Marshal(&struct {
|
||||
Security []map[string][]string `json:"security"`
|
||||
*Alias
|
||||
}{
|
||||
Security: op.Security,
|
||||
Alias: (*Alias)(&op),
|
||||
})
|
||||
}
|
||||
|
||||
// Operation describes a single API operation on a path.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#operationObject
|
||||
type Operation struct {
|
||||
VendorExtensible
|
||||
OperationProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (o *Operation) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, o)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &o.OperationProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &o.VendorExtensible)
|
||||
}
|
||||
|
||||
func (o *Operation) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
type OperationPropsNoMethods OperationProps // strip MarshalJSON method
|
||||
var x struct {
|
||||
Extensions
|
||||
OperationPropsNoMethods
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
o.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
o.OperationProps = OperationProps(x.OperationPropsNoMethods)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (o Operation) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(o)
|
||||
}
|
||||
b1, err := json.Marshal(o.OperationProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(o.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
|
||||
func (o Operation) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
OperationProps operationPropsOmitZero `json:",inline"`
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(o.Extensions)
|
||||
x.OperationProps = operationPropsOmitZero(o.OperationProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
172
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/parameter.go
generated
vendored
Normal file
172
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/parameter.go
generated
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// ParamProps describes the specific attributes of an operation parameter
|
||||
//
|
||||
// NOTE:
|
||||
// - Schema is defined when "in" == "body": see validate
|
||||
// - AllowEmptyValue is allowed where "in" == "query" || "formData"
|
||||
type ParamProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
In string `json:"in,omitempty"`
|
||||
Required bool `json:"required,omitempty"`
|
||||
Schema *Schema `json:"schema,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type paramPropsOmitZero struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
In string `json:"in,omitempty"`
|
||||
Required bool `json:"required,omitzero"`
|
||||
Schema *Schema `json:"schema,omitzero"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitzero"`
|
||||
}
|
||||
|
||||
// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn).
|
||||
//
|
||||
// There are five possible parameter types.
|
||||
// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part
|
||||
//
|
||||
// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`,
|
||||
// the path parameter is `itemId`.
|
||||
//
|
||||
// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`.
|
||||
// * Header - Custom headers that are expected as part of the request.
|
||||
// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be
|
||||
//
|
||||
// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for
|
||||
// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist
|
||||
// together for the same operation.
|
||||
//
|
||||
// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or
|
||||
//
|
||||
// `multipart/form-data` are used as the content type of the request (in Swagger's definition,
|
||||
// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used
|
||||
// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be
|
||||
// declared together with a body parameter for the same operation. Form parameters have a different format based on
|
||||
// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4).
|
||||
// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload.
|
||||
// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple
|
||||
// parameters that are being transferred.
|
||||
// * `multipart/form-data` - each parameter takes a section in the payload with an internal header.
|
||||
// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is
|
||||
// `submit-name`. This type of form parameters is more commonly used for file transfers.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#parameterObject
|
||||
type Parameter struct {
|
||||
Refable
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
VendorExtensible
|
||||
ParamProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *Parameter) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &p.CommonValidations); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.SimpleSchema); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &p.ParamProps)
|
||||
}
|
||||
|
||||
func (p *Parameter) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
CommonValidations
|
||||
SimpleSchema
|
||||
Extensions
|
||||
ParamProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.Refable.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
p.CommonValidations = x.CommonValidations
|
||||
p.SimpleSchema = x.SimpleSchema
|
||||
p.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
p.ParamProps = x.ParamProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (p Parameter) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(p)
|
||||
}
|
||||
b1, err := json.Marshal(p.CommonValidations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(p.SimpleSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5, err := json.Marshal(p.ParamProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b3, b1, b2, b4, b5), nil
|
||||
}
|
||||
|
||||
func (p Parameter) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
CommonValidations commonValidationsOmitZero `json:",inline"`
|
||||
SimpleSchema simpleSchemaOmitZero `json:",inline"`
|
||||
ParamProps paramPropsOmitZero `json:",inline"`
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
Extensions
|
||||
}
|
||||
x.CommonValidations = commonValidationsOmitZero(p.CommonValidations)
|
||||
x.SimpleSchema = simpleSchemaOmitZero(p.SimpleSchema)
|
||||
x.Extensions = internal.SanitizeExtensions(p.Extensions)
|
||||
x.ParamProps = paramPropsOmitZero(p.ParamProps)
|
||||
x.Ref = p.Refable.Ref.String()
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
113
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/path_item.go
generated
vendored
Normal file
113
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/path_item.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// PathItemProps the path item specific properties
|
||||
type PathItemProps struct {
|
||||
Get *Operation `json:"get,omitempty"`
|
||||
Put *Operation `json:"put,omitempty"`
|
||||
Post *Operation `json:"post,omitempty"`
|
||||
Delete *Operation `json:"delete,omitempty"`
|
||||
Options *Operation `json:"options,omitempty"`
|
||||
Head *Operation `json:"head,omitempty"`
|
||||
Patch *Operation `json:"patch,omitempty"`
|
||||
Parameters []Parameter `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// PathItem describes the operations available on a single path.
|
||||
// A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||
// The path itself is still exposed to the documentation viewer but they will
|
||||
// not know which operations and parameters are available.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#pathItemObject
|
||||
type PathItem struct {
|
||||
Refable
|
||||
VendorExtensible
|
||||
PathItemProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *PathItem) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &p.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &p.PathItemProps)
|
||||
}
|
||||
|
||||
func (p *PathItem) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
PathItemProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.Refable.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
p.PathItemProps = x.PathItemProps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (p PathItem) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(p)
|
||||
}
|
||||
b3, err := json.Marshal(p.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5, err := json.Marshal(p.PathItemProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b3, b4, b5)
|
||||
return concated, nil
|
||||
}
|
||||
|
||||
func (p PathItem) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
Extensions
|
||||
PathItemProps
|
||||
}
|
||||
x.Ref = p.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(p.Extensions)
|
||||
x.PathItemProps = p.PathItemProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
164
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/paths.go
generated
vendored
Normal file
164
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/paths.go
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Paths holds the relative paths to the individual endpoints.
|
||||
// The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order
|
||||
// to construct the full URL.
|
||||
// The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#pathsObject
|
||||
type Paths struct {
|
||||
VendorExtensible
|
||||
Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/"
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (p *Paths) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, p)
|
||||
}
|
||||
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range res {
|
||||
if strings.HasPrefix(strings.ToLower(k), "x-") {
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]interface{})
|
||||
}
|
||||
var d interface{}
|
||||
if err := json.Unmarshal(v, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Extensions[k] = d
|
||||
}
|
||||
if strings.HasPrefix(k, "/") {
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]PathItem)
|
||||
}
|
||||
var pi PathItem
|
||||
if err := json.Unmarshal(v, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Paths[k] = pi
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Paths) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ext any
|
||||
var pi PathItem
|
||||
switch k := tok.Kind(); k {
|
||||
case 'n':
|
||||
return nil // noop
|
||||
case '{':
|
||||
for {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tok.Kind() == '}' {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch k := tok.String(); {
|
||||
case internal.IsExtensionKey(k):
|
||||
ext = nil
|
||||
if err := opts.UnmarshalNext(dec, &ext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Extensions == nil {
|
||||
p.Extensions = make(map[string]any)
|
||||
}
|
||||
p.Extensions[k] = ext
|
||||
case len(k) > 0 && k[0] == '/':
|
||||
pi = PathItem{}
|
||||
if err := opts.UnmarshalNext(dec, &pi); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Paths == nil {
|
||||
p.Paths = make(map[string]PathItem)
|
||||
}
|
||||
p.Paths[k] = pi
|
||||
default:
|
||||
_, err := dec.ReadValue() // skip value
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown JSON kind: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (p Paths) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(p)
|
||||
}
|
||||
b1, err := json.Marshal(p.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pths := make(map[string]PathItem)
|
||||
for k, v := range p.Paths {
|
||||
if strings.HasPrefix(k, "/") {
|
||||
pths[k] = v
|
||||
}
|
||||
}
|
||||
b2, err := json.Marshal(pths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
|
||||
func (p Paths) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
m := make(map[string]any, len(p.Extensions)+len(p.Paths))
|
||||
for k, v := range p.Extensions {
|
||||
if internal.IsExtensionKey(k) {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range p.Paths {
|
||||
if strings.HasPrefix(k, "/") {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
return opts.MarshalNext(enc, m)
|
||||
}
|
155
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/ref.go
generated
vendored
Normal file
155
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/ref.go
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-openapi/jsonreference"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
)
|
||||
|
||||
// Refable is a struct for things that accept a $ref property
|
||||
type Refable struct {
|
||||
Ref Ref
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the ref to json
|
||||
func (r Refable) MarshalJSON() ([]byte, error) {
|
||||
return r.Ref.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshalss the ref from json
|
||||
func (r *Refable) UnmarshalJSON(d []byte) error {
|
||||
return json.Unmarshal(d, &r.Ref)
|
||||
}
|
||||
|
||||
// Ref represents a json reference that is potentially resolved
|
||||
type Ref struct {
|
||||
jsonreference.Ref
|
||||
}
|
||||
|
||||
// RemoteURI gets the remote uri part of the ref
|
||||
func (r *Ref) RemoteURI() string {
|
||||
if r.String() == "" {
|
||||
return r.String()
|
||||
}
|
||||
|
||||
u := *r.GetURL()
|
||||
u.Fragment = ""
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// IsValidURI returns true when the url the ref points to can be found
|
||||
func (r *Ref) IsValidURI(basepaths ...string) bool {
|
||||
if r.String() == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
v := r.RemoteURI()
|
||||
if v == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if r.HasFullURL {
|
||||
rr, err := http.Get(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return rr.StatusCode/100 == 2
|
||||
}
|
||||
|
||||
if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) {
|
||||
return false
|
||||
}
|
||||
|
||||
// check for local file
|
||||
pth := v
|
||||
if r.HasURLPathOnly {
|
||||
base := "."
|
||||
if len(basepaths) > 0 {
|
||||
base = filepath.Dir(filepath.Join(basepaths...))
|
||||
}
|
||||
p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth)))
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
pth = p
|
||||
}
|
||||
|
||||
fi, err := os.Stat(filepath.ToSlash(pth))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return !fi.IsDir()
|
||||
}
|
||||
|
||||
// Inherits creates a new reference from a parent and a child
|
||||
// If the child cannot inherit from the parent, an error is returned
|
||||
func (r *Ref) Inherits(child Ref) (*Ref, error) {
|
||||
ref, err := r.Ref.Inherits(child.Ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ref{Ref: *ref}, nil
|
||||
}
|
||||
|
||||
// NewRef creates a new instance of a ref object
|
||||
// returns an error when the reference uri is an invalid uri
|
||||
func NewRef(refURI string) (Ref, error) {
|
||||
ref, err := jsonreference.New(refURI)
|
||||
if err != nil {
|
||||
return Ref{}, err
|
||||
}
|
||||
return Ref{Ref: ref}, nil
|
||||
}
|
||||
|
||||
// MustCreateRef creates a ref object but panics when refURI is invalid.
|
||||
// Use the NewRef method for a version that returns an error.
|
||||
func MustCreateRef(refURI string) Ref {
|
||||
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this ref into a JSON object
|
||||
func (r Ref) MarshalJSON() ([]byte, error) {
|
||||
str := r.String()
|
||||
if str == "" {
|
||||
if r.IsRoot() {
|
||||
return []byte(`{"$ref":""}`), nil
|
||||
}
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
v := map[string]interface{}{"$ref": str}
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this ref from a JSON object
|
||||
func (r *Ref) UnmarshalJSON(d []byte) error {
|
||||
var v map[string]interface{}
|
||||
if err := json.Unmarshal(d, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.fromMap(v)
|
||||
}
|
||||
|
||||
func (r *Ref) fromMap(v map[string]interface{}) error {
|
||||
return internal.JSONRefFromMap(&r.Ref, v)
|
||||
}
|
131
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/response.go
generated
vendored
Normal file
131
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/response.go
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// ResponseProps properties specific to a response
|
||||
type ResponseProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Schema *Schema `json:"schema,omitempty"`
|
||||
Headers map[string]Header `json:"headers,omitempty"`
|
||||
Examples map[string]interface{} `json:"examples,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type responsePropsOmitZero struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Schema *Schema `json:"schema,omitzero"`
|
||||
Headers map[string]Header `json:"headers,omitempty"`
|
||||
Examples map[string]interface{} `json:"examples,omitempty"`
|
||||
}
|
||||
|
||||
// Response describes a single response from an API Operation.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#responseObject
|
||||
type Response struct {
|
||||
Refable
|
||||
ResponseProps
|
||||
VendorExtensible
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.Refable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Response) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
ResponseProps
|
||||
Extensions
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.Refable.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
r.ResponseProps = x.ResponseProps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (r Response) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(r)
|
||||
}
|
||||
b1, err := json.Marshal(r.ResponseProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.Refable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3), nil
|
||||
}
|
||||
|
||||
func (r Response) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
Extensions
|
||||
ResponseProps responsePropsOmitZero `json:",inline"`
|
||||
}
|
||||
x.Ref = r.Refable.Ref.String()
|
||||
x.Extensions = internal.SanitizeExtensions(r.Extensions)
|
||||
x.ResponseProps = responsePropsOmitZero(r.ResponseProps)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// NewResponse creates a new response instance
|
||||
func NewResponse() *Response {
|
||||
return new(Response)
|
||||
}
|
||||
|
||||
// ResponseRef creates a response as a json reference
|
||||
func ResponseRef(url string) *Response {
|
||||
resp := NewResponse()
|
||||
resp.Ref = MustCreateRef(url)
|
||||
return resp
|
||||
}
|
208
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/responses.go
generated
vendored
Normal file
208
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/responses.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Responses is a container for the expected responses of an operation.
|
||||
// The container maps a HTTP response code to the expected response.
|
||||
// It is not expected from the documentation to necessarily cover all possible HTTP response codes,
|
||||
// since they may not be known in advance. However, it is expected from the documentation to cover
|
||||
// a successful operation response and any known errors.
|
||||
//
|
||||
// The `default` can be used a default response object for all HTTP codes that are not covered
|
||||
// individually by the specification.
|
||||
//
|
||||
// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response
|
||||
// for a successful operation call.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#responsesObject
|
||||
type Responses struct {
|
||||
VendorExtensible
|
||||
ResponsesProps
|
||||
}
|
||||
|
||||
// UnmarshalJSON hydrates this items instance with the data from JSON
|
||||
func (r *Responses) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) {
|
||||
r.ResponsesProps = ResponsesProps{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this items object to JSON
|
||||
func (r Responses) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(r)
|
||||
}
|
||||
b1, err := json.Marshal(r.ResponsesProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(r.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
concated := swag.ConcatJSON(b1, b2)
|
||||
return concated, nil
|
||||
}
|
||||
|
||||
func (r Responses) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
type ArbitraryKeys map[string]interface{}
|
||||
var x struct {
|
||||
ArbitraryKeys
|
||||
Default *Response `json:"default,omitempty"`
|
||||
}
|
||||
x.ArbitraryKeys = make(map[string]any, len(r.Extensions)+len(r.StatusCodeResponses))
|
||||
for k, v := range r.Extensions {
|
||||
if internal.IsExtensionKey(k) {
|
||||
x.ArbitraryKeys[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range r.StatusCodeResponses {
|
||||
x.ArbitraryKeys[strconv.Itoa(k)] = v
|
||||
}
|
||||
x.Default = r.Default
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// ResponsesProps describes all responses for an operation.
|
||||
// It tells what is the default response and maps all responses with a
|
||||
// HTTP status code.
|
||||
type ResponsesProps struct {
|
||||
Default *Response
|
||||
StatusCodeResponses map[int]Response
|
||||
}
|
||||
|
||||
// MarshalJSON marshals responses as JSON
|
||||
func (r ResponsesProps) MarshalJSON() ([]byte, error) {
|
||||
toser := map[string]Response{}
|
||||
if r.Default != nil {
|
||||
toser["default"] = *r.Default
|
||||
}
|
||||
for k, v := range r.StatusCodeResponses {
|
||||
toser[strconv.Itoa(k)] = v
|
||||
}
|
||||
return json.Marshal(toser)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals responses from JSON
|
||||
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, r)
|
||||
}
|
||||
var res map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
if v, ok := res["default"]; ok {
|
||||
value := Response{}
|
||||
if err := json.Unmarshal(v, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Default = &value
|
||||
delete(res, "default")
|
||||
}
|
||||
for k, v := range res {
|
||||
// Take all integral keys
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]Response{}
|
||||
}
|
||||
value := Response{}
|
||||
if err := json.Unmarshal(v, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
r.StatusCodeResponses[nk] = value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Responses) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) (err error) {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ext any
|
||||
var resp Response
|
||||
switch k := tok.Kind(); k {
|
||||
case 'n':
|
||||
return nil // noop
|
||||
case '{':
|
||||
for {
|
||||
tok, err := dec.ReadToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok.Kind() == '}' {
|
||||
return nil
|
||||
}
|
||||
switch k := tok.String(); {
|
||||
case internal.IsExtensionKey(k):
|
||||
ext = nil
|
||||
if err := opts.UnmarshalNext(dec, &ext); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.Extensions == nil {
|
||||
r.Extensions = make(map[string]any)
|
||||
}
|
||||
r.Extensions[k] = ext
|
||||
case k == "default":
|
||||
resp = Response{}
|
||||
if err := opts.UnmarshalNext(dec, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respCopy := resp
|
||||
r.ResponsesProps.Default = &respCopy
|
||||
default:
|
||||
if nk, err := strconv.Atoi(k); err == nil {
|
||||
resp = Response{}
|
||||
if err := opts.UnmarshalNext(dec, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.StatusCodeResponses == nil {
|
||||
r.StatusCodeResponses = map[int]Response{}
|
||||
}
|
||||
r.StatusCodeResponses[nk] = resp
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown JSON kind: %v", k)
|
||||
}
|
||||
}
|
631
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/schema.go
generated
vendored
Normal file
631
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/schema.go
generated
vendored
Normal file
@ -0,0 +1,631 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// BooleanProperty creates a boolean property
|
||||
func BooleanProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}}
|
||||
}
|
||||
|
||||
// BoolProperty creates a boolean property
|
||||
func BoolProperty() *Schema { return BooleanProperty() }
|
||||
|
||||
// StringProperty creates a string property
|
||||
func StringProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
|
||||
}
|
||||
|
||||
// CharProperty creates a string property
|
||||
func CharProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
|
||||
}
|
||||
|
||||
// Float64Property creates a float64/double property
|
||||
func Float64Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}}
|
||||
}
|
||||
|
||||
// Float32Property creates a float32/float property
|
||||
func Float32Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}}
|
||||
}
|
||||
|
||||
// Int8Property creates an int8 property
|
||||
func Int8Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}}
|
||||
}
|
||||
|
||||
// Int16Property creates an int16 property
|
||||
func Int16Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}}
|
||||
}
|
||||
|
||||
// Int32Property creates an int32 property
|
||||
func Int32Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}}
|
||||
}
|
||||
|
||||
// Int64Property creates an int64 property
|
||||
func Int64Property() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}
|
||||
}
|
||||
|
||||
// StrFmtProperty creates a property for the named string format
|
||||
func StrFmtProperty(format string) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}}
|
||||
}
|
||||
|
||||
// DateProperty creates a date property
|
||||
func DateProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}}
|
||||
}
|
||||
|
||||
// DateTimeProperty creates a date time property
|
||||
func DateTimeProperty() *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}}
|
||||
}
|
||||
|
||||
// MapProperty creates a map property
|
||||
func MapProperty(property *Schema) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"object"},
|
||||
AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}}
|
||||
}
|
||||
|
||||
// RefProperty creates a ref property
|
||||
func RefProperty(name string) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
|
||||
}
|
||||
|
||||
// RefSchema creates a ref property
|
||||
func RefSchema(name string) *Schema {
|
||||
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
|
||||
}
|
||||
|
||||
// ArrayProperty creates an array property
|
||||
func ArrayProperty(items *Schema) *Schema {
|
||||
if items == nil {
|
||||
return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}}
|
||||
}
|
||||
return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}}
|
||||
}
|
||||
|
||||
// ComposedSchema creates a schema with allOf
|
||||
func ComposedSchema(schemas ...Schema) *Schema {
|
||||
s := new(Schema)
|
||||
s.AllOf = schemas
|
||||
return s
|
||||
}
|
||||
|
||||
// SchemaURL represents a schema url
|
||||
type SchemaURL string
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (r SchemaURL) MarshalJSON() ([]byte, error) {
|
||||
if r == "" {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
v := map[string]interface{}{"$schema": string(r)}
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshal this from JSON
|
||||
func (r *SchemaURL) UnmarshalJSON(data []byte) error {
|
||||
var v map[string]interface{}
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.fromMap(v)
|
||||
}
|
||||
|
||||
func (r *SchemaURL) fromMap(v map[string]interface{}) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if vv, ok := v["$schema"]; ok {
|
||||
if str, ok := vv.(string); ok {
|
||||
u, err := url.Parse(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*r = SchemaURL(u.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SchemaProps describes a JSON schema (draft 4)
|
||||
type SchemaProps struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Ref Ref `json:"-"`
|
||||
Schema SchemaURL `json:"-"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Type StringOrArray `json:"type,omitempty"`
|
||||
Nullable bool `json:"nullable,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||
MinLength *int64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||
MinItems *int64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||
Enum []interface{} `json:"enum,omitempty"`
|
||||
MaxProperties *int64 `json:"maxProperties,omitempty"`
|
||||
MinProperties *int64 `json:"minProperties,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
Items *SchemaOrArray `json:"items,omitempty"`
|
||||
AllOf []Schema `json:"allOf,omitempty"`
|
||||
OneOf []Schema `json:"oneOf,omitempty"`
|
||||
AnyOf []Schema `json:"anyOf,omitempty"`
|
||||
Not *Schema `json:"not,omitempty"`
|
||||
Properties map[string]Schema `json:"properties,omitempty"`
|
||||
AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"`
|
||||
PatternProperties map[string]Schema `json:"patternProperties,omitempty"`
|
||||
Dependencies Dependencies `json:"dependencies,omitempty"`
|
||||
AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"`
|
||||
Definitions Definitions `json:"definitions,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type schemaPropsOmitZero struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Ref Ref `json:"-"`
|
||||
Schema SchemaURL `json:"-"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Type StringOrArray `json:"type,omitzero"`
|
||||
Nullable bool `json:"nullable,omitzero"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Default interface{} `json:"default,omitzero"`
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitzero"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitzero"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty"`
|
||||
MinLength *int64 `json:"minLength,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty"`
|
||||
MinItems *int64 `json:"minItems,omitempty"`
|
||||
UniqueItems bool `json:"uniqueItems,omitzero"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty"`
|
||||
Enum []interface{} `json:"enum,omitempty"`
|
||||
MaxProperties *int64 `json:"maxProperties,omitempty"`
|
||||
MinProperties *int64 `json:"minProperties,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
Items *SchemaOrArray `json:"items,omitzero"`
|
||||
AllOf []Schema `json:"allOf,omitempty"`
|
||||
OneOf []Schema `json:"oneOf,omitempty"`
|
||||
AnyOf []Schema `json:"anyOf,omitempty"`
|
||||
Not *Schema `json:"not,omitzero"`
|
||||
Properties map[string]Schema `json:"properties,omitempty"`
|
||||
AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitzero"`
|
||||
PatternProperties map[string]Schema `json:"patternProperties,omitempty"`
|
||||
Dependencies Dependencies `json:"dependencies,omitempty"`
|
||||
AdditionalItems *SchemaOrBool `json:"additionalItems,omitzero"`
|
||||
Definitions Definitions `json:"definitions,omitempty"`
|
||||
}
|
||||
|
||||
// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4)
|
||||
type SwaggerSchemaProps struct {
|
||||
Discriminator string `json:"discriminator,omitempty"`
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
// Marshaling structure only, always edit along with corresponding
|
||||
// struct (or compilation will fail).
|
||||
type swaggerSchemaPropsOmitZero struct {
|
||||
Discriminator string `json:"discriminator,omitempty"`
|
||||
ReadOnly bool `json:"readOnly,omitzero"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"`
|
||||
Example interface{} `json:"example,omitempty"`
|
||||
}
|
||||
|
||||
// Schema the schema object allows the definition of input and output data types.
|
||||
// These types can be objects, but also primitives and arrays.
|
||||
// This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/)
|
||||
// and uses a predefined subset of it.
|
||||
// On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#schemaObject
|
||||
type Schema struct {
|
||||
VendorExtensible
|
||||
SchemaProps
|
||||
SwaggerSchemaProps
|
||||
ExtraProps map[string]interface{} `json:"-"`
|
||||
}
|
||||
|
||||
// WithID sets the id for this schema, allows for chaining
|
||||
func (s *Schema) WithID(id string) *Schema {
|
||||
s.ID = id
|
||||
return s
|
||||
}
|
||||
|
||||
// WithTitle sets the title for this schema, allows for chaining
|
||||
func (s *Schema) WithTitle(title string) *Schema {
|
||||
s.Title = title
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDescription sets the description for this schema, allows for chaining
|
||||
func (s *Schema) WithDescription(description string) *Schema {
|
||||
s.Description = description
|
||||
return s
|
||||
}
|
||||
|
||||
// WithProperties sets the properties for this schema
|
||||
func (s *Schema) WithProperties(schemas map[string]Schema) *Schema {
|
||||
s.Properties = schemas
|
||||
return s
|
||||
}
|
||||
|
||||
// SetProperty sets a property on this schema
|
||||
func (s *Schema) SetProperty(name string, schema Schema) *Schema {
|
||||
if s.Properties == nil {
|
||||
s.Properties = make(map[string]Schema)
|
||||
}
|
||||
s.Properties[name] = schema
|
||||
return s
|
||||
}
|
||||
|
||||
// WithAllOf sets the all of property
|
||||
func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
|
||||
s.AllOf = schemas
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaxProperties sets the max number of properties an object can have
|
||||
func (s *Schema) WithMaxProperties(max int64) *Schema {
|
||||
s.MaxProperties = &max
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinProperties sets the min number of properties an object must have
|
||||
func (s *Schema) WithMinProperties(min int64) *Schema {
|
||||
s.MinProperties = &min
|
||||
return s
|
||||
}
|
||||
|
||||
// Typed sets the type of this schema for a single value item
|
||||
func (s *Schema) Typed(tpe, format string) *Schema {
|
||||
s.Type = []string{tpe}
|
||||
s.Format = format
|
||||
return s
|
||||
}
|
||||
|
||||
// AddType adds a type with potential format to the types for this schema
|
||||
func (s *Schema) AddType(tpe, format string) *Schema {
|
||||
s.Type = append(s.Type, tpe)
|
||||
if format != "" {
|
||||
s.Format = format
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// AsNullable flags this schema as nullable.
|
||||
func (s *Schema) AsNullable() *Schema {
|
||||
s.Nullable = true
|
||||
return s
|
||||
}
|
||||
|
||||
// CollectionOf a fluent builder method for an array parameter
|
||||
func (s *Schema) CollectionOf(items Schema) *Schema {
|
||||
s.Type = []string{jsonArray}
|
||||
s.Items = &SchemaOrArray{Schema: &items}
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDefault sets the default value on this parameter
|
||||
func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
|
||||
s.Default = defaultValue
|
||||
return s
|
||||
}
|
||||
|
||||
// WithRequired flags this parameter as required
|
||||
func (s *Schema) WithRequired(items ...string) *Schema {
|
||||
s.Required = items
|
||||
return s
|
||||
}
|
||||
|
||||
// AddRequired adds field names to the required properties array
|
||||
func (s *Schema) AddRequired(items ...string) *Schema {
|
||||
s.Required = append(s.Required, items...)
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaxLength sets a max length value
|
||||
func (s *Schema) WithMaxLength(max int64) *Schema {
|
||||
s.MaxLength = &max
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinLength sets a min length value
|
||||
func (s *Schema) WithMinLength(min int64) *Schema {
|
||||
s.MinLength = &min
|
||||
return s
|
||||
}
|
||||
|
||||
// WithPattern sets a pattern value
|
||||
func (s *Schema) WithPattern(pattern string) *Schema {
|
||||
s.Pattern = pattern
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMultipleOf sets a multiple of value
|
||||
func (s *Schema) WithMultipleOf(number float64) *Schema {
|
||||
s.MultipleOf = &number
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaximum sets a maximum number value
|
||||
func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
|
||||
s.Maximum = &max
|
||||
s.ExclusiveMaximum = exclusive
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinimum sets a minimum number value
|
||||
func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
|
||||
s.Minimum = &min
|
||||
s.ExclusiveMinimum = exclusive
|
||||
return s
|
||||
}
|
||||
|
||||
// WithEnum sets a the enum values (replace)
|
||||
func (s *Schema) WithEnum(values ...interface{}) *Schema {
|
||||
s.Enum = append([]interface{}{}, values...)
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMaxItems sets the max items
|
||||
func (s *Schema) WithMaxItems(size int64) *Schema {
|
||||
s.MaxItems = &size
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMinItems sets the min items
|
||||
func (s *Schema) WithMinItems(size int64) *Schema {
|
||||
s.MinItems = &size
|
||||
return s
|
||||
}
|
||||
|
||||
// UniqueValues dictates that this array can only have unique items
|
||||
func (s *Schema) UniqueValues() *Schema {
|
||||
s.UniqueItems = true
|
||||
return s
|
||||
}
|
||||
|
||||
// AllowDuplicates this array can have duplicates
|
||||
func (s *Schema) AllowDuplicates() *Schema {
|
||||
s.UniqueItems = false
|
||||
return s
|
||||
}
|
||||
|
||||
// AddToAllOf adds a schema to the allOf property
|
||||
func (s *Schema) AddToAllOf(schemas ...Schema) *Schema {
|
||||
s.AllOf = append(s.AllOf, schemas...)
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDiscriminator sets the name of the discriminator field
|
||||
func (s *Schema) WithDiscriminator(discriminator string) *Schema {
|
||||
s.Discriminator = discriminator
|
||||
return s
|
||||
}
|
||||
|
||||
// AsReadOnly flags this schema as readonly
|
||||
func (s *Schema) AsReadOnly() *Schema {
|
||||
s.ReadOnly = true
|
||||
return s
|
||||
}
|
||||
|
||||
// AsWritable flags this schema as writeable (not read-only)
|
||||
func (s *Schema) AsWritable() *Schema {
|
||||
s.ReadOnly = false
|
||||
return s
|
||||
}
|
||||
|
||||
// WithExample sets the example for this schema
|
||||
func (s *Schema) WithExample(example interface{}) *Schema {
|
||||
s.Example = example
|
||||
return s
|
||||
}
|
||||
|
||||
// WithExternalDocs sets/removes the external docs for/from this schema.
|
||||
// When you pass empty strings as params the external documents will be removed.
|
||||
// When you pass non-empty string as one value then those values will be used on the external docs object.
|
||||
// So when you pass a non-empty description, you should also pass the url and vice versa.
|
||||
func (s *Schema) WithExternalDocs(description, url string) *Schema {
|
||||
if description == "" && url == "" {
|
||||
s.ExternalDocs = nil
|
||||
return s
|
||||
}
|
||||
|
||||
if s.ExternalDocs == nil {
|
||||
s.ExternalDocs = &ExternalDocumentation{}
|
||||
}
|
||||
s.ExternalDocs.Description = description
|
||||
s.ExternalDocs.URL = url
|
||||
return s
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (s Schema) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
b1, err := json.Marshal(s.SchemaProps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("schema props %v", err)
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("vendor props %v", err)
|
||||
}
|
||||
b3, err := s.Ref.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ref prop %v", err)
|
||||
}
|
||||
b4, err := s.Schema.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("schema prop %v", err)
|
||||
}
|
||||
b5, err := json.Marshal(s.SwaggerSchemaProps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("common validations %v", err)
|
||||
}
|
||||
var b6 []byte
|
||||
if s.ExtraProps != nil {
|
||||
jj, err := json.Marshal(s.ExtraProps)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extra props %v", err)
|
||||
}
|
||||
b6 = jj
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
|
||||
}
|
||||
|
||||
func (s Schema) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
type ArbitraryKeys map[string]interface{}
|
||||
var x struct {
|
||||
ArbitraryKeys
|
||||
SchemaProps schemaPropsOmitZero `json:",inline"`
|
||||
SwaggerSchemaProps swaggerSchemaPropsOmitZero `json:",inline"`
|
||||
Schema string `json:"$schema,omitempty"`
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
}
|
||||
x.ArbitraryKeys = make(map[string]any, len(s.Extensions)+len(s.ExtraProps))
|
||||
for k, v := range s.Extensions {
|
||||
if internal.IsExtensionKey(k) {
|
||||
x.ArbitraryKeys[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range s.ExtraProps {
|
||||
x.ArbitraryKeys[k] = v
|
||||
}
|
||||
x.SchemaProps = schemaPropsOmitZero(s.SchemaProps)
|
||||
x.SwaggerSchemaProps = swaggerSchemaPropsOmitZero(s.SwaggerSchemaProps)
|
||||
x.Ref = s.Ref.String()
|
||||
x.Schema = string(s.Schema)
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (s *Schema) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
props := struct {
|
||||
SchemaProps
|
||||
SwaggerSchemaProps
|
||||
}{}
|
||||
if err := json.Unmarshal(data, &props); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sch := Schema{
|
||||
SchemaProps: props.SchemaProps,
|
||||
SwaggerSchemaProps: props.SwaggerSchemaProps,
|
||||
}
|
||||
|
||||
var d map[string]interface{}
|
||||
if err := json.Unmarshal(data, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = sch.Ref.fromMap(d)
|
||||
_ = sch.Schema.fromMap(d)
|
||||
|
||||
delete(d, "$ref")
|
||||
delete(d, "$schema")
|
||||
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
|
||||
delete(d, pn)
|
||||
}
|
||||
|
||||
for k, vv := range d {
|
||||
lk := strings.ToLower(k)
|
||||
if strings.HasPrefix(lk, "x-") {
|
||||
if sch.Extensions == nil {
|
||||
sch.Extensions = map[string]interface{}{}
|
||||
}
|
||||
sch.Extensions[k] = vv
|
||||
continue
|
||||
}
|
||||
if sch.ExtraProps == nil {
|
||||
sch.ExtraProps = map[string]interface{}{}
|
||||
}
|
||||
sch.ExtraProps[k] = vv
|
||||
}
|
||||
|
||||
*s = sch
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Schema) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
SchemaProps
|
||||
SwaggerSchemaProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.Ref.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := x.Schema.fromMap(x.Extensions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(x.Extensions, "$ref")
|
||||
delete(x.Extensions, "$schema")
|
||||
|
||||
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
|
||||
delete(x.Extensions, pn)
|
||||
}
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
|
||||
s.ExtraProps = x.Extensions.sanitizeWithExtra()
|
||||
s.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
s.SchemaProps = x.SchemaProps
|
||||
s.SwaggerSchemaProps = x.SwaggerSchemaProps
|
||||
return nil
|
||||
}
|
92
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/security_scheme.go
generated
vendored
Normal file
92
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/security_scheme.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section
|
||||
type SecuritySchemeProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"` // api key
|
||||
In string `json:"in,omitempty"` // api key
|
||||
Flow string `json:"flow,omitempty"` // oauth2
|
||||
AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2
|
||||
TokenURL string `json:"tokenUrl,omitempty"` // oauth2
|
||||
Scopes map[string]string `json:"scopes,omitempty"` // oauth2
|
||||
}
|
||||
|
||||
// SecurityScheme allows the definition of a security scheme that can be used by the operations.
|
||||
// Supported schemes are basic authentication, an API key (either as a header or as a query parameter)
|
||||
// and OAuth2's common flows (implicit, password, application and access code).
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#securitySchemeObject
|
||||
type SecurityScheme struct {
|
||||
VendorExtensible
|
||||
SecuritySchemeProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (s SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
b1, err := json.Marshal(s.SecuritySchemeProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (s SecurityScheme) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
SecuritySchemeProps
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(s.Extensions)
|
||||
x.SecuritySchemeProps = s.SecuritySchemeProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &s.VendorExtensible)
|
||||
}
|
||||
|
||||
func (s *SecurityScheme) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
SecuritySchemeProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
s.SecuritySchemeProps = x.SecuritySchemeProps
|
||||
return nil
|
||||
}
|
439
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/swagger.go
generated
vendored
Normal file
439
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/swagger.go
generated
vendored
Normal file
@ -0,0 +1,439 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// Swagger this is the root document object for the API specification.
|
||||
// It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier)
|
||||
// together into one document.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#swagger-object-
|
||||
type Swagger struct {
|
||||
VendorExtensible
|
||||
SwaggerProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this swagger structure to json
|
||||
func (s Swagger) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
b1, err := json.Marshal(s.SwaggerProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(s.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals this swagger structure to json
|
||||
func (s Swagger) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
SwaggerProps
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(s.Extensions)
|
||||
x.SwaggerProps = s.SwaggerProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a swagger spec from json
|
||||
func (s *Swagger) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
var sw Swagger
|
||||
if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = sw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Swagger) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
// Note: If you're willing to make breaking changes, it is possible to
|
||||
// optimize this and other usages of this pattern:
|
||||
// https://github.com/kubernetes/kube-openapi/pull/319#discussion_r983165948
|
||||
var x struct {
|
||||
Extensions
|
||||
SwaggerProps
|
||||
}
|
||||
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
s.SwaggerProps = x.SwaggerProps
|
||||
return nil
|
||||
}
|
||||
|
||||
// SwaggerProps captures the top-level properties of an Api specification
|
||||
//
|
||||
// NOTE: validation rules
|
||||
// - the scheme, when present must be from [http, https, ws, wss]
|
||||
// - BasePath must start with a leading "/"
|
||||
// - Paths is required
|
||||
type SwaggerProps struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Schemes []string `json:"schemes,omitempty"`
|
||||
Swagger string `json:"swagger,omitempty"`
|
||||
Info *Info `json:"info,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
BasePath string `json:"basePath,omitempty"`
|
||||
Paths *Paths `json:"paths"`
|
||||
Definitions Definitions `json:"definitions,omitempty"`
|
||||
Parameters map[string]Parameter `json:"parameters,omitempty"`
|
||||
Responses map[string]Response `json:"responses,omitempty"`
|
||||
SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"`
|
||||
Security []map[string][]string `json:"security,omitempty"`
|
||||
Tags []Tag `json:"tags,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
// Dependencies represent a dependencies property
|
||||
type Dependencies map[string]SchemaOrStringArray
|
||||
|
||||
// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property
|
||||
type SchemaOrBool struct {
|
||||
Allows bool
|
||||
Schema *Schema
|
||||
}
|
||||
|
||||
var jsTrue = []byte("true")
|
||||
var jsFalse = []byte("false")
|
||||
|
||||
// MarshalJSON convert this object to JSON
|
||||
func (s SchemaOrBool) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
if s.Schema == nil && !s.Allows {
|
||||
return jsFalse, nil
|
||||
}
|
||||
return jsTrue, nil
|
||||
}
|
||||
|
||||
// MarshalJSON convert this object to JSON
|
||||
func (s SchemaOrBool) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
if s.Schema != nil {
|
||||
return opts.MarshalNext(enc, s.Schema)
|
||||
}
|
||||
|
||||
if s.Schema == nil && !s.Allows {
|
||||
return enc.WriteToken(jsonv2.False)
|
||||
}
|
||||
return enc.WriteToken(jsonv2.True)
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts this bool or schema object from a JSON structure
|
||||
func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var nw SchemaOrBool
|
||||
if len(data) > 0 && data[0] == '{' {
|
||||
var sch Schema
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
nw.Allows = true
|
||||
} else {
|
||||
json.Unmarshal(data, &nw.Allows)
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SchemaOrBool) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch k := dec.PeekKind(); k {
|
||||
case '{':
|
||||
err := opts.UnmarshalNext(dec, &s.Schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Allows = true
|
||||
return nil
|
||||
case 't', 'f':
|
||||
err := opts.UnmarshalNext(dec, &s.Allows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("expected object or bool, not '%v'", k.String())
|
||||
}
|
||||
}
|
||||
|
||||
// SchemaOrStringArray represents a schema or a string array
|
||||
type SchemaOrStringArray struct {
|
||||
Schema *Schema
|
||||
Property []string
|
||||
}
|
||||
|
||||
// MarshalJSON converts this schema object or array into JSON structure
|
||||
func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
if len(s.Property) > 0 {
|
||||
return json.Marshal(s.Property)
|
||||
}
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
// MarshalJSON converts this schema object or array into JSON structure
|
||||
func (s SchemaOrStringArray) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
if len(s.Property) > 0 {
|
||||
return opts.MarshalNext(enc, s.Property)
|
||||
}
|
||||
if s.Schema != nil {
|
||||
return opts.MarshalNext(enc, s.Schema)
|
||||
}
|
||||
return enc.WriteToken(jsonv2.Null)
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts this schema object or array from a JSON structure
|
||||
func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
var nw SchemaOrStringArray
|
||||
if first == '{' {
|
||||
var sch Schema
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.Property); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SchemaOrStringArray) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch dec.PeekKind() {
|
||||
case '{':
|
||||
return opts.UnmarshalNext(dec, &s.Schema)
|
||||
case '[':
|
||||
return opts.UnmarshalNext(dec, &s.Property)
|
||||
default:
|
||||
_, err := dec.ReadValue()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Definitions contains the models explicitly defined in this spec
|
||||
// An object to hold data types that can be consumed and produced by operations.
|
||||
// These data types can be primitives, arrays or models.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#definitionsObject
|
||||
type Definitions map[string]Schema
|
||||
|
||||
// SecurityDefinitions a declaration of the security schemes available to be used in the specification.
|
||||
// This does not enforce the security schemes on the operations and only serves to provide
|
||||
// the relevant details for each scheme.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#securityDefinitionsObject
|
||||
type SecurityDefinitions map[string]*SecurityScheme
|
||||
|
||||
// StringOrArray represents a value that can either be a string
|
||||
// or an array of strings. Mainly here for serialization purposes
|
||||
type StringOrArray []string
|
||||
|
||||
// Contains returns true when the value is contained in the slice
|
||||
func (s StringOrArray) Contains(value string) bool {
|
||||
for _, str := range s {
|
||||
if str == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string
|
||||
func (s *StringOrArray) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
|
||||
if first == '[' {
|
||||
var parsed []string
|
||||
if err := json.Unmarshal(data, &parsed); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = StringOrArray(parsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
var single interface{}
|
||||
if err := json.Unmarshal(data, &single); err != nil {
|
||||
return err
|
||||
}
|
||||
if single == nil {
|
||||
return nil
|
||||
}
|
||||
switch v := single.(type) {
|
||||
case string:
|
||||
*s = StringOrArray([]string{v})
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("only string or array is allowed, not %T", single)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StringOrArray) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch k := dec.PeekKind(); k {
|
||||
case '[':
|
||||
*s = StringOrArray{}
|
||||
return opts.UnmarshalNext(dec, (*[]string)(s))
|
||||
case '"':
|
||||
*s = StringOrArray{""}
|
||||
return opts.UnmarshalNext(dec, &(*s)[0])
|
||||
case 'n':
|
||||
// Throw out null token
|
||||
_, _ = dec.ReadToken()
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("expected string or array, not '%v'", k.String())
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON converts this string or array to a JSON array or JSON string
|
||||
func (s StringOrArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s) == 1 {
|
||||
return json.Marshal([]string(s)[0])
|
||||
}
|
||||
return json.Marshal([]string(s))
|
||||
}
|
||||
|
||||
// SchemaOrArray represents a value that can either be a Schema
|
||||
// or an array of Schema. Mainly here for serialization purposes
|
||||
type SchemaOrArray struct {
|
||||
Schema *Schema
|
||||
Schemas []Schema
|
||||
}
|
||||
|
||||
// Len returns the number of schemas in this property
|
||||
func (s SchemaOrArray) Len() int {
|
||||
if s.Schema != nil {
|
||||
return 1
|
||||
}
|
||||
return len(s.Schemas)
|
||||
}
|
||||
|
||||
// ContainsType returns true when one of the schemas is of the specified type
|
||||
func (s *SchemaOrArray) ContainsType(name string) bool {
|
||||
if s.Schema != nil {
|
||||
return s.Schema.Type != nil && s.Schema.Type.Contains(name)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalJSON converts this schema object or array into JSON structure
|
||||
func (s SchemaOrArray) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(s)
|
||||
}
|
||||
if s.Schemas != nil {
|
||||
return json.Marshal(s.Schemas)
|
||||
}
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
// MarshalJSON converts this schema object or array into JSON structure
|
||||
func (s SchemaOrArray) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
if s.Schemas != nil {
|
||||
return opts.MarshalNext(enc, s.Schemas)
|
||||
}
|
||||
return opts.MarshalNext(enc, s.Schema)
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts this schema object or array from a JSON structure
|
||||
func (s *SchemaOrArray) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
var nw SchemaOrArray
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
if first == '{' {
|
||||
var sch Schema
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.Schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SchemaOrArray) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
switch dec.PeekKind() {
|
||||
case '{':
|
||||
return opts.UnmarshalNext(dec, &s.Schema)
|
||||
case '[':
|
||||
return opts.UnmarshalNext(dec, &s.Schemas)
|
||||
default:
|
||||
_, err := dec.ReadValue()
|
||||
return err
|
||||
}
|
||||
}
|
91
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/tag.go
generated
vendored
Normal file
91
e2e/vendor/k8s.io/kube-openapi/pkg/validation/spec/tag.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 spec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"k8s.io/kube-openapi/pkg/internal"
|
||||
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
|
||||
)
|
||||
|
||||
// TagProps describe a tag entry in the top level tags section of a swagger spec
|
||||
type TagProps struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
// Tag allows adding meta data to a single tag that is used by the
|
||||
// [Operation Object](http://goo.gl/8us55a#operationObject).
|
||||
// It is not mandatory to have a Tag Object per tag used there.
|
||||
//
|
||||
// For more information: http://goo.gl/8us55a#tagObject
|
||||
type Tag struct {
|
||||
VendorExtensible
|
||||
TagProps
|
||||
}
|
||||
|
||||
// MarshalJSON marshal this to JSON
|
||||
func (t Tag) MarshalJSON() ([]byte, error) {
|
||||
if internal.UseOptimizedJSONMarshaling {
|
||||
return internal.DeterministicMarshal(t)
|
||||
}
|
||||
b1, err := json.Marshal(t.TagProps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b2, err := json.Marshal(t.VendorExtensible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return swag.ConcatJSON(b1, b2), nil
|
||||
}
|
||||
|
||||
func (t Tag) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
TagProps
|
||||
}
|
||||
x.Extensions = internal.SanitizeExtensions(t.Extensions)
|
||||
x.TagProps = t.TagProps
|
||||
return opts.MarshalNext(enc, x)
|
||||
}
|
||||
|
||||
// UnmarshalJSON marshal this from JSON
|
||||
func (t *Tag) UnmarshalJSON(data []byte) error {
|
||||
if internal.UseOptimizedJSONUnmarshaling {
|
||||
return jsonv2.Unmarshal(data, t)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &t.TagProps); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, &t.VendorExtensible)
|
||||
}
|
||||
|
||||
func (t *Tag) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error {
|
||||
var x struct {
|
||||
Extensions
|
||||
TagProps
|
||||
}
|
||||
if err := opts.UnmarshalNext(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Extensions = internal.SanitizeExtensions(x.Extensions)
|
||||
t.TagProps = x.TagProps
|
||||
return nil
|
||||
}
|
2
e2e/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/.gitignore
generated
vendored
Normal file
2
e2e/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
secrets.yml
|
||||
coverage.out
|
202
e2e/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/LICENSE
generated
vendored
Normal file
202
e2e/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user