rebase: update kubernetes to 1.28.0 in main

updating kubernetes to 1.28.0
in the main repo.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna
2023-08-17 07:15:28 +02:00
committed by mergify[bot]
parent b2fdc269c3
commit ff3e84ad67
706 changed files with 45252 additions and 16346 deletions

View File

@ -152,7 +152,7 @@ func (o *openAPI) finalizeSwagger() (*spec.Swagger, error) {
}
}
return o.swagger, nil
return deduplicateParameters(o.swagger)
}
func (o *openAPI) buildDefinitionRecursively(name string) error {

259
vendor/k8s.io/kube-openapi/pkg/builder/parameters.go generated vendored Normal file
View 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
}

View File

@ -19,6 +19,8 @@ limitations under the License.
// 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
@ -34,12 +36,6 @@ limitations under the License.
// replaced with a new one, and saves the previous results in case an
// error pops-up.
//
// # Atomicity
//
// Most of the operations are not atomic/thread-safe, except for
// [Replaceable.Replace] which can be performed while the objects
// are being read.
//
// # Etags
//
// Etags in this library is a cache version identifier. It doesn't
@ -54,6 +50,7 @@ package cached
import (
"fmt"
"sync"
"sync/atomic"
)
@ -100,14 +97,6 @@ type Data[T any] interface {
Get() Result[T]
}
// T is the source type, V is the destination type.
type merger[K comparable, T, V any] struct {
mergeFn func(map[K]Result[T]) Result[V]
caches map[K]Data[T]
cacheResults map[K]Result[T]
result Result[V]
}
// NewMerger creates a new merge cache, a cache that merges the result
// of other caches. The function only gets called if any of the
// dependency has changed.
@ -125,27 +114,89 @@ type merger[K comparable, T, V any] struct {
// 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 NewMerger[K comparable, T, V any](mergeFn func(results map[K]Result[T]) Result[V], caches map[K]Data[T]) Data[V] {
return &merger[K, T, V]{
listCaches := make([]Data[T], 0, len(caches))
// maps from index to key
indexes := make(map[int]K, len(caches))
i := 0
for k := range caches {
listCaches = append(listCaches, caches[k])
indexes[i] = k
i++
}
return NewListMerger(func(results []Result[T]) Result[V] {
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)
}, listCaches)
}
type listMerger[T, V any] struct {
lock sync.Mutex
mergeFn func([]Result[T]) Result[V]
caches []Data[T]
cacheResults []Result[T]
result Result[V]
}
// NewListMerger creates a new merge cache that merges the results of
// other caches in list form. 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 NewListMerger[T, V any](mergeFn func(results []Result[T]) Result[V], caches []Data[T]) Data[V] {
return &listMerger[T, V]{
mergeFn: mergeFn,
caches: caches,
}
}
func (c *merger[K, T, V]) prepareResults() map[K]Result[T] {
cacheResults := make(map[K]Result[T], len(c.caches))
for key, cache := range c.caches {
cacheResults[key] = cache.Get()
func (c *listMerger[T, V]) prepareResultsLocked() []Result[T] {
cacheResults := make([]Result[T], len(c.caches))
ch := make(chan struct {
int
Result[T]
}, len(c.caches))
for i := range c.caches {
go func(index int) {
ch <- struct {
int
Result[T]
}{
index,
c.caches[index].Get(),
}
}(i)
}
for i := 0; i < len(c.caches); i++ {
res := <-ch
cacheResults[res.int] = res.Result
}
return cacheResults
}
// Rerun if:
// - The last run resulted in an error
// - Any of the dependency previously returned an error
// - Any of the dependency just returned an error
// - Any of the dependency's etag changed
func (c *merger[K, T, V]) needsRunning(results map[K]Result[T]) bool {
func (c *listMerger[T, V]) needsRunningLocked(results []Result[T]) bool {
if c.cacheResults == nil {
return true
}
@ -155,12 +206,8 @@ func (c *merger[K, T, V]) needsRunning(results map[K]Result[T]) bool {
if len(results) != len(c.cacheResults) {
panic(fmt.Errorf("invalid number of results: %v (expected %v)", len(results), len(c.cacheResults)))
}
for key, oldResult := range c.cacheResults {
newResult, ok := results[key]
if !ok {
panic(fmt.Errorf("unknown cache entry: %v", key))
}
for i, oldResult := range c.cacheResults {
newResult := results[i]
if newResult.Etag != oldResult.Etag || newResult.Err != nil || oldResult.Err != nil {
return true
}
@ -168,17 +215,17 @@ func (c *merger[K, T, V]) needsRunning(results map[K]Result[T]) bool {
return false
}
func (c *merger[K, T, V]) Get() Result[V] {
cacheResults := c.prepareResults()
if c.needsRunning(cacheResults) {
func (c *listMerger[T, V]) Get() Result[V] {
c.lock.Lock()
defer c.lock.Unlock()
cacheResults := c.prepareResultsLocked()
if c.needsRunningLocked(cacheResults) {
c.cacheResults = cacheResults
c.result = c.mergeFn(c.cacheResults)
}
return c.result
}
type transformerCacheKeyType struct{}
// NewTransformer creates a new cache that transforms the result of
// another cache. The transformFn will only be called if the source
// cache has updated the output, otherwise, the cached result will be
@ -188,20 +235,17 @@ type transformerCacheKeyType struct{}
// this time, or if the transformerFn failed before, the function is
// reran.
func NewTransformer[T, V any](transformerFn func(Result[T]) Result[V], source Data[T]) Data[V] {
return NewMerger(func(caches map[transformerCacheKeyType]Result[T]) Result[V] {
cache, ok := caches[transformerCacheKeyType{}]
if len(caches) != 1 || !ok {
return NewListMerger(func(caches []Result[T]) Result[V] {
if len(caches) != 1 {
panic(fmt.Errorf("invalid cache for transformer cache: %v", caches))
}
return transformerFn(cache)
}, map[transformerCacheKeyType]Data[T]{
{}: source,
})
return transformerFn(caches[0])
}, []Data[T]{source})
}
// NewSource creates a new cache that generates some data. This
// will always be called since we don't know the origin of the data and
// if it needs to be updated or not.
// if it needs to be updated or not. sourceFn MUST be thread-safe.
func NewSource[T any](sourceFn func() Result[T]) Data[T] {
c := source[T](sourceFn)
return &c
@ -222,25 +266,24 @@ func NewStaticSource[T any](staticFn func() Result[T]) Data[T] {
}
type static[T any] struct {
once sync.Once
fn func() Result[T]
result *Result[T]
result Result[T]
}
func (c *static[T]) Get() Result[T] {
if c.result == nil {
result := c.fn()
c.result = &result
}
return *c.result
c.once.Do(func() {
c.result = c.fn()
})
return c.result
}
// Replaceable is a cache that carries the result even when the
// cache is replaced. The cache can be replaced atomically (without any
// lock held). This is the type that should typically be stored in
// Replaceable is a cache that carries the result even when the cache is
// replaced. This is the type that should typically be stored in
// structs.
type Replaceable[T any] struct {
cache atomic.Pointer[Data[T]]
result *Result[T]
result atomic.Pointer[Result[T]]
}
// Get retrieves the data from the underlying source. [Replaceable]
@ -251,14 +294,19 @@ type Replaceable[T any] struct {
// failure is returned.
func (c *Replaceable[T]) Get() Result[T] {
result := (*c.cache.Load()).Get()
if result.Err != nil && c.result != nil && c.result.Err == nil {
return *c.result
for {
cResult := c.result.Load()
if result.Err != nil && cResult != nil && cResult.Err == nil {
return *cResult
}
if c.result.CompareAndSwap(cResult, &result) {
return result
}
}
c.result = &result
return *c.result
}
// Replace changes the cache in a thread-safe way.
// Replace changes the cache.
func (c *Replaceable[T]) Replace(cache Data[T]) {
c.cache.Swap(&cache)
}

View File

@ -22,13 +22,12 @@ import (
"fmt"
"net/http"
"strconv"
"sync"
"time"
"github.com/NYTimes/gziphandler"
"github.com/emicklei/go-restful/v3"
"github.com/golang/protobuf/proto"
openapi_v2 "github.com/google/gnostic/openapiv2"
openapi_v2 "github.com/google/gnostic-models/openapiv2"
"github.com/google/uuid"
"github.com/munnerz/goautoneg"
klog "k8s.io/klog/v2"
@ -119,16 +118,14 @@ func ToProtoBinary(json []byte) ([]byte, error) {
// 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, error) {
func RegisterOpenAPIVersionedService(spec *spec.Swagger, servePath string, handler common.PathHandler) *OpenAPIService {
o := NewOpenAPIService(spec)
return o, o.RegisterOpenAPIVersionedService(servePath, handler)
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) error {
// Mutex protects the cache chain
var mutex sync.Mutex
func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handler common.PathHandler) {
accepted := []struct {
Type string
SubType string
@ -157,9 +154,7 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl
continue
}
// serve the first matching media type in the sorted clause list
mutex.Lock()
result := accepts.GetDataAndEtag.Get()
mutex.Unlock()
if result.Err != nil {
klog.Errorf("Error in OpenAPI handler: %s", result.Err)
// only return a 503 if we have no older cache data to serve
@ -183,8 +178,6 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl
return
}),
))
return nil
}
// BuildAndRegisterOpenAPIVersionedService builds the spec and registers a handler to provide access to it.
@ -203,5 +196,6 @@ func BuildAndRegisterOpenAPIVersionedServiceFromRoutes(servePath string, routeCo
return nil, err
}
o := NewOpenAPIService(spec)
return o, o.RegisterOpenAPIVersionedService(servePath, handler)
o.RegisterOpenAPIVersionedService(servePath, handler)
return o, nil
}

View File

@ -30,7 +30,7 @@ import (
"time"
"github.com/golang/protobuf/proto"
openapi_v3 "github.com/google/gnostic/openapiv3"
openapi_v3 "github.com/google/gnostic-models/openapiv3"
"github.com/google/uuid"
"github.com/munnerz/goautoneg"
"k8s.io/klog/v2"

View File

@ -21,7 +21,7 @@ import (
"sort"
"strings"
openapi_v2 "github.com/google/gnostic/openapiv2"
openapi_v2 "github.com/google/gnostic-models/openapiv2"
"gopkg.in/yaml.v2"
)

View File

@ -21,7 +21,7 @@ import (
"reflect"
"strings"
openapi_v3 "github.com/google/gnostic/openapiv3"
openapi_v3 "github.com/google/gnostic-models/openapiv3"
"gopkg.in/yaml.v3"
)

View File

@ -21,7 +21,7 @@ import (
"strconv"
"github.com/go-openapi/jsonreference"
openapi_v2 "github.com/google/gnostic/openapiv2"
openapi_v2 "github.com/google/gnostic-models/openapiv2"
)
// Interfaces

View File

@ -16,13 +16,10 @@ package strfmt
import (
"encoding"
"fmt"
"reflect"
"strings"
"sync"
"time"
"github.com/mitchellh/mapstructure"
"k8s.io/kube-openapi/pkg/validation/errors"
)
@ -50,7 +47,6 @@ type Registry interface {
ContainsName(string) bool
Validates(string, string) bool
Parse(string, string) (interface{}, error)
MapStructureHookFunc() mapstructure.DecodeHookFunc
}
type knownFormat struct {
@ -92,83 +88,6 @@ func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry {
}
}
// MapStructureHookFunc is a decode hook function for mapstructure
func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
if from.Kind() != reflect.String {
return data, nil
}
for _, v := range f.data {
tpe, _ := f.GetType(v.Name)
if to == tpe {
switch v.Name {
case "date":
d, err := time.Parse(RFC3339FullDate, data.(string))
if err != nil {
return nil, err
}
return Date(d), nil
case "datetime":
input := data.(string)
if len(input) == 0 {
return nil, fmt.Errorf("empty string is an invalid datetime format")
}
return ParseDateTime(input)
case "duration":
dur, err := ParseDuration(data.(string))
if err != nil {
return nil, err
}
return Duration(dur), nil
case "uri":
return URI(data.(string)), nil
case "email":
return Email(data.(string)), nil
case "uuid":
return UUID(data.(string)), nil
case "uuid3":
return UUID3(data.(string)), nil
case "uuid4":
return UUID4(data.(string)), nil
case "uuid5":
return UUID5(data.(string)), nil
case "hostname":
return Hostname(data.(string)), nil
case "ipv4":
return IPv4(data.(string)), nil
case "ipv6":
return IPv6(data.(string)), nil
case "cidr":
return CIDR(data.(string)), nil
case "mac":
return MAC(data.(string)), nil
case "isbn":
return ISBN(data.(string)), nil
case "isbn10":
return ISBN10(data.(string)), nil
case "isbn13":
return ISBN13(data.(string)), nil
case "creditcard":
return CreditCard(data.(string)), nil
case "ssn":
return SSN(data.(string)), nil
case "hexcolor":
return HexColor(data.(string)), nil
case "rgbcolor":
return RGBColor(data.(string)), nil
case "byte":
return Base64(data.(string)), nil
case "password":
return Password(data.(string)), nil
default:
return nil, errors.InvalidTypeName(v.Name)
}
}
}
return data, nil
}
}
// Add adds a new format, return true if this was a new item instead of a replacement
func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bool {
f.Lock()