mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 18:43:34 +00:00
rebase: bump k8s.io/api in /api in the k8s-dependencies group
Bumps the k8s-dependencies group in /api with 1 update: [k8s.io/api](https://github.com/kubernetes/api). Updates `k8s.io/api` from 0.32.3 to 0.33.0 - [Commits](https://github.com/kubernetes/api/compare/v0.32.3...v0.33.0) --- updated-dependencies: - dependency-name: k8s.io/api dependency-version: 0.33.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
mergify[bot]
parent
05e3827a4f
commit
af12c6bf1b
56
api/vendor/k8s.io/apimachinery/pkg/api/operation/operation.go
generated
vendored
Normal file
56
api/vendor/k8s.io/apimachinery/pkg/api/operation/operation.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2024 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 operation
|
||||
|
||||
import "k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
// Operation provides contextual information about a validation request and the API
|
||||
// operation being validated.
|
||||
// This type is intended for use with generate validation code and may be enhanced
|
||||
// in the future to include other information needed to validate requests.
|
||||
type Operation struct {
|
||||
// Type is the category of operation being validated. This does not
|
||||
// differentiate between HTTP verbs like PUT and PATCH, but rather merges
|
||||
// those into a single "Update" category.
|
||||
Type Type
|
||||
|
||||
// Options declare the options enabled for validation.
|
||||
//
|
||||
// Options should be set according to a resource validation strategy before validation
|
||||
// is performed, and must be treated as read-only during validation.
|
||||
//
|
||||
// Options are identified by string names. Option string names may match the name of a feature
|
||||
// gate, in which case the presence of the name in the set indicates that the feature is
|
||||
// considered enabled for the resource being validated. Note that a resource may have a
|
||||
// feature enabled even when the feature gate is disabled. This can happen when feature is
|
||||
// already in-use by a resource, often because the feature gate was enabled when the
|
||||
// resource first began using the feature.
|
||||
//
|
||||
// Unset options are disabled/false.
|
||||
Options sets.Set[string]
|
||||
}
|
||||
|
||||
// Code is the request operation to be validated.
|
||||
type Type uint32
|
||||
|
||||
const (
|
||||
// Create indicates the request being validated is for a resource create operation.
|
||||
Create Type = iota
|
||||
|
||||
// Update indicates the request being validated is for a resource update operation.
|
||||
Update
|
||||
)
|
2
api/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go
generated
vendored
@ -21,4 +21,4 @@ limitations under the License.
|
||||
|
||||
// +groupName=meta.k8s.io
|
||||
|
||||
package v1 // import "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
package v1
|
||||
|
13
api/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_fuzz.go
generated
vendored
13
api/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_fuzz.go
generated
vendored
@ -20,21 +20,22 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"sigs.k8s.io/randfill"
|
||||
)
|
||||
|
||||
// Fuzz satisfies fuzz.Interface.
|
||||
func (t *MicroTime) Fuzz(c fuzz.Continue) {
|
||||
// Fuzz satisfies randfill.SimpleSelfFiller.
|
||||
func (t *MicroTime) RandFill(r *rand.Rand) {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
// Allow for about 1000 years of randomness. Accurate to a tenth of
|
||||
// micro second. Leave off nanoseconds because JSON doesn't
|
||||
// represent them so they can't round-trip properly.
|
||||
t.Time = time.Unix(c.Rand.Int63n(1000*365*24*60*60), 1000*c.Rand.Int63n(1000000))
|
||||
t.Time = time.Unix(r.Int63n(1000*365*24*60*60), 1000*r.Int63n(1000000))
|
||||
}
|
||||
|
||||
// ensure MicroTime implements fuzz.Interface
|
||||
var _ fuzz.Interface = &MicroTime{}
|
||||
// ensure MicroTime implements randfill.Interface
|
||||
var _ randfill.SimpleSelfFiller = &MicroTime{}
|
||||
|
13
api/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_fuzz.go
generated
vendored
13
api/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_fuzz.go
generated
vendored
@ -20,21 +20,22 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"sigs.k8s.io/randfill"
|
||||
)
|
||||
|
||||
// Fuzz satisfies fuzz.Interface.
|
||||
func (t *Time) Fuzz(c fuzz.Continue) {
|
||||
// Fuzz satisfies randfill.SimpleSelfFiller.
|
||||
func (t *Time) RandFill(r *rand.Rand) {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
// Allow for about 1000 years of randomness. Leave off nanoseconds
|
||||
// because JSON doesn't represent them so they can't round-trip
|
||||
// properly.
|
||||
t.Time = time.Unix(c.Rand.Int63n(1000*365*24*60*60), 0)
|
||||
t.Time = time.Unix(r.Int63n(1000*365*24*60*60), 0)
|
||||
}
|
||||
|
||||
// ensure Time implements fuzz.Interface
|
||||
var _ fuzz.Interface = &Time{}
|
||||
// ensure Time implements randfill.SimpleSelfFiller
|
||||
var _ randfill.SimpleSelfFiller = &Time{}
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/conversion/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/conversion/doc.go
generated
vendored
@ -21,4 +21,4 @@ limitations under the License.
|
||||
// but for the fields which did not change, copying is automated. This makes it
|
||||
// easy to modify the structures you use in memory without affecting the format
|
||||
// you store on disk or respond to in your external API calls.
|
||||
package conversion // import "k8s.io/apimachinery/pkg/conversion"
|
||||
package conversion
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go
generated
vendored
@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package queryparams provides conversion from versioned
|
||||
// runtime objects to URL query values
|
||||
package queryparams // import "k8s.io/apimachinery/pkg/conversion/queryparams"
|
||||
package queryparams
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/fields/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/fields/doc.go
generated
vendored
@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package fields implements a simple field system, parsing and matching
|
||||
// selectors with sets of fields.
|
||||
package fields // import "k8s.io/apimachinery/pkg/fields"
|
||||
package fields
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/labels/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/labels/doc.go
generated
vendored
@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package labels implements a simple label system, parsing and matching
|
||||
// selectors with sets of labels.
|
||||
package labels // import "k8s.io/apimachinery/pkg/labels"
|
||||
package labels
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/runtime/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/runtime/doc.go
generated
vendored
@ -48,4 +48,4 @@ limitations under the License.
|
||||
//
|
||||
// As a bonus, a few common types useful from all api objects and versions
|
||||
// are provided in types.go.
|
||||
package runtime // import "k8s.io/apimachinery/pkg/runtime"
|
||||
package runtime
|
||||
|
1
api/vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go
generated
vendored
1
api/vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go
generated
vendored
@ -259,6 +259,7 @@ type ObjectDefaulter interface {
|
||||
|
||||
type ObjectVersioner interface {
|
||||
ConvertToVersion(in Object, gv GroupVersioner) (out Object, err error)
|
||||
PrioritizedVersionsForGroup(group string) []schema.GroupVersion
|
||||
}
|
||||
|
||||
// ObjectConvertor converts an object to a different version.
|
||||
|
39
api/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go
generated
vendored
39
api/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go
generated
vendored
@ -17,15 +17,18 @@ limitations under the License.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/operation"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/naming"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// Scheme defines methods for serializing and deserializing API objects, a type
|
||||
@ -68,6 +71,12 @@ type Scheme struct {
|
||||
// the provided object must be a pointer.
|
||||
defaulterFuncs map[reflect.Type]func(interface{})
|
||||
|
||||
// validationFuncs is a map to funcs to be called with an object to perform validation.
|
||||
// The provided object must be a pointer.
|
||||
// If oldObject is non-nil, update validation is performed and may perform additional
|
||||
// validation such as transition rules and immutability checks.
|
||||
validationFuncs map[reflect.Type]func(ctx context.Context, op operation.Operation, object, oldObject interface{}, subresources ...string) field.ErrorList
|
||||
|
||||
// converter stores all registered conversion functions. It also has
|
||||
// default converting behavior.
|
||||
converter *conversion.Converter
|
||||
@ -96,6 +105,7 @@ func NewScheme() *Scheme {
|
||||
unversionedKinds: map[string]reflect.Type{},
|
||||
fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{},
|
||||
defaulterFuncs: map[reflect.Type]func(interface{}){},
|
||||
validationFuncs: map[reflect.Type]func(ctx context.Context, op operation.Operation, object, oldObject interface{}, subresource ...string) field.ErrorList{},
|
||||
versionPriority: map[string][]string{},
|
||||
schemeName: naming.GetNameFromCallsite(internalPackages...),
|
||||
}
|
||||
@ -347,6 +357,35 @@ func (s *Scheme) Default(src Object) {
|
||||
}
|
||||
}
|
||||
|
||||
// AddValidationFunc registered a function that can validate the object, and
|
||||
// oldObject. These functions will be invoked when Validate() or ValidateUpdate()
|
||||
// is called. The function will never be called unless the validated object
|
||||
// matches srcType. If this function is invoked twice with the same srcType, the
|
||||
// fn passed to the later call will be used instead.
|
||||
func (s *Scheme) AddValidationFunc(srcType Object, fn func(ctx context.Context, op operation.Operation, object, oldObject interface{}, subresources ...string) field.ErrorList) {
|
||||
s.validationFuncs[reflect.TypeOf(srcType)] = fn
|
||||
}
|
||||
|
||||
// Validate validates the provided Object according to the generated declarative validation code.
|
||||
// WARNING: This does not validate all objects! The handwritten validation code in validation.go
|
||||
// is not run when this is called. Only the generated zz_generated.validations.go validation code is run.
|
||||
func (s *Scheme) Validate(ctx context.Context, options sets.Set[string], object Object, subresources ...string) field.ErrorList {
|
||||
if fn, ok := s.validationFuncs[reflect.TypeOf(object)]; ok {
|
||||
return fn(ctx, operation.Operation{Type: operation.Create, Options: options}, object, nil, subresources...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUpdate validates the provided object and oldObject according to the generated declarative validation code.
|
||||
// WARNING: This does not validate all objects! The handwritten validation code in validation.go
|
||||
// is not run when this is called. Only the generated zz_generated.validations.go validation code is run.
|
||||
func (s *Scheme) ValidateUpdate(ctx context.Context, options sets.Set[string], object, oldObject Object, subresources ...string) field.ErrorList {
|
||||
if fn, ok := s.validationFuncs[reflect.TypeOf(object)]; ok {
|
||||
return fn(ctx, operation.Operation{Type: operation.Update, Options: options}, object, oldObject, subresources...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert will attempt to convert in into out. Both must be pointers. For easy
|
||||
// testing of conversion functions. Returns an error if the conversion isn't
|
||||
// possible. You can call this with types that haven't been registered (for example,
|
||||
|
4
api/vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go
generated
vendored
4
api/vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go
generated
vendored
@ -140,7 +140,7 @@ func (cache *checkers) getCheckerInternal(rt reflect.Type, parent *path) (c chec
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
c = checker{
|
||||
placeholder := checker{
|
||||
safe: func() bool {
|
||||
wg.Wait()
|
||||
return c.safe()
|
||||
@ -150,7 +150,7 @@ func (cache *checkers) getCheckerInternal(rt reflect.Type, parent *path) (c chec
|
||||
return c.check(rv, depth)
|
||||
},
|
||||
}
|
||||
if actual, loaded := cache.m.LoadOrStore(rt, &c); loaded {
|
||||
if actual, loaded := cache.m.LoadOrStore(rt, &placeholder); loaded {
|
||||
// Someone else stored an entry for this type, use it.
|
||||
return *actual.(*checker)
|
||||
}
|
||||
|
127
api/vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go
generated
vendored
127
api/vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go
generated
vendored
@ -18,6 +18,7 @@ package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ProtobufMarshaller interface {
|
||||
@ -28,6 +29,124 @@ type ProtobufReverseMarshaller interface {
|
||||
MarshalToSizedBuffer(data []byte) (int, error)
|
||||
}
|
||||
|
||||
const (
|
||||
typeMetaTag = 0xa
|
||||
rawTag = 0x12
|
||||
contentEncodingTag = 0x1a
|
||||
contentTypeTag = 0x22
|
||||
|
||||
// max length of a varint for a uint64
|
||||
maxUint64VarIntLength = 10
|
||||
)
|
||||
|
||||
// MarshalToWriter allows a caller to provide a streaming writer for raw bytes,
|
||||
// instead of populating them inside the Unknown struct.
|
||||
// rawSize is the number of bytes rawWriter will write in a success case.
|
||||
// writeRaw is called when it is time to write the raw bytes. It must return `rawSize, nil` or an error.
|
||||
func (m *Unknown) MarshalToWriter(w io.Writer, rawSize int, writeRaw func(io.Writer) (int, error)) (int, error) {
|
||||
size := 0
|
||||
|
||||
// reuse the buffer for varint marshaling
|
||||
varintBuffer := make([]byte, maxUint64VarIntLength)
|
||||
writeVarint := func(i int) (int, error) {
|
||||
offset := encodeVarintGenerated(varintBuffer, len(varintBuffer), uint64(i))
|
||||
return w.Write(varintBuffer[offset:])
|
||||
}
|
||||
|
||||
// TypeMeta
|
||||
{
|
||||
n, err := w.Write([]byte{typeMetaTag})
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
typeMetaBytes, err := m.TypeMeta.Marshal()
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = writeVarint(len(typeMetaBytes))
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = w.Write(typeMetaBytes)
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
}
|
||||
|
||||
// Raw, delegating write to writeRaw()
|
||||
{
|
||||
n, err := w.Write([]byte{rawTag})
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = writeVarint(rawSize)
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = writeRaw(w)
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
if n != int(rawSize) {
|
||||
return size, fmt.Errorf("the size value was %d, but encoding wrote %d bytes to data", rawSize, n)
|
||||
}
|
||||
}
|
||||
|
||||
// ContentEncoding
|
||||
{
|
||||
n, err := w.Write([]byte{contentEncodingTag})
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = writeVarint(len(m.ContentEncoding))
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = w.Write([]byte(m.ContentEncoding))
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
}
|
||||
|
||||
// ContentEncoding
|
||||
{
|
||||
n, err := w.Write([]byte{contentTypeTag})
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = writeVarint(len(m.ContentType))
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
|
||||
n, err = w.Write([]byte(m.ContentType))
|
||||
size += n
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
}
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// NestedMarshalTo allows a caller to avoid extra allocations during serialization of an Unknown
|
||||
// that will contain an object that implements ProtobufMarshaller or ProtobufReverseMarshaller.
|
||||
func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64) (int, error) {
|
||||
@ -43,12 +162,12 @@ func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64
|
||||
copy(data[i:], m.ContentType)
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.ContentType)))
|
||||
i--
|
||||
data[i] = 0x22
|
||||
data[i] = contentTypeTag
|
||||
i -= len(m.ContentEncoding)
|
||||
copy(data[i:], m.ContentEncoding)
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.ContentEncoding)))
|
||||
i--
|
||||
data[i] = 0x1a
|
||||
data[i] = contentEncodingTag
|
||||
if b != nil {
|
||||
if r, ok := b.(ProtobufReverseMarshaller); ok {
|
||||
n1, err := r.MarshalToSizedBuffer(data[:i])
|
||||
@ -75,7 +194,7 @@ func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64
|
||||
}
|
||||
i = encodeVarintGenerated(data, i, size)
|
||||
i--
|
||||
data[i] = 0x12
|
||||
data[i] = rawTag
|
||||
}
|
||||
n2, err := m.TypeMeta.MarshalToSizedBuffer(data[:i])
|
||||
if err != nil {
|
||||
@ -84,6 +203,6 @@ func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64
|
||||
i -= n2
|
||||
i = encodeVarintGenerated(data, i, uint64(n2))
|
||||
i--
|
||||
data[i] = 0xa
|
||||
data[i] = typeMetaTag
|
||||
return msgSize - i, nil
|
||||
}
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/types/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/types/doc.go
generated
vendored
@ -15,4 +15,4 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
// Package types implements various generic types used throughout kubernetes.
|
||||
package types // import "k8s.io/apimachinery/pkg/types"
|
||||
package types
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/util/errors/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/util/errors/doc.go
generated
vendored
@ -15,4 +15,4 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
// Package errors implements various utility functions and types around errors.
|
||||
package errors // import "k8s.io/apimachinery/pkg/util/errors"
|
||||
package errors
|
||||
|
14
api/vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go
generated
vendored
14
api/vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go
generated
vendored
@ -20,24 +20,24 @@ limitations under the License.
|
||||
package intstr
|
||||
|
||||
import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"sigs.k8s.io/randfill"
|
||||
)
|
||||
|
||||
// Fuzz satisfies fuzz.Interface
|
||||
func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
|
||||
// RandFill satisfies randfill.NativeSelfFiller
|
||||
func (intstr *IntOrString) RandFill(c randfill.Continue) {
|
||||
if intstr == nil {
|
||||
return
|
||||
}
|
||||
if c.RandBool() {
|
||||
if c.Bool() {
|
||||
intstr.Type = Int
|
||||
c.Fuzz(&intstr.IntVal)
|
||||
c.Fill(&intstr.IntVal)
|
||||
intstr.StrVal = ""
|
||||
} else {
|
||||
intstr.Type = String
|
||||
intstr.IntVal = 0
|
||||
c.Fuzz(&intstr.StrVal)
|
||||
c.Fill(&intstr.StrVal)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure IntOrString implements fuzz.Interface
|
||||
var _ fuzz.Interface = &IntOrString{}
|
||||
var _ randfill.NativeSelfFiller = &IntOrString{}
|
||||
|
46
api/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
generated
vendored
46
api/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
generated
vendored
@ -36,6 +36,11 @@ var (
|
||||
)
|
||||
|
||||
// PanicHandlers is a list of functions which will be invoked when a panic happens.
|
||||
//
|
||||
// The code invoking these handlers prepares a contextual logger so that
|
||||
// klog.FromContext(ctx) already skips over the panic handler itself and
|
||||
// several other intermediate functions, ideally such that the log output
|
||||
// is attributed to the code which triggered the panic.
|
||||
var PanicHandlers = []func(context.Context, interface{}){logPanic}
|
||||
|
||||
// HandleCrash simply catches a crash and logs an error. Meant to be called via
|
||||
@ -45,7 +50,7 @@ var PanicHandlers = []func(context.Context, interface{}){logPanic}
|
||||
//
|
||||
// E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully.
|
||||
//
|
||||
// Contextual logging: HandleCrashWithContext should be used instead of HandleCrash in code which supports contextual logging.
|
||||
// Contextual logging: HandleCrashWithContext or HandleCrashWithLogger should be used instead of HandleCrash in code which supports contextual logging.
|
||||
func HandleCrash(additionalHandlers ...func(interface{})) {
|
||||
if r := recover(); r != nil {
|
||||
additionalHandlersWithContext := make([]func(context.Context, interface{}), len(additionalHandlers))
|
||||
@ -74,10 +79,30 @@ func HandleCrashWithContext(ctx context.Context, additionalHandlers ...func(cont
|
||||
}
|
||||
}
|
||||
|
||||
// handleCrash is the common implementation of HandleCrash and HandleCrash.
|
||||
// HandleCrashWithLogger simply catches a crash and logs an error. Meant to be called via
|
||||
// defer. Additional context-specific handlers can be provided, and will be
|
||||
// called in case of panic. HandleCrash actually crashes, after calling the
|
||||
// handlers and logging the panic message.
|
||||
//
|
||||
// E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully.
|
||||
func HandleCrashWithLogger(logger klog.Logger, additionalHandlers ...func(context.Context, interface{})) {
|
||||
if r := recover(); r != nil {
|
||||
ctx := klog.NewContext(context.Background(), logger)
|
||||
handleCrash(ctx, r, additionalHandlers...)
|
||||
}
|
||||
}
|
||||
|
||||
// handleCrash is the common implementation of the HandleCrash* variants.
|
||||
// Having those call a common implementation ensures that the stack depth
|
||||
// is the same regardless through which path the handlers get invoked.
|
||||
func handleCrash(ctx context.Context, r any, additionalHandlers ...func(context.Context, interface{})) {
|
||||
// We don't really know how many call frames to skip because the Go
|
||||
// panic handler is between us and the code where the panic occurred.
|
||||
// If it's one function (as in Go 1.21), then skipping four levels
|
||||
// gets us to the function which called the `defer HandleCrashWithontext(...)`.
|
||||
logger := klog.FromContext(ctx).WithCallDepth(4)
|
||||
ctx = klog.NewContext(ctx, logger)
|
||||
|
||||
for _, fn := range PanicHandlers {
|
||||
fn(ctx, r)
|
||||
}
|
||||
@ -106,11 +131,7 @@ func logPanic(ctx context.Context, r interface{}) {
|
||||
stacktrace := make([]byte, size)
|
||||
stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
|
||||
|
||||
// We don't really know how many call frames to skip because the Go
|
||||
// panic handler is between us and the code where the panic occurred.
|
||||
// If it's one function (as in Go 1.21), then skipping four levels
|
||||
// gets us to the function which called the `defer HandleCrashWithontext(...)`.
|
||||
logger := klog.FromContext(ctx).WithCallDepth(4)
|
||||
logger := klog.FromContext(ctx)
|
||||
|
||||
// For backwards compatibility, conversion to string
|
||||
// is handled here instead of defering to the logging
|
||||
@ -176,12 +197,19 @@ func HandleError(err error) {
|
||||
// and key/value pairs.
|
||||
//
|
||||
// This variant should be used instead of HandleError because it supports
|
||||
// structured, contextual logging.
|
||||
// structured, contextual logging. Alternatively, [HandleErrorWithLogger] can
|
||||
// be used if a logger is available instead of a context.
|
||||
func HandleErrorWithContext(ctx context.Context, err error, msg string, keysAndValues ...interface{}) {
|
||||
handleError(ctx, err, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// handleError is the common implementation of HandleError and HandleErrorWithContext.
|
||||
// HandleErrorWithLogger is an alternative to [HandlerErrorWithContext] which accepts
|
||||
// a logger for contextual logging.
|
||||
func HandleErrorWithLogger(logger klog.Logger, err error, msg string, keysAndValues ...interface{}) {
|
||||
handleError(klog.NewContext(context.Background(), logger), err, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// handleError is the common implementation of the HandleError* variants.
|
||||
// Using this common implementation ensures that the stack depth
|
||||
// is the same regardless through which path the handlers get invoked.
|
||||
func handleError(ctx context.Context, err error, msg string, keysAndValues ...interface{}) {
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/util/sets/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/util/sets/doc.go
generated
vendored
@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package sets has generic set and specified sets. Generic set will
|
||||
// replace specified ones over time. And specific ones are deprecated.
|
||||
package sets // import "k8s.io/apimachinery/pkg/util/sets"
|
||||
package sets
|
||||
|
212
api/vendor/k8s.io/apimachinery/pkg/util/validation/field/error_matcher.go
generated
vendored
Normal file
212
api/vendor/k8s.io/apimachinery/pkg/util/validation/field/error_matcher.go
generated
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
Copyright 2025 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 field
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrorMatcher is a helper for comparing Error objects.
|
||||
type ErrorMatcher struct {
|
||||
// TODO(thockin): consider whether type is ever NOT required, maybe just
|
||||
// assume it.
|
||||
matchType bool
|
||||
// TODO(thockin): consider whether field could be assumed - if the
|
||||
// "want" error has a nil field, don't match on field.
|
||||
matchField bool
|
||||
// TODO(thockin): consider whether value could be assumed - if the
|
||||
// "want" error has a nil value, don't match on field.
|
||||
matchValue bool
|
||||
matchOrigin bool
|
||||
matchDetail func(want, got string) bool
|
||||
requireOriginWhenInvalid bool
|
||||
}
|
||||
|
||||
// Matches returns true if the two Error objects match according to the
|
||||
// configured criteria.
|
||||
func (m ErrorMatcher) Matches(want, got *Error) bool {
|
||||
if m.matchType && want.Type != got.Type {
|
||||
return false
|
||||
}
|
||||
if m.matchField && want.Field != got.Field {
|
||||
return false
|
||||
}
|
||||
if m.matchValue && !reflect.DeepEqual(want.BadValue, got.BadValue) {
|
||||
return false
|
||||
}
|
||||
if m.matchOrigin {
|
||||
if want.Origin != got.Origin {
|
||||
return false
|
||||
}
|
||||
if m.requireOriginWhenInvalid && want.Type == ErrorTypeInvalid {
|
||||
if want.Origin == "" || got.Origin == "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if m.matchDetail != nil && !m.matchDetail(want.Detail, got.Detail) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Render returns a string representation of the specified Error object,
|
||||
// according to the criteria configured in the ErrorMatcher.
|
||||
func (m ErrorMatcher) Render(e *Error) string {
|
||||
buf := strings.Builder{}
|
||||
|
||||
comma := func() {
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
}
|
||||
|
||||
if m.matchType {
|
||||
comma()
|
||||
buf.WriteString(fmt.Sprintf("Type=%q", e.Type))
|
||||
}
|
||||
if m.matchField {
|
||||
comma()
|
||||
buf.WriteString(fmt.Sprintf("Field=%q", e.Field))
|
||||
}
|
||||
if m.matchValue {
|
||||
comma()
|
||||
buf.WriteString(fmt.Sprintf("Value=%v", e.BadValue))
|
||||
}
|
||||
if m.matchOrigin || m.requireOriginWhenInvalid && e.Type == ErrorTypeInvalid {
|
||||
comma()
|
||||
buf.WriteString(fmt.Sprintf("Origin=%q", e.Origin))
|
||||
}
|
||||
if m.matchDetail != nil {
|
||||
comma()
|
||||
buf.WriteString(fmt.Sprintf("Detail=%q", e.Detail))
|
||||
}
|
||||
return "{" + buf.String() + "}"
|
||||
}
|
||||
|
||||
// Exactly returns a derived ErrorMatcher which matches all fields exactly.
|
||||
func (m ErrorMatcher) Exactly() ErrorMatcher {
|
||||
return m.ByType().ByField().ByValue().ByOrigin().ByDetailExact()
|
||||
}
|
||||
|
||||
// ByType returns a derived ErrorMatcher which also matches by type.
|
||||
func (m ErrorMatcher) ByType() ErrorMatcher {
|
||||
m.matchType = true
|
||||
return m
|
||||
}
|
||||
|
||||
// ByField returns a derived ErrorMatcher which also matches by field path.
|
||||
func (m ErrorMatcher) ByField() ErrorMatcher {
|
||||
m.matchField = true
|
||||
return m
|
||||
}
|
||||
|
||||
// ByValue returns a derived ErrorMatcher which also matches by the errant
|
||||
// value.
|
||||
func (m ErrorMatcher) ByValue() ErrorMatcher {
|
||||
m.matchValue = true
|
||||
return m
|
||||
}
|
||||
|
||||
// ByOrigin returns a derived ErrorMatcher which also matches by the origin.
|
||||
func (m ErrorMatcher) ByOrigin() ErrorMatcher {
|
||||
m.matchOrigin = true
|
||||
return m
|
||||
}
|
||||
|
||||
// RequireOriginWhenInvalid returns a derived ErrorMatcher which also requires
|
||||
// the Origin field to be set when the Type is Invalid and the matcher is
|
||||
// matching by Origin.
|
||||
func (m ErrorMatcher) RequireOriginWhenInvalid() ErrorMatcher {
|
||||
m.requireOriginWhenInvalid = true
|
||||
return m
|
||||
}
|
||||
|
||||
// ByDetailExact returns a derived ErrorMatcher which also matches errors by
|
||||
// the exact detail string.
|
||||
func (m ErrorMatcher) ByDetailExact() ErrorMatcher {
|
||||
m.matchDetail = func(want, got string) bool {
|
||||
return got == want
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ByDetailSubstring returns a derived ErrorMatcher which also matches errors
|
||||
// by a substring of the detail string.
|
||||
func (m ErrorMatcher) ByDetailSubstring() ErrorMatcher {
|
||||
m.matchDetail = func(want, got string) bool {
|
||||
return strings.Contains(got, want)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ByDetailRegexp returns a derived ErrorMatcher which also matches errors by a
|
||||
// regular expression of the detail string, where the "want" string is assumed
|
||||
// to be a valid regular expression.
|
||||
func (m ErrorMatcher) ByDetailRegexp() ErrorMatcher {
|
||||
m.matchDetail = func(want, got string) bool {
|
||||
return regexp.MustCompile(want).MatchString(got)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// TestIntf lets users pass a testing.T while not coupling this package to Go's
|
||||
// testing package.
|
||||
type TestIntf interface {
|
||||
Helper()
|
||||
Errorf(format string, args ...any)
|
||||
Logf(format string, args ...any)
|
||||
}
|
||||
|
||||
// Test compares two ErrorLists by the criteria configured in this matcher, and
|
||||
// fails the test if they don't match. If a given "want" error matches multiple
|
||||
// "got" errors, they will all be consumed. This might be OK (e.g. if there are
|
||||
// multiple errors on the same field from the same origin) or it might be an
|
||||
// insufficiently specific matcher, so these will be logged.
|
||||
func (m ErrorMatcher) Test(tb TestIntf, want, got ErrorList) {
|
||||
tb.Helper()
|
||||
|
||||
remaining := got
|
||||
for _, w := range want {
|
||||
tmp := make(ErrorList, 0, len(remaining))
|
||||
n := 0
|
||||
for _, g := range remaining {
|
||||
if m.Matches(w, g) {
|
||||
n++
|
||||
} else {
|
||||
tmp = append(tmp, g)
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
tb.Errorf("expected an error matching:\n%s", m.Render(w))
|
||||
} else if n > 1 {
|
||||
// This is not necessarily and error, but it's worth logging in
|
||||
// case it's not what the test author intended.
|
||||
tb.Logf("multiple errors matched:\n%s", m.Render(w))
|
||||
}
|
||||
remaining = tmp
|
||||
}
|
||||
if len(remaining) > 0 {
|
||||
for _, e := range remaining {
|
||||
exactly := m.Exactly() // makes a copy
|
||||
tb.Errorf("unmatched error:\n%s", exactly.Render(e))
|
||||
}
|
||||
}
|
||||
}
|
132
api/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go
generated
vendored
132
api/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go
generated
vendored
@ -33,13 +33,35 @@ type Error struct {
|
||||
Field string
|
||||
BadValue interface{}
|
||||
Detail string
|
||||
|
||||
// Origin uniquely identifies where this error was generated from. It is used in testing to
|
||||
// compare expected errors against actual errors without relying on exact detail string matching.
|
||||
// This allows tests to verify the correct validation logic triggered the error
|
||||
// regardless of how the error message might be formatted or localized.
|
||||
//
|
||||
// The value should be either:
|
||||
// - A simple camelCase identifier (e.g., "maximum", "maxItems")
|
||||
// - A structured format using "format=<dash-style-identifier>" for validation errors related to specific formats
|
||||
// (e.g., "format=dns-label", "format=qualified-name")
|
||||
//
|
||||
// If the Origin corresponds to an existing declarative validation tag or JSON Schema keyword,
|
||||
// use that same name for consistency.
|
||||
//
|
||||
// Origin should be set in the most deeply nested validation function that
|
||||
// can still identify the unique source of the error.
|
||||
Origin string
|
||||
|
||||
// CoveredByDeclarative is true when this error is covered by declarative
|
||||
// validation. This field is to identify errors from imperative validation
|
||||
// that should also be caught by declarative validation.
|
||||
CoveredByDeclarative bool
|
||||
}
|
||||
|
||||
var _ error = &Error{}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (v *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", v.Field, v.ErrorBody())
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Field, e.ErrorBody())
|
||||
}
|
||||
|
||||
type OmitValueType struct{}
|
||||
@ -48,21 +70,21 @@ var omitValue = OmitValueType{}
|
||||
|
||||
// ErrorBody returns the error message without the field name. This is useful
|
||||
// for building nice-looking higher-level error reporting.
|
||||
func (v *Error) ErrorBody() string {
|
||||
func (e *Error) ErrorBody() string {
|
||||
var s string
|
||||
switch {
|
||||
case v.Type == ErrorTypeRequired:
|
||||
s = v.Type.String()
|
||||
case v.Type == ErrorTypeForbidden:
|
||||
s = v.Type.String()
|
||||
case v.Type == ErrorTypeTooLong:
|
||||
s = v.Type.String()
|
||||
case v.Type == ErrorTypeInternal:
|
||||
s = v.Type.String()
|
||||
case v.BadValue == omitValue:
|
||||
s = v.Type.String()
|
||||
case e.Type == ErrorTypeRequired:
|
||||
s = e.Type.String()
|
||||
case e.Type == ErrorTypeForbidden:
|
||||
s = e.Type.String()
|
||||
case e.Type == ErrorTypeTooLong:
|
||||
s = e.Type.String()
|
||||
case e.Type == ErrorTypeInternal:
|
||||
s = e.Type.String()
|
||||
case e.BadValue == omitValue:
|
||||
s = e.Type.String()
|
||||
default:
|
||||
value := v.BadValue
|
||||
value := e.BadValue
|
||||
valueType := reflect.TypeOf(value)
|
||||
if value == nil || valueType == nil {
|
||||
value = "null"
|
||||
@ -76,26 +98,38 @@ func (v *Error) ErrorBody() string {
|
||||
switch t := value.(type) {
|
||||
case int64, int32, float64, float32, bool:
|
||||
// use simple printer for simple types
|
||||
s = fmt.Sprintf("%s: %v", v.Type, value)
|
||||
s = fmt.Sprintf("%s: %v", e.Type, value)
|
||||
case string:
|
||||
s = fmt.Sprintf("%s: %q", v.Type, t)
|
||||
s = fmt.Sprintf("%s: %q", e.Type, t)
|
||||
case fmt.Stringer:
|
||||
// anything that defines String() is better than raw struct
|
||||
s = fmt.Sprintf("%s: %s", v.Type, t.String())
|
||||
s = fmt.Sprintf("%s: %s", e.Type, t.String())
|
||||
default:
|
||||
// fallback to raw struct
|
||||
// TODO: internal types have panic guards against json.Marshalling to prevent
|
||||
// accidental use of internal types in external serialized form. For now, use
|
||||
// %#v, although it would be better to show a more expressive output in the future
|
||||
s = fmt.Sprintf("%s: %#v", v.Type, value)
|
||||
s = fmt.Sprintf("%s: %#v", e.Type, value)
|
||||
}
|
||||
}
|
||||
if len(v.Detail) != 0 {
|
||||
s += fmt.Sprintf(": %s", v.Detail)
|
||||
if len(e.Detail) != 0 {
|
||||
s += fmt.Sprintf(": %s", e.Detail)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// WithOrigin adds origin information to the FieldError
|
||||
func (e *Error) WithOrigin(o string) *Error {
|
||||
e.Origin = o
|
||||
return e
|
||||
}
|
||||
|
||||
// MarkCoveredByDeclarative marks the error as covered by declarative validation.
|
||||
func (e *Error) MarkCoveredByDeclarative() *Error {
|
||||
e.CoveredByDeclarative = true
|
||||
return e
|
||||
}
|
||||
|
||||
// ErrorType is a machine readable value providing more detail about why
|
||||
// a field is invalid. These values are expected to match 1-1 with
|
||||
// CauseType in api/types.go.
|
||||
@ -169,32 +203,32 @@ func (t ErrorType) String() string {
|
||||
|
||||
// TypeInvalid returns a *Error indicating "type is invalid"
|
||||
func TypeInvalid(field *Path, value interface{}, detail string) *Error {
|
||||
return &Error{ErrorTypeTypeInvalid, field.String(), value, detail}
|
||||
return &Error{ErrorTypeTypeInvalid, field.String(), value, detail, "", false}
|
||||
}
|
||||
|
||||
// NotFound returns a *Error indicating "value not found". This is
|
||||
// used to report failure to find a requested value (e.g. looking up an ID).
|
||||
func NotFound(field *Path, value interface{}) *Error {
|
||||
return &Error{ErrorTypeNotFound, field.String(), value, ""}
|
||||
return &Error{ErrorTypeNotFound, field.String(), value, "", "", false}
|
||||
}
|
||||
|
||||
// Required returns a *Error indicating "value required". This is used
|
||||
// to report required values that are not provided (e.g. empty strings, null
|
||||
// values, or empty arrays).
|
||||
func Required(field *Path, detail string) *Error {
|
||||
return &Error{ErrorTypeRequired, field.String(), "", detail}
|
||||
return &Error{ErrorTypeRequired, field.String(), "", detail, "", false}
|
||||
}
|
||||
|
||||
// Duplicate returns a *Error indicating "duplicate value". This is
|
||||
// used to report collisions of values that must be unique (e.g. names or IDs).
|
||||
func Duplicate(field *Path, value interface{}) *Error {
|
||||
return &Error{ErrorTypeDuplicate, field.String(), value, ""}
|
||||
return &Error{ErrorTypeDuplicate, field.String(), value, "", "", false}
|
||||
}
|
||||
|
||||
// Invalid returns a *Error indicating "invalid value". This is used
|
||||
// to report malformed values (e.g. failed regex match, too long, out of bounds).
|
||||
func Invalid(field *Path, value interface{}, detail string) *Error {
|
||||
return &Error{ErrorTypeInvalid, field.String(), value, detail}
|
||||
return &Error{ErrorTypeInvalid, field.String(), value, detail, "", false}
|
||||
}
|
||||
|
||||
// NotSupported returns a *Error indicating "unsupported value".
|
||||
@ -209,7 +243,7 @@ func NotSupported[T ~string](field *Path, value interface{}, validValues []T) *E
|
||||
}
|
||||
detail = "supported values: " + strings.Join(quotedValues, ", ")
|
||||
}
|
||||
return &Error{ErrorTypeNotSupported, field.String(), value, detail}
|
||||
return &Error{ErrorTypeNotSupported, field.String(), value, detail, "", false}
|
||||
}
|
||||
|
||||
// Forbidden returns a *Error indicating "forbidden". This is used to
|
||||
@ -217,7 +251,7 @@ func NotSupported[T ~string](field *Path, value interface{}, validValues []T) *E
|
||||
// some conditions, but which are not permitted by current conditions (e.g.
|
||||
// security policy).
|
||||
func Forbidden(field *Path, detail string) *Error {
|
||||
return &Error{ErrorTypeForbidden, field.String(), "", detail}
|
||||
return &Error{ErrorTypeForbidden, field.String(), "", detail, "", false}
|
||||
}
|
||||
|
||||
// TooLong returns a *Error indicating "too long". This is used to report that
|
||||
@ -231,7 +265,7 @@ func TooLong(field *Path, value interface{}, maxLength int) *Error {
|
||||
} else {
|
||||
msg = "value is too long"
|
||||
}
|
||||
return &Error{ErrorTypeTooLong, field.String(), "<value omitted>", msg}
|
||||
return &Error{ErrorTypeTooLong, field.String(), "<value omitted>", msg, "", false}
|
||||
}
|
||||
|
||||
// TooLongMaxLength returns a *Error indicating "too long".
|
||||
@ -259,14 +293,14 @@ func TooMany(field *Path, actualQuantity, maxQuantity int) *Error {
|
||||
actual = omitValue
|
||||
}
|
||||
|
||||
return &Error{ErrorTypeTooMany, field.String(), actual, msg}
|
||||
return &Error{ErrorTypeTooMany, field.String(), actual, msg, "", false}
|
||||
}
|
||||
|
||||
// InternalError returns a *Error indicating "internal error". This is used
|
||||
// to signal that an error was found that was not directly related to user
|
||||
// input. The err argument must be non-nil.
|
||||
func InternalError(field *Path, err error) *Error {
|
||||
return &Error{ErrorTypeInternal, field.String(), nil, err.Error()}
|
||||
return &Error{ErrorTypeInternal, field.String(), nil, err.Error(), "", false}
|
||||
}
|
||||
|
||||
// ErrorList holds a set of Errors. It is plausible that we might one day have
|
||||
@ -285,6 +319,22 @@ func NewErrorTypeMatcher(t ErrorType) utilerrors.Matcher {
|
||||
}
|
||||
}
|
||||
|
||||
// WithOrigin sets the origin for all errors in the list and returns the updated list.
|
||||
func (list ErrorList) WithOrigin(origin string) ErrorList {
|
||||
for _, err := range list {
|
||||
err.Origin = origin
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// MarkCoveredByDeclarative marks all errors in the list as covered by declarative validation.
|
||||
func (list ErrorList) MarkCoveredByDeclarative() ErrorList {
|
||||
for _, err := range list {
|
||||
err.CoveredByDeclarative = true
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// ToAggregate converts the ErrorList into an errors.Aggregate.
|
||||
func (list ErrorList) ToAggregate() utilerrors.Aggregate {
|
||||
if len(list) == 0 {
|
||||
@ -321,3 +371,25 @@ func (list ErrorList) Filter(fns ...utilerrors.Matcher) ErrorList {
|
||||
// FilterOut takes an Aggregate and returns an Aggregate
|
||||
return fromAggregate(err.(utilerrors.Aggregate))
|
||||
}
|
||||
|
||||
// ExtractCoveredByDeclarative returns a new ErrorList containing only the errors that should be covered by declarative validation.
|
||||
func (list ErrorList) ExtractCoveredByDeclarative() ErrorList {
|
||||
newList := ErrorList{}
|
||||
for _, err := range list {
|
||||
if err.CoveredByDeclarative {
|
||||
newList = append(newList, err)
|
||||
}
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
// RemoveCoveredByDeclarative returns a new ErrorList containing only the errors that should not be covered by declarative validation.
|
||||
func (list ErrorList) RemoveCoveredByDeclarative() ErrorList {
|
||||
newList := ErrorList{}
|
||||
for _, err := range list {
|
||||
if !err.CoveredByDeclarative {
|
||||
newList = append(newList, err)
|
||||
}
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
278
api/vendor/k8s.io/apimachinery/pkg/util/validation/ip.go
generated
vendored
Normal file
278
api/vendor/k8s.io/apimachinery/pkg/util/validation/ip.go
generated
vendored
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/klog/v2"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
func parseIP(fldPath *field.Path, value string, strictValidation bool) (net.IP, field.ErrorList) {
|
||||
var allErrors field.ErrorList
|
||||
|
||||
ip := netutils.ParseIPSloppy(value)
|
||||
if ip == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)"))
|
||||
return nil, allErrors
|
||||
}
|
||||
|
||||
if strictValidation {
|
||||
addr, err := netip.ParseAddr(value)
|
||||
if err != nil {
|
||||
// If netutils.ParseIPSloppy parsed it, but netip.ParseAddr
|
||||
// doesn't, then it must have illegal leading 0s.
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have leading 0s"))
|
||||
}
|
||||
if addr.Is4In6() {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must not be an IPv4-mapped IPv6 address"))
|
||||
}
|
||||
}
|
||||
|
||||
return ip, allErrors
|
||||
}
|
||||
|
||||
// IsValidIPForLegacyField tests that the argument is a valid IP address for a "legacy"
|
||||
// API field that predates strict IP validation. In particular, this allows IPs that are
|
||||
// not in canonical form (e.g., "FE80:0:0:0:0:0:0:0abc" instead of "fe80::abc").
|
||||
//
|
||||
// If strictValidation is false, this also allows IPs in certain invalid or ambiguous
|
||||
// formats:
|
||||
//
|
||||
// 1. IPv4 IPs are allowed to have leading "0"s in octets (e.g. "010.002.003.004").
|
||||
// Historically, net.ParseIP (and later netutils.ParseIPSloppy) simply ignored leading
|
||||
// "0"s in IPv4 addresses, but most libc-based software treats 0-prefixed IPv4 octets
|
||||
// as octal, meaning different software might interpret the same string as two
|
||||
// different IPs, potentially leading to security issues. (Current net.ParseIP and
|
||||
// netip.ParseAddr simply reject inputs with leading "0"s.)
|
||||
//
|
||||
// 2. IPv4-mapped IPv6 IPs (e.g. "::ffff:1.2.3.4") are allowed. These can also lead to
|
||||
// different software interpreting the value in different ways, because they may be
|
||||
// treated as IPv4 by some software and IPv6 by other software. (net.ParseIP and
|
||||
// netip.ParseAddr both allow these, but there are no use cases for representing IPv4
|
||||
// addresses as IPv4-mapped IPv6 addresses in Kubernetes.)
|
||||
//
|
||||
// Alternatively, when validating an update to an existing field, you can pass a list of
|
||||
// IP values from the old object that should be accepted if they appear in the new object
|
||||
// even if they are not valid.
|
||||
//
|
||||
// This function should only be used to validate the existing fields that were
|
||||
// historically validated in this way, and strictValidation should be true unless the
|
||||
// StrictIPCIDRValidation feature gate is disabled. Use IsValidIP for parsing new fields.
|
||||
func IsValidIPForLegacyField(fldPath *field.Path, value string, strictValidation bool, validOldIPs []string) field.ErrorList {
|
||||
if slices.Contains(validOldIPs, value) {
|
||||
return nil
|
||||
}
|
||||
_, allErrors := parseIP(fldPath, value, strictValidation)
|
||||
return allErrors.WithOrigin("format=ip-sloppy")
|
||||
}
|
||||
|
||||
// IsValidIP tests that the argument is a valid IP address, according to current
|
||||
// Kubernetes standards for IP address validation.
|
||||
func IsValidIP(fldPath *field.Path, value string) field.ErrorList {
|
||||
ip, allErrors := parseIP(fldPath, value, true)
|
||||
if len(allErrors) != 0 {
|
||||
return allErrors.WithOrigin("format=ip-strict")
|
||||
}
|
||||
|
||||
if value != ip.String() {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, fmt.Sprintf("must be in canonical form (%q)", ip.String())))
|
||||
}
|
||||
return allErrors.WithOrigin("format=ip-strict")
|
||||
}
|
||||
|
||||
// GetWarningsForIP returns warnings for IP address values in non-standard forms. This
|
||||
// should only be used with fields that are validated with IsValidIPForLegacyField().
|
||||
func GetWarningsForIP(fldPath *field.Path, value string) []string {
|
||||
ip := netutils.ParseIPSloppy(value)
|
||||
if ip == nil {
|
||||
klog.ErrorS(nil, "GetWarningsForIP called on value that was not validated with IsValidIPForLegacyField", "field", fldPath, "value", value)
|
||||
return nil
|
||||
}
|
||||
|
||||
addr, _ := netip.ParseAddr(value)
|
||||
if !addr.IsValid() || addr.Is4In6() {
|
||||
// This catches 2 cases: leading 0s (if ParseIPSloppy() accepted it but
|
||||
// ParseAddr() doesn't) or IPv4-mapped IPv6 (.Is4In6()). Either way,
|
||||
// re-stringifying the net.IP value will give the preferred form.
|
||||
return []string{
|
||||
fmt.Sprintf("%s: non-standard IP address %q will be considered invalid in a future Kubernetes release: use %q", fldPath, value, ip.String()),
|
||||
}
|
||||
}
|
||||
|
||||
// If ParseIPSloppy() and ParseAddr() both accept it then it's fully valid, though
|
||||
// it may be non-canonical.
|
||||
if addr.Is6() && addr.String() != value {
|
||||
return []string{
|
||||
fmt.Sprintf("%s: IPv6 address %q should be in RFC 5952 canonical format (%q)", fldPath, value, addr.String()),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseCIDR(fldPath *field.Path, value string, strictValidation bool) (*net.IPNet, field.ErrorList) {
|
||||
var allErrors field.ErrorList
|
||||
|
||||
_, ipnet, err := netutils.ParseCIDRSloppy(value)
|
||||
if err != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)"))
|
||||
return nil, allErrors
|
||||
}
|
||||
|
||||
if strictValidation {
|
||||
prefix, err := netip.ParsePrefix(value)
|
||||
if err != nil {
|
||||
// If netutils.ParseCIDRSloppy parsed it, but netip.ParsePrefix
|
||||
// doesn't, then it must have illegal leading 0s (either in the
|
||||
// IP part or the prefix).
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have leading 0s in IP or prefix length"))
|
||||
} else if prefix.Addr().Is4In6() {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have an IPv4-mapped IPv6 address"))
|
||||
} else if prefix.Addr() != prefix.Masked().Addr() {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have bits set beyond the prefix length"))
|
||||
}
|
||||
}
|
||||
|
||||
return ipnet, allErrors
|
||||
}
|
||||
|
||||
// IsValidCIDRForLegacyField tests that the argument is a valid CIDR value for a "legacy"
|
||||
// API field that predates strict IP validation. In particular, this allows IPs that are
|
||||
// not in canonical form (e.g., "FE80:0abc:0:0:0:0:0:0/64" instead of "fe80:abc::/64").
|
||||
//
|
||||
// If strictValidation is false, this also allows CIDR values in certain invalid or
|
||||
// ambiguous formats:
|
||||
//
|
||||
// 1. The IP part of the CIDR value is parsed as with IsValidIPForLegacyField with
|
||||
// strictValidation=false.
|
||||
//
|
||||
// 2. The CIDR value is allowed to be either a "subnet"/"mask" (with the lower bits after
|
||||
// the prefix length all being 0), or an "interface address" as with `ip addr` (with a
|
||||
// complete IP address and associated subnet length). With strict validation, the
|
||||
// value is required to be in "subnet"/"mask" form.
|
||||
//
|
||||
// 3. The prefix length is allowed to have leading 0s.
|
||||
//
|
||||
// Alternatively, when validating an update to an existing field, you can pass a list of
|
||||
// CIDR values from the old object that should be accepted if they appear in the new
|
||||
// object even if they are not valid.
|
||||
//
|
||||
// This function should only be used to validate the existing fields that were
|
||||
// historically validated in this way, and strictValidation should be true unless the
|
||||
// StrictIPCIDRValidation feature gate is disabled. Use IsValidCIDR or
|
||||
// IsValidInterfaceAddress for parsing new fields.
|
||||
func IsValidCIDRForLegacyField(fldPath *field.Path, value string, strictValidation bool, validOldCIDRs []string) field.ErrorList {
|
||||
if slices.Contains(validOldCIDRs, value) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, allErrors := parseCIDR(fldPath, value, strictValidation)
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidCIDR tests that the argument is a valid CIDR value, according to current
|
||||
// Kubernetes standards for CIDR validation. This function is only for
|
||||
// "subnet"/"mask"-style CIDR values (e.g., "192.168.1.0/24", with no bits set beyond the
|
||||
// prefix length). Use IsValidInterfaceAddress for "ifaddr"-style CIDR values.
|
||||
func IsValidCIDR(fldPath *field.Path, value string) field.ErrorList {
|
||||
ipnet, allErrors := parseCIDR(fldPath, value, true)
|
||||
if len(allErrors) != 0 {
|
||||
return allErrors
|
||||
}
|
||||
|
||||
if value != ipnet.String() {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, fmt.Sprintf("must be in canonical form (%q)", ipnet.String())))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// GetWarningsForCIDR returns warnings for CIDR values in non-standard forms. This should
|
||||
// only be used with fields that are validated with IsValidCIDRForLegacyField().
|
||||
func GetWarningsForCIDR(fldPath *field.Path, value string) []string {
|
||||
ip, ipnet, err := netutils.ParseCIDRSloppy(value)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "GetWarningsForCIDR called on value that was not validated with IsValidCIDRForLegacyField", "field", fldPath, "value", value)
|
||||
return nil
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
|
||||
// Check for bits set after prefix length
|
||||
if !ip.Equal(ipnet.IP) {
|
||||
_, addrlen := ipnet.Mask.Size()
|
||||
singleIPCIDR := fmt.Sprintf("%s/%d", ip.String(), addrlen)
|
||||
warnings = append(warnings,
|
||||
fmt.Sprintf("%s: CIDR value %q is ambiguous in this context (should be %q or %q?)", fldPath, value, ipnet.String(), singleIPCIDR),
|
||||
)
|
||||
}
|
||||
|
||||
prefix, _ := netip.ParsePrefix(value)
|
||||
addr := prefix.Addr()
|
||||
if !prefix.IsValid() || addr.Is4In6() {
|
||||
// This catches 2 cases: leading 0s (if ParseCIDRSloppy() accepted it but
|
||||
// ParsePrefix() doesn't) or IPv4-mapped IPv6 (.Is4In6()). Either way,
|
||||
// re-stringifying the net.IPNet value will give the preferred form.
|
||||
warnings = append(warnings,
|
||||
fmt.Sprintf("%s: non-standard CIDR value %q will be considered invalid in a future Kubernetes release: use %q", fldPath, value, ipnet.String()),
|
||||
)
|
||||
}
|
||||
|
||||
// If ParseCIDRSloppy() and ParsePrefix() both accept it then it's fully valid,
|
||||
// though it may be non-canonical. But only check this if there are no other
|
||||
// warnings, since either of the other warnings would also cause a round-trip
|
||||
// failure.
|
||||
if len(warnings) == 0 && addr.Is6() && prefix.String() != value {
|
||||
warnings = append(warnings,
|
||||
fmt.Sprintf("%s: IPv6 CIDR value %q should be in RFC 5952 canonical format (%q)", fldPath, value, prefix.String()),
|
||||
)
|
||||
}
|
||||
|
||||
return warnings
|
||||
}
|
||||
|
||||
// IsValidInterfaceAddress tests that the argument is a valid "ifaddr"-style CIDR value in
|
||||
// canonical form (e.g., "192.168.1.5/24", with a complete IP address and associated
|
||||
// subnet length). Use IsValidCIDR for "subnet"/"mask"-style CIDR values (e.g.,
|
||||
// "192.168.1.0/24").
|
||||
func IsValidInterfaceAddress(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip, ipnet, err := netutils.ParseCIDRSloppy(value)
|
||||
if err != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid address in CIDR form, (e.g. 10.9.8.7/24 or 2001:db8::1/64)"))
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// The canonical form of `value` is not `ipnet.String()`, because `ipnet` doesn't
|
||||
// include the bits after the prefix. We need to construct the canonical form
|
||||
// ourselves from `ip` and `ipnet.Mask`.
|
||||
maskSize, _ := ipnet.Mask.Size()
|
||||
if netutils.IsIPv4(ip) && maskSize > net.IPv4len*8 {
|
||||
// "::ffff:192.168.0.1/120" -> "192.168.0.1/24"
|
||||
maskSize -= (net.IPv6len - net.IPv4len) * 8
|
||||
}
|
||||
canonical := fmt.Sprintf("%s/%d", ip.String(), maskSize)
|
||||
if value != canonical {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, fmt.Sprintf("must be in canonical form (%q)", canonical)))
|
||||
}
|
||||
return allErrors
|
||||
}
|
40
api/vendor/k8s.io/apimachinery/pkg/util/validation/validation.go
generated
vendored
40
api/vendor/k8s.io/apimachinery/pkg/util/validation/validation.go
generated
vendored
@ -24,7 +24,6 @@ import (
|
||||
"unicode"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
const qnameCharFmt string = "[A-Za-z0-9]"
|
||||
@ -369,45 +368,6 @@ func IsValidPortName(port string) []string {
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsValidIP tests that the argument is a valid IP address.
|
||||
func IsValidIP(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if netutils.ParseIPSloppy(value) == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidIPv4Address tests that the argument is a valid IPv4 address.
|
||||
func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := netutils.ParseIPSloppy(value)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv4 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidIPv6Address tests that the argument is a valid IPv6 address.
|
||||
func IsValidIPv6Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := netutils.ParseIPSloppy(value)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidCIDR tests that the argument is a valid CIDR value.
|
||||
func IsValidCIDR(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
_, _, err := netutils.ParseCIDRSloppy(value)
|
||||
if err != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
const percentFmt string = "[0-9]+%"
|
||||
const percentErrMsg string = "a valid percent string must be a numeric string followed by an ending '%'"
|
||||
|
||||
|
2
api/vendor/k8s.io/apimachinery/pkg/watch/doc.go
generated
vendored
2
api/vendor/k8s.io/apimachinery/pkg/watch/doc.go
generated
vendored
@ -16,4 +16,4 @@ limitations under the License.
|
||||
|
||||
// Package watch contains a generic watchable interface, and a fake for
|
||||
// testing code that uses the watch interface.
|
||||
package watch // import "k8s.io/apimachinery/pkg/watch"
|
||||
package watch
|
||||
|
15
api/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go
generated
vendored
15
api/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go
generated
vendored
@ -51,6 +51,7 @@ type Reporter interface {
|
||||
// StreamWatcher turns any stream for which you can write a Decoder interface
|
||||
// into a watch.Interface.
|
||||
type StreamWatcher struct {
|
||||
logger klog.Logger
|
||||
sync.Mutex
|
||||
source Decoder
|
||||
reporter Reporter
|
||||
@ -59,8 +60,16 @@ type StreamWatcher struct {
|
||||
}
|
||||
|
||||
// NewStreamWatcher creates a StreamWatcher from the given decoder.
|
||||
//
|
||||
// Contextual logging: NewStreamWatcherWithLogger should be used instead of NewStreamWatcher in code which supports contextual logging.
|
||||
func NewStreamWatcher(d Decoder, r Reporter) *StreamWatcher {
|
||||
return NewStreamWatcherWithLogger(klog.Background(), d, r)
|
||||
}
|
||||
|
||||
// NewStreamWatcherWithLogger creates a StreamWatcher from the given decoder and logger.
|
||||
func NewStreamWatcherWithLogger(logger klog.Logger, d Decoder, r Reporter) *StreamWatcher {
|
||||
sw := &StreamWatcher{
|
||||
logger: logger,
|
||||
source: d,
|
||||
reporter: r,
|
||||
// It's easy for a consumer to add buffering via an extra
|
||||
@ -98,7 +107,7 @@ func (sw *StreamWatcher) Stop() {
|
||||
|
||||
// receive reads result from the decoder in a loop and sends down the result channel.
|
||||
func (sw *StreamWatcher) receive() {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer utilruntime.HandleCrashWithLogger(sw.logger)
|
||||
defer close(sw.result)
|
||||
defer sw.Stop()
|
||||
for {
|
||||
@ -108,10 +117,10 @@ func (sw *StreamWatcher) receive() {
|
||||
case io.EOF:
|
||||
// watch closed normally
|
||||
case io.ErrUnexpectedEOF:
|
||||
klog.V(1).Infof("Unexpected EOF during watch stream event decoding: %v", err)
|
||||
sw.logger.V(1).Info("Unexpected EOF during watch stream event decoding", "err", err)
|
||||
default:
|
||||
if net.IsProbableEOF(err) || net.IsTimeout(err) {
|
||||
klog.V(5).Infof("Unable to decode an event from the watch stream: %v", err)
|
||||
sw.logger.V(5).Info("Unable to decode an event from the watch stream", "err", err)
|
||||
} else {
|
||||
select {
|
||||
case <-sw.done:
|
||||
|
37
api/vendor/k8s.io/apimachinery/pkg/watch/watch.go
generated
vendored
37
api/vendor/k8s.io/apimachinery/pkg/watch/watch.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
// Interface can be implemented by anything that knows how to watch and report changes.
|
||||
@ -103,21 +104,34 @@ func (w emptyWatch) ResultChan() <-chan Event {
|
||||
|
||||
// FakeWatcher lets you test anything that consumes a watch.Interface; threadsafe.
|
||||
type FakeWatcher struct {
|
||||
logger klog.Logger
|
||||
result chan Event
|
||||
stopped bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
var _ Interface = &FakeWatcher{}
|
||||
|
||||
// Contextual logging: NewFakeWithOptions and a logger in the FakeOptions should be used instead in code which supports contextual logging.
|
||||
func NewFake() *FakeWatcher {
|
||||
return NewFakeWithOptions(FakeOptions{})
|
||||
}
|
||||
|
||||
// Contextual logging: NewFakeWithOptions and a logger in the FakeOptions should be used instead in code which supports contextual logging.
|
||||
func NewFakeWithChanSize(size int, blocking bool) *FakeWatcher {
|
||||
return NewFakeWithOptions(FakeOptions{ChannelSize: size})
|
||||
}
|
||||
|
||||
func NewFakeWithOptions(options FakeOptions) *FakeWatcher {
|
||||
return &FakeWatcher{
|
||||
result: make(chan Event),
|
||||
logger: ptr.Deref(options.Logger, klog.Background()),
|
||||
result: make(chan Event, options.ChannelSize),
|
||||
}
|
||||
}
|
||||
|
||||
func NewFakeWithChanSize(size int, blocking bool) *FakeWatcher {
|
||||
return &FakeWatcher{
|
||||
result: make(chan Event, size),
|
||||
}
|
||||
type FakeOptions struct {
|
||||
Logger *klog.Logger
|
||||
ChannelSize int
|
||||
}
|
||||
|
||||
// Stop implements Interface.Stop().
|
||||
@ -125,7 +139,7 @@ func (f *FakeWatcher) Stop() {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
if !f.stopped {
|
||||
klog.V(4).Infof("Stopping fake watcher.")
|
||||
f.logger.V(4).Info("Stopping fake watcher")
|
||||
close(f.result)
|
||||
f.stopped = true
|
||||
}
|
||||
@ -176,13 +190,22 @@ func (f *FakeWatcher) Action(action EventType, obj runtime.Object) {
|
||||
|
||||
// RaceFreeFakeWatcher lets you test anything that consumes a watch.Interface; threadsafe.
|
||||
type RaceFreeFakeWatcher struct {
|
||||
logger klog.Logger
|
||||
result chan Event
|
||||
Stopped bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
var _ Interface = &RaceFreeFakeWatcher{}
|
||||
|
||||
// Contextual logging: RaceFreeFakeWatcherWithLogger should be used instead of NewRaceFreeFake in code which supports contextual logging.
|
||||
func NewRaceFreeFake() *RaceFreeFakeWatcher {
|
||||
return NewRaceFreeFakeWithLogger(klog.Background())
|
||||
}
|
||||
|
||||
func NewRaceFreeFakeWithLogger(logger klog.Logger) *RaceFreeFakeWatcher {
|
||||
return &RaceFreeFakeWatcher{
|
||||
logger: logger,
|
||||
result: make(chan Event, DefaultChanSize),
|
||||
}
|
||||
}
|
||||
@ -192,7 +215,7 @@ func (f *RaceFreeFakeWatcher) Stop() {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
if !f.Stopped {
|
||||
klog.V(4).Infof("Stopping fake watcher.")
|
||||
f.logger.V(4).Info("Stopping fake watcher")
|
||||
close(f.result)
|
||||
f.Stopped = true
|
||||
}
|
||||
|
Reference in New Issue
Block a user