rebase: bump github.com/kubernetes-csi/external-snapshotter/client/v6

Bumps [github.com/kubernetes-csi/external-snapshotter/client/v6](https://github.com/kubernetes-csi/external-snapshotter) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/kubernetes-csi/external-snapshotter/releases)
- [Commits](https://github.com/kubernetes-csi/external-snapshotter/compare/v6.1.0...v6.2.0)

---
updated-dependencies:
- dependency-name: github.com/kubernetes-csi/external-snapshotter/client/v6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-01-09 20:03:41 +00:00
committed by mergify[bot]
parent 544c5f33f3
commit c1a636b431
41 changed files with 10254 additions and 36 deletions

502
vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go generated vendored Normal file
View File

@ -0,0 +1,502 @@
/*
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 spec
import (
"github.com/go-openapi/jsonreference"
"github.com/google/go-cmp/cmp"
fuzz "github.com/google/gofuzz"
)
var SwaggerFuzzFuncs []interface{} = []interface{}{
func(v *Responses, c fuzz.Continue) {
c.FuzzNoCustom(v)
if v.Default != nil {
// Check if we hit maxDepth and left an incomplete value
if v.Default.Description == "" {
v.Default = nil
v.StatusCodeResponses = nil
}
}
// conversion has no way to discern empty statusCodeResponses from
// nil, since "default" is always included in the map.
// So avoid empty responses list
if len(v.StatusCodeResponses) == 0 {
v.StatusCodeResponses = nil
}
},
func(v *Operation, c fuzz.Continue) {
c.FuzzNoCustom(v)
if v != nil {
// force non-nil
v.Responses = &Responses{}
c.Fuzz(v.Responses)
v.Schemes = nil
if c.RandBool() {
v.Schemes = append(v.Schemes, "http")
}
if c.RandBool() {
v.Schemes = append(v.Schemes, "https")
}
if c.RandBool() {
v.Schemes = append(v.Schemes, "ws")
}
if c.RandBool() {
v.Schemes = append(v.Schemes, "wss")
}
// Gnostic unconditionally makes security values non-null
// So do not fuzz null values into the array.
for i, val := range v.Security {
if val == nil {
v.Security[i] = make(map[string][]string)
}
for k, v := range val {
if v == nil {
val[k] = make([]string, 0)
}
}
}
}
},
func(v map[int]Response, c fuzz.Continue) {
n := 0
c.Fuzz(&n)
if n == 0 {
// Test that fuzzer is not at maxDepth so we do not
// end up with empty elements
return
}
// Prevent negative numbers
num := c.Intn(4)
for i := 0; i < num+2; i++ {
val := Response{}
c.Fuzz(&val)
val.Description = c.RandString() + "x"
v[100*(i+1)+c.Intn(100)] = val
}
},
func(v map[string]PathItem, c fuzz.Continue) {
n := 0
c.Fuzz(&n)
if n == 0 {
// Test that fuzzer is not at maxDepth so we do not
// end up with empty elements
return
}
num := c.Intn(5)
for i := 0; i < num+2; i++ {
val := PathItem{}
c.Fuzz(&val)
// Ref params are only allowed in certain locations, so
// possibly add a few to PathItems
numRefsToAdd := c.Intn(5)
for i := 0; i < numRefsToAdd; i++ {
theRef := Parameter{}
c.Fuzz(&theRef.Refable)
val.Parameters = append(val.Parameters, theRef)
}
v["/"+c.RandString()] = val
}
},
func(v *SchemaOrArray, c fuzz.Continue) {
*v = SchemaOrArray{}
// gnostic parser just doesn't support more
// than one Schema here
v.Schema = &Schema{}
c.Fuzz(&v.Schema)
},
func(v *SchemaOrBool, c fuzz.Continue) {
*v = SchemaOrBool{}
if c.RandBool() {
v.Allows = c.RandBool()
} else {
v.Schema = &Schema{}
v.Allows = true
c.Fuzz(&v.Schema)
}
},
func(v map[string]Response, c fuzz.Continue) {
n := 0
c.Fuzz(&n)
if n == 0 {
// Test that fuzzer is not at maxDepth so we do not
// end up with empty elements
return
}
// Response definitions are not allowed to
// be refs
for i := 0; i < c.Intn(5)+1; i++ {
resp := &Response{}
c.Fuzz(resp)
resp.Ref = Ref{}
resp.Description = c.RandString() + "x"
// Response refs are not vendor extensible by gnostic
resp.VendorExtensible.Extensions = nil
v[c.RandString()+"x"] = *resp
}
},
func(v *Header, c fuzz.Continue) {
if v != nil {
c.FuzzNoCustom(v)
// descendant Items of Header may not be refs
cur := v.Items
for cur != nil {
cur.Ref = Ref{}
cur = cur.Items
}
}
},
func(v *Ref, c fuzz.Continue) {
*v = Ref{}
v.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString())
},
func(v *Response, c fuzz.Continue) {
*v = Response{}
if c.RandBool() {
v.Ref = Ref{}
v.Ref.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString())
} else {
c.Fuzz(&v.VendorExtensible)
c.Fuzz(&v.Schema)
c.Fuzz(&v.ResponseProps)
v.Headers = nil
v.Ref = Ref{}
n := 0
c.Fuzz(&n)
if n != 0 {
// Test that fuzzer is not at maxDepth so we do not
// end up with empty elements
num := c.Intn(4)
for i := 0; i < num; i++ {
if v.Headers == nil {
v.Headers = make(map[string]Header)
}
hdr := Header{}
c.Fuzz(&hdr)
if hdr.Type == "" {
// hit maxDepth, just abort trying to make haders
v.Headers = nil
break
}
v.Headers[c.RandString()+"x"] = hdr
}
} else {
v.Headers = nil
}
}
v.Description = c.RandString() + "x"
// Gnostic parses empty as nil, so to keep avoid putting empty
if len(v.Headers) == 0 {
v.Headers = nil
}
},
func(v **Info, c fuzz.Continue) {
// Info is never nil
*v = &Info{}
c.FuzzNoCustom(*v)
(*v).Title = c.RandString() + "x"
},
func(v *Extensions, c fuzz.Continue) {
// gnostic parser only picks up x- vendor extensions
numChildren := c.Intn(5)
for i := 0; i < numChildren; i++ {
if *v == nil {
*v = Extensions{}
}
(*v)["x-"+c.RandString()] = c.RandString()
}
},
func(v *Swagger, c fuzz.Continue) {
c.FuzzNoCustom(v)
if v.Paths == nil {
// Force paths non-nil since it does not have omitempty in json tag.
// This means a perfect roundtrip (via json) is impossible,
// since we can't tell the difference between empty/unspecified paths
v.Paths = &Paths{}
c.Fuzz(v.Paths)
}
v.Swagger = "2.0"
// Gnostic support serializing ID at all
// unavoidable data loss
v.ID = ""
v.Schemes = nil
if c.RandUint64()%2 == 1 {
v.Schemes = append(v.Schemes, "http")
}
if c.RandUint64()%2 == 1 {
v.Schemes = append(v.Schemes, "https")
}
if c.RandUint64()%2 == 1 {
v.Schemes = append(v.Schemes, "ws")
}
if c.RandUint64()%2 == 1 {
v.Schemes = append(v.Schemes, "wss")
}
// Gnostic unconditionally makes security values non-null
// So do not fuzz null values into the array.
for i, val := range v.Security {
if val == nil {
v.Security[i] = make(map[string][]string)
}
for k, v := range val {
if v == nil {
val[k] = make([]string, 0)
}
}
}
},
func(v *SecurityScheme, c fuzz.Continue) {
v.Description = c.RandString() + "x"
c.Fuzz(&v.VendorExtensible)
switch c.Intn(3) {
case 0:
v.Type = "basic"
case 1:
v.Type = "apiKey"
switch c.Intn(2) {
case 0:
v.In = "header"
case 1:
v.In = "query"
default:
panic("unreachable")
}
v.Name = "x" + c.RandString()
case 2:
v.Type = "oauth2"
switch c.Intn(4) {
case 0:
v.Flow = "accessCode"
v.TokenURL = "https://" + c.RandString()
v.AuthorizationURL = "https://" + c.RandString()
case 1:
v.Flow = "application"
v.TokenURL = "https://" + c.RandString()
case 2:
v.Flow = "implicit"
v.AuthorizationURL = "https://" + c.RandString()
case 3:
v.Flow = "password"
v.TokenURL = "https://" + c.RandString()
default:
panic("unreachable")
}
c.Fuzz(&v.Scopes)
default:
panic("unreachable")
}
},
func(v *interface{}, c fuzz.Continue) {
*v = c.RandString() + "x"
},
func(v *string, c fuzz.Continue) {
*v = c.RandString() + "x"
},
func(v *ExternalDocumentation, c fuzz.Continue) {
v.Description = c.RandString() + "x"
v.URL = c.RandString() + "x"
},
func(v *SimpleSchema, c fuzz.Continue) {
c.FuzzNoCustom(v)
switch c.Intn(5) {
case 0:
v.Type = "string"
case 1:
v.Type = "number"
case 2:
v.Type = "boolean"
case 3:
v.Type = "integer"
case 4:
v.Type = "array"
default:
panic("unreachable")
}
switch c.Intn(5) {
case 0:
v.CollectionFormat = "csv"
case 1:
v.CollectionFormat = "ssv"
case 2:
v.CollectionFormat = "tsv"
case 3:
v.CollectionFormat = "pipes"
case 4:
v.CollectionFormat = ""
default:
panic("unreachable")
}
// None of the types which include SimpleSchema in our definitions
// actually support "example" in the official spec
v.Example = nil
// unsupported by openapi
v.Nullable = false
},
func(v *int64, c fuzz.Continue) {
c.Fuzz(v)
// Gnostic does not differentiate between 0 and non-specified
// so avoid using 0 for fuzzer
if *v == 0 {
*v = 1
}
},
func(v *float64, c fuzz.Continue) {
c.Fuzz(v)
// Gnostic does not differentiate between 0 and non-specified
// so avoid using 0 for fuzzer
if *v == 0.0 {
*v = 1.0
}
},
func(v *Parameter, c fuzz.Continue) {
if v == nil {
return
}
c.Fuzz(&v.VendorExtensible)
if c.RandBool() {
// body param
v.Description = c.RandString() + "x"
v.Name = c.RandString() + "x"
v.In = "body"
c.Fuzz(&v.Description)
c.Fuzz(&v.Required)
v.Schema = &Schema{}
c.Fuzz(&v.Schema)
} else {
c.Fuzz(&v.SimpleSchema)
c.Fuzz(&v.CommonValidations)
v.AllowEmptyValue = false
v.Description = c.RandString() + "x"
v.Name = c.RandString() + "x"
switch c.Intn(4) {
case 0:
// Header param
v.In = "header"
case 1:
// Form data param
v.In = "formData"
v.AllowEmptyValue = c.RandBool()
case 2:
// Query param
v.In = "query"
v.AllowEmptyValue = c.RandBool()
case 3:
// Path param
v.In = "path"
v.Required = true
default:
panic("unreachable")
}
// descendant Items of Parameter may not be refs
cur := v.Items
for cur != nil {
cur.Ref = Ref{}
cur = cur.Items
}
}
},
func(v *Schema, c fuzz.Continue) {
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 = StringOrArray{"file"}
} else {
// normal schema
c.Fuzz(&v.SchemaProps)
c.Fuzz(&v.SwaggerSchemaProps)
c.Fuzz(&v.VendorExtensible)
// c.Fuzz(&v.ExtraProps)
// ExtraProps will not roundtrip - gnostic throws out
// unrecognized keys
}
// Not supported by official openapi v2 spec
// and stripped by k8s apiserver
v.ID = ""
v.AnyOf = nil
v.OneOf = nil
v.Not = nil
v.Nullable = false
v.AdditionalItems = nil
v.Schema = ""
v.PatternProperties = nil
v.Definitions = nil
v.Dependencies = nil
},
}
var SwaggerDiffOptions = []cmp.Option{
// cmp.Diff panics on Ref since jsonreference.Ref uses unexported fields
cmp.Comparer(func(a Ref, b Ref) bool {
return a.String() == b.String()
}),
}

View File

@ -219,8 +219,8 @@ func (k *Ref) FromGnostic(g string) error {
// Caveats:
//
// - gnostic v2 documents treats zero as unspecified for numerical fields of
//CommonValidations fields such as Maximum, Minimum, MaximumItems, etc.
//There will always be data loss if one of the values of these fields is set to zero.
// CommonValidations fields such as Maximum, Minimum, MaximumItems, etc.
// There will always be data loss if one of the values of these fields is set to zero.
//
// Returns:
//
@ -1263,6 +1263,8 @@ func (k *Schema) FromGnostic(g *openapi_v2.Schema) (ok bool, err error) {
k.AdditionalProperties.Allows = g.AdditionalProperties.GetBoolean()
} else {
k.AdditionalProperties.Schema = &Schema{}
k.AdditionalProperties.Allows = true
if nok, err := k.AdditionalProperties.Schema.FromGnostic(g.AdditionalProperties.GetSchema()); err != nil {
return false, err
} else if !nok {

View File

@ -18,6 +18,8 @@ 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 (
@ -62,6 +64,10 @@ func (h Header) MarshalJSON() ([]byte, error) {
// 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
}
@ -73,3 +79,27 @@ func (h *Header) UnmarshalJSON(data []byte) error {
}
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 = x.Extensions
h.HeaderProps = x.HeaderProps
h.Extensions.sanitize()
if len(h.Extensions) == 0 {
h.Extensions = nil
}
return nil
}

View File

@ -19,6 +19,8 @@ import (
"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
@ -87,6 +89,31 @@ func (e Extensions) GetObject(key string, out interface{}) error {
return nil
}
func (e Extensions) sanitize() {
for k := range e {
if !isExtensionKey(k) {
delete(e, k)
}
}
}
func (e Extensions) sanitizeWithExtra() (extra map[string]any) {
for k, v := range e {
if !isExtensionKey(k) {
if extra == nil {
extra = make(map[string]any)
}
extra[k] = v
delete(e, k)
}
}
return extra
}
func isExtensionKey(k string) bool {
return len(k) > 1 && (k[0] == 'x' || k[0] == 'X') && k[1] == '-'
}
// VendorExtensible composition block.
type VendorExtensible struct {
Extensions Extensions
@ -167,8 +194,29 @@ func (i Info) MarshalJSON() ([]byte, error) {
// 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
}
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
i.VendorExtensible.Extensions = x.Extensions
i.InfoProps = x.InfoProps
return nil
}

View File

@ -18,6 +18,8 @@ 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 (
@ -64,6 +66,10 @@ type Items struct {
// 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
@ -87,6 +93,28 @@ func (i *Items) UnmarshalJSON(data []byte) error {
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
}
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
i.CommonValidations = x.CommonValidations
i.SimpleSchema = x.SimpleSchema
i.VendorExtensible.Extensions = x.Extensions
return nil
}
// MarshalJSON converts this items object to JSON
func (i Items) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(i.CommonValidations)

View File

@ -18,6 +18,8 @@ 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
@ -75,12 +77,34 @@ type Operation struct {
// 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
}
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
o.VendorExtensible.Extensions = x.Extensions
o.OperationProps = OperationProps(x.OperationPropsNoMethods)
return nil
}
// MarshalJSON converts this items object to JSON
func (o Operation) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(o.OperationProps)

View File

@ -18,6 +18,8 @@ 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
@ -38,26 +40,31 @@ type ParamProps struct {
//
// 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`.
//
// 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.
//
// _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.
//
// `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 {
@ -70,6 +77,10 @@ type Parameter struct {
// 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
}
@ -85,6 +96,30 @@ func (p *Parameter) UnmarshalJSON(data []byte) error {
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
}
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
p.CommonValidations = x.CommonValidations
p.SimpleSchema = x.SimpleSchema
p.VendorExtensible.Extensions = x.Extensions
p.ParamProps = x.ParamProps
return nil
}
// MarshalJSON converts this items object to JSON
func (p Parameter) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(p.CommonValidations)

View File

@ -18,6 +18,8 @@ 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
@ -46,6 +48,10 @@ type PathItem struct {
// 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
}
@ -55,6 +61,31 @@ func (p *PathItem) UnmarshalJSON(data []byte) error {
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
}
p.Extensions = x.Extensions
p.PathItemProps = x.PathItemProps
if err := p.Refable.Ref.fromMap(p.Extensions); err != nil {
return err
}
p.Extensions.sanitize()
if len(p.Extensions) == 0 {
p.Extensions = nil
}
return nil
}
// MarshalJSON converts this items object to JSON
func (p PathItem) MarshalJSON() ([]byte, error) {
b3, err := json.Marshal(p.Refable)

View File

@ -16,9 +16,12 @@ 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.
@ -34,6 +37,10 @@ type Paths struct {
// 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
@ -63,6 +70,58 @@ func (p *Paths) UnmarshalJSON(data []byte) error {
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 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
return err
}
}
default:
return fmt.Errorf("unknown JSON kind: %v", k)
}
}
// MarshalJSON converts this items object to JSON
func (p Paths) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(p.VendorExtensible)

View File

@ -18,6 +18,8 @@ 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
@ -39,13 +41,46 @@ type Response struct {
// 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
}
return json.Unmarshal(data, &r.VendorExtensible)
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
}
r.Extensions = x.Extensions
r.ResponseProps = x.ResponseProps
if err := r.Refable.Ref.fromMap(r.Extensions); err != nil {
return err
}
r.Extensions.sanitize()
if len(r.Extensions) == 0 {
r.Extensions = nil
}
return nil
}
// MarshalJSON converts this items object to JSON

View File

@ -16,10 +16,13 @@ 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.
@ -42,6 +45,10 @@ type Responses struct {
// 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
}
@ -90,21 +97,90 @@ func (r ResponsesProps) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals responses from JSON
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
var res map[string]Response
if internal.UseOptimizedJSONUnmarshaling {
return jsonv2.Unmarshal(data, r)
}
var res map[string]json.RawMessage
if err := json.Unmarshal(data, &res); err != nil {
return nil
return err
}
if v, ok := res["default"]; ok {
r.Default = &v
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{}
}
r.StatusCodeResponses[nk] = v
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 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)
}
}

View File

@ -21,6 +21,8 @@ import (
"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
@ -465,6 +467,10 @@ func (s Schema) MarshalJSON() ([]byte, error) {
// UnmarshalJSON marshal this from JSON
func (s *Schema) UnmarshalJSON(data []byte) error {
if internal.UseOptimizedJSONUnmarshaling {
return jsonv2.Unmarshal(data, s)
}
props := struct {
SchemaProps
SwaggerSchemaProps
@ -511,3 +517,38 @@ func (s *Schema) UnmarshalJSON(data []byte) error {
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.VendorExtensible.Extensions = x.Extensions
s.SchemaProps = x.SchemaProps
s.SwaggerSchemaProps = x.SwaggerSchemaProps
return nil
}

View File

@ -18,6 +18,7 @@ import (
"encoding/json"
"github.com/go-openapi/swag"
jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
)
// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section
@ -62,3 +63,20 @@ func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
}
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
}
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
s.VendorExtensible.Extensions = x.Extensions
s.SecuritySchemeProps = x.SecuritySchemeProps
return nil
}

View File

@ -19,6 +19,8 @@ import (
"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.
@ -46,6 +48,10 @@ func (s Swagger) MarshalJSON() ([]byte, error) {
// 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
@ -57,6 +63,30 @@ func (s *Swagger) UnmarshalJSON(data []byte) error {
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 = x.Extensions
s.SwaggerProps = x.SwaggerProps
s.Extensions.sanitize()
if len(s.Extensions) == 0 {
s.Extensions = nil
}
return nil
}
// SwaggerProps captures the top-level properties of an Api specification
//
// NOTE: validation rules
@ -108,6 +138,10 @@ func (s SchemaOrBool) MarshalJSON() ([]byte, error) {
// 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) >= 4 {
if data[0] == '{' {
@ -123,6 +157,26 @@ func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
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
@ -142,6 +196,10 @@ func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) {
// 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]
@ -163,6 +221,18 @@ func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error {
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.
@ -193,6 +263,10 @@ func (s StringOrArray) Contains(value string) bool {
// 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]
@ -223,6 +297,23 @@ func (s *StringOrArray) UnmarshalJSON(data []byte) error {
}
}
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 {
@ -264,6 +355,10 @@ func (s SchemaOrArray) MarshalJSON() ([]byte, error) {
// 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 {
@ -284,3 +379,15 @@ func (s *SchemaOrArray) UnmarshalJSON(data []byte) error {
*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
}
}

View File

@ -18,6 +18,8 @@ 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
@ -52,8 +54,29 @@ func (t Tag) MarshalJSON() ([]byte, error) {
// 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
}
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
t.VendorExtensible.Extensions = x.Extensions
t.TagProps = x.TagProps
return nil
}