mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-22 03:08:03 +08:00
vendor: update buildkit to 2943a0838
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
29
vendor/k8s.io/apimachinery/pkg/util/clock/clock.go
generated
vendored
29
vendor/k8s.io/apimachinery/pkg/util/clock/clock.go
generated
vendored
@@ -52,23 +52,26 @@ func (RealClock) Since(ts time.Time) time.Duration {
|
||||
return time.Since(ts)
|
||||
}
|
||||
|
||||
// Same as time.After(d).
|
||||
// After is the same as time.After(d).
|
||||
func (RealClock) After(d time.Duration) <-chan time.Time {
|
||||
return time.After(d)
|
||||
}
|
||||
|
||||
// NewTimer returns a new Timer.
|
||||
func (RealClock) NewTimer(d time.Duration) Timer {
|
||||
return &realTimer{
|
||||
timer: time.NewTimer(d),
|
||||
}
|
||||
}
|
||||
|
||||
// NewTicker returns a new Ticker.
|
||||
func (RealClock) NewTicker(d time.Duration) Ticker {
|
||||
return &realTicker{
|
||||
ticker: time.NewTicker(d),
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep pauses the RealClock for duration d.
|
||||
func (RealClock) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
@@ -94,12 +97,14 @@ type fakeClockWaiter struct {
|
||||
destChan chan time.Time
|
||||
}
|
||||
|
||||
// NewFakePassiveClock returns a new FakePassiveClock.
|
||||
func NewFakePassiveClock(t time.Time) *FakePassiveClock {
|
||||
return &FakePassiveClock{
|
||||
time: t,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFakeClock returns a new FakeClock
|
||||
func NewFakeClock(t time.Time) *FakeClock {
|
||||
return &FakeClock{
|
||||
FakePassiveClock: *NewFakePassiveClock(t),
|
||||
@@ -120,14 +125,14 @@ func (f *FakePassiveClock) Since(ts time.Time) time.Duration {
|
||||
return f.time.Sub(ts)
|
||||
}
|
||||
|
||||
// Sets the time.
|
||||
// SetTime sets the time on the FakePassiveClock.
|
||||
func (f *FakePassiveClock) SetTime(t time.Time) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
f.time = t
|
||||
}
|
||||
|
||||
// Fake version of time.After(d).
|
||||
// After is the Fake version of time.After(d).
|
||||
func (f *FakeClock) After(d time.Duration) <-chan time.Time {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
@@ -140,7 +145,7 @@ func (f *FakeClock) After(d time.Duration) <-chan time.Time {
|
||||
return ch
|
||||
}
|
||||
|
||||
// Fake version of time.NewTimer(d).
|
||||
// NewTimer is the Fake version of time.NewTimer(d).
|
||||
func (f *FakeClock) NewTimer(d time.Duration) Timer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
@@ -157,6 +162,7 @@ func (f *FakeClock) NewTimer(d time.Duration) Timer {
|
||||
return timer
|
||||
}
|
||||
|
||||
// NewTicker returns a new Ticker.
|
||||
func (f *FakeClock) NewTicker(d time.Duration) Ticker {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
@@ -174,14 +180,14 @@ func (f *FakeClock) NewTicker(d time.Duration) Ticker {
|
||||
}
|
||||
}
|
||||
|
||||
// Move clock by Duration, notify anyone that's called After, Tick, or NewTimer
|
||||
// Step moves clock by Duration, notifies anyone that's called After, Tick, or NewTimer
|
||||
func (f *FakeClock) Step(d time.Duration) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
f.setTimeLocked(f.time.Add(d))
|
||||
}
|
||||
|
||||
// Sets the time.
|
||||
// SetTime sets the time on a FakeClock.
|
||||
func (f *FakeClock) SetTime(t time.Time) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
@@ -219,7 +225,7 @@ func (f *FakeClock) setTimeLocked(t time.Time) {
|
||||
f.waiters = newWaiters
|
||||
}
|
||||
|
||||
// Returns true if After has been called on f but not yet satisfied (so you can
|
||||
// HasWaiters returns true if After has been called on f but not yet satisfied (so you can
|
||||
// write race-free tests).
|
||||
func (f *FakeClock) HasWaiters() bool {
|
||||
f.lock.RLock()
|
||||
@@ -227,6 +233,7 @@ func (f *FakeClock) HasWaiters() bool {
|
||||
return len(f.waiters) > 0
|
||||
}
|
||||
|
||||
// Sleep pauses the FakeClock for duration d.
|
||||
func (f *FakeClock) Sleep(d time.Duration) {
|
||||
f.Step(d)
|
||||
}
|
||||
@@ -248,24 +255,25 @@ func (i *IntervalClock) Since(ts time.Time) time.Duration {
|
||||
return i.Time.Sub(ts)
|
||||
}
|
||||
|
||||
// Unimplemented, will panic.
|
||||
// After is currently unimplemented, will panic.
|
||||
// TODO: make interval clock use FakeClock so this can be implemented.
|
||||
func (*IntervalClock) After(d time.Duration) <-chan time.Time {
|
||||
panic("IntervalClock doesn't implement After")
|
||||
}
|
||||
|
||||
// Unimplemented, will panic.
|
||||
// NewTimer is currently unimplemented, will panic.
|
||||
// TODO: make interval clock use FakeClock so this can be implemented.
|
||||
func (*IntervalClock) NewTimer(d time.Duration) Timer {
|
||||
panic("IntervalClock doesn't implement NewTimer")
|
||||
}
|
||||
|
||||
// Unimplemented, will panic.
|
||||
// NewTicker is currently unimplemented, will panic.
|
||||
// TODO: make interval clock use FakeClock so this can be implemented.
|
||||
func (*IntervalClock) NewTicker(d time.Duration) Ticker {
|
||||
panic("IntervalClock doesn't implement NewTicker")
|
||||
}
|
||||
|
||||
// Sleep is currently unimplemented; will panic.
|
||||
func (*IntervalClock) Sleep(d time.Duration) {
|
||||
panic("IntervalClock doesn't implement Sleep")
|
||||
}
|
||||
@@ -355,6 +363,7 @@ func (f *fakeTimer) Reset(d time.Duration) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Ticker defines the Ticker interface
|
||||
type Ticker interface {
|
||||
C() <-chan time.Time
|
||||
Stop()
|
||||
|
32
vendor/k8s.io/apimachinery/pkg/util/errors/errors.go
generated
vendored
32
vendor/k8s.io/apimachinery/pkg/util/errors/errors.go
generated
vendored
@@ -28,9 +28,14 @@ type MessageCountMap map[string]int
|
||||
|
||||
// Aggregate represents an object that contains multiple errors, but does not
|
||||
// necessarily have singular semantic meaning.
|
||||
// The aggregate can be used with `errors.Is()` to check for the occurrence of
|
||||
// a specific error type.
|
||||
// Errors.As() is not supported, because the caller presumably cares about a
|
||||
// specific error of potentially multiple that match the given type.
|
||||
type Aggregate interface {
|
||||
error
|
||||
Errors() []error
|
||||
Is(error) bool
|
||||
}
|
||||
|
||||
// NewAggregate converts a slice of errors into an Aggregate interface, which
|
||||
@@ -71,16 +76,17 @@ func (agg aggregate) Error() string {
|
||||
}
|
||||
seenerrs := sets.NewString()
|
||||
result := ""
|
||||
agg.visit(func(err error) {
|
||||
agg.visit(func(err error) bool {
|
||||
msg := err.Error()
|
||||
if seenerrs.Has(msg) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
seenerrs.Insert(msg)
|
||||
if len(seenerrs) > 1 {
|
||||
result += ", "
|
||||
}
|
||||
result += msg
|
||||
return false
|
||||
})
|
||||
if len(seenerrs) == 1 {
|
||||
return result
|
||||
@@ -88,19 +94,33 @@ func (agg aggregate) Error() string {
|
||||
return "[" + result + "]"
|
||||
}
|
||||
|
||||
func (agg aggregate) visit(f func(err error)) {
|
||||
func (agg aggregate) Is(target error) bool {
|
||||
return agg.visit(func(err error) bool {
|
||||
return errors.Is(err, target)
|
||||
})
|
||||
}
|
||||
|
||||
func (agg aggregate) visit(f func(err error) bool) bool {
|
||||
for _, err := range agg {
|
||||
switch err := err.(type) {
|
||||
case aggregate:
|
||||
err.visit(f)
|
||||
if match := err.visit(f); match {
|
||||
return match
|
||||
}
|
||||
case Aggregate:
|
||||
for _, nestedErr := range err.Errors() {
|
||||
f(nestedErr)
|
||||
if match := f(nestedErr); match {
|
||||
return match
|
||||
}
|
||||
}
|
||||
default:
|
||||
f(err)
|
||||
if match := f(err); match {
|
||||
return match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Errors is part of the Aggregate interface.
|
||||
|
22
vendor/k8s.io/apimachinery/pkg/util/httpstream/httpstream.go
generated
vendored
22
vendor/k8s.io/apimachinery/pkg/util/httpstream/httpstream.go
generated
vendored
@@ -114,6 +114,18 @@ func negotiateProtocol(clientProtocols, serverProtocols []string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func commaSeparatedHeaderValues(header []string) []string {
|
||||
var parsedClientProtocols []string
|
||||
for i := range header {
|
||||
for _, clientProtocol := range strings.Split(header[i], ",") {
|
||||
if proto := strings.Trim(clientProtocol, " "); len(proto) > 0 {
|
||||
parsedClientProtocols = append(parsedClientProtocols, proto)
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsedClientProtocols
|
||||
}
|
||||
|
||||
// Handshake performs a subprotocol negotiation. If the client did request a
|
||||
// subprotocol, Handshake will select the first common value found in
|
||||
// serverProtocols. If a match is found, Handshake adds a response header
|
||||
@@ -121,17 +133,13 @@ func negotiateProtocol(clientProtocols, serverProtocols []string) string {
|
||||
// returned, along with a response header containing the list of protocols the
|
||||
// server can accept.
|
||||
func Handshake(req *http.Request, w http.ResponseWriter, serverProtocols []string) (string, error) {
|
||||
clientProtocols := req.Header[http.CanonicalHeaderKey(HeaderProtocolVersion)]
|
||||
clientProtocols := commaSeparatedHeaderValues(req.Header[http.CanonicalHeaderKey(HeaderProtocolVersion)])
|
||||
if len(clientProtocols) == 0 {
|
||||
// Kube 1.0 clients didn't support subprotocol negotiation.
|
||||
// TODO require clientProtocols once Kube 1.0 is no longer supported
|
||||
return "", nil
|
||||
return "", fmt.Errorf("unable to upgrade: %s is required", HeaderProtocolVersion)
|
||||
}
|
||||
|
||||
if len(serverProtocols) == 0 {
|
||||
// Kube 1.0 servers didn't support subprotocol negotiation. This is mainly for testing.
|
||||
// TODO require serverProtocols once Kube 1.0 is no longer supported
|
||||
return "", nil
|
||||
panic(fmt.Errorf("unable to upgrade: serverProtocols is required"))
|
||||
}
|
||||
|
||||
negotiatedProtocol := negotiateProtocol(clientProtocols, serverProtocols)
|
||||
|
2
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/connection.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/connection.go
generated
vendored
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
"github.com/docker/spdystream"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// connection maintains state about a spdystream.Connection and its associated
|
||||
|
21
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go
generated
vendored
21
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go
generated
vendored
@@ -76,19 +76,20 @@ var _ utilnet.TLSClientConfigHolder = &SpdyRoundTripper{}
|
||||
var _ httpstream.UpgradeRoundTripper = &SpdyRoundTripper{}
|
||||
var _ utilnet.Dialer = &SpdyRoundTripper{}
|
||||
|
||||
// NewRoundTripper creates a new SpdyRoundTripper that will use
|
||||
// the specified tlsConfig.
|
||||
func NewRoundTripper(tlsConfig *tls.Config, followRedirects, requireSameHostRedirects bool) httpstream.UpgradeRoundTripper {
|
||||
return NewSpdyRoundTripper(tlsConfig, followRedirects, requireSameHostRedirects)
|
||||
// NewRoundTripper creates a new SpdyRoundTripper that will use the specified
|
||||
// tlsConfig.
|
||||
func NewRoundTripper(tlsConfig *tls.Config, followRedirects, requireSameHostRedirects bool) *SpdyRoundTripper {
|
||||
return NewRoundTripperWithProxy(tlsConfig, followRedirects, requireSameHostRedirects, utilnet.NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment))
|
||||
}
|
||||
|
||||
// NewSpdyRoundTripper creates a new SpdyRoundTripper that will use
|
||||
// the specified tlsConfig. This function is mostly meant for unit tests.
|
||||
func NewSpdyRoundTripper(tlsConfig *tls.Config, followRedirects, requireSameHostRedirects bool) *SpdyRoundTripper {
|
||||
// NewRoundTripperWithProxy creates a new SpdyRoundTripper that will use the
|
||||
// specified tlsConfig and proxy func.
|
||||
func NewRoundTripperWithProxy(tlsConfig *tls.Config, followRedirects, requireSameHostRedirects bool, proxier func(*http.Request) (*url.URL, error)) *SpdyRoundTripper {
|
||||
return &SpdyRoundTripper{
|
||||
tlsConfig: tlsConfig,
|
||||
followRedirects: followRedirects,
|
||||
requireSameHostRedirects: requireSameHostRedirects,
|
||||
proxier: proxier,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,11 +117,7 @@ func (s *SpdyRoundTripper) Dial(req *http.Request) (net.Conn, error) {
|
||||
// dial dials the host specified by req, using TLS if appropriate, optionally
|
||||
// using a proxy server if one is configured via environment variables.
|
||||
func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||
proxier := s.proxier
|
||||
if proxier == nil {
|
||||
proxier = utilnet.NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment)
|
||||
}
|
||||
proxyURL, err := proxier(req)
|
||||
proxyURL, err := s.proxier(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
60
vendor/k8s.io/apimachinery/pkg/util/intstr/generated.pb.go
generated
vendored
60
vendor/k8s.io/apimachinery/pkg/util/intstr/generated.pb.go
generated
vendored
@@ -38,7 +38,7 @@ var _ = math.Inf
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
func (m *IntOrString) Reset() { *m = IntOrString{} }
|
||||
func (*IntOrString) ProtoMessage() {}
|
||||
@@ -289,6 +289,7 @@ func (m *IntOrString) Unmarshal(dAtA []byte) error {
|
||||
func skipGenerated(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
@@ -320,10 +321,8 @@ func skipGenerated(dAtA []byte) (n int, err error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
@@ -344,55 +343,30 @@ func skipGenerated(dAtA []byte) (n int, err error) {
|
||||
return 0, ErrInvalidLengthGenerated
|
||||
}
|
||||
iNdEx += length
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthGenerated
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipGenerated(dAtA[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthGenerated
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
depth++
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupGenerated
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthGenerated
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
|
||||
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
|
5
vendor/k8s.io/apimachinery/pkg/util/intstr/intstr.go
generated
vendored
5
vendor/k8s.io/apimachinery/pkg/util/intstr/intstr.go
generated
vendored
@@ -26,7 +26,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// IntOrString is a type that can hold an int32 or a string. When used in
|
||||
@@ -97,7 +97,8 @@ func (intstr *IntOrString) String() string {
|
||||
}
|
||||
|
||||
// IntValue returns the IntVal if type Int, or if
|
||||
// it is a String, will attempt a conversion to int.
|
||||
// it is a String, will attempt a conversion to int,
|
||||
// returning 0 if a parsing error occurs.
|
||||
func (intstr *IntOrString) IntValue() int {
|
||||
if intstr.Type == String {
|
||||
i, _ := strconv.Atoi(intstr.StrVal)
|
||||
|
25
vendor/k8s.io/apimachinery/pkg/util/json/json.go
generated
vendored
25
vendor/k8s.io/apimachinery/pkg/util/json/json.go
generated
vendored
@@ -66,11 +66,36 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
|
||||
return convertSliceNumbers(*v, 0)
|
||||
|
||||
case *interface{}:
|
||||
// Build a decoder from the given data
|
||||
decoder := json.NewDecoder(bytes.NewBuffer(data))
|
||||
// Preserve numbers, rather than casting to float64 automatically
|
||||
decoder.UseNumber()
|
||||
// Run the decode
|
||||
if err := decoder.Decode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
|
||||
return convertInterfaceNumbers(v, 0)
|
||||
|
||||
default:
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
}
|
||||
|
||||
func convertInterfaceNumbers(v *interface{}, depth int) error {
|
||||
var err error
|
||||
switch v2 := (*v).(type) {
|
||||
case json.Number:
|
||||
*v, err = convertNumber(v2)
|
||||
case map[string]interface{}:
|
||||
err = convertMapNumbers(v2, depth+1)
|
||||
case []interface{}:
|
||||
err = convertSliceNumbers(v2, depth+1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// convertMapNumbers traverses the map, converting any json.Number values to int64 or float64.
|
||||
// values which are map[string]interface{} or []interface{} are recursively visited
|
||||
func convertMapNumbers(m map[string]interface{}, depth int) error {
|
||||
|
2
vendor/k8s.io/apimachinery/pkg/util/naming/from_stack.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/naming/from_stack.go
generated
vendored
@@ -82,7 +82,7 @@ var stackCreator = regexp.MustCompile(`(?m)^created by (.*)\n\s+(.*):(\d+) \+0x[
|
||||
func extractStackCreator() (string, int, bool) {
|
||||
stack := debug.Stack()
|
||||
matches := stackCreator.FindStringSubmatch(string(stack))
|
||||
if matches == nil || len(matches) != 4 {
|
||||
if len(matches) != 4 {
|
||||
return "", 0, false
|
||||
}
|
||||
line, err := strconv.Atoi(matches[3])
|
||||
|
305
vendor/k8s.io/apimachinery/pkg/util/net/http.go
generated
vendored
305
vendor/k8s.io/apimachinery/pkg/util/net/http.go
generated
vendored
@@ -21,18 +21,23 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// JoinPreservingTrailingSlash does a path.Join of the specified elements,
|
||||
@@ -55,6 +60,15 @@ func JoinPreservingTrailingSlash(elem ...string) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// IsTimeout returns true if the given error is a network timeout error
|
||||
func IsTimeout(err error) bool {
|
||||
var neterr net.Error
|
||||
if errors.As(err, &neterr) {
|
||||
return neterr != nil && neterr.Timeout()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsProbableEOF returns true if the given error resembles a connection termination
|
||||
// scenario that would justify assuming that the watch is empty.
|
||||
// These errors are what the Go http stack returns back to us which are general
|
||||
@@ -65,13 +79,16 @@ func IsProbableEOF(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if uerr, ok := err.(*url.Error); ok {
|
||||
var uerr *url.Error
|
||||
if errors.As(err, &uerr) {
|
||||
err = uerr.Err
|
||||
}
|
||||
msg := err.Error()
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
return true
|
||||
case err == io.ErrUnexpectedEOF:
|
||||
return true
|
||||
case msg == "http: can't write HTTP request on broken connection":
|
||||
return true
|
||||
case strings.Contains(msg, "http2: server sent GOAWAY and closed the connection"):
|
||||
@@ -206,13 +223,17 @@ func GetHTTPClient(req *http.Request) string {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// SourceIPs splits the comma separated X-Forwarded-For header or returns the X-Real-Ip header or req.RemoteAddr,
|
||||
// in that order, ignoring invalid IPs. It returns nil if all of these are empty or invalid.
|
||||
// SourceIPs splits the comma separated X-Forwarded-For header and joins it with
|
||||
// the X-Real-Ip header and/or req.RemoteAddr, ignoring invalid IPs.
|
||||
// The X-Real-Ip is omitted if it's already present in the X-Forwarded-For chain.
|
||||
// The req.RemoteAddr is always the last IP in the returned list.
|
||||
// It returns nil if all of these are empty or invalid.
|
||||
func SourceIPs(req *http.Request) []net.IP {
|
||||
var srcIPs []net.IP
|
||||
|
||||
hdr := req.Header
|
||||
// First check the X-Forwarded-For header for requests via proxy.
|
||||
hdrForwardedFor := hdr.Get("X-Forwarded-For")
|
||||
forwardedForIPs := []net.IP{}
|
||||
if hdrForwardedFor != "" {
|
||||
// X-Forwarded-For can be a csv of IPs in case of multiple proxies.
|
||||
// Use the first valid one.
|
||||
@@ -220,38 +241,49 @@ func SourceIPs(req *http.Request) []net.IP {
|
||||
for _, part := range parts {
|
||||
ip := net.ParseIP(strings.TrimSpace(part))
|
||||
if ip != nil {
|
||||
forwardedForIPs = append(forwardedForIPs, ip)
|
||||
srcIPs = append(srcIPs, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(forwardedForIPs) > 0 {
|
||||
return forwardedForIPs
|
||||
}
|
||||
|
||||
// Try the X-Real-Ip header.
|
||||
hdrRealIp := hdr.Get("X-Real-Ip")
|
||||
if hdrRealIp != "" {
|
||||
ip := net.ParseIP(hdrRealIp)
|
||||
if ip != nil {
|
||||
return []net.IP{ip}
|
||||
// Only append the X-Real-Ip if it's not already contained in the X-Forwarded-For chain.
|
||||
if ip != nil && !containsIP(srcIPs, ip) {
|
||||
srcIPs = append(srcIPs, ip)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to Remote Address in request, which will give the correct client IP when there is no proxy.
|
||||
// Always include the request Remote Address as it cannot be easily spoofed.
|
||||
var remoteIP net.IP
|
||||
// Remote Address in Go's HTTP server is in the form host:port so we need to split that first.
|
||||
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err == nil {
|
||||
if remoteIP := net.ParseIP(host); remoteIP != nil {
|
||||
return []net.IP{remoteIP}
|
||||
remoteIP = net.ParseIP(host)
|
||||
}
|
||||
// Fallback if Remote Address was just IP.
|
||||
if remoteIP == nil {
|
||||
remoteIP = net.ParseIP(req.RemoteAddr)
|
||||
}
|
||||
|
||||
// Don't duplicate remote IP if it's already the last address in the chain.
|
||||
if remoteIP != nil && (len(srcIPs) == 0 || !remoteIP.Equal(srcIPs[len(srcIPs)-1])) {
|
||||
srcIPs = append(srcIPs, remoteIP)
|
||||
}
|
||||
|
||||
return srcIPs
|
||||
}
|
||||
|
||||
// Checks whether the given IP address is contained in the list of IPs.
|
||||
func containsIP(ips []net.IP, ip net.IP) bool {
|
||||
for _, v := range ips {
|
||||
if v.Equal(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback if Remote Address was just IP.
|
||||
if remoteIP := net.ParseIP(req.RemoteAddr); remoteIP != nil {
|
||||
return []net.IP{remoteIP}
|
||||
}
|
||||
|
||||
return nil
|
||||
return false
|
||||
}
|
||||
|
||||
// Extracts and returns the clients IP from the given request.
|
||||
@@ -425,7 +457,7 @@ redirectLoop:
|
||||
|
||||
// Only follow redirects to the same host. Otherwise, propagate the redirect response back.
|
||||
if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() {
|
||||
break redirectLoop
|
||||
return nil, nil, fmt.Errorf("hostname mismatch: expected %s, found %s", originalLocation.Hostname(), location.Hostname())
|
||||
}
|
||||
|
||||
// Reset the connection.
|
||||
@@ -461,3 +493,232 @@ func CloneHeader(in http.Header) http.Header {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// WarningHeader contains a single RFC2616 14.46 warnings header
|
||||
type WarningHeader struct {
|
||||
// Codeindicates the type of warning. 299 is a miscellaneous persistent warning
|
||||
Code int
|
||||
// Agent contains the name or pseudonym of the server adding the Warning header.
|
||||
// A single "-" is recommended when agent is unknown.
|
||||
Agent string
|
||||
// Warning text
|
||||
Text string
|
||||
}
|
||||
|
||||
// ParseWarningHeaders extract RFC2616 14.46 warnings headers from the specified set of header values.
|
||||
// Multiple comma-separated warnings per header are supported.
|
||||
// If errors are encountered on a header, the remainder of that header are skipped and subsequent headers are parsed.
|
||||
// Returns successfully parsed warnings and any errors encountered.
|
||||
func ParseWarningHeaders(headers []string) ([]WarningHeader, []error) {
|
||||
var (
|
||||
results []WarningHeader
|
||||
errs []error
|
||||
)
|
||||
for _, header := range headers {
|
||||
for len(header) > 0 {
|
||||
result, remainder, err := ParseWarningHeader(header)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
break
|
||||
}
|
||||
results = append(results, result)
|
||||
header = remainder
|
||||
}
|
||||
}
|
||||
return results, errs
|
||||
}
|
||||
|
||||
var (
|
||||
codeMatcher = regexp.MustCompile(`^[0-9]{3}$`)
|
||||
wordDecoder = &mime.WordDecoder{}
|
||||
)
|
||||
|
||||
// ParseWarningHeader extracts one RFC2616 14.46 warning from the specified header,
|
||||
// returning an error if the header does not contain a correctly formatted warning.
|
||||
// Any remaining content in the header is returned.
|
||||
func ParseWarningHeader(header string) (result WarningHeader, remainder string, err error) {
|
||||
// https://tools.ietf.org/html/rfc2616#section-14.46
|
||||
// updated by
|
||||
// https://tools.ietf.org/html/rfc7234#section-5.5
|
||||
// https://tools.ietf.org/html/rfc7234#appendix-A
|
||||
// Some requirements regarding production and processing of the Warning
|
||||
// header fields have been relaxed, as it is not widely implemented.
|
||||
// Furthermore, the Warning header field no longer uses RFC 2047
|
||||
// encoding, nor does it allow multiple languages, as these aspects were
|
||||
// not implemented.
|
||||
//
|
||||
// Format is one of:
|
||||
// warn-code warn-agent "warn-text"
|
||||
// warn-code warn-agent "warn-text" "warn-date"
|
||||
//
|
||||
// warn-code is a three digit number
|
||||
// warn-agent is unquoted and contains no spaces
|
||||
// warn-text is quoted with backslash escaping (RFC2047-encoded according to RFC2616, not encoded according to RFC7234)
|
||||
// warn-date is optional, quoted, and in HTTP-date format (no embedded or escaped quotes)
|
||||
//
|
||||
// additional warnings can optionally be included in the same header by comma-separating them:
|
||||
// warn-code warn-agent "warn-text" "warn-date"[, warn-code warn-agent "warn-text" "warn-date", ...]
|
||||
|
||||
// tolerate leading whitespace
|
||||
header = strings.TrimSpace(header)
|
||||
|
||||
parts := strings.SplitN(header, " ", 3)
|
||||
if len(parts) != 3 {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: fewer than 3 segments")
|
||||
}
|
||||
code, agent, textDateRemainder := parts[0], parts[1], parts[2]
|
||||
|
||||
// verify code format
|
||||
if !codeMatcher.Match([]byte(code)) {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: code segment is not 3 digits between 100-299")
|
||||
}
|
||||
codeInt, _ := strconv.ParseInt(code, 10, 64)
|
||||
|
||||
// verify agent presence
|
||||
if len(agent) == 0 {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: empty agent segment")
|
||||
}
|
||||
if !utf8.ValidString(agent) || hasAnyRunes(agent, unicode.IsControl) {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: invalid agent")
|
||||
}
|
||||
|
||||
// verify textDateRemainder presence
|
||||
if len(textDateRemainder) == 0 {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: empty text segment")
|
||||
}
|
||||
|
||||
// extract text
|
||||
text, dateAndRemainder, err := parseQuotedString(textDateRemainder)
|
||||
if err != nil {
|
||||
return WarningHeader{}, "", fmt.Errorf("invalid warning header: %v", err)
|
||||
}
|
||||
// tolerate RFC2047-encoded text from warnings produced according to RFC2616
|
||||
if decodedText, err := wordDecoder.DecodeHeader(text); err == nil {
|
||||
text = decodedText
|
||||
}
|
||||
if !utf8.ValidString(text) || hasAnyRunes(text, unicode.IsControl) {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: invalid text")
|
||||
}
|
||||
result = WarningHeader{Code: int(codeInt), Agent: agent, Text: text}
|
||||
|
||||
if len(dateAndRemainder) > 0 {
|
||||
if dateAndRemainder[0] == '"' {
|
||||
// consume date
|
||||
foundEndQuote := false
|
||||
for i := 1; i < len(dateAndRemainder); i++ {
|
||||
if dateAndRemainder[i] == '"' {
|
||||
foundEndQuote = true
|
||||
remainder = strings.TrimSpace(dateAndRemainder[i+1:])
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundEndQuote {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: unterminated date segment")
|
||||
}
|
||||
} else {
|
||||
remainder = dateAndRemainder
|
||||
}
|
||||
}
|
||||
if len(remainder) > 0 {
|
||||
if remainder[0] == ',' {
|
||||
// consume comma if present
|
||||
remainder = strings.TrimSpace(remainder[1:])
|
||||
} else {
|
||||
return WarningHeader{}, "", errors.New("invalid warning header: unexpected token after warn-date")
|
||||
}
|
||||
}
|
||||
|
||||
return result, remainder, nil
|
||||
}
|
||||
|
||||
func parseQuotedString(quotedString string) (string, string, error) {
|
||||
if len(quotedString) == 0 {
|
||||
return "", "", errors.New("invalid quoted string: 0-length")
|
||||
}
|
||||
|
||||
if quotedString[0] != '"' {
|
||||
return "", "", errors.New("invalid quoted string: missing initial quote")
|
||||
}
|
||||
|
||||
quotedString = quotedString[1:]
|
||||
var remainder string
|
||||
escaping := false
|
||||
closedQuote := false
|
||||
result := &bytes.Buffer{}
|
||||
loop:
|
||||
for i := 0; i < len(quotedString); i++ {
|
||||
b := quotedString[i]
|
||||
switch b {
|
||||
case '"':
|
||||
if escaping {
|
||||
result.WriteByte(b)
|
||||
escaping = false
|
||||
} else {
|
||||
closedQuote = true
|
||||
remainder = strings.TrimSpace(quotedString[i+1:])
|
||||
break loop
|
||||
}
|
||||
case '\\':
|
||||
if escaping {
|
||||
result.WriteByte(b)
|
||||
escaping = false
|
||||
} else {
|
||||
escaping = true
|
||||
}
|
||||
default:
|
||||
result.WriteByte(b)
|
||||
escaping = false
|
||||
}
|
||||
}
|
||||
|
||||
if !closedQuote {
|
||||
return "", "", errors.New("invalid quoted string: missing closing quote")
|
||||
}
|
||||
return result.String(), remainder, nil
|
||||
}
|
||||
|
||||
func NewWarningHeader(code int, agent, text string) (string, error) {
|
||||
if code < 0 || code > 999 {
|
||||
return "", errors.New("code must be between 0 and 999")
|
||||
}
|
||||
if len(agent) == 0 {
|
||||
agent = "-"
|
||||
} else if !utf8.ValidString(agent) || strings.ContainsAny(agent, `\"`) || hasAnyRunes(agent, unicode.IsSpace, unicode.IsControl) {
|
||||
return "", errors.New("agent must be valid UTF-8 and must not contain spaces, quotes, backslashes, or control characters")
|
||||
}
|
||||
if !utf8.ValidString(text) || hasAnyRunes(text, unicode.IsControl) {
|
||||
return "", errors.New("text must be valid UTF-8 and must not contain control characters")
|
||||
}
|
||||
return fmt.Sprintf("%03d %s %s", code, agent, makeQuotedString(text)), nil
|
||||
}
|
||||
|
||||
func hasAnyRunes(s string, runeCheckers ...func(rune) bool) bool {
|
||||
for _, r := range s {
|
||||
for _, checker := range runeCheckers {
|
||||
if checker(r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func makeQuotedString(s string) string {
|
||||
result := &bytes.Buffer{}
|
||||
// opening quote
|
||||
result.WriteRune('"')
|
||||
for _, c := range s {
|
||||
switch c {
|
||||
case '"', '\\':
|
||||
// escape " and \
|
||||
result.WriteRune('\\')
|
||||
result.WriteRune(c)
|
||||
default:
|
||||
// write everything else as-is
|
||||
result.WriteRune(c)
|
||||
}
|
||||
}
|
||||
// closing quote
|
||||
result.WriteRune('"')
|
||||
return result.String()
|
||||
}
|
||||
|
75
vendor/k8s.io/apimachinery/pkg/util/net/interface.go
generated
vendored
75
vendor/k8s.io/apimachinery/pkg/util/net/interface.go
generated
vendored
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
type AddressFamily uint
|
||||
@@ -36,6 +36,18 @@ const (
|
||||
familyIPv6 AddressFamily = 6
|
||||
)
|
||||
|
||||
type AddressFamilyPreference []AddressFamily
|
||||
|
||||
var (
|
||||
preferIPv4 = AddressFamilyPreference{familyIPv4, familyIPv6}
|
||||
preferIPv6 = AddressFamilyPreference{familyIPv6, familyIPv4}
|
||||
)
|
||||
|
||||
const (
|
||||
// LoopbackInterfaceName is the default name of the loopback interface
|
||||
LoopbackInterfaceName = "lo"
|
||||
)
|
||||
|
||||
const (
|
||||
ipv4RouteFile = "/proc/net/route"
|
||||
ipv6RouteFile = "/proc/net/ipv6_route"
|
||||
@@ -53,7 +65,7 @@ type RouteFile struct {
|
||||
parse func(input io.Reader) ([]Route, error)
|
||||
}
|
||||
|
||||
// noRoutesError can be returned by ChooseBindAddress() in case of no routes
|
||||
// noRoutesError can be returned in case of no routes
|
||||
type noRoutesError struct {
|
||||
message string
|
||||
}
|
||||
@@ -254,7 +266,7 @@ func getIPFromInterface(intfName string, forFamily AddressFamily, nw networkInte
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// memberOF tells if the IP is of the desired family. Used for checking interface addresses.
|
||||
// memberOf tells if the IP is of the desired family. Used for checking interface addresses.
|
||||
func memberOf(ip net.IP, family AddressFamily) bool {
|
||||
if ip.To4() != nil {
|
||||
return family == familyIPv4
|
||||
@@ -265,8 +277,8 @@ func memberOf(ip net.IP, family AddressFamily) bool {
|
||||
|
||||
// chooseIPFromHostInterfaces looks at all system interfaces, trying to find one that is up that
|
||||
// has a global unicast address (non-loopback, non-link local, non-point2point), and returns the IP.
|
||||
// Searches for IPv4 addresses, and then IPv6 addresses.
|
||||
func chooseIPFromHostInterfaces(nw networkInterfacer) (net.IP, error) {
|
||||
// addressFamilies determines whether it prefers IPv4 or IPv6
|
||||
func chooseIPFromHostInterfaces(nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) {
|
||||
intfs, err := nw.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -274,7 +286,7 @@ func chooseIPFromHostInterfaces(nw networkInterfacer) (net.IP, error) {
|
||||
if len(intfs) == 0 {
|
||||
return nil, fmt.Errorf("no interfaces found on host.")
|
||||
}
|
||||
for _, family := range []AddressFamily{familyIPv4, familyIPv6} {
|
||||
for _, family := range addressFamilies {
|
||||
klog.V(4).Infof("Looking for system interface with a global IPv%d address", uint(family))
|
||||
for _, intf := range intfs {
|
||||
if !isInterfaceUp(&intf) {
|
||||
@@ -321,15 +333,19 @@ func chooseIPFromHostInterfaces(nw networkInterfacer) (net.IP, error) {
|
||||
// IP of the interface with a gateway on it (with priority given to IPv4). For a node
|
||||
// with no internet connection, it returns error.
|
||||
func ChooseHostInterface() (net.IP, error) {
|
||||
return chooseHostInterface(preferIPv4)
|
||||
}
|
||||
|
||||
func chooseHostInterface(addressFamilies AddressFamilyPreference) (net.IP, error) {
|
||||
var nw networkInterfacer = networkInterface{}
|
||||
if _, err := os.Stat(ipv4RouteFile); os.IsNotExist(err) {
|
||||
return chooseIPFromHostInterfaces(nw)
|
||||
return chooseIPFromHostInterfaces(nw, addressFamilies)
|
||||
}
|
||||
routes, err := getAllDefaultRoutes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return chooseHostInterfaceFromRoute(routes, nw)
|
||||
return chooseHostInterfaceFromRoute(routes, nw, addressFamilies)
|
||||
}
|
||||
|
||||
// networkInterfacer defines an interface for several net library functions. Production
|
||||
@@ -377,10 +393,10 @@ func getAllDefaultRoutes() ([]Route, error) {
|
||||
}
|
||||
|
||||
// chooseHostInterfaceFromRoute cycles through each default route provided, looking for a
|
||||
// global IP address from the interface for the route. Will first look all each IPv4 route for
|
||||
// an IPv4 IP, and then will look at each IPv6 route for an IPv6 IP.
|
||||
func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer) (net.IP, error) {
|
||||
for _, family := range []AddressFamily{familyIPv4, familyIPv6} {
|
||||
// global IP address from the interface for the route. addressFamilies determines whether it
|
||||
// prefers IPv4 or IPv6
|
||||
func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) {
|
||||
for _, family := range addressFamilies {
|
||||
klog.V(4).Infof("Looking for default routes with IPv%d addresses", uint(family))
|
||||
for _, route := range routes {
|
||||
if route.Family != family {
|
||||
@@ -401,12 +417,19 @@ func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer) (net.IP,
|
||||
return nil, fmt.Errorf("unable to select an IP from default routes.")
|
||||
}
|
||||
|
||||
// If bind-address is usable, return it directly
|
||||
// If bind-address is not usable (unset, 0.0.0.0, or loopback), we will use the host's default
|
||||
// interface.
|
||||
func ChooseBindAddress(bindAddress net.IP) (net.IP, error) {
|
||||
// ResolveBindAddress returns the IP address of a daemon, based on the given bindAddress:
|
||||
// If bindAddress is unset, it returns the host's default IP, as with ChooseHostInterface().
|
||||
// If bindAddress is unspecified or loopback, it returns the default IP of the same
|
||||
// address family as bindAddress.
|
||||
// Otherwise, it just returns bindAddress.
|
||||
func ResolveBindAddress(bindAddress net.IP) (net.IP, error) {
|
||||
addressFamilies := preferIPv4
|
||||
if bindAddress != nil && memberOf(bindAddress, familyIPv6) {
|
||||
addressFamilies = preferIPv6
|
||||
}
|
||||
|
||||
if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() {
|
||||
hostIP, err := ChooseHostInterface()
|
||||
hostIP, err := chooseHostInterface(addressFamilies)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -414,3 +437,21 @@ func ChooseBindAddress(bindAddress net.IP) (net.IP, error) {
|
||||
}
|
||||
return bindAddress, nil
|
||||
}
|
||||
|
||||
// ChooseBindAddressForInterface choose a global IP for a specific interface, with priority given to IPv4.
|
||||
// This is required in case of network setups where default routes are present, but network
|
||||
// interfaces use only link-local addresses (e.g. as described in RFC5549).
|
||||
// e.g when using BGP to announce a host IP over link-local ip addresses and this ip address is attached to the lo interface.
|
||||
func ChooseBindAddressForInterface(intfName string) (net.IP, error) {
|
||||
var nw networkInterfacer = networkInterface{}
|
||||
for _, family := range preferIPv4 {
|
||||
ip, err := getIPFromInterface(intfName, family, nw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ip != nil {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to select an IP from %s network interface", intfName)
|
||||
}
|
||||
|
31
vendor/k8s.io/apimachinery/pkg/util/net/util.go
generated
vendored
31
vendor/k8s.io/apimachinery/pkg/util/net/util.go
generated
vendored
@@ -17,9 +17,8 @@ limitations under the License.
|
||||
package net
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"syscall"
|
||||
)
|
||||
@@ -40,34 +39,18 @@ func IPNetEqual(ipnet1, ipnet2 *net.IPNet) bool {
|
||||
|
||||
// Returns if the given err is "connection reset by peer" error.
|
||||
func IsConnectionReset(err error) bool {
|
||||
if urlErr, ok := err.(*url.Error); ok {
|
||||
err = urlErr.Err
|
||||
}
|
||||
if opErr, ok := err.(*net.OpError); ok {
|
||||
err = opErr.Err
|
||||
}
|
||||
if osErr, ok := err.(*os.SyscallError); ok {
|
||||
err = osErr.Err
|
||||
}
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.ECONNRESET {
|
||||
return true
|
||||
var errno syscall.Errno
|
||||
if errors.As(err, &errno) {
|
||||
return errno == syscall.ECONNRESET
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns if the given err is "connection refused" error
|
||||
func IsConnectionRefused(err error) bool {
|
||||
if urlErr, ok := err.(*url.Error); ok {
|
||||
err = urlErr.Err
|
||||
}
|
||||
if opErr, ok := err.(*net.OpError); ok {
|
||||
err = opErr.Err
|
||||
}
|
||||
if osErr, ok := err.(*os.SyscallError); ok {
|
||||
err = osErr.Err
|
||||
}
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED {
|
||||
return true
|
||||
var errno syscall.Errno
|
||||
if errors.As(err, &errno) {
|
||||
return errno == syscall.ECONNREFUSED
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
2
vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
generated
vendored
@@ -23,7 +23,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
|
2
vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go
generated
vendored
@@ -204,7 +204,7 @@ func Forbidden(field *Path, detail string) *Error {
|
||||
// Invalid, but the returned error will not include the too-long
|
||||
// value.
|
||||
func TooLong(field *Path, value interface{}, maxLength int) *Error {
|
||||
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d characters", maxLength)}
|
||||
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d bytes", maxLength)}
|
||||
}
|
||||
|
||||
// TooMany returns a *Error indicating "too many". This is used to
|
||||
|
89
vendor/k8s.io/apimachinery/pkg/util/validation/validation.go
generated
vendored
89
vendor/k8s.io/apimachinery/pkg/util/validation/validation.go
generated
vendored
@@ -70,7 +70,11 @@ func IsQualifiedName(value string) []string {
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsFullyQualifiedName checks if the name is fully qualified.
|
||||
// IsFullyQualifiedName checks if the name is fully qualified. This is similar
|
||||
// to IsFullyQualifiedDomainName but requires a minimum of 3 segments instead of
|
||||
// 2 and does not accept a trailing . as valid.
|
||||
// TODO: This function is deprecated and preserved until all callers migrate to
|
||||
// IsFullyQualifiedDomainName; please don't add new callers.
|
||||
func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
@@ -85,6 +89,69 @@ func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsFullyQualifiedDomainName checks if the domain name is fully qualified. This
|
||||
// is similar to IsFullyQualifiedName but only requires a minimum of 2 segments
|
||||
// instead of 3 and accepts a trailing . as valid.
|
||||
func IsFullyQualifiedDomainName(fldPath *field.Path, name string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
return append(allErrors, field.Required(fldPath, ""))
|
||||
}
|
||||
if strings.HasSuffix(name, ".") {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
if errs := IsDNS1123Subdomain(name); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ",")))
|
||||
}
|
||||
if len(strings.Split(name, ".")) < 2 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least two segments separated by dots"))
|
||||
}
|
||||
for _, label := range strings.Split(name, ".") {
|
||||
if errs := IsDNS1123Label(label); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, label, strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// Allowed characters in an HTTP Path as defined by RFC 3986. A HTTP path may
|
||||
// contain:
|
||||
// * unreserved characters (alphanumeric, '-', '.', '_', '~')
|
||||
// * percent-encoded octets
|
||||
// * sub-delims ("!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=")
|
||||
// * a colon character (":")
|
||||
const httpPathFmt string = `[A-Za-z0-9/\-._~%!$&'()*+,;=:]+`
|
||||
|
||||
var httpPathRegexp = regexp.MustCompile("^" + httpPathFmt + "$")
|
||||
|
||||
// IsDomainPrefixedPath checks if the given string is a domain-prefixed path
|
||||
// (e.g. acme.io/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
func IsDomainPrefixedPath(fldPath *field.Path, dpPath string) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if len(dpPath) == 0 {
|
||||
return append(allErrs, field.Required(fldPath, ""))
|
||||
}
|
||||
|
||||
segments := strings.SplitN(dpPath, "/", 2)
|
||||
if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
|
||||
return append(allErrs, field.Invalid(fldPath, dpPath, "must be a domain-prefixed path (such as \"acme.io/foo\")"))
|
||||
}
|
||||
|
||||
host := segments[0]
|
||||
for _, err := range IsDNS1123Subdomain(host) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, host, err))
|
||||
}
|
||||
|
||||
path := segments[1]
|
||||
if !httpPathRegexp.MatchString(path) {
|
||||
return append(allErrs, field.Invalid(fldPath, path, RegexError("Invalid path", httpPathFmt)))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
||||
const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
|
||||
@@ -285,6 +352,26 @@ func IsValidIP(value string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidIPv4Address tests that the argument is a valid IPv4 address.
|
||||
func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(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 := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
const percentFmt string = "[0-9]+%"
|
||||
const percentErrMsg string = "a valid percent string must be a numeric string followed by an ending '%'"
|
||||
|
||||
|
19
vendor/k8s.io/apimachinery/pkg/util/wait/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/apimachinery/pkg/util/wait/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2014 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 wait provides tools for polling or listening for changes
|
||||
// to a condition.
|
||||
package wait // import "k8s.io/apimachinery/pkg/util/wait"
|
606
vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
generated
vendored
Normal file
606
vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
generated
vendored
Normal file
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
Copyright 2014 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 wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
// For any test of the style:
|
||||
// ...
|
||||
// <- time.After(timeout):
|
||||
// t.Errorf("Timed out")
|
||||
// The value for timeout should effectively be "forever." Obviously we don't want our tests to truly lock up forever, but 30s
|
||||
// is long enough that it is effectively forever for the things that can slow down a run on a heavily contended machine
|
||||
// (GC, seeks, etc), but not so long as to make a developer ctrl-c a test run if they do happen to break that test.
|
||||
var ForeverTestTimeout = time.Second * 30
|
||||
|
||||
// NeverStop may be passed to Until to make it never stop.
|
||||
var NeverStop <-chan struct{} = make(chan struct{})
|
||||
|
||||
// Group allows to start a group of goroutines and wait for their completion.
|
||||
type Group struct {
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func (g *Group) Wait() {
|
||||
g.wg.Wait()
|
||||
}
|
||||
|
||||
// StartWithChannel starts f in a new goroutine in the group.
|
||||
// stopCh is passed to f as an argument. f should stop when stopCh is available.
|
||||
func (g *Group) StartWithChannel(stopCh <-chan struct{}, f func(stopCh <-chan struct{})) {
|
||||
g.Start(func() {
|
||||
f(stopCh)
|
||||
})
|
||||
}
|
||||
|
||||
// StartWithContext starts f in a new goroutine in the group.
|
||||
// ctx is passed to f as an argument. f should stop when ctx.Done() is available.
|
||||
func (g *Group) StartWithContext(ctx context.Context, f func(context.Context)) {
|
||||
g.Start(func() {
|
||||
f(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
// Start starts f in a new goroutine in the group.
|
||||
func (g *Group) Start(f func()) {
|
||||
g.wg.Add(1)
|
||||
go func() {
|
||||
defer g.wg.Done()
|
||||
f()
|
||||
}()
|
||||
}
|
||||
|
||||
// Forever calls f every period for ever.
|
||||
//
|
||||
// Forever is syntactic sugar on top of Until.
|
||||
func Forever(f func(), period time.Duration) {
|
||||
Until(f, period, NeverStop)
|
||||
}
|
||||
|
||||
// Until loops until stop channel is closed, running f every period.
|
||||
//
|
||||
// Until is syntactic sugar on top of JitterUntil with zero jitter factor and
|
||||
// with sliding = true (which means the timer for period starts after the f
|
||||
// completes).
|
||||
func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
|
||||
JitterUntil(f, period, 0.0, true, stopCh)
|
||||
}
|
||||
|
||||
// UntilWithContext loops until context is done, running f every period.
|
||||
//
|
||||
// UntilWithContext is syntactic sugar on top of JitterUntilWithContext
|
||||
// with zero jitter factor and with sliding = true (which means the timer
|
||||
// for period starts after the f completes).
|
||||
func UntilWithContext(ctx context.Context, f func(context.Context), period time.Duration) {
|
||||
JitterUntilWithContext(ctx, f, period, 0.0, true)
|
||||
}
|
||||
|
||||
// NonSlidingUntil loops until stop channel is closed, running f every
|
||||
// period.
|
||||
//
|
||||
// NonSlidingUntil is syntactic sugar on top of JitterUntil with zero jitter
|
||||
// factor, with sliding = false (meaning the timer for period starts at the same
|
||||
// time as the function starts).
|
||||
func NonSlidingUntil(f func(), period time.Duration, stopCh <-chan struct{}) {
|
||||
JitterUntil(f, period, 0.0, false, stopCh)
|
||||
}
|
||||
|
||||
// NonSlidingUntilWithContext loops until context is done, running f every
|
||||
// period.
|
||||
//
|
||||
// NonSlidingUntilWithContext is syntactic sugar on top of JitterUntilWithContext
|
||||
// with zero jitter factor, with sliding = false (meaning the timer for period
|
||||
// starts at the same time as the function starts).
|
||||
func NonSlidingUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration) {
|
||||
JitterUntilWithContext(ctx, f, period, 0.0, false)
|
||||
}
|
||||
|
||||
// JitterUntil loops until stop channel is closed, running f every period.
|
||||
//
|
||||
// If jitterFactor is positive, the period is jittered before every run of f.
|
||||
// If jitterFactor is not positive, the period is unchanged and not jittered.
|
||||
//
|
||||
// If sliding is true, the period is computed after f runs. If it is false then
|
||||
// period includes the runtime for f.
|
||||
//
|
||||
// Close stopCh to stop. f may not be invoked if stop channel is already
|
||||
// closed. Pass NeverStop to if you don't want it stop.
|
||||
func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding bool, stopCh <-chan struct{}) {
|
||||
BackoffUntil(f, NewJitteredBackoffManager(period, jitterFactor, &clock.RealClock{}), sliding, stopCh)
|
||||
}
|
||||
|
||||
// BackoffUntil loops until stop channel is closed, run f every duration given by BackoffManager.
|
||||
//
|
||||
// If sliding is true, the period is computed after f runs. If it is false then
|
||||
// period includes the runtime for f.
|
||||
func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan struct{}) {
|
||||
var t clock.Timer
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
if !sliding {
|
||||
t = backoff.Backoff()
|
||||
}
|
||||
|
||||
func() {
|
||||
defer runtime.HandleCrash()
|
||||
f()
|
||||
}()
|
||||
|
||||
if sliding {
|
||||
t = backoff.Backoff()
|
||||
}
|
||||
|
||||
// NOTE: b/c there is no priority selection in golang
|
||||
// it is possible for this to race, meaning we could
|
||||
// trigger t.C and stopCh, and t.C select falls through.
|
||||
// In order to mitigate we re-check stopCh at the beginning
|
||||
// of every loop to prevent extra executions of f().
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-t.C():
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JitterUntilWithContext loops until context is done, running f every period.
|
||||
//
|
||||
// If jitterFactor is positive, the period is jittered before every run of f.
|
||||
// If jitterFactor is not positive, the period is unchanged and not jittered.
|
||||
//
|
||||
// If sliding is true, the period is computed after f runs. If it is false then
|
||||
// period includes the runtime for f.
|
||||
//
|
||||
// Cancel context to stop. f may not be invoked if context is already expired.
|
||||
func JitterUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration, jitterFactor float64, sliding bool) {
|
||||
JitterUntil(func() { f(ctx) }, period, jitterFactor, sliding, ctx.Done())
|
||||
}
|
||||
|
||||
// Jitter returns a time.Duration between duration and duration + maxFactor *
|
||||
// duration.
|
||||
//
|
||||
// This allows clients to avoid converging on periodic behavior. If maxFactor
|
||||
// is 0.0, a suggested default value will be chosen.
|
||||
func Jitter(duration time.Duration, maxFactor float64) time.Duration {
|
||||
if maxFactor <= 0.0 {
|
||||
maxFactor = 1.0
|
||||
}
|
||||
wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
|
||||
return wait
|
||||
}
|
||||
|
||||
// ErrWaitTimeout is returned when the condition exited without success.
|
||||
var ErrWaitTimeout = errors.New("timed out waiting for the condition")
|
||||
|
||||
// ConditionFunc returns true if the condition is satisfied, or an error
|
||||
// if the loop should be aborted.
|
||||
type ConditionFunc func() (done bool, err error)
|
||||
|
||||
// runConditionWithCrashProtection runs a ConditionFunc with crash protection
|
||||
func runConditionWithCrashProtection(condition ConditionFunc) (bool, error) {
|
||||
defer runtime.HandleCrash()
|
||||
return condition()
|
||||
}
|
||||
|
||||
// Backoff holds parameters applied to a Backoff function.
|
||||
type Backoff struct {
|
||||
// The initial duration.
|
||||
Duration time.Duration
|
||||
// Duration is multiplied by factor each iteration, if factor is not zero
|
||||
// and the limits imposed by Steps and Cap have not been reached.
|
||||
// Should not be negative.
|
||||
// The jitter does not contribute to the updates to the duration parameter.
|
||||
Factor float64
|
||||
// The sleep at each iteration is the duration plus an additional
|
||||
// amount chosen uniformly at random from the interval between
|
||||
// zero and `jitter*duration`.
|
||||
Jitter float64
|
||||
// The remaining number of iterations in which the duration
|
||||
// parameter may change (but progress can be stopped earlier by
|
||||
// hitting the cap). If not positive, the duration is not
|
||||
// changed. Used for exponential backoff in combination with
|
||||
// Factor and Cap.
|
||||
Steps int
|
||||
// A limit on revised values of the duration parameter. If a
|
||||
// multiplication by the factor parameter would make the duration
|
||||
// exceed the cap then the duration is set to the cap and the
|
||||
// steps parameter is set to zero.
|
||||
Cap time.Duration
|
||||
}
|
||||
|
||||
// Step (1) returns an amount of time to sleep determined by the
|
||||
// original Duration and Jitter and (2) mutates the provided Backoff
|
||||
// to update its Steps and Duration.
|
||||
func (b *Backoff) Step() time.Duration {
|
||||
if b.Steps < 1 {
|
||||
if b.Jitter > 0 {
|
||||
return Jitter(b.Duration, b.Jitter)
|
||||
}
|
||||
return b.Duration
|
||||
}
|
||||
b.Steps--
|
||||
|
||||
duration := b.Duration
|
||||
|
||||
// calculate the next step
|
||||
if b.Factor != 0 {
|
||||
b.Duration = time.Duration(float64(b.Duration) * b.Factor)
|
||||
if b.Cap > 0 && b.Duration > b.Cap {
|
||||
b.Duration = b.Cap
|
||||
b.Steps = 0
|
||||
}
|
||||
}
|
||||
|
||||
if b.Jitter > 0 {
|
||||
duration = Jitter(duration, b.Jitter)
|
||||
}
|
||||
return duration
|
||||
}
|
||||
|
||||
// contextForChannel derives a child context from a parent channel.
|
||||
//
|
||||
// The derived context's Done channel is closed when the returned cancel function
|
||||
// is called or when the parent channel is closed, whichever happens first.
|
||||
//
|
||||
// Note the caller must *always* call the CancelFunc, otherwise resources may be leaked.
|
||||
func contextForChannel(parentCh <-chan struct{}) (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-parentCh:
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
return ctx, cancel
|
||||
}
|
||||
|
||||
// BackoffManager manages backoff with a particular scheme based on its underlying implementation. It provides
|
||||
// an interface to return a timer for backoff, and caller shall backoff until Timer.C() drains. If the second Backoff()
|
||||
// is called before the timer from the first Backoff() call finishes, the first timer will NOT be drained and result in
|
||||
// undetermined behavior.
|
||||
// The BackoffManager is supposed to be called in a single-threaded environment.
|
||||
type BackoffManager interface {
|
||||
Backoff() clock.Timer
|
||||
}
|
||||
|
||||
type exponentialBackoffManagerImpl struct {
|
||||
backoff *Backoff
|
||||
backoffTimer clock.Timer
|
||||
lastBackoffStart time.Time
|
||||
initialBackoff time.Duration
|
||||
backoffResetDuration time.Duration
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
// NewExponentialBackoffManager returns a manager for managing exponential backoff. Each backoff is jittered and
|
||||
// backoff will not exceed the given max. If the backoff is not called within resetDuration, the backoff is reset.
|
||||
// This backoff manager is used to reduce load during upstream unhealthiness.
|
||||
func NewExponentialBackoffManager(initBackoff, maxBackoff, resetDuration time.Duration, backoffFactor, jitter float64, c clock.Clock) BackoffManager {
|
||||
return &exponentialBackoffManagerImpl{
|
||||
backoff: &Backoff{
|
||||
Duration: initBackoff,
|
||||
Factor: backoffFactor,
|
||||
Jitter: jitter,
|
||||
|
||||
// the current impl of wait.Backoff returns Backoff.Duration once steps are used up, which is not
|
||||
// what we ideally need here, we set it to max int and assume we will never use up the steps
|
||||
Steps: math.MaxInt32,
|
||||
Cap: maxBackoff,
|
||||
},
|
||||
backoffTimer: nil,
|
||||
initialBackoff: initBackoff,
|
||||
lastBackoffStart: c.Now(),
|
||||
backoffResetDuration: resetDuration,
|
||||
clock: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *exponentialBackoffManagerImpl) getNextBackoff() time.Duration {
|
||||
if b.clock.Now().Sub(b.lastBackoffStart) > b.backoffResetDuration {
|
||||
b.backoff.Steps = math.MaxInt32
|
||||
b.backoff.Duration = b.initialBackoff
|
||||
}
|
||||
b.lastBackoffStart = b.clock.Now()
|
||||
return b.backoff.Step()
|
||||
}
|
||||
|
||||
// Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for exponential backoff.
|
||||
// The returned timer must be drained before calling Backoff() the second time
|
||||
func (b *exponentialBackoffManagerImpl) Backoff() clock.Timer {
|
||||
if b.backoffTimer == nil {
|
||||
b.backoffTimer = b.clock.NewTimer(b.getNextBackoff())
|
||||
} else {
|
||||
b.backoffTimer.Reset(b.getNextBackoff())
|
||||
}
|
||||
return b.backoffTimer
|
||||
}
|
||||
|
||||
type jitteredBackoffManagerImpl struct {
|
||||
clock clock.Clock
|
||||
duration time.Duration
|
||||
jitter float64
|
||||
backoffTimer clock.Timer
|
||||
}
|
||||
|
||||
// NewJitteredBackoffManager returns a BackoffManager that backoffs with given duration plus given jitter. If the jitter
|
||||
// is negative, backoff will not be jittered.
|
||||
func NewJitteredBackoffManager(duration time.Duration, jitter float64, c clock.Clock) BackoffManager {
|
||||
return &jitteredBackoffManagerImpl{
|
||||
clock: c,
|
||||
duration: duration,
|
||||
jitter: jitter,
|
||||
backoffTimer: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (j *jitteredBackoffManagerImpl) getNextBackoff() time.Duration {
|
||||
jitteredPeriod := j.duration
|
||||
if j.jitter > 0.0 {
|
||||
jitteredPeriod = Jitter(j.duration, j.jitter)
|
||||
}
|
||||
return jitteredPeriod
|
||||
}
|
||||
|
||||
// Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for jittered backoff.
|
||||
// The returned timer must be drained before calling Backoff() the second time
|
||||
func (j *jitteredBackoffManagerImpl) Backoff() clock.Timer {
|
||||
backoff := j.getNextBackoff()
|
||||
if j.backoffTimer == nil {
|
||||
j.backoffTimer = j.clock.NewTimer(backoff)
|
||||
} else {
|
||||
j.backoffTimer.Reset(backoff)
|
||||
}
|
||||
return j.backoffTimer
|
||||
}
|
||||
|
||||
// ExponentialBackoff repeats a condition check with exponential backoff.
|
||||
//
|
||||
// It repeatedly checks the condition and then sleeps, using `backoff.Step()`
|
||||
// to determine the length of the sleep and adjust Duration and Steps.
|
||||
// Stops and returns as soon as:
|
||||
// 1. the condition check returns true or an error,
|
||||
// 2. `backoff.Steps` checks of the condition have been done, or
|
||||
// 3. a sleep truncated by the cap on duration has been completed.
|
||||
// In case (1) the returned error is what the condition function returned.
|
||||
// In all other cases, ErrWaitTimeout is returned.
|
||||
func ExponentialBackoff(backoff Backoff, condition ConditionFunc) error {
|
||||
for backoff.Steps > 0 {
|
||||
if ok, err := runConditionWithCrashProtection(condition); err != nil || ok {
|
||||
return err
|
||||
}
|
||||
if backoff.Steps == 1 {
|
||||
break
|
||||
}
|
||||
time.Sleep(backoff.Step())
|
||||
}
|
||||
return ErrWaitTimeout
|
||||
}
|
||||
|
||||
// Poll tries a condition func until it returns true, an error, or the timeout
|
||||
// is reached.
|
||||
//
|
||||
// Poll always waits the interval before the run of 'condition'.
|
||||
// 'condition' will always be invoked at least once.
|
||||
//
|
||||
// Some intervals may be missed if the condition takes too long or the time
|
||||
// window is too short.
|
||||
//
|
||||
// If you want to Poll something forever, see PollInfinite.
|
||||
func Poll(interval, timeout time.Duration, condition ConditionFunc) error {
|
||||
return pollInternal(poller(interval, timeout), condition)
|
||||
}
|
||||
|
||||
func pollInternal(wait WaitFunc, condition ConditionFunc) error {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
return WaitFor(wait, condition, done)
|
||||
}
|
||||
|
||||
// PollImmediate tries a condition func until it returns true, an error, or the timeout
|
||||
// is reached.
|
||||
//
|
||||
// PollImmediate always checks 'condition' before waiting for the interval. 'condition'
|
||||
// will always be invoked at least once.
|
||||
//
|
||||
// Some intervals may be missed if the condition takes too long or the time
|
||||
// window is too short.
|
||||
//
|
||||
// If you want to immediately Poll something forever, see PollImmediateInfinite.
|
||||
func PollImmediate(interval, timeout time.Duration, condition ConditionFunc) error {
|
||||
return pollImmediateInternal(poller(interval, timeout), condition)
|
||||
}
|
||||
|
||||
func pollImmediateInternal(wait WaitFunc, condition ConditionFunc) error {
|
||||
done, err := runConditionWithCrashProtection(condition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
return pollInternal(wait, condition)
|
||||
}
|
||||
|
||||
// PollInfinite tries a condition func until it returns true or an error
|
||||
//
|
||||
// PollInfinite always waits the interval before the run of 'condition'.
|
||||
//
|
||||
// Some intervals may be missed if the condition takes too long or the time
|
||||
// window is too short.
|
||||
func PollInfinite(interval time.Duration, condition ConditionFunc) error {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
return PollUntil(interval, condition, done)
|
||||
}
|
||||
|
||||
// PollImmediateInfinite tries a condition func until it returns true or an error
|
||||
//
|
||||
// PollImmediateInfinite runs the 'condition' before waiting for the interval.
|
||||
//
|
||||
// Some intervals may be missed if the condition takes too long or the time
|
||||
// window is too short.
|
||||
func PollImmediateInfinite(interval time.Duration, condition ConditionFunc) error {
|
||||
done, err := runConditionWithCrashProtection(condition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
return PollInfinite(interval, condition)
|
||||
}
|
||||
|
||||
// PollUntil tries a condition func until it returns true, an error or stopCh is
|
||||
// closed.
|
||||
//
|
||||
// PollUntil always waits interval before the first run of 'condition'.
|
||||
// 'condition' will always be invoked at least once.
|
||||
func PollUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error {
|
||||
ctx, cancel := contextForChannel(stopCh)
|
||||
defer cancel()
|
||||
return WaitFor(poller(interval, 0), condition, ctx.Done())
|
||||
}
|
||||
|
||||
// PollImmediateUntil tries a condition func until it returns true, an error or stopCh is closed.
|
||||
//
|
||||
// PollImmediateUntil runs the 'condition' before waiting for the interval.
|
||||
// 'condition' will always be invoked at least once.
|
||||
func PollImmediateUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error {
|
||||
done, err := condition()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
select {
|
||||
case <-stopCh:
|
||||
return ErrWaitTimeout
|
||||
default:
|
||||
return PollUntil(interval, condition, stopCh)
|
||||
}
|
||||
}
|
||||
|
||||
// WaitFunc creates a channel that receives an item every time a test
|
||||
// should be executed and is closed when the last test should be invoked.
|
||||
type WaitFunc func(done <-chan struct{}) <-chan struct{}
|
||||
|
||||
// WaitFor continually checks 'fn' as driven by 'wait'.
|
||||
//
|
||||
// WaitFor gets a channel from 'wait()'', and then invokes 'fn' once for every value
|
||||
// placed on the channel and once more when the channel is closed. If the channel is closed
|
||||
// and 'fn' returns false without error, WaitFor returns ErrWaitTimeout.
|
||||
//
|
||||
// If 'fn' returns an error the loop ends and that error is returned. If
|
||||
// 'fn' returns true the loop ends and nil is returned.
|
||||
//
|
||||
// ErrWaitTimeout will be returned if the 'done' channel is closed without fn ever
|
||||
// returning true.
|
||||
//
|
||||
// When the done channel is closed, because the golang `select` statement is
|
||||
// "uniform pseudo-random", the `fn` might still run one or multiple time,
|
||||
// though eventually `WaitFor` will return.
|
||||
func WaitFor(wait WaitFunc, fn ConditionFunc, done <-chan struct{}) error {
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
c := wait(stopCh)
|
||||
for {
|
||||
select {
|
||||
case _, open := <-c:
|
||||
ok, err := runConditionWithCrashProtection(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
if !open {
|
||||
return ErrWaitTimeout
|
||||
}
|
||||
case <-done:
|
||||
return ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// poller returns a WaitFunc that will send to the channel every interval until
|
||||
// timeout has elapsed and then closes the channel.
|
||||
//
|
||||
// Over very short intervals you may receive no ticks before the channel is
|
||||
// closed. A timeout of 0 is interpreted as an infinity, and in such a case
|
||||
// it would be the caller's responsibility to close the done channel.
|
||||
// Failure to do so would result in a leaked goroutine.
|
||||
//
|
||||
// Output ticks are not buffered. If the channel is not ready to receive an
|
||||
// item, the tick is skipped.
|
||||
func poller(interval, timeout time.Duration) WaitFunc {
|
||||
return WaitFunc(func(done <-chan struct{}) <-chan struct{} {
|
||||
ch := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
||||
tick := time.NewTicker(interval)
|
||||
defer tick.Stop()
|
||||
|
||||
var after <-chan time.Time
|
||||
if timeout != 0 {
|
||||
// time.After is more convenient, but it
|
||||
// potentially leaves timers around much longer
|
||||
// than necessary if we exit early.
|
||||
timer := time.NewTimer(timeout)
|
||||
after = timer.C
|
||||
defer timer.Stop()
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
// If the consumer isn't ready for this signal drop it and
|
||||
// check the other channels.
|
||||
select {
|
||||
case ch <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
case <-after:
|
||||
return
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return ch
|
||||
})
|
||||
}
|
6
vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go
generated
vendored
6
vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go
generated
vendored
@@ -26,7 +26,7 @@ import (
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -92,6 +92,10 @@ type YAMLDecoder struct {
|
||||
// the caller in framing the chunk.
|
||||
func NewDocumentDecoder(r io.ReadCloser) io.ReadCloser {
|
||||
scanner := bufio.NewScanner(r)
|
||||
// the size of initial allocation for buffer 4k
|
||||
buf := make([]byte, 4*1024)
|
||||
// the maximum size used to buffer a token 5M
|
||||
scanner.Buffer(buf, 5*1024*1024)
|
||||
scanner.Split(splitYAMLDocument)
|
||||
return &YAMLDecoder{
|
||||
r: r,
|
||||
|
Reference in New Issue
Block a user