Upgrade k8s package verison (#5358)
* upgrade k8s package version Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> * Script upgrade and code formatting. Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
This commit is contained in:
8
vendor/k8s.io/apimachinery/pkg/util/cache/expiring.go
generated
vendored
8
vendor/k8s.io/apimachinery/pkg/util/cache/expiring.go
generated
vendored
@@ -21,17 +21,17 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
utilclock "k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
// NewExpiring returns an initialized expiring cache.
|
||||
func NewExpiring() *Expiring {
|
||||
return NewExpiringWithClock(utilclock.RealClock{})
|
||||
return NewExpiringWithClock(clock.RealClock{})
|
||||
}
|
||||
|
||||
// NewExpiringWithClock is like NewExpiring but allows passing in a custom
|
||||
// clock for testing.
|
||||
func NewExpiringWithClock(clock utilclock.Clock) *Expiring {
|
||||
func NewExpiringWithClock(clock clock.Clock) *Expiring {
|
||||
return &Expiring{
|
||||
clock: clock,
|
||||
cache: make(map[interface{}]entry),
|
||||
@@ -40,7 +40,7 @@ func NewExpiringWithClock(clock utilclock.Clock) *Expiring {
|
||||
|
||||
// Expiring is a map whose entries expire after a per-entry timeout.
|
||||
type Expiring struct {
|
||||
clock utilclock.Clock
|
||||
clock clock.Clock
|
||||
|
||||
// mu protects the below fields
|
||||
mu sync.RWMutex
|
||||
|
||||
94
vendor/k8s.io/apimachinery/pkg/util/cache/lruexpirecache.go
generated
vendored
94
vendor/k8s.io/apimachinery/pkg/util/cache/lruexpirecache.go
generated
vendored
@@ -17,10 +17,9 @@ limitations under the License.
|
||||
package cache
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
// Clock defines an interface for obtaining the current time
|
||||
@@ -39,8 +38,11 @@ type LRUExpireCache struct {
|
||||
// clock is used to obtain the current time
|
||||
clock Clock
|
||||
|
||||
cache *lru.Cache
|
||||
lock sync.Mutex
|
||||
lock sync.Mutex
|
||||
|
||||
maxSize int
|
||||
evictionList list.List
|
||||
entries map[interface{}]*list.Element
|
||||
}
|
||||
|
||||
// NewLRUExpireCache creates an expiring cache with the given size
|
||||
@@ -50,15 +52,19 @@ func NewLRUExpireCache(maxSize int) *LRUExpireCache {
|
||||
|
||||
// NewLRUExpireCacheWithClock creates an expiring cache with the given size, using the specified clock to obtain the current time.
|
||||
func NewLRUExpireCacheWithClock(maxSize int, clock Clock) *LRUExpireCache {
|
||||
cache, err := lru.New(maxSize)
|
||||
if err != nil {
|
||||
// if called with an invalid size
|
||||
panic(err)
|
||||
if maxSize <= 0 {
|
||||
panic("maxSize must be > 0")
|
||||
}
|
||||
|
||||
return &LRUExpireCache{
|
||||
clock: clock,
|
||||
maxSize: maxSize,
|
||||
entries: map[interface{}]*list.Element{},
|
||||
}
|
||||
return &LRUExpireCache{clock: clock, cache: cache}
|
||||
}
|
||||
|
||||
type cacheEntry struct {
|
||||
key interface{}
|
||||
value interface{}
|
||||
expireTime time.Time
|
||||
}
|
||||
@@ -67,7 +73,31 @@ type cacheEntry struct {
|
||||
func (c *LRUExpireCache) Add(key interface{}, value interface{}, ttl time.Duration) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.cache.Add(key, &cacheEntry{value, c.clock.Now().Add(ttl)})
|
||||
|
||||
// Key already exists
|
||||
oldElement, ok := c.entries[key]
|
||||
if ok {
|
||||
c.evictionList.MoveToFront(oldElement)
|
||||
oldElement.Value.(*cacheEntry).value = value
|
||||
oldElement.Value.(*cacheEntry).expireTime = c.clock.Now().Add(ttl)
|
||||
return
|
||||
}
|
||||
|
||||
// Make space if necessary
|
||||
if c.evictionList.Len() >= c.maxSize {
|
||||
toEvict := c.evictionList.Back()
|
||||
c.evictionList.Remove(toEvict)
|
||||
delete(c.entries, toEvict.Value.(*cacheEntry).key)
|
||||
}
|
||||
|
||||
// Add new entry
|
||||
entry := &cacheEntry{
|
||||
key: key,
|
||||
value: value,
|
||||
expireTime: c.clock.Now().Add(ttl),
|
||||
}
|
||||
element := c.evictionList.PushFront(entry)
|
||||
c.entries[key] = element
|
||||
}
|
||||
|
||||
// Get returns the value at the specified key from the cache if it exists and is not
|
||||
@@ -75,28 +105,56 @@ func (c *LRUExpireCache) Add(key interface{}, value interface{}, ttl time.Durati
|
||||
func (c *LRUExpireCache) Get(key interface{}) (interface{}, bool) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
e, ok := c.cache.Get(key)
|
||||
|
||||
element, ok := c.entries[key]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
if c.clock.Now().After(e.(*cacheEntry).expireTime) {
|
||||
c.cache.Remove(key)
|
||||
|
||||
if c.clock.Now().After(element.Value.(*cacheEntry).expireTime) {
|
||||
c.evictionList.Remove(element)
|
||||
delete(c.entries, key)
|
||||
return nil, false
|
||||
}
|
||||
return e.(*cacheEntry).value, true
|
||||
|
||||
c.evictionList.MoveToFront(element)
|
||||
|
||||
return element.Value.(*cacheEntry).value, true
|
||||
}
|
||||
|
||||
// Remove removes the specified key from the cache if it exists
|
||||
func (c *LRUExpireCache) Remove(key interface{}) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.cache.Remove(key)
|
||||
|
||||
element, ok := c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.evictionList.Remove(element)
|
||||
delete(c.entries, key)
|
||||
}
|
||||
|
||||
// Keys returns all the keys in the cache, even if they are expired. Subsequent calls to
|
||||
// get may return not found. It returns all keys from oldest to newest.
|
||||
// Keys returns all unexpired keys in the cache.
|
||||
//
|
||||
// Keep in mind that subsequent calls to Get() for any of the returned keys
|
||||
// might return "not found".
|
||||
//
|
||||
// Keys are returned ordered from least recently used to most recently used.
|
||||
func (c *LRUExpireCache) Keys() []interface{} {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
return c.cache.Keys()
|
||||
|
||||
now := c.clock.Now()
|
||||
|
||||
val := make([]interface{}, 0, c.evictionList.Len())
|
||||
for element := c.evictionList.Back(); element != nil; element = element.Prev() {
|
||||
// Only return unexpired keys
|
||||
if !now.After(element.Value.(*cacheEntry).expireTime) {
|
||||
val = append(val, element.Value.(*cacheEntry).key)
|
||||
}
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
445
vendor/k8s.io/apimachinery/pkg/util/clock/clock.go
generated
vendored
445
vendor/k8s.io/apimachinery/pkg/util/clock/clock.go
generated
vendored
@@ -1,445 +0,0 @@
|
||||
/*
|
||||
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 clock
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PassiveClock allows for injecting fake or real clocks into code
|
||||
// that needs to read the current time but does not support scheduling
|
||||
// activity in the future.
|
||||
type PassiveClock interface {
|
||||
Now() time.Time
|
||||
Since(time.Time) time.Duration
|
||||
}
|
||||
|
||||
// Clock allows for injecting fake or real clocks into code that
|
||||
// needs to do arbitrary things based on time.
|
||||
type Clock interface {
|
||||
PassiveClock
|
||||
After(time.Duration) <-chan time.Time
|
||||
AfterFunc(time.Duration, func()) Timer
|
||||
NewTimer(time.Duration) Timer
|
||||
Sleep(time.Duration)
|
||||
NewTicker(time.Duration) Ticker
|
||||
}
|
||||
|
||||
// RealClock really calls time.Now()
|
||||
type RealClock struct{}
|
||||
|
||||
// Now returns the current time.
|
||||
func (RealClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// Since returns time since the specified timestamp.
|
||||
func (RealClock) Since(ts time.Time) time.Duration {
|
||||
return time.Since(ts)
|
||||
}
|
||||
|
||||
// After is the same as time.After(d).
|
||||
func (RealClock) After(d time.Duration) <-chan time.Time {
|
||||
return time.After(d)
|
||||
}
|
||||
|
||||
// AfterFunc is the same as time.AfterFunc(d, f).
|
||||
func (RealClock) AfterFunc(d time.Duration, f func()) Timer {
|
||||
return &realTimer{
|
||||
timer: time.AfterFunc(d, f),
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// FakePassiveClock implements PassiveClock, but returns an arbitrary time.
|
||||
type FakePassiveClock struct {
|
||||
lock sync.RWMutex
|
||||
time time.Time
|
||||
}
|
||||
|
||||
// FakeClock implements Clock, but returns an arbitrary time.
|
||||
type FakeClock struct {
|
||||
FakePassiveClock
|
||||
|
||||
// waiters are waiting for the fake time to pass their specified time
|
||||
waiters []fakeClockWaiter
|
||||
}
|
||||
|
||||
type fakeClockWaiter struct {
|
||||
targetTime time.Time
|
||||
stepInterval time.Duration
|
||||
skipIfBlocked bool
|
||||
destChan chan time.Time
|
||||
afterFunc func()
|
||||
}
|
||||
|
||||
// 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),
|
||||
}
|
||||
}
|
||||
|
||||
// Now returns f's time.
|
||||
func (f *FakePassiveClock) Now() time.Time {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
return f.time
|
||||
}
|
||||
|
||||
// Since returns time since the time in f.
|
||||
func (f *FakePassiveClock) Since(ts time.Time) time.Duration {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
return f.time.Sub(ts)
|
||||
}
|
||||
|
||||
// SetTime sets the time on the FakePassiveClock.
|
||||
func (f *FakePassiveClock) SetTime(t time.Time) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
f.time = t
|
||||
}
|
||||
|
||||
// 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()
|
||||
stopTime := f.time.Add(d)
|
||||
ch := make(chan time.Time, 1) // Don't block!
|
||||
f.waiters = append(f.waiters, fakeClockWaiter{
|
||||
targetTime: stopTime,
|
||||
destChan: ch,
|
||||
})
|
||||
return ch
|
||||
}
|
||||
|
||||
// AfterFunc is the Fake version of time.AfterFunc(d, callback).
|
||||
func (f *FakeClock) AfterFunc(d time.Duration, cb func()) Timer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
stopTime := f.time.Add(d)
|
||||
ch := make(chan time.Time, 1) // Don't block!
|
||||
|
||||
timer := &fakeTimer{
|
||||
fakeClock: f,
|
||||
waiter: fakeClockWaiter{
|
||||
targetTime: stopTime,
|
||||
destChan: ch,
|
||||
afterFunc: cb,
|
||||
},
|
||||
}
|
||||
f.waiters = append(f.waiters, timer.waiter)
|
||||
return timer
|
||||
}
|
||||
|
||||
// NewTimer is the Fake version of time.NewTimer(d).
|
||||
func (f *FakeClock) NewTimer(d time.Duration) Timer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
stopTime := f.time.Add(d)
|
||||
ch := make(chan time.Time, 1) // Don't block!
|
||||
timer := &fakeTimer{
|
||||
fakeClock: f,
|
||||
waiter: fakeClockWaiter{
|
||||
targetTime: stopTime,
|
||||
destChan: ch,
|
||||
},
|
||||
}
|
||||
f.waiters = append(f.waiters, timer.waiter)
|
||||
return timer
|
||||
}
|
||||
|
||||
// NewTicker returns a new Ticker.
|
||||
func (f *FakeClock) NewTicker(d time.Duration) Ticker {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
tickTime := f.time.Add(d)
|
||||
ch := make(chan time.Time, 1) // hold one tick
|
||||
f.waiters = append(f.waiters, fakeClockWaiter{
|
||||
targetTime: tickTime,
|
||||
stepInterval: d,
|
||||
skipIfBlocked: true,
|
||||
destChan: ch,
|
||||
})
|
||||
|
||||
return &fakeTicker{
|
||||
c: ch,
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// SetTime sets the time on a FakeClock.
|
||||
func (f *FakeClock) SetTime(t time.Time) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
f.setTimeLocked(t)
|
||||
}
|
||||
|
||||
// Actually changes the time and checks any waiters. f must be write-locked.
|
||||
func (f *FakeClock) setTimeLocked(t time.Time) {
|
||||
f.time = t
|
||||
newWaiters := make([]fakeClockWaiter, 0, len(f.waiters))
|
||||
for i := range f.waiters {
|
||||
w := &f.waiters[i]
|
||||
if !w.targetTime.After(t) {
|
||||
|
||||
if w.skipIfBlocked {
|
||||
select {
|
||||
case w.destChan <- t:
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
w.destChan <- t
|
||||
}
|
||||
|
||||
if w.afterFunc != nil {
|
||||
w.afterFunc()
|
||||
}
|
||||
|
||||
if w.stepInterval > 0 {
|
||||
for !w.targetTime.After(t) {
|
||||
w.targetTime = w.targetTime.Add(w.stepInterval)
|
||||
}
|
||||
newWaiters = append(newWaiters, *w)
|
||||
}
|
||||
|
||||
} else {
|
||||
newWaiters = append(newWaiters, f.waiters[i])
|
||||
}
|
||||
}
|
||||
f.waiters = newWaiters
|
||||
}
|
||||
|
||||
// HasWaiters returns true if After or AfterFunc has been called on f but not yet satisfied
|
||||
// (so you can write race-free tests).
|
||||
func (f *FakeClock) HasWaiters() bool {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
return len(f.waiters) > 0
|
||||
}
|
||||
|
||||
// Sleep pauses the FakeClock for duration d.
|
||||
func (f *FakeClock) Sleep(d time.Duration) {
|
||||
f.Step(d)
|
||||
}
|
||||
|
||||
// IntervalClock implements Clock, but each invocation of Now steps the clock forward the specified duration
|
||||
type IntervalClock struct {
|
||||
Time time.Time
|
||||
Duration time.Duration
|
||||
}
|
||||
|
||||
// Now returns i's time.
|
||||
func (i *IntervalClock) Now() time.Time {
|
||||
i.Time = i.Time.Add(i.Duration)
|
||||
return i.Time
|
||||
}
|
||||
|
||||
// Since returns time since the time in i.
|
||||
func (i *IntervalClock) Since(ts time.Time) time.Duration {
|
||||
return i.Time.Sub(ts)
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
// AfterFunc is currently unimplemented, will panic.
|
||||
// TODO: make interval clock use FakeClock so this can be implemented.
|
||||
func (*IntervalClock) AfterFunc(d time.Duration, cb func()) Timer {
|
||||
panic("IntervalClock doesn't implement AfterFunc")
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
// Timer allows for injecting fake or real timers into code that
|
||||
// needs to do arbitrary things based on time.
|
||||
type Timer interface {
|
||||
C() <-chan time.Time
|
||||
Stop() bool
|
||||
Reset(d time.Duration) bool
|
||||
}
|
||||
|
||||
// realTimer is backed by an actual time.Timer.
|
||||
type realTimer struct {
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
// C returns the underlying timer's channel.
|
||||
func (r *realTimer) C() <-chan time.Time {
|
||||
return r.timer.C
|
||||
}
|
||||
|
||||
// Stop calls Stop() on the underlying timer.
|
||||
func (r *realTimer) Stop() bool {
|
||||
return r.timer.Stop()
|
||||
}
|
||||
|
||||
// Reset calls Reset() on the underlying timer.
|
||||
func (r *realTimer) Reset(d time.Duration) bool {
|
||||
return r.timer.Reset(d)
|
||||
}
|
||||
|
||||
// fakeTimer implements Timer based on a FakeClock.
|
||||
type fakeTimer struct {
|
||||
fakeClock *FakeClock
|
||||
waiter fakeClockWaiter
|
||||
}
|
||||
|
||||
// C returns the channel that notifies when this timer has fired.
|
||||
func (f *fakeTimer) C() <-chan time.Time {
|
||||
return f.waiter.destChan
|
||||
}
|
||||
|
||||
// Stop conditionally stops the timer. If the timer has neither fired
|
||||
// nor been stopped then this call stops the timer and returns true,
|
||||
// otherwise this call returns false. This is like time.Timer::Stop.
|
||||
func (f *fakeTimer) Stop() bool {
|
||||
f.fakeClock.lock.Lock()
|
||||
defer f.fakeClock.lock.Unlock()
|
||||
// The timer has already fired or been stopped, unless it is found
|
||||
// among the clock's waiters.
|
||||
stopped := false
|
||||
oldWaiters := f.fakeClock.waiters
|
||||
newWaiters := make([]fakeClockWaiter, 0, len(oldWaiters))
|
||||
seekChan := f.waiter.destChan
|
||||
for i := range oldWaiters {
|
||||
// Identify the timer's fakeClockWaiter by the identity of the
|
||||
// destination channel, nothing else is necessarily unique and
|
||||
// constant since the timer's creation.
|
||||
if oldWaiters[i].destChan == seekChan {
|
||||
stopped = true
|
||||
} else {
|
||||
newWaiters = append(newWaiters, oldWaiters[i])
|
||||
}
|
||||
}
|
||||
|
||||
f.fakeClock.waiters = newWaiters
|
||||
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Reset conditionally updates the firing time of the timer. If the
|
||||
// timer has neither fired nor been stopped then this call resets the
|
||||
// timer to the fake clock's "now" + d and returns true, otherwise
|
||||
// it creates a new waiter, adds it to the clock, and returns true.
|
||||
//
|
||||
// It is not possible to return false, because a fake timer can be reset
|
||||
// from any state (waiting to fire, already fired, and stopped).
|
||||
//
|
||||
// See the GoDoc for time.Timer::Reset for more context on why
|
||||
// the return value of Reset() is not useful.
|
||||
func (f *fakeTimer) Reset(d time.Duration) bool {
|
||||
f.fakeClock.lock.Lock()
|
||||
defer f.fakeClock.lock.Unlock()
|
||||
waiters := f.fakeClock.waiters
|
||||
seekChan := f.waiter.destChan
|
||||
for i := range waiters {
|
||||
if waiters[i].destChan == seekChan {
|
||||
waiters[i].targetTime = f.fakeClock.time.Add(d)
|
||||
return true
|
||||
}
|
||||
}
|
||||
// No existing waiter, timer has already fired or been reset.
|
||||
// We should still enable Reset() to succeed by creating a
|
||||
// new waiter and adding it to the clock's waiters.
|
||||
newWaiter := fakeClockWaiter{
|
||||
targetTime: f.fakeClock.time.Add(d),
|
||||
destChan: seekChan,
|
||||
}
|
||||
f.fakeClock.waiters = append(f.fakeClock.waiters, newWaiter)
|
||||
return true
|
||||
}
|
||||
|
||||
// Ticker defines the Ticker interface
|
||||
type Ticker interface {
|
||||
C() <-chan time.Time
|
||||
Stop()
|
||||
}
|
||||
|
||||
type realTicker struct {
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
func (t *realTicker) C() <-chan time.Time {
|
||||
return t.ticker.C
|
||||
}
|
||||
|
||||
func (t *realTicker) Stop() {
|
||||
t.ticker.Stop()
|
||||
}
|
||||
|
||||
type fakeTicker struct {
|
||||
c <-chan time.Time
|
||||
}
|
||||
|
||||
func (t *fakeTicker) C() <-chan time.Time {
|
||||
return t.c
|
||||
}
|
||||
|
||||
func (t *fakeTicker) Stop() {
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/util/diff/diff.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/diff/diff.go
generated
vendored
@@ -135,7 +135,7 @@ func IgnoreUnset() cmp.Option {
|
||||
if v2.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
case reflect.Interface, reflect.Pointer:
|
||||
if v2.IsNil() {
|
||||
return true
|
||||
}
|
||||
|
||||
8
vendor/k8s.io/apimachinery/pkg/util/duration/duration.go
generated
vendored
8
vendor/k8s.io/apimachinery/pkg/util/duration/duration.go
generated
vendored
@@ -27,9 +27,9 @@ func ShortHumanDuration(d time.Duration) string {
|
||||
// Allow deviation no more than 2 seconds(excluded) to tolerate machine time
|
||||
// inconsistence, it can be considered as almost now.
|
||||
if seconds := int(d.Seconds()); seconds < -1 {
|
||||
return fmt.Sprintf("<invalid>")
|
||||
return "<invalid>"
|
||||
} else if seconds < 0 {
|
||||
return fmt.Sprintf("0s")
|
||||
return "0s"
|
||||
} else if seconds < 60 {
|
||||
return fmt.Sprintf("%ds", seconds)
|
||||
} else if minutes := int(d.Minutes()); minutes < 60 {
|
||||
@@ -49,9 +49,9 @@ func HumanDuration(d time.Duration) string {
|
||||
// Allow deviation no more than 2 seconds(excluded) to tolerate machine time
|
||||
// inconsistence, it can be considered as almost now.
|
||||
if seconds := int(d.Seconds()); seconds < -1 {
|
||||
return fmt.Sprintf("<invalid>")
|
||||
return "<invalid>"
|
||||
} else if seconds < 0 {
|
||||
return fmt.Sprintf("0s")
|
||||
return "0s"
|
||||
} else if seconds < 60*2 {
|
||||
return fmt.Sprintf("%ds", seconds)
|
||||
}
|
||||
|
||||
14
vendor/k8s.io/apimachinery/pkg/util/framer/framer.go
generated
vendored
14
vendor/k8s.io/apimachinery/pkg/util/framer/framer.go
generated
vendored
@@ -56,10 +56,10 @@ type lengthDelimitedFrameReader struct {
|
||||
//
|
||||
// The protocol is:
|
||||
//
|
||||
// stream: message ...
|
||||
// message: prefix body
|
||||
// prefix: 4 byte uint32 in BigEndian order, denotes length of body
|
||||
// body: bytes (0..prefix)
|
||||
// stream: message ...
|
||||
// message: prefix body
|
||||
// prefix: 4 byte uint32 in BigEndian order, denotes length of body
|
||||
// body: bytes (0..prefix)
|
||||
//
|
||||
// If the buffer passed to Read is not long enough to contain an entire frame, io.ErrShortRead
|
||||
// will be returned along with the number of bytes read.
|
||||
@@ -132,14 +132,14 @@ func (r *jsonFrameReader) Read(data []byte) (int, error) {
|
||||
// Return whatever remaining data exists from an in progress frame
|
||||
if n := len(r.remaining); n > 0 {
|
||||
if n <= len(data) {
|
||||
//lint:ignore SA4006,SA4010 underlying array of data is modified here.
|
||||
//nolint:staticcheck // SA4006,SA4010 underlying array of data is modified here.
|
||||
data = append(data[0:0], r.remaining...)
|
||||
r.remaining = nil
|
||||
return n, nil
|
||||
}
|
||||
|
||||
n = len(data)
|
||||
//lint:ignore SA4006,SA4010 underlying array of data is modified here.
|
||||
//nolint:staticcheck // SA4006,SA4010 underlying array of data is modified here.
|
||||
data = append(data[0:0], r.remaining[:n]...)
|
||||
r.remaining = r.remaining[n:]
|
||||
return n, io.ErrShortBuffer
|
||||
@@ -157,7 +157,7 @@ func (r *jsonFrameReader) Read(data []byte) (int, error) {
|
||||
// and set m to it, which means we need to copy the partial result back into data and preserve
|
||||
// the remaining result for subsequent reads.
|
||||
if len(m) > n {
|
||||
//lint:ignore SA4006,SA4010 underlying array of data is modified here.
|
||||
//nolint:staticcheck // SA4006,SA4010 underlying array of data is modified here.
|
||||
data = append(data[0:0], m[:n]...)
|
||||
r.remaining = m[n:]
|
||||
return n, io.ErrShortBuffer
|
||||
|
||||
2
vendor/k8s.io/apimachinery/pkg/util/httpstream/httpstream.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/httpstream/httpstream.go
generated
vendored
@@ -78,6 +78,8 @@ type Connection interface {
|
||||
// SetIdleTimeout sets the amount of time the connection may remain idle before
|
||||
// it is automatically closed.
|
||||
SetIdleTimeout(timeout time.Duration)
|
||||
// RemoveStreams can be used to remove a set of streams from the Connection.
|
||||
RemoveStreams(streams ...Stream)
|
||||
}
|
||||
|
||||
// Stream represents a bidirectional communications channel that is part of an
|
||||
|
||||
25
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/connection.go
generated
vendored
25
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/connection.go
generated
vendored
@@ -31,7 +31,7 @@ import (
|
||||
// streams.
|
||||
type connection struct {
|
||||
conn *spdystream.Connection
|
||||
streams []httpstream.Stream
|
||||
streams map[uint32]httpstream.Stream
|
||||
streamLock sync.Mutex
|
||||
newStreamHandler httpstream.NewStreamHandler
|
||||
ping func() (time.Duration, error)
|
||||
@@ -85,7 +85,12 @@ func NewServerConnectionWithPings(conn net.Conn, newStreamHandler httpstream.New
|
||||
// will be invoked when the server receives a newly created stream from the
|
||||
// client.
|
||||
func newConnection(conn *spdystream.Connection, newStreamHandler httpstream.NewStreamHandler, pingPeriod time.Duration, pingFn func() (time.Duration, error)) httpstream.Connection {
|
||||
c := &connection{conn: conn, newStreamHandler: newStreamHandler, ping: pingFn}
|
||||
c := &connection{
|
||||
conn: conn,
|
||||
newStreamHandler: newStreamHandler,
|
||||
ping: pingFn,
|
||||
streams: make(map[uint32]httpstream.Stream),
|
||||
}
|
||||
go conn.Serve(c.newSpdyStream)
|
||||
if pingPeriod > 0 && pingFn != nil {
|
||||
go c.sendPings(pingPeriod)
|
||||
@@ -105,7 +110,7 @@ func (c *connection) Close() error {
|
||||
// calling Reset instead of Close ensures that all streams are fully torn down
|
||||
s.Reset()
|
||||
}
|
||||
c.streams = make([]httpstream.Stream, 0)
|
||||
c.streams = make(map[uint32]httpstream.Stream, 0)
|
||||
c.streamLock.Unlock()
|
||||
|
||||
// now that all streams are fully torn down, it's safe to call close on the underlying connection,
|
||||
@@ -114,6 +119,18 @@ func (c *connection) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
// RemoveStreams can be used to removes a set of streams from the Connection.
|
||||
func (c *connection) RemoveStreams(streams ...httpstream.Stream) {
|
||||
c.streamLock.Lock()
|
||||
for _, stream := range streams {
|
||||
// It may be possible that the provided stream is nil if timed out.
|
||||
if stream != nil {
|
||||
delete(c.streams, stream.Identifier())
|
||||
}
|
||||
}
|
||||
c.streamLock.Unlock()
|
||||
}
|
||||
|
||||
// CreateStream creates a new stream with the specified headers and registers
|
||||
// it with the connection.
|
||||
func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error) {
|
||||
@@ -133,7 +150,7 @@ func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error
|
||||
// it owns.
|
||||
func (c *connection) registerStream(s httpstream.Stream) {
|
||||
c.streamLock.Lock()
|
||||
c.streams = append(c.streams, s)
|
||||
c.streams[s.Identifier()] = s
|
||||
c.streamLock.Unlock()
|
||||
}
|
||||
|
||||
|
||||
197
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go
generated
vendored
197
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go
generated
vendored
@@ -18,12 +18,11 @@ package spdy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -32,6 +31,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -65,12 +65,6 @@ type SpdyRoundTripper struct {
|
||||
// Used primarily for mocking the proxy discovery in tests.
|
||||
proxier func(req *http.Request) (*url.URL, error)
|
||||
|
||||
// followRedirects indicates if the round tripper should examine responses for redirects and
|
||||
// follow them.
|
||||
followRedirects bool
|
||||
// requireSameHostRedirects restricts redirect following to only follow redirects to the same host
|
||||
// as the original request.
|
||||
requireSameHostRedirects bool
|
||||
// pingPeriod is a period for sending Ping frames over established
|
||||
// connections.
|
||||
pingPeriod time.Duration
|
||||
@@ -82,37 +76,31 @@ var _ utilnet.Dialer = &SpdyRoundTripper{}
|
||||
|
||||
// NewRoundTripper creates a new SpdyRoundTripper that will use the specified
|
||||
// tlsConfig.
|
||||
func NewRoundTripper(tlsConfig *tls.Config, followRedirects, requireSameHostRedirects bool) *SpdyRoundTripper {
|
||||
func NewRoundTripper(tlsConfig *tls.Config) *SpdyRoundTripper {
|
||||
return NewRoundTripperWithConfig(RoundTripperConfig{
|
||||
TLS: tlsConfig,
|
||||
FollowRedirects: followRedirects,
|
||||
RequireSameHostRedirects: requireSameHostRedirects,
|
||||
TLS: tlsConfig,
|
||||
})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
func NewRoundTripperWithProxy(tlsConfig *tls.Config, proxier func(*http.Request) (*url.URL, error)) *SpdyRoundTripper {
|
||||
return NewRoundTripperWithConfig(RoundTripperConfig{
|
||||
TLS: tlsConfig,
|
||||
FollowRedirects: followRedirects,
|
||||
RequireSameHostRedirects: requireSameHostRedirects,
|
||||
Proxier: proxier,
|
||||
TLS: tlsConfig,
|
||||
Proxier: proxier,
|
||||
})
|
||||
}
|
||||
|
||||
// NewRoundTripperWithProxy creates a new SpdyRoundTripper with the specified
|
||||
// NewRoundTripperWithConfig creates a new SpdyRoundTripper with the specified
|
||||
// configuration.
|
||||
func NewRoundTripperWithConfig(cfg RoundTripperConfig) *SpdyRoundTripper {
|
||||
if cfg.Proxier == nil {
|
||||
cfg.Proxier = utilnet.NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment)
|
||||
}
|
||||
return &SpdyRoundTripper{
|
||||
tlsConfig: cfg.TLS,
|
||||
followRedirects: cfg.FollowRedirects,
|
||||
requireSameHostRedirects: cfg.RequireSameHostRedirects,
|
||||
proxier: cfg.Proxier,
|
||||
pingPeriod: cfg.PingPeriod,
|
||||
tlsConfig: cfg.TLS,
|
||||
proxier: cfg.Proxier,
|
||||
pingPeriod: cfg.PingPeriod,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,9 +113,6 @@ type RoundTripperConfig struct {
|
||||
// PingPeriod is a period for sending SPDY Pings on the connection.
|
||||
// Optional.
|
||||
PingPeriod time.Duration
|
||||
|
||||
FollowRedirects bool
|
||||
RequireSameHostRedirects bool
|
||||
}
|
||||
|
||||
// TLSClientConfig implements pkg/util/net.TLSClientConfigHolder for proper TLS checking during
|
||||
@@ -163,6 +148,18 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||
return s.dialWithoutProxy(req.Context(), req.URL)
|
||||
}
|
||||
|
||||
switch proxyURL.Scheme {
|
||||
case "socks5":
|
||||
return s.dialWithSocks5Proxy(req, proxyURL)
|
||||
case "https", "http", "":
|
||||
return s.dialWithHttpProxy(req, proxyURL)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("proxy URL scheme not supported: %s", proxyURL.Scheme)
|
||||
}
|
||||
|
||||
// dialWithHttpProxy dials the host specified by url through an http or an https proxy.
|
||||
func (s *SpdyRoundTripper) dialWithHttpProxy(req *http.Request, proxyURL *url.URL) (net.Conn, error) {
|
||||
// ensure we use a canonical host with proxyReq
|
||||
targetHost := netutil.CanonicalAddr(req.URL)
|
||||
|
||||
@@ -173,27 +170,81 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||
Host: targetHost,
|
||||
}
|
||||
|
||||
proxyReq = *proxyReq.WithContext(req.Context())
|
||||
|
||||
if pa := s.proxyAuth(proxyURL); pa != "" {
|
||||
proxyReq.Header = http.Header{}
|
||||
proxyReq.Header.Set("Proxy-Authorization", pa)
|
||||
}
|
||||
|
||||
proxyDialConn, err := s.dialWithoutProxy(req.Context(), proxyURL)
|
||||
proxyDialConn, err := s.dialWithoutProxy(proxyReq.Context(), proxyURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019 ignore deprecated httputil.NewProxyClientConn
|
||||
proxyClientConn := httputil.NewProxyClientConn(proxyDialConn, nil)
|
||||
_, err = proxyClientConn.Do(&proxyReq)
|
||||
//nolint:staticcheck // SA1019 ignore deprecated httputil.ErrPersistEOF: it might be
|
||||
// returned from the invocation of proxyClientConn.Do
|
||||
if err != nil && err != httputil.ErrPersistEOF {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rwc, _ := proxyClientConn.Hijack()
|
||||
|
||||
if req.URL.Scheme != "https" {
|
||||
return rwc, nil
|
||||
if req.URL.Scheme == "https" {
|
||||
return s.tlsConn(proxyReq.Context(), rwc, targetHost)
|
||||
}
|
||||
return rwc, nil
|
||||
}
|
||||
|
||||
// dialWithSocks5Proxy dials the host specified by url through a socks5 proxy.
|
||||
func (s *SpdyRoundTripper) dialWithSocks5Proxy(req *http.Request, proxyURL *url.URL) (net.Conn, error) {
|
||||
// ensure we use a canonical host with proxyReq
|
||||
targetHost := netutil.CanonicalAddr(req.URL)
|
||||
proxyDialAddr := netutil.CanonicalAddr(proxyURL)
|
||||
|
||||
var auth *proxy.Auth
|
||||
if proxyURL.User != nil {
|
||||
pass, _ := proxyURL.User.Password()
|
||||
auth = &proxy.Auth{
|
||||
User: proxyURL.User.Username(),
|
||||
Password: pass,
|
||||
}
|
||||
}
|
||||
|
||||
dialer := s.Dialer
|
||||
if dialer == nil {
|
||||
dialer = &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
proxyDialer, err := proxy.SOCKS5("tcp", proxyDialAddr, auth, dialer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// According to the implementation of proxy.SOCKS5, the type assertion will always succeed
|
||||
contextDialer, ok := proxyDialer.(proxy.ContextDialer)
|
||||
if !ok {
|
||||
return nil, errors.New("SOCKS5 Dialer must implement ContextDialer")
|
||||
}
|
||||
|
||||
proxyDialConn, err := contextDialer.DialContext(req.Context(), "tcp", targetHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.URL.Scheme == "https" {
|
||||
return s.tlsConn(req.Context(), proxyDialConn, targetHost)
|
||||
}
|
||||
return proxyDialConn, nil
|
||||
}
|
||||
|
||||
// tlsConn returns a TLS client side connection using rwc as the underlying transport.
|
||||
func (s *SpdyRoundTripper) tlsConn(ctx context.Context, rwc net.Conn, targetHost string) (net.Conn, error) {
|
||||
|
||||
host, _, err := net.SplitHostPort(targetHost)
|
||||
if err != nil {
|
||||
@@ -211,17 +262,8 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||
|
||||
tlsConn := tls.Client(rwc, tlsConfig)
|
||||
|
||||
// need to manually call Handshake() so we can call VerifyHostname() below
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return if we were configured to skip validation
|
||||
if tlsConfig.InsecureSkipVerify {
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
if err := tlsConn.VerifyHostname(tlsConfig.ServerName); err != nil {
|
||||
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||
tlsConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -231,46 +273,20 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||
// dialWithoutProxy dials the host specified by url, using TLS if appropriate.
|
||||
func (s *SpdyRoundTripper) dialWithoutProxy(ctx context.Context, url *url.URL) (net.Conn, error) {
|
||||
dialAddr := netutil.CanonicalAddr(url)
|
||||
dialer := s.Dialer
|
||||
if dialer == nil {
|
||||
dialer = &net.Dialer{}
|
||||
}
|
||||
|
||||
if url.Scheme == "http" {
|
||||
if s.Dialer == nil {
|
||||
var d net.Dialer
|
||||
return d.DialContext(ctx, "tcp", dialAddr)
|
||||
} else {
|
||||
return s.Dialer.DialContext(ctx, "tcp", dialAddr)
|
||||
}
|
||||
return dialer.DialContext(ctx, "tcp", dialAddr)
|
||||
}
|
||||
|
||||
// TODO validate the TLSClientConfig is set up?
|
||||
var conn *tls.Conn
|
||||
var err error
|
||||
if s.Dialer == nil {
|
||||
conn, err = tls.Dial("tcp", dialAddr, s.tlsConfig)
|
||||
} else {
|
||||
conn, err = tls.DialWithDialer(s.Dialer, "tcp", dialAddr, s.tlsConfig)
|
||||
tlsDialer := tls.Dialer{
|
||||
NetDialer: dialer,
|
||||
Config: s.tlsConfig,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return if we were configured to skip validation
|
||||
if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(dialAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.tlsConfig != nil && len(s.tlsConfig.ServerName) > 0 {
|
||||
host = s.tlsConfig.ServerName
|
||||
}
|
||||
err = conn.VerifyHostname(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
return tlsDialer.DialContext(ctx, "tcp", dialAddr)
|
||||
}
|
||||
|
||||
// proxyAuth returns, for a given proxy URL, the value to be used for the Proxy-Authorization header
|
||||
@@ -287,39 +303,20 @@ func (s *SpdyRoundTripper) proxyAuth(proxyURL *url.URL) string {
|
||||
// clients may call SpdyRoundTripper.Connection() to retrieve the upgraded
|
||||
// connection.
|
||||
func (s *SpdyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
header := utilnet.CloneHeader(req.Header)
|
||||
header.Add(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
|
||||
header.Add(httpstream.HeaderUpgrade, HeaderSpdy31)
|
||||
req = utilnet.CloneRequest(req)
|
||||
req.Header.Add(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
|
||||
req.Header.Add(httpstream.HeaderUpgrade, HeaderSpdy31)
|
||||
|
||||
var (
|
||||
conn net.Conn
|
||||
rawResponse []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if s.followRedirects {
|
||||
conn, rawResponse, err = utilnet.ConnectWithRedirects(req.Method, req.URL, header, req.Body, s, s.requireSameHostRedirects)
|
||||
} else {
|
||||
clone := utilnet.CloneRequest(req)
|
||||
clone.Header = header
|
||||
conn, err = s.Dial(clone)
|
||||
}
|
||||
conn, err := s.Dial(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseReader := bufio.NewReader(
|
||||
io.MultiReader(
|
||||
bytes.NewBuffer(rawResponse),
|
||||
conn,
|
||||
),
|
||||
)
|
||||
responseReader := bufio.NewReader(conn)
|
||||
|
||||
resp, err := http.ReadResponse(responseReader, nil)
|
||||
if err != nil {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
2
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/upgrade.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/upgrade.go
generated
vendored
@@ -94,7 +94,7 @@ func (u responseUpgrader) UpgradeResponse(w http.ResponseWriter, req *http.Reque
|
||||
|
||||
hijacker, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
errorMsg := fmt.Sprintf("unable to upgrade: unable to hijack response")
|
||||
errorMsg := "unable to upgrade: unable to hijack response"
|
||||
http.Error(w, errorMsg, http.StatusInternalServerError)
|
||||
return nil
|
||||
}
|
||||
|
||||
38
vendor/k8s.io/apimachinery/pkg/util/intstr/generated.pb.go
generated
vendored
38
vendor/k8s.io/apimachinery/pkg/util/intstr/generated.pb.go
generated
vendored
@@ -78,25 +78,25 @@ func init() {
|
||||
|
||||
var fileDescriptor_94e046ae3ce6121c = []byte{
|
||||
// 292 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x8f, 0x31, 0x4b, 0x33, 0x31,
|
||||
0x1c, 0xc6, 0x93, 0xb7, 0x7d, 0x8b, 0x9e, 0xe0, 0x50, 0x1c, 0x8a, 0x43, 0x7a, 0x28, 0xc8, 0x0d,
|
||||
0x9a, 0xac, 0xe2, 0xd8, 0xad, 0x20, 0x08, 0x57, 0x71, 0x70, 0xbb, 0x6b, 0x63, 0x1a, 0xae, 0x4d,
|
||||
0x42, 0xee, 0x7f, 0xc2, 0x6d, 0xfd, 0x08, 0xba, 0x39, 0xfa, 0x71, 0x6e, 0xec, 0xd8, 0x41, 0x8a,
|
||||
0x17, 0xbf, 0x85, 0x93, 0x5c, 0xee, 0x40, 0xa7, 0xe4, 0x79, 0x9e, 0xdf, 0x2f, 0x90, 0xe0, 0x36,
|
||||
0xbb, 0xce, 0xa9, 0xd4, 0x2c, 0x2b, 0x52, 0x6e, 0x15, 0x07, 0x9e, 0xb3, 0x67, 0xae, 0x16, 0xda,
|
||||
0xb2, 0x6e, 0x48, 0x8c, 0x5c, 0x27, 0xf3, 0xa5, 0x54, 0xdc, 0x96, 0xcc, 0x64, 0x82, 0x15, 0x20,
|
||||
0x57, 0x4c, 0x2a, 0xc8, 0xc1, 0x32, 0xc1, 0x15, 0xb7, 0x09, 0xf0, 0x05, 0x35, 0x56, 0x83, 0x1e,
|
||||
0x9e, 0xb7, 0x12, 0xfd, 0x2b, 0x51, 0x93, 0x09, 0xda, 0x48, 0xb4, 0x95, 0x4e, 0xaf, 0x84, 0x84,
|
||||
0x65, 0x91, 0xd2, 0xb9, 0x5e, 0x33, 0xa1, 0x85, 0x66, 0xde, 0x4d, 0x8b, 0x27, 0x9f, 0x7c, 0xf0,
|
||||
0xb7, 0xf6, 0xcd, 0xb3, 0x57, 0x1c, 0x1c, 0x4d, 0x15, 0xdc, 0xd9, 0x19, 0x58, 0xa9, 0xc4, 0x30,
|
||||
0x0a, 0xfa, 0x50, 0x1a, 0x3e, 0xc2, 0x21, 0x8e, 0x7a, 0x93, 0x93, 0x6a, 0x3f, 0x46, 0x6e, 0x3f,
|
||||
0xee, 0xdf, 0x97, 0x86, 0x7f, 0x77, 0x67, 0xec, 0x89, 0xe1, 0x45, 0x30, 0x90, 0x0a, 0x1e, 0x92,
|
||||
0xd5, 0xe8, 0x5f, 0x88, 0xa3, 0xff, 0x93, 0xe3, 0x8e, 0x1d, 0x4c, 0x7d, 0x1b, 0x77, 0x6b, 0xc3,
|
||||
0xe5, 0x60, 0x1b, 0xae, 0x17, 0xe2, 0xe8, 0xf0, 0x97, 0x9b, 0xf9, 0x36, 0xee, 0xd6, 0x9b, 0x83,
|
||||
0xb7, 0xf7, 0x31, 0xda, 0x7c, 0x84, 0x68, 0x72, 0x59, 0xd5, 0x04, 0x6d, 0x6b, 0x82, 0x76, 0x35,
|
||||
0x41, 0x1b, 0x47, 0x70, 0xe5, 0x08, 0xde, 0x3a, 0x82, 0x77, 0x8e, 0xe0, 0x4f, 0x47, 0xf0, 0xcb,
|
||||
0x17, 0x41, 0x8f, 0x83, 0xf6, 0xc3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x52, 0xa0, 0xb5, 0xc9,
|
||||
0x64, 0x01, 0x00, 0x00,
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0xb1, 0x4a, 0x03, 0x31,
|
||||
0x1c, 0xc6, 0x13, 0x5b, 0x8b, 0x9e, 0xe0, 0x50, 0x1c, 0x8a, 0x43, 0x7a, 0x58, 0x90, 0x5b, 0x4c,
|
||||
0x56, 0x71, 0xec, 0x56, 0x10, 0x84, 0x56, 0x1c, 0xdc, 0xee, 0xda, 0x98, 0x86, 0x6b, 0x93, 0x90,
|
||||
0xfb, 0x9f, 0x70, 0x5b, 0x1f, 0x41, 0x37, 0x47, 0x1f, 0xe7, 0xc6, 0x8e, 0x1d, 0xa4, 0x78, 0xf1,
|
||||
0x2d, 0x9c, 0xe4, 0x72, 0x07, 0x3a, 0x3a, 0x25, 0xdf, 0xf7, 0xfd, 0x7e, 0x19, 0x12, 0xdc, 0xa6,
|
||||
0xd7, 0x19, 0x95, 0x9a, 0xa5, 0x79, 0xc2, 0xad, 0xe2, 0xc0, 0x33, 0xf6, 0xcc, 0xd5, 0x42, 0x5b,
|
||||
0xd6, 0x0e, 0xb1, 0x91, 0xeb, 0x78, 0xbe, 0x94, 0x8a, 0xdb, 0x82, 0x99, 0x54, 0xb0, 0x1c, 0xe4,
|
||||
0x8a, 0x49, 0x05, 0x19, 0x58, 0x26, 0xb8, 0xe2, 0x36, 0x06, 0xbe, 0xa0, 0xc6, 0x6a, 0xd0, 0xfd,
|
||||
0x51, 0x23, 0xd1, 0xbf, 0x12, 0x35, 0xa9, 0xa0, 0xb5, 0x44, 0x1b, 0xe9, 0xfc, 0x4a, 0x48, 0x58,
|
||||
0xe6, 0x09, 0x9d, 0xeb, 0x35, 0x13, 0x5a, 0x68, 0xe6, 0xdd, 0x24, 0x7f, 0xf2, 0xc9, 0x07, 0x7f,
|
||||
0x6b, 0xde, 0xbc, 0x78, 0xc5, 0xc1, 0xc9, 0x44, 0xc1, 0x9d, 0x9d, 0x81, 0x95, 0x4a, 0xf4, 0xa3,
|
||||
0xa0, 0x0b, 0x85, 0xe1, 0x03, 0x1c, 0xe2, 0xa8, 0x33, 0x3e, 0x2b, 0xf7, 0x43, 0xe4, 0xf6, 0xc3,
|
||||
0xee, 0x7d, 0x61, 0xf8, 0x77, 0x7b, 0x4e, 0x3d, 0xd1, 0xbf, 0x0c, 0x7a, 0x52, 0xc1, 0x43, 0xbc,
|
||||
0x1a, 0x1c, 0x84, 0x38, 0x3a, 0x1c, 0x9f, 0xb6, 0x6c, 0x6f, 0xe2, 0xdb, 0x69, 0xbb, 0xd6, 0x5c,
|
||||
0x06, 0xb6, 0xe6, 0x3a, 0x21, 0x8e, 0x8e, 0x7f, 0xb9, 0x99, 0x6f, 0xa7, 0xed, 0x7a, 0x73, 0xf4,
|
||||
0xf6, 0x3e, 0x44, 0x9b, 0x8f, 0x10, 0x8d, 0x27, 0x65, 0x45, 0xd0, 0xb6, 0x22, 0x68, 0x57, 0x11,
|
||||
0xb4, 0x71, 0x04, 0x97, 0x8e, 0xe0, 0xad, 0x23, 0x78, 0xe7, 0x08, 0xfe, 0x74, 0x04, 0xbf, 0x7c,
|
||||
0x11, 0xf4, 0x38, 0xfa, 0xc7, 0x17, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xc4, 0xf0, 0xa0,
|
||||
0x81, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *IntOrString) Marshal() (dAtA []byte, err error) {
|
||||
|
||||
2
vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto
generated
vendored
@@ -22,7 +22,7 @@ syntax = "proto2";
|
||||
package k8s.io.apimachinery.pkg.util.intstr;
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "intstr";
|
||||
option go_package = "k8s.io/apimachinery/pkg/util/intstr";
|
||||
|
||||
// IntOrString is a type that can hold an int32 or a string. When used in
|
||||
// JSON or YAML marshalling and unmarshalling, it produces or consumes the
|
||||
|
||||
1
vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go
generated
vendored
1
vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build !notest
|
||||
// +build !notest
|
||||
|
||||
/*
|
||||
|
||||
6
vendor/k8s.io/apimachinery/pkg/util/intstr/intstr.go
generated
vendored
6
vendor/k8s.io/apimachinery/pkg/util/intstr/intstr.go
generated
vendored
@@ -131,6 +131,10 @@ func (IntOrString) OpenAPISchemaType() []string { return []string{"string"} }
|
||||
// the OpenAPI spec of this type.
|
||||
func (IntOrString) OpenAPISchemaFormat() string { return "int-or-string" }
|
||||
|
||||
// OpenAPIV3OneOfTypes is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI v3 spec of this type.
|
||||
func (IntOrString) OpenAPIV3OneOfTypes() []string { return []string{"integer", "string"} }
|
||||
|
||||
func ValueOrDefault(intOrPercent *IntOrString, defaultValue IntOrString) *IntOrString {
|
||||
if intOrPercent == nil {
|
||||
return &defaultValue
|
||||
@@ -141,7 +145,7 @@ func ValueOrDefault(intOrPercent *IntOrString, defaultValue IntOrString) *IntOrS
|
||||
// GetScaledValueFromIntOrPercent is meant to replace GetValueFromIntOrPercent.
|
||||
// This method returns a scaled value from an IntOrString type. If the IntOrString
|
||||
// is a percentage string value it's treated as a percentage and scaled appropriately
|
||||
// in accordance to the total, if it's an int value it's treated as a a simple value and
|
||||
// in accordance to the total, if it's an int value it's treated as a simple value and
|
||||
// if it is a string value which is either non-numeric or numeric but lacking a trailing '%' it returns an error.
|
||||
func GetScaledValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) {
|
||||
if intOrPercent == nil {
|
||||
|
||||
50
vendor/k8s.io/apimachinery/pkg/util/json/json.go
generated
vendored
50
vendor/k8s.io/apimachinery/pkg/util/json/json.go
generated
vendored
@@ -17,10 +17,11 @@ limitations under the License.
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
kjson "sigs.k8s.io/json"
|
||||
)
|
||||
|
||||
// NewEncoder delegates to json.NewEncoder
|
||||
@@ -38,50 +39,11 @@ func Marshal(v interface{}) ([]byte, error) {
|
||||
// limit recursive depth to prevent stack overflow errors
|
||||
const maxDepth = 10000
|
||||
|
||||
// Unmarshal unmarshals the given data
|
||||
// If v is a *map[string]interface{}, *[]interface{}, or *interface{} numbers
|
||||
// are converted to int64 or float64
|
||||
// Unmarshal unmarshals the given data.
|
||||
// Object keys are case-sensitive.
|
||||
// Numbers decoded into interface{} fields are converted to int64 or float64.
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case *map[string]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 ConvertMapNumbers(*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 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)
|
||||
}
|
||||
return kjson.UnmarshalCaseSensitivePreserveInts(data, v)
|
||||
}
|
||||
|
||||
// ConvertInterfaceNumbers converts any json.Number values to int64 or float64.
|
||||
|
||||
30
vendor/k8s.io/apimachinery/pkg/util/managedfields/extract.go
generated
vendored
30
vendor/k8s.io/apimachinery/pkg/util/managedfields/extract.go
generated
vendored
@@ -35,7 +35,22 @@ import (
|
||||
// that no managed fields were found for the fieldManager because other field managers
|
||||
// have taken ownership of all the fields previously owned by the fieldManager. It is
|
||||
// also possible the fieldManager never owned fields.
|
||||
func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldManager string, applyConfiguration interface{}) error {
|
||||
//
|
||||
// The provided object MUST bo a root resource object since subresource objects
|
||||
// do not contain their own managed fields. For example, an autoscaling.Scale
|
||||
// object read from a "scale" subresource does not have any managed fields and so
|
||||
// cannot be used as the object.
|
||||
//
|
||||
// If the fields of a subresource are a subset of the fields of the root object,
|
||||
// and their field paths and types are exactly the same, then ExtractInto can be
|
||||
// called with the root resource as the object and the subresource as the
|
||||
// applyConfiguration. This works for "status", obviously, because status is
|
||||
// represented by the exact same object as the root resource. This does NOT
|
||||
// work, for example, with the "scale" subresources of Deployment, ReplicaSet and
|
||||
// StatefulSet. While the spec.replicas, status.replicas fields are in the same
|
||||
// exact field path locations as they are in autoscaling.Scale, the selector
|
||||
// fields are in different locations, and are a different type.
|
||||
func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldManager string, applyConfiguration interface{}, subresource string) error {
|
||||
typedObj, err := toTyped(object, objectType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting obj to typed: %w", err)
|
||||
@@ -45,7 +60,7 @@ func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldMan
|
||||
if err != nil {
|
||||
return fmt.Errorf("error accessing metadata: %w", err)
|
||||
}
|
||||
fieldsEntry, ok := findManagedFields(accessor, fieldManager)
|
||||
fieldsEntry, ok := findManagedFields(accessor, fieldManager, subresource)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -60,16 +75,23 @@ func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldMan
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to convert managed fields for %s to unstructured, expected map, got %T", fieldManager, u)
|
||||
}
|
||||
|
||||
// set the type meta manually if it doesn't exist to avoid missing kind errors
|
||||
// when decoding from unstructured JSON
|
||||
if _, ok := m["kind"]; !ok && object.GetObjectKind().GroupVersionKind().Kind != "" {
|
||||
m["kind"] = object.GetObjectKind().GroupVersionKind().Kind
|
||||
m["apiVersion"] = object.GetObjectKind().GroupVersionKind().GroupVersion().String()
|
||||
}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, applyConfiguration); err != nil {
|
||||
return fmt.Errorf("error extracting into obj from unstructured: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findManagedFields(accessor metav1.Object, fieldManager string) (metav1.ManagedFieldsEntry, bool) {
|
||||
func findManagedFields(accessor metav1.Object, fieldManager string, subresource string) (metav1.ManagedFieldsEntry, bool) {
|
||||
objManagedFields := accessor.GetManagedFields()
|
||||
for _, mf := range objManagedFields {
|
||||
if mf.Manager == fieldManager && mf.Operation == metav1.ManagedFieldsOperationApply {
|
||||
if mf.Manager == fieldManager && mf.Operation == metav1.ManagedFieldsOperationApply && mf.Subresource == subresource {
|
||||
return mf, true
|
||||
}
|
||||
}
|
||||
|
||||
128
vendor/k8s.io/apimachinery/pkg/util/managedfields/gvkparser.go
generated
vendored
Normal file
128
vendor/k8s.io/apimachinery/pkg/util/managedfields/gvkparser.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright 2018 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 managedfields
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kube-openapi/pkg/schemaconv"
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
smdschema "sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
)
|
||||
|
||||
// groupVersionKindExtensionKey is the key used to lookup the
|
||||
// GroupVersionKind value for an object definition from the
|
||||
// definition's "extensions" map.
|
||||
const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
|
||||
|
||||
// GvkParser contains a Parser that allows introspecting the schema.
|
||||
type GvkParser struct {
|
||||
gvks map[schema.GroupVersionKind]string
|
||||
parser typed.Parser
|
||||
}
|
||||
|
||||
// Type returns a helper which can produce objects of the given type. Any
|
||||
// errors are deferred until a further function is called.
|
||||
func (p *GvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
|
||||
typeName, ok := p.gvks[gvk]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
t := p.parser.Type(typeName)
|
||||
return &t
|
||||
}
|
||||
|
||||
// NewGVKParser builds a GVKParser from a proto.Models. This
|
||||
// will automatically find the proper version of the object, and the
|
||||
// corresponding schema information.
|
||||
func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser, error) {
|
||||
typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert models to schema: %v", err)
|
||||
}
|
||||
parser := GvkParser{
|
||||
gvks: map[schema.GroupVersionKind]string{},
|
||||
}
|
||||
parser.parser = typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}}
|
||||
for _, modelName := range models.ListModels() {
|
||||
model := models.LookupModel(modelName)
|
||||
if model == nil {
|
||||
panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName))
|
||||
}
|
||||
gvkList := parseGroupVersionKind(model)
|
||||
for _, gvk := range gvkList {
|
||||
if len(gvk.Kind) > 0 {
|
||||
_, ok := parser.gvks[gvk]
|
||||
if ok {
|
||||
return nil, fmt.Errorf("duplicate entry for %v", gvk)
|
||||
}
|
||||
parser.gvks[gvk] = modelName
|
||||
}
|
||||
}
|
||||
}
|
||||
return &parser, nil
|
||||
}
|
||||
|
||||
// Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one.
|
||||
func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind {
|
||||
extensions := s.GetExtensions()
|
||||
|
||||
gvkListResult := []schema.GroupVersionKind{}
|
||||
|
||||
// Get the extensions
|
||||
gvkExtension, ok := extensions[groupVersionKindExtensionKey]
|
||||
if !ok {
|
||||
return []schema.GroupVersionKind{}
|
||||
}
|
||||
|
||||
// gvk extension must be a list of at least 1 element.
|
||||
gvkList, ok := gvkExtension.([]interface{})
|
||||
if !ok {
|
||||
return []schema.GroupVersionKind{}
|
||||
}
|
||||
|
||||
for _, gvk := range gvkList {
|
||||
// gvk extension list must be a map with group, version, and
|
||||
// kind fields
|
||||
gvkMap, ok := gvk.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
group, ok := gvkMap["group"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
version, ok := gvkMap["version"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
kind, ok := gvkMap["kind"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gvkListResult = append(gvkListResult, schema.GroupVersionKind{
|
||||
Group: group,
|
||||
Version: version,
|
||||
Kind: kind,
|
||||
})
|
||||
}
|
||||
|
||||
return gvkListResult
|
||||
}
|
||||
5
vendor/k8s.io/apimachinery/pkg/util/mergepatch/OWNERS
generated
vendored
5
vendor/k8s.io/apimachinery/pkg/util/mergepatch/OWNERS
generated
vendored
@@ -1,7 +1,6 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- pwittrock
|
||||
- pwittrock
|
||||
reviewers:
|
||||
- mengqiy
|
||||
- apelisse
|
||||
- apelisse
|
||||
|
||||
3
vendor/k8s.io/apimachinery/pkg/util/mergepatch/util.go
generated
vendored
3
vendor/k8s.io/apimachinery/pkg/util/mergepatch/util.go
generated
vendored
@@ -88,7 +88,8 @@ func toYAML(v interface{}) (string, error) {
|
||||
// supports JSON merge patch semantics.
|
||||
//
|
||||
// NOTE: Numbers with different types (e.g. int(0) vs int64(0)) will be detected as conflicts.
|
||||
// Make sure the unmarshaling of left and right are consistent (e.g. use the same library).
|
||||
//
|
||||
// Make sure the unmarshaling of left and right are consistent (e.g. use the same library).
|
||||
func HasConflicts(left, right interface{}) (bool, error) {
|
||||
switch typedLeft := left.(type) {
|
||||
case map[string]interface{}:
|
||||
|
||||
136
vendor/k8s.io/apimachinery/pkg/util/net/http.go
generated
vendored
136
vendor/k8s.io/apimachinery/pkg/util/net/http.go
generated
vendored
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package net
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
@@ -39,6 +38,7 @@ import (
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
"k8s.io/klog/v2"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
// JoinPreservingTrailingSlash does a path.Join of the specified elements,
|
||||
@@ -113,6 +113,7 @@ func SetOldTransportDefaults(t *http.Transport) *http.Transport {
|
||||
t.Proxy = NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment)
|
||||
}
|
||||
// If no custom dialer is set, use the default context dialer
|
||||
//lint:file-ignore SA1019 Keep supporting deprecated Dial method of custom transports
|
||||
if t.DialContext == nil && t.Dial == nil {
|
||||
t.DialContext = defaultTransport.DialContext
|
||||
}
|
||||
@@ -236,6 +237,29 @@ func DialerFor(transport http.RoundTripper) (DialFunc, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// CloseIdleConnectionsFor close idles connections for the Transport.
|
||||
// If the Transport is wrapped it iterates over the wrapped round trippers
|
||||
// until it finds one that implements the CloseIdleConnections method.
|
||||
// If the Transport does not have a CloseIdleConnections method
|
||||
// then this function does nothing.
|
||||
func CloseIdleConnectionsFor(transport http.RoundTripper) {
|
||||
if transport == nil {
|
||||
return
|
||||
}
|
||||
type closeIdler interface {
|
||||
CloseIdleConnections()
|
||||
}
|
||||
|
||||
switch transport := transport.(type) {
|
||||
case closeIdler:
|
||||
transport.CloseIdleConnections()
|
||||
case RoundTripperWrapper:
|
||||
CloseIdleConnectionsFor(transport.WrappedRoundTripper())
|
||||
default:
|
||||
klog.Warningf("unknown transport type: %T", transport)
|
||||
}
|
||||
}
|
||||
|
||||
type TLSClientConfigHolder interface {
|
||||
TLSClientConfig() *tls.Config
|
||||
}
|
||||
@@ -288,7 +312,7 @@ func SourceIPs(req *http.Request) []net.IP {
|
||||
// Use the first valid one.
|
||||
parts := strings.Split(hdrForwardedFor, ",")
|
||||
for _, part := range parts {
|
||||
ip := net.ParseIP(strings.TrimSpace(part))
|
||||
ip := netutils.ParseIPSloppy(strings.TrimSpace(part))
|
||||
if ip != nil {
|
||||
srcIPs = append(srcIPs, ip)
|
||||
}
|
||||
@@ -298,7 +322,7 @@ func SourceIPs(req *http.Request) []net.IP {
|
||||
// Try the X-Real-Ip header.
|
||||
hdrRealIp := hdr.Get("X-Real-Ip")
|
||||
if hdrRealIp != "" {
|
||||
ip := net.ParseIP(hdrRealIp)
|
||||
ip := netutils.ParseIPSloppy(hdrRealIp)
|
||||
// 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)
|
||||
@@ -310,11 +334,11 @@ func SourceIPs(req *http.Request) []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 {
|
||||
remoteIP = net.ParseIP(host)
|
||||
remoteIP = netutils.ParseIPSloppy(host)
|
||||
}
|
||||
// Fallback if Remote Address was just IP.
|
||||
if remoteIP == nil {
|
||||
remoteIP = net.ParseIP(req.RemoteAddr)
|
||||
remoteIP = netutils.ParseIPSloppy(req.RemoteAddr)
|
||||
}
|
||||
|
||||
// Don't duplicate remote IP if it's already the last address in the chain.
|
||||
@@ -381,7 +405,7 @@ func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error
|
||||
|
||||
cidrs := []*net.IPNet{}
|
||||
for _, noProxyRule := range noProxyRules {
|
||||
_, cidr, _ := net.ParseCIDR(noProxyRule)
|
||||
_, cidr, _ := netutils.ParseCIDRSloppy(noProxyRule)
|
||||
if cidr != nil {
|
||||
cidrs = append(cidrs, cidr)
|
||||
}
|
||||
@@ -392,7 +416,7 @@ func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error
|
||||
}
|
||||
|
||||
return func(req *http.Request) (*url.URL, error) {
|
||||
ip := net.ParseIP(req.URL.Hostname())
|
||||
ip := netutils.ParseIPSloppy(req.URL.Hostname())
|
||||
if ip == nil {
|
||||
return delegate(req)
|
||||
}
|
||||
@@ -421,104 +445,6 @@ type Dialer interface {
|
||||
Dial(req *http.Request) (net.Conn, error)
|
||||
}
|
||||
|
||||
// ConnectWithRedirects uses dialer to send req, following up to 10 redirects (relative to
|
||||
// originalLocation). It returns the opened net.Conn and the raw response bytes.
|
||||
// If requireSameHostRedirects is true, only redirects to the same host are permitted.
|
||||
func ConnectWithRedirects(originalMethod string, originalLocation *url.URL, header http.Header, originalBody io.Reader, dialer Dialer, requireSameHostRedirects bool) (net.Conn, []byte, error) {
|
||||
const (
|
||||
maxRedirects = 9 // Fail on the 10th redirect
|
||||
maxResponseSize = 16384 // play it safe to allow the potential for lots of / large headers
|
||||
)
|
||||
|
||||
var (
|
||||
location = originalLocation
|
||||
method = originalMethod
|
||||
intermediateConn net.Conn
|
||||
rawResponse = bytes.NewBuffer(make([]byte, 0, 256))
|
||||
body = originalBody
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if intermediateConn != nil {
|
||||
intermediateConn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
redirectLoop:
|
||||
for redirects := 0; ; redirects++ {
|
||||
if redirects > maxRedirects {
|
||||
return nil, nil, fmt.Errorf("too many redirects (%d)", redirects)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, location.String(), body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req.Header = header
|
||||
|
||||
intermediateConn, err = dialer.Dial(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Peek at the backend response.
|
||||
rawResponse.Reset()
|
||||
respReader := bufio.NewReader(io.TeeReader(
|
||||
io.LimitReader(intermediateConn, maxResponseSize), // Don't read more than maxResponseSize bytes.
|
||||
rawResponse)) // Save the raw response.
|
||||
resp, err := http.ReadResponse(respReader, nil)
|
||||
if err != nil {
|
||||
// Unable to read the backend response; let the client handle it.
|
||||
klog.Warningf("Error reading backend response: %v", err)
|
||||
break redirectLoop
|
||||
}
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusFound:
|
||||
// Redirect, continue.
|
||||
default:
|
||||
// Don't redirect.
|
||||
break redirectLoop
|
||||
}
|
||||
|
||||
// Redirected requests switch to "GET" according to the HTTP spec:
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3
|
||||
method = "GET"
|
||||
// don't send a body when following redirects
|
||||
body = nil
|
||||
|
||||
resp.Body.Close() // not used
|
||||
|
||||
// Prepare to follow the redirect.
|
||||
redirectStr := resp.Header.Get("Location")
|
||||
if redirectStr == "" {
|
||||
return nil, nil, fmt.Errorf("%d response missing Location header", resp.StatusCode)
|
||||
}
|
||||
// We have to parse relative to the current location, NOT originalLocation. For example,
|
||||
// if we request http://foo.com/a and get back "http://bar.com/b", the result should be
|
||||
// http://bar.com/b. If we then make that request and get back a redirect to "/c", the result
|
||||
// should be http://bar.com/c, not http://foo.com/c.
|
||||
location, err = location.Parse(redirectStr)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("malformed Location header: %v", err)
|
||||
}
|
||||
|
||||
// Only follow redirects to the same host. Otherwise, propagate the redirect response back.
|
||||
if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() {
|
||||
return nil, nil, fmt.Errorf("hostname mismatch: expected %s, found %s", originalLocation.Hostname(), location.Hostname())
|
||||
}
|
||||
|
||||
// Reset the connection.
|
||||
intermediateConn.Close()
|
||||
intermediateConn = nil
|
||||
}
|
||||
|
||||
connToReturn := intermediateConn
|
||||
intermediateConn = nil // Don't close the connection when we return it.
|
||||
return connToReturn, rawResponse.Bytes(), nil
|
||||
}
|
||||
|
||||
// CloneRequest creates a shallow copy of the request along with a deep copy of the Headers.
|
||||
func CloneRequest(req *http.Request) *http.Request {
|
||||
r := new(http.Request)
|
||||
|
||||
7
vendor/k8s.io/apimachinery/pkg/util/net/interface.go
generated
vendored
7
vendor/k8s.io/apimachinery/pkg/util/net/interface.go
generated
vendored
@@ -27,6 +27,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
type AddressFamily uint
|
||||
@@ -221,7 +222,7 @@ func getMatchingGlobalIP(addrs []net.Addr, family AddressFamily) (net.IP, error)
|
||||
if len(addrs) > 0 {
|
||||
for i := range addrs {
|
||||
klog.V(4).Infof("Checking addr %s.", addrs[i].String())
|
||||
ip, _, err := net.ParseCIDR(addrs[i].String())
|
||||
ip, _, err := netutils.ParseCIDRSloppy(addrs[i].String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -336,9 +337,9 @@ func chooseIPFromHostInterfaces(nw networkInterfacer, addressFamilies AddressFam
|
||||
continue
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
ip, _, err := net.ParseCIDR(addr.String())
|
||||
ip, _, err := netutils.ParseCIDRSloppy(addr.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse CIDR for interface %q: %s", intf.Name, err)
|
||||
return nil, fmt.Errorf("unable to parse CIDR for interface %q: %s", intf.Name, err)
|
||||
}
|
||||
if !memberOf(ip, family) {
|
||||
klog.V(4).Infof("Skipping: no address family match for %q on interface %q.", ip, intf.Name)
|
||||
|
||||
13
vendor/k8s.io/apimachinery/pkg/util/net/port_split.go
generated
vendored
13
vendor/k8s.io/apimachinery/pkg/util/net/port_split.go
generated
vendored
@@ -25,9 +25,9 @@ import (
|
||||
var validSchemes = sets.NewString("http", "https", "")
|
||||
|
||||
// SplitSchemeNamePort takes a string of the following forms:
|
||||
// * "<name>", returns "", "<name>","", true
|
||||
// * "<name>:<port>", returns "", "<name>","<port>",true
|
||||
// * "<scheme>:<name>:<port>", returns "<scheme>","<name>","<port>",true
|
||||
// - "<name>", returns "", "<name>","", true
|
||||
// - "<name>:<port>", returns "", "<name>","<port>",true
|
||||
// - "<scheme>:<name>:<port>", returns "<scheme>","<name>","<port>",true
|
||||
//
|
||||
// Name must be non-empty or valid will be returned false.
|
||||
// Scheme must be "http" or "https" if specified
|
||||
@@ -57,9 +57,10 @@ func SplitSchemeNamePort(id string) (scheme, name, port string, valid bool) {
|
||||
}
|
||||
|
||||
// JoinSchemeNamePort returns a string that specifies the scheme, name, and port:
|
||||
// * "<name>"
|
||||
// * "<name>:<port>"
|
||||
// * "<scheme>:<name>:<port>"
|
||||
// - "<name>"
|
||||
// - "<name>:<port>"
|
||||
// - "<scheme>:<name>:<port>"
|
||||
//
|
||||
// None of the parameters may contain a ':' character
|
||||
// Name is required
|
||||
// Scheme must be "", "http", or "https"
|
||||
|
||||
1
vendor/k8s.io/apimachinery/pkg/util/net/util.go
generated
vendored
1
vendor/k8s.io/apimachinery/pkg/util/net/util.go
generated
vendored
@@ -25,6 +25,7 @@ import (
|
||||
|
||||
// IPNetEqual checks if the two input IPNets are representing the same subnet.
|
||||
// For example,
|
||||
//
|
||||
// 10.0.0.1/24 and 10.0.0.0/24 are the same subnet.
|
||||
// 10.0.0.1/24 and 10.0.0.0/25 are not the same subnet.
|
||||
func IPNetEqual(ipnet1, ipnet2 *net.IPNet) bool {
|
||||
|
||||
47
vendor/k8s.io/apimachinery/pkg/util/proxy/dial.go
generated
vendored
47
vendor/k8s.io/apimachinery/pkg/util/proxy/dial.go
generated
vendored
@@ -24,10 +24,9 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/third_party/forked/golang/netutil"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// dialURL will dial the specified URL using the underlying dialer held by the passed
|
||||
@@ -52,10 +51,7 @@ func dialURL(ctx context.Context, url *url.URL, transport http.RoundTripper) (ne
|
||||
return d.DialContext(ctx, "tcp", dialAddr)
|
||||
case "https":
|
||||
// Get the tls config from the transport if we recognize it
|
||||
var tlsConfig *tls.Config
|
||||
var tlsConn *tls.Conn
|
||||
var err error
|
||||
tlsConfig, err = utilnet.TLSClientConfig(transport)
|
||||
tlsConfig, err := utilnet.TLSClientConfig(transport)
|
||||
if err != nil {
|
||||
klog.V(5).Infof("Unable to unwrap transport %T to get at TLS config: %v", transport, err)
|
||||
}
|
||||
@@ -75,7 +71,7 @@ func dialURL(ctx context.Context, url *url.URL, transport http.RoundTripper) (ne
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
} else if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify {
|
||||
// tls.Handshake() requires ServerName or InsecureSkipVerify
|
||||
// tls.HandshakeContext() requires ServerName or InsecureSkipVerify
|
||||
// infer the ServerName from the hostname we're connecting to.
|
||||
inferredHost := dialAddr
|
||||
if host, _, err := net.SplitHostPort(dialAddr); err == nil {
|
||||
@@ -87,7 +83,7 @@ func dialURL(ctx context.Context, url *url.URL, transport http.RoundTripper) (ne
|
||||
tlsConfig = tlsConfigCopy
|
||||
}
|
||||
|
||||
// Since this method is primary used within a "Connection: Upgrade" call we assume the caller is
|
||||
// Since this method is primarily used within a "Connection: Upgrade" call we assume the caller is
|
||||
// going to write HTTP/1.1 request to the wire. http2 should not be allowed in the TLSConfig.NextProtos,
|
||||
// so we explicitly set that here. We only do this check if the TLSConfig support http/1.1.
|
||||
if supportsHTTP11(tlsConfig.NextProtos) {
|
||||
@@ -95,38 +91,21 @@ func dialURL(ctx context.Context, url *url.URL, transport http.RoundTripper) (ne
|
||||
tlsConfig.NextProtos = []string{"http/1.1"}
|
||||
}
|
||||
|
||||
tlsConn = tls.Client(netConn, tlsConfig)
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
tlsConn := tls.Client(netConn, tlsConfig)
|
||||
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||
netConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
// Dial. This Dial method does not allow to pass a context unfortunately
|
||||
tlsConn, err = tls.Dial("tcp", dialAddr, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Return if we were configured to skip validation
|
||||
if tlsConfig != nil && tlsConfig.InsecureSkipVerify {
|
||||
return tlsConn, nil
|
||||
} else {
|
||||
// Dial.
|
||||
tlsDialer := tls.Dialer{
|
||||
Config: tlsConfig,
|
||||
}
|
||||
return tlsDialer.DialContext(ctx, "tcp", dialAddr)
|
||||
}
|
||||
|
||||
// Verify
|
||||
host, _, _ := net.SplitHostPort(dialAddr)
|
||||
if tlsConfig != nil && len(tlsConfig.ServerName) > 0 {
|
||||
host = tlsConfig.ServerName
|
||||
}
|
||||
if err := tlsConn.VerifyHostname(host); err != nil {
|
||||
tlsConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tlsConn, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown scheme: %s", url.Scheme)
|
||||
return nil, fmt.Errorf("unknown scheme: %s", url.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
36
vendor/k8s.io/apimachinery/pkg/util/proxy/transport.go
generated
vendored
36
vendor/k8s.io/apimachinery/pkg/util/proxy/transport.go
generated
vendored
@@ -39,7 +39,8 @@ import (
|
||||
|
||||
// atomsToAttrs states which attributes of which tags require URL substitution.
|
||||
// Sources: http://www.w3.org/TR/REC-html40/index/attributes.html
|
||||
// http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1
|
||||
//
|
||||
// http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1
|
||||
var atomsToAttrs = map[atom.Atom]sets.String{
|
||||
atom.A: sets.NewString("href"),
|
||||
atom.Applet: sets.NewString("codebase"),
|
||||
@@ -83,7 +84,7 @@ type Transport struct {
|
||||
// RoundTrip implements the http.RoundTripper interface
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// Add reverse proxy headers.
|
||||
forwardedURI := path.Join(t.PathPrepend, req.URL.Path)
|
||||
forwardedURI := path.Join(t.PathPrepend, req.URL.EscapedPath())
|
||||
if strings.HasSuffix(req.URL.Path, "/") {
|
||||
forwardedURI = forwardedURI + "/"
|
||||
}
|
||||
@@ -106,7 +107,11 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
}
|
||||
|
||||
if redirect := resp.Header.Get("Location"); redirect != "" {
|
||||
resp.Header.Set("Location", t.rewriteURL(redirect, req.URL, req.Host))
|
||||
targetURL, err := url.Parse(redirect)
|
||||
if err != nil {
|
||||
return nil, errors.NewInternalError(fmt.Errorf("error trying to parse Location header: %v", err))
|
||||
}
|
||||
resp.Header.Set("Location", t.rewriteURL(targetURL, req.URL, req.Host))
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -128,14 +133,8 @@ func (rt *Transport) WrappedRoundTripper() http.RoundTripper {
|
||||
|
||||
// rewriteURL rewrites a single URL to go through the proxy, if the URL refers
|
||||
// to the same host as sourceURL, which is the page on which the target URL
|
||||
// occurred, or if the URL matches the sourceRequestHost. If any error occurs (e.g.
|
||||
// parsing), it returns targetURL.
|
||||
func (t *Transport) rewriteURL(targetURL string, sourceURL *url.URL, sourceRequestHost string) string {
|
||||
url, err := url.Parse(targetURL)
|
||||
if err != nil {
|
||||
return targetURL
|
||||
}
|
||||
|
||||
// occurred, or if the URL matches the sourceRequestHost.
|
||||
func (t *Transport) rewriteURL(url *url.URL, sourceURL *url.URL, sourceRequestHost string) string {
|
||||
// Example:
|
||||
// When API server processes a proxy request to a service (e.g. /api/v1/namespace/foo/service/bar/proxy/),
|
||||
// the sourceURL.Host (i.e. req.URL.Host) is the endpoint IP address of the service. The
|
||||
@@ -151,7 +150,7 @@ func (t *Transport) rewriteURL(targetURL string, sourceURL *url.URL, sourceReque
|
||||
isDifferentHost := url.Host != "" && url.Host != sourceURL.Host && url.Host != sourceRequestHost
|
||||
isRelative := !strings.HasPrefix(url.Path, "/")
|
||||
if isDifferentHost || isRelative {
|
||||
return targetURL
|
||||
return url.String()
|
||||
}
|
||||
|
||||
// Do not rewrite scheme and host if the Transport has empty scheme and host
|
||||
@@ -178,7 +177,7 @@ func (t *Transport) rewriteURL(targetURL string, sourceURL *url.URL, sourceReque
|
||||
// rewriteHTML scans the HTML for tags with url-valued attributes, and updates
|
||||
// those values with the urlRewriter function. The updated HTML is output to the
|
||||
// writer.
|
||||
func rewriteHTML(reader io.Reader, writer io.Writer, urlRewriter func(string) string) error {
|
||||
func rewriteHTML(reader io.Reader, writer io.Writer, urlRewriter func(*url.URL) string) error {
|
||||
// Note: This assumes the content is UTF-8.
|
||||
tokenizer := html.NewTokenizer(reader)
|
||||
|
||||
@@ -193,7 +192,14 @@ func rewriteHTML(reader io.Reader, writer io.Writer, urlRewriter func(string) st
|
||||
if urlAttrs, ok := atomsToAttrs[token.DataAtom]; ok {
|
||||
for i, attr := range token.Attr {
|
||||
if urlAttrs.Has(attr.Key) {
|
||||
token.Attr[i].Val = urlRewriter(attr.Val)
|
||||
url, err := url.Parse(attr.Val)
|
||||
if err != nil {
|
||||
// Do not rewrite the URL if it isn't valid. It is intended not
|
||||
// to error here to prevent the inability to understand the
|
||||
// content of the body to cause a fatal error.
|
||||
continue
|
||||
}
|
||||
token.Attr[i].Val = urlRewriter(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +254,7 @@ func (t *Transport) rewriteResponse(req *http.Request, resp *http.Response) (*ht
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
urlRewriter := func(targetUrl string) string {
|
||||
urlRewriter := func(targetUrl *url.URL) string {
|
||||
return t.rewriteURL(targetUrl, req.URL, req.Host)
|
||||
}
|
||||
err := rewriteHTML(reader, writer, urlRewriter)
|
||||
|
||||
107
vendor/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go
generated
vendored
107
vendor/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go
generated
vendored
@@ -60,6 +60,8 @@ type UpgradeAwareHandler struct {
|
||||
// Location is the location of the upstream proxy. It is used as the location to Dial on the upstream server
|
||||
// for upgrade requests unless UseRequestLocationOnUpgrade is true.
|
||||
Location *url.URL
|
||||
// AppendLocationPath determines if the original path of the Location should be appended to the upstream proxy request path
|
||||
AppendLocationPath bool
|
||||
// Transport provides an optional round tripper to use to proxy. If nil, the default proxy transport is used
|
||||
Transport http.RoundTripper
|
||||
// UpgradeTransport, if specified, will be used as the backend transport when upgrade requests are provided.
|
||||
@@ -67,11 +69,6 @@ type UpgradeAwareHandler struct {
|
||||
UpgradeTransport UpgradeRequestRoundTripper
|
||||
// WrapTransport indicates whether the provided Transport should be wrapped with default proxy transport behavior (URL rewriting, X-Forwarded-* header setting)
|
||||
WrapTransport bool
|
||||
// InterceptRedirects determines whether the proxy should sniff backend responses for redirects,
|
||||
// following them as necessary.
|
||||
InterceptRedirects bool
|
||||
// RequireSameHostRedirects only allows redirects to the same host. It is only used if InterceptRedirects=true.
|
||||
RequireSameHostRedirects bool
|
||||
// UseRequestLocation will use the incoming request URL when talking to the backend server.
|
||||
UseRequestLocation bool
|
||||
// UseLocationHost overrides the HTTP host header in requests to the backend server to use the Host from Location.
|
||||
@@ -86,6 +83,8 @@ type UpgradeAwareHandler struct {
|
||||
MaxBytesPerSec int64
|
||||
// Responder is passed errors that occur while setting up proxying.
|
||||
Responder ErrorResponder
|
||||
// Reject to forward redirect response
|
||||
RejectForwardingRedirects bool
|
||||
}
|
||||
|
||||
const defaultFlushInterval = 200 * time.Millisecond
|
||||
@@ -190,6 +189,26 @@ func NewUpgradeAwareHandler(location *url.URL, transport http.RoundTripper, wrap
|
||||
}
|
||||
}
|
||||
|
||||
func proxyRedirectsforRootPath(path string, w http.ResponseWriter, req *http.Request) bool {
|
||||
redirect := false
|
||||
method := req.Method
|
||||
|
||||
// From pkg/genericapiserver/endpoints/handlers/proxy.go#ServeHTTP:
|
||||
// Redirect requests with an empty path to a location that ends with a '/'
|
||||
// This is essentially a hack for http://issue.k8s.io/4958.
|
||||
// Note: Keep this code after tryUpgrade to not break that flow.
|
||||
if len(path) == 0 && (method == http.MethodGet || method == http.MethodHead) {
|
||||
var queryPart string
|
||||
if len(req.URL.RawQuery) > 0 {
|
||||
queryPart = "?" + req.URL.RawQuery
|
||||
}
|
||||
w.Header().Set("Location", req.URL.Path+"/"+queryPart)
|
||||
w.WriteHeader(http.StatusMovedPermanently)
|
||||
redirect = true
|
||||
}
|
||||
return redirect
|
||||
}
|
||||
|
||||
// ServeHTTP handles the proxy request
|
||||
func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
if h.tryUpgrade(w, req) {
|
||||
@@ -209,17 +228,8 @@ func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request
|
||||
loc.Path += "/"
|
||||
}
|
||||
|
||||
// From pkg/genericapiserver/endpoints/handlers/proxy.go#ServeHTTP:
|
||||
// Redirect requests with an empty path to a location that ends with a '/'
|
||||
// This is essentially a hack for http://issue.k8s.io/4958.
|
||||
// Note: Keep this code after tryUpgrade to not break that flow.
|
||||
if len(loc.Path) == 0 {
|
||||
var queryPart string
|
||||
if len(req.URL.RawQuery) > 0 {
|
||||
queryPart = "?" + req.URL.RawQuery
|
||||
}
|
||||
w.Header().Set("Location", req.URL.Path+"/"+queryPart)
|
||||
w.WriteHeader(http.StatusMovedPermanently)
|
||||
proxyRedirect := proxyRedirectsforRootPath(loc.Path, w, req)
|
||||
if proxyRedirect {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -239,10 +249,41 @@ func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request
|
||||
newReq.Host = h.Location.Host
|
||||
}
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: h.Location.Scheme, Host: h.Location.Host})
|
||||
// create the target location to use for the reverse proxy
|
||||
reverseProxyLocation := &url.URL{Scheme: h.Location.Scheme, Host: h.Location.Host}
|
||||
if h.AppendLocationPath {
|
||||
reverseProxyLocation.Path = h.Location.Path
|
||||
}
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(reverseProxyLocation)
|
||||
proxy.Transport = h.Transport
|
||||
proxy.FlushInterval = h.FlushInterval
|
||||
proxy.ErrorLog = log.New(noSuppressPanicError{}, "", log.LstdFlags)
|
||||
if h.RejectForwardingRedirects {
|
||||
oldModifyResponse := proxy.ModifyResponse
|
||||
proxy.ModifyResponse = func(response *http.Response) error {
|
||||
code := response.StatusCode
|
||||
if code >= 300 && code <= 399 && len(response.Header.Get("Location")) > 0 {
|
||||
// close the original response
|
||||
response.Body.Close()
|
||||
msg := "the backend attempted to redirect this request, which is not permitted"
|
||||
// replace the response
|
||||
*response = http.Response{
|
||||
StatusCode: http.StatusBadGateway,
|
||||
Status: fmt.Sprintf("%d %s", response.StatusCode, http.StatusText(response.StatusCode)),
|
||||
Body: io.NopCloser(strings.NewReader(msg)),
|
||||
ContentLength: int64(len(msg)),
|
||||
}
|
||||
} else {
|
||||
if oldModifyResponse != nil {
|
||||
if err := oldModifyResponse(response); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if h.Responder != nil {
|
||||
// if an optional error interceptor/responder was provided wire it
|
||||
// the custom responder might be used for providing a unified error reporting
|
||||
@@ -282,23 +323,21 @@ func (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Reques
|
||||
location = *req.URL
|
||||
location.Scheme = h.Location.Scheme
|
||||
location.Host = h.Location.Host
|
||||
if h.AppendLocationPath {
|
||||
location.Path = singleJoiningSlash(h.Location.Path, location.Path)
|
||||
}
|
||||
}
|
||||
|
||||
clone := utilnet.CloneRequest(req)
|
||||
// Only append X-Forwarded-For in the upgrade path, since httputil.NewSingleHostReverseProxy
|
||||
// handles this in the non-upgrade path.
|
||||
utilnet.AppendForwardedForHeader(clone)
|
||||
if h.InterceptRedirects {
|
||||
klog.V(6).Infof("Connecting to backend proxy (intercepting redirects) %s\n Headers: %v", &location, clone.Header)
|
||||
backendConn, rawResponse, err = utilnet.ConnectWithRedirects(req.Method, &location, clone.Header, req.Body, utilnet.DialerFunc(h.DialForUpgrade), h.RequireSameHostRedirects)
|
||||
} else {
|
||||
klog.V(6).Infof("Connecting to backend proxy (direct dial) %s\n Headers: %v", &location, clone.Header)
|
||||
if h.UseLocationHost {
|
||||
clone.Host = h.Location.Host
|
||||
}
|
||||
clone.URL = &location
|
||||
backendConn, err = h.DialForUpgrade(clone)
|
||||
klog.V(6).Infof("Connecting to backend proxy (direct dial) %s\n Headers: %v", &location, clone.Header)
|
||||
if h.UseLocationHost {
|
||||
clone.Host = h.Location.Host
|
||||
}
|
||||
clone.URL = &location
|
||||
backendConn, err = h.DialForUpgrade(clone)
|
||||
if err != nil {
|
||||
klog.V(6).Infof("Proxy connection error: %v", err)
|
||||
h.Responder.Error(w, req, err)
|
||||
@@ -414,6 +453,20 @@ func (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Reques
|
||||
return true
|
||||
}
|
||||
|
||||
// FIXME: Taken from net/http/httputil/reverseproxy.go as singleJoiningSlash is not exported to be re-used.
|
||||
// See-also: https://github.com/golang/go/issues/44290
|
||||
func singleJoiningSlash(a, b string) string {
|
||||
aslash := strings.HasSuffix(a, "/")
|
||||
bslash := strings.HasPrefix(b, "/")
|
||||
switch {
|
||||
case aslash && bslash:
|
||||
return a + b[1:]
|
||||
case !aslash && !bslash:
|
||||
return a + "/" + b
|
||||
}
|
||||
return a + b
|
||||
}
|
||||
|
||||
func (h *UpgradeAwareHandler) DialForUpgrade(req *http.Request) (net.Conn, error) {
|
||||
if h.UpgradeTransport == nil {
|
||||
return dial(req, h.Transport)
|
||||
|
||||
9
vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
generated
vendored
9
vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
generated
vendored
@@ -27,9 +27,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ReallyCrash controls the behavior of HandleCrash and now defaults
|
||||
// true. It's still exposed so components can optionally set to false
|
||||
// to restore prior behavior.
|
||||
// ReallyCrash controls the behavior of HandleCrash and defaults to
|
||||
// true. It's exposed so components can optionally set to false
|
||||
// to restore prior behavior. This flag is mostly used for tests to validate
|
||||
// crash conditions.
|
||||
ReallyCrash = true
|
||||
)
|
||||
|
||||
@@ -141,7 +142,7 @@ func GetCaller() string {
|
||||
runtime.Callers(3, pc[:])
|
||||
f := runtime.FuncForPC(pc[0])
|
||||
if f == nil {
|
||||
return fmt.Sprintf("Unable to find caller")
|
||||
return "Unable to find caller"
|
||||
}
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
16
vendor/k8s.io/apimachinery/pkg/util/sets/byte.go
generated
vendored
16
vendor/k8s.io/apimachinery/pkg/util/sets/byte.go
generated
vendored
@@ -28,7 +28,7 @@ type Byte map[byte]Empty
|
||||
|
||||
// NewByte creates a Byte from a list of values.
|
||||
func NewByte(items ...byte) Byte {
|
||||
ss := Byte{}
|
||||
ss := make(Byte, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
@@ -87,6 +87,15 @@ func (s Byte) HasAny(items ...byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Byte) Clone() Byte {
|
||||
result := make(Byte, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
@@ -110,10 +119,7 @@ func (s Byte) Difference(s2 Byte) Byte {
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Byte) Union(s2 Byte) Byte {
|
||||
result := NewByte()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
|
||||
16
vendor/k8s.io/apimachinery/pkg/util/sets/int.go
generated
vendored
16
vendor/k8s.io/apimachinery/pkg/util/sets/int.go
generated
vendored
@@ -28,7 +28,7 @@ type Int map[int]Empty
|
||||
|
||||
// NewInt creates a Int from a list of values.
|
||||
func NewInt(items ...int) Int {
|
||||
ss := Int{}
|
||||
ss := make(Int, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
@@ -87,6 +87,15 @@ func (s Int) HasAny(items ...int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Int) Clone() Int {
|
||||
result := make(Int, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
@@ -110,10 +119,7 @@ func (s Int) Difference(s2 Int) Int {
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int) Union(s2 Int) Int {
|
||||
result := NewInt()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
|
||||
16
vendor/k8s.io/apimachinery/pkg/util/sets/int32.go
generated
vendored
16
vendor/k8s.io/apimachinery/pkg/util/sets/int32.go
generated
vendored
@@ -28,7 +28,7 @@ type Int32 map[int32]Empty
|
||||
|
||||
// NewInt32 creates a Int32 from a list of values.
|
||||
func NewInt32(items ...int32) Int32 {
|
||||
ss := Int32{}
|
||||
ss := make(Int32, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
@@ -87,6 +87,15 @@ func (s Int32) HasAny(items ...int32) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Int32) Clone() Int32 {
|
||||
result := make(Int32, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
@@ -110,10 +119,7 @@ func (s Int32) Difference(s2 Int32) Int32 {
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int32) Union(s2 Int32) Int32 {
|
||||
result := NewInt32()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
|
||||
16
vendor/k8s.io/apimachinery/pkg/util/sets/int64.go
generated
vendored
16
vendor/k8s.io/apimachinery/pkg/util/sets/int64.go
generated
vendored
@@ -28,7 +28,7 @@ type Int64 map[int64]Empty
|
||||
|
||||
// NewInt64 creates a Int64 from a list of values.
|
||||
func NewInt64(items ...int64) Int64 {
|
||||
ss := Int64{}
|
||||
ss := make(Int64, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
@@ -87,6 +87,15 @@ func (s Int64) HasAny(items ...int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s Int64) Clone() Int64 {
|
||||
result := make(Int64, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
@@ -110,10 +119,7 @@ func (s Int64) Difference(s2 Int64) Int64 {
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 Int64) Union(s2 Int64) Int64 {
|
||||
result := NewInt64()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
|
||||
16
vendor/k8s.io/apimachinery/pkg/util/sets/string.go
generated
vendored
16
vendor/k8s.io/apimachinery/pkg/util/sets/string.go
generated
vendored
@@ -28,7 +28,7 @@ type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := String{}
|
||||
ss := make(String, len(items))
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
@@ -87,6 +87,15 @@ func (s String) HasAny(items ...string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Clone returns a new set which is a copy of the current set.
|
||||
func (s String) Clone() String {
|
||||
result := make(String, len(s))
|
||||
for key := range s {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
@@ -110,10 +119,7 @@ func (s String) Difference(s2 String) String {
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
result := s1.Clone()
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
|
||||
8
vendor/k8s.io/apimachinery/pkg/util/strategicpatch/OWNERS
generated
vendored
8
vendor/k8s.io/apimachinery/pkg/util/strategicpatch/OWNERS
generated
vendored
@@ -1,8 +1,8 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- pwittrock
|
||||
- mengqiy
|
||||
- pwittrock
|
||||
reviewers:
|
||||
- mengqiy
|
||||
- apelisse
|
||||
- apelisse
|
||||
emeritus_approvers:
|
||||
- mengqiy
|
||||
|
||||
12
vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go
generated
vendored
12
vendor/k8s.io/apimachinery/pkg/util/strategicpatch/meta.go
generated
vendored
@@ -31,22 +31,22 @@ type PatchMeta struct {
|
||||
patchMergeKey string
|
||||
}
|
||||
|
||||
func (pm PatchMeta) GetPatchStrategies() []string {
|
||||
func (pm *PatchMeta) GetPatchStrategies() []string {
|
||||
if pm.patchStrategies == nil {
|
||||
return []string{}
|
||||
}
|
||||
return pm.patchStrategies
|
||||
}
|
||||
|
||||
func (pm PatchMeta) SetPatchStrategies(ps []string) {
|
||||
func (pm *PatchMeta) SetPatchStrategies(ps []string) {
|
||||
pm.patchStrategies = ps
|
||||
}
|
||||
|
||||
func (pm PatchMeta) GetPatchMergeKey() string {
|
||||
func (pm *PatchMeta) GetPatchMergeKey() string {
|
||||
return pm.patchMergeKey
|
||||
}
|
||||
|
||||
func (pm PatchMeta) SetPatchMergeKey(pmk string) {
|
||||
func (pm *PatchMeta) SetPatchMergeKey(pmk string) {
|
||||
pm.patchMergeKey = pmk
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func (s PatchMetaFromStruct) LookupPatchMetadataForSlice(key string) (LookupPatc
|
||||
// If the underlying element is neither an array nor a slice, the pointer is pointing to a slice,
|
||||
// e.g. https://github.com/kubernetes/kubernetes/blob/bc22e206c79282487ea0bf5696d5ccec7e839a76/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go#L2782-L2822
|
||||
// If the underlying element is either an array or a slice, return its element type.
|
||||
case reflect.Ptr:
|
||||
case reflect.Pointer:
|
||||
t = t.Elem()
|
||||
if t.Kind() == reflect.Array || t.Kind() == reflect.Slice {
|
||||
t = t.Elem()
|
||||
@@ -129,7 +129,7 @@ func getTagStructType(dataStruct interface{}) (reflect.Type, error) {
|
||||
|
||||
t := reflect.TypeOf(dataStruct)
|
||||
// Get the underlying type for pointers
|
||||
if t.Kind() == reflect.Ptr {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
|
||||
40
vendor/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go
generated
vendored
40
vendor/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go
generated
vendored
@@ -987,10 +987,10 @@ func validatePatchWithSetOrderList(patchList, setOrderList interface{}, mergeKey
|
||||
return nil
|
||||
}
|
||||
|
||||
var nonDeleteList, toDeleteList []interface{}
|
||||
var nonDeleteList []interface{}
|
||||
var err error
|
||||
if len(mergeKey) > 0 {
|
||||
nonDeleteList, toDeleteList, err = extractToDeleteItems(typedPatchList)
|
||||
nonDeleteList, _, err = extractToDeleteItems(typedPatchList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1018,7 +1018,6 @@ func validatePatchWithSetOrderList(patchList, setOrderList interface{}, mergeKey
|
||||
if patchIndex < len(nonDeleteList) && setOrderIndex >= len(typedSetOrderList) {
|
||||
return fmt.Errorf("The order in patch list:\n%v\n doesn't match %s list:\n%v\n", typedPatchList, setElementOrderDirectivePrefix, setOrderList)
|
||||
}
|
||||
typedPatchList = append(nonDeleteList, toDeleteList...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1329,15 +1328,25 @@ func mergeMap(original, patch map[string]interface{}, schema LookupPatchMeta, me
|
||||
|
||||
_, ok := original[k]
|
||||
if !ok {
|
||||
// If it's not in the original document, just take the patch value.
|
||||
original[k] = patchV
|
||||
if !isDeleteList {
|
||||
// If it's not in the original document, just take the patch value.
|
||||
if mergeOptions.IgnoreUnmatchedNulls {
|
||||
discardNullValuesFromPatch(patchV)
|
||||
}
|
||||
original[k] = patchV
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
originalType := reflect.TypeOf(original[k])
|
||||
patchType := reflect.TypeOf(patchV)
|
||||
if originalType != patchType {
|
||||
original[k] = patchV
|
||||
if !isDeleteList {
|
||||
if mergeOptions.IgnoreUnmatchedNulls {
|
||||
discardNullValuesFromPatch(patchV)
|
||||
}
|
||||
original[k] = patchV
|
||||
}
|
||||
continue
|
||||
}
|
||||
// If they're both maps or lists, recurse into the value.
|
||||
@@ -1372,6 +1381,25 @@ func mergeMap(original, patch map[string]interface{}, schema LookupPatchMeta, me
|
||||
return original, nil
|
||||
}
|
||||
|
||||
// discardNullValuesFromPatch discards all null property values from patch.
|
||||
// It traverses all slices and map types.
|
||||
func discardNullValuesFromPatch(patchV interface{}) {
|
||||
switch patchV := patchV.(type) {
|
||||
case map[string]interface{}:
|
||||
for k, v := range patchV {
|
||||
if v == nil {
|
||||
delete(patchV, k)
|
||||
} else {
|
||||
discardNullValuesFromPatch(v)
|
||||
}
|
||||
}
|
||||
case []interface{}:
|
||||
for _, v := range patchV {
|
||||
discardNullValuesFromPatch(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mergeMapHandler handles how to merge `patchV` whose key is `key` with `original` respecting
|
||||
// fieldPatchStrategy and mergeOptions.
|
||||
func mergeMapHandler(original, patch interface{}, schema LookupPatchMeta,
|
||||
|
||||
63
vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go
generated
vendored
63
vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go
generated
vendored
@@ -42,19 +42,31 @@ func (v *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", v.Field, v.ErrorBody())
|
||||
}
|
||||
|
||||
type OmitValueType struct{}
|
||||
|
||||
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 {
|
||||
var s string
|
||||
switch v.Type {
|
||||
case ErrorTypeRequired, ErrorTypeForbidden, ErrorTypeTooLong, ErrorTypeInternal:
|
||||
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()
|
||||
default:
|
||||
value := v.BadValue
|
||||
valueType := reflect.TypeOf(value)
|
||||
if value == nil || valueType == nil {
|
||||
value = "null"
|
||||
} else if valueType.Kind() == reflect.Ptr {
|
||||
} else if valueType.Kind() == reflect.Pointer {
|
||||
if reflectValue := reflect.ValueOf(value); reflectValue.IsNil() {
|
||||
value = "null"
|
||||
} else {
|
||||
@@ -123,6 +135,8 @@ const (
|
||||
// ErrorTypeInternal is used to report other errors that are not related
|
||||
// to user input. See InternalError().
|
||||
ErrorTypeInternal ErrorType = "InternalError"
|
||||
// ErrorTypeTypeInvalid is for the value did not match the schema type for that field
|
||||
ErrorTypeTypeInvalid ErrorType = "FieldValueTypeInvalid"
|
||||
)
|
||||
|
||||
// String converts a ErrorType into its corresponding canonical error message.
|
||||
@@ -146,11 +160,18 @@ func (t ErrorType) String() string {
|
||||
return "Too many"
|
||||
case ErrorTypeInternal:
|
||||
return "Internal error"
|
||||
case ErrorTypeTypeInvalid:
|
||||
return "Invalid value"
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized validation error: %q", string(t)))
|
||||
}
|
||||
}
|
||||
|
||||
// TypeInvalid returns a *Error indicating "type is invalid"
|
||||
func TypeInvalid(field *Path, value interface{}, detail string) *Error {
|
||||
return &Error{ErrorTypeTypeInvalid, field.String(), value, detail}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -181,7 +202,7 @@ func Invalid(field *Path, value interface{}, detail string) *Error {
|
||||
// valid values).
|
||||
func NotSupported(field *Path, value interface{}, validValues []string) *Error {
|
||||
detail := ""
|
||||
if validValues != nil && len(validValues) > 0 {
|
||||
if len(validValues) > 0 {
|
||||
quotedValues := make([]string, len(validValues))
|
||||
for i, v := range validValues {
|
||||
quotedValues[i] = strconv.Quote(v)
|
||||
@@ -207,11 +228,40 @@ func TooLong(field *Path, value interface{}, maxLength int) *Error {
|
||||
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d bytes", maxLength)}
|
||||
}
|
||||
|
||||
// TooLongMaxLength returns a *Error indicating "too long". This is used to
|
||||
// report that the given value is too long. This is similar to
|
||||
// Invalid, but the returned error will not include the too-long
|
||||
// value. If maxLength is negative, no max length will be included in the message.
|
||||
func TooLongMaxLength(field *Path, value interface{}, maxLength int) *Error {
|
||||
var msg string
|
||||
if maxLength >= 0 {
|
||||
msg = fmt.Sprintf("may not be longer than %d", maxLength)
|
||||
} else {
|
||||
msg = "value is too long"
|
||||
}
|
||||
return &Error{ErrorTypeTooLong, field.String(), value, msg}
|
||||
}
|
||||
|
||||
// TooMany returns a *Error indicating "too many". This is used to
|
||||
// report that a given list has too many items. This is similar to TooLong,
|
||||
// but the returned error indicates quantity instead of length.
|
||||
func TooMany(field *Path, actualQuantity, maxQuantity int) *Error {
|
||||
return &Error{ErrorTypeTooMany, field.String(), actualQuantity, fmt.Sprintf("must have at most %d items", maxQuantity)}
|
||||
var msg string
|
||||
|
||||
if maxQuantity >= 0 {
|
||||
msg = fmt.Sprintf("must have at most %d items", maxQuantity)
|
||||
} else {
|
||||
msg = "has too many items"
|
||||
}
|
||||
|
||||
var actual interface{}
|
||||
if actualQuantity >= 0 {
|
||||
actual = actualQuantity
|
||||
} else {
|
||||
actual = omitValue
|
||||
}
|
||||
|
||||
return &Error{ErrorTypeTooMany, field.String(), actual, msg}
|
||||
}
|
||||
|
||||
// InternalError returns a *Error indicating "internal error". This is used
|
||||
@@ -239,6 +289,9 @@ func NewErrorTypeMatcher(t ErrorType) utilerrors.Matcher {
|
||||
|
||||
// ToAggregate converts the ErrorList into an errors.Aggregate.
|
||||
func (list ErrorList) ToAggregate() utilerrors.Aggregate {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
errs := make([]error, 0, len(list))
|
||||
errorMsgs := sets.NewString()
|
||||
for _, err := range list {
|
||||
|
||||
9
vendor/k8s.io/apimachinery/pkg/util/validation/validation.go
generated
vendored
9
vendor/k8s.io/apimachinery/pkg/util/validation/validation.go
generated
vendored
@@ -25,6 +25,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
const qnameCharFmt string = "[A-Za-z0-9]"
|
||||
@@ -333,7 +334,7 @@ func IsValidPortName(port string) []string {
|
||||
errs = append(errs, "must contain only alpha-numeric characters (a-z, 0-9), and hyphens (-)")
|
||||
}
|
||||
if !portNameOneLetterRegexp.MatchString(port) {
|
||||
errs = append(errs, "must contain at least one letter or number (a-z, 0-9)")
|
||||
errs = append(errs, "must contain at least one letter (a-z)")
|
||||
}
|
||||
if strings.Contains(port, "--") {
|
||||
errs = append(errs, "must not contain consecutive hyphens")
|
||||
@@ -346,7 +347,7 @@ func IsValidPortName(port string) []string {
|
||||
|
||||
// IsValidIP tests that the argument is a valid IP address.
|
||||
func IsValidIP(value string) []string {
|
||||
if net.ParseIP(value) == nil {
|
||||
if netutils.ParseIPSloppy(value) == nil {
|
||||
return []string{"must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)"}
|
||||
}
|
||||
return nil
|
||||
@@ -355,7 +356,7 @@ func IsValidIP(value string) []string {
|
||||
// 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)
|
||||
ip := netutils.ParseIPSloppy(value)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv4 address"))
|
||||
}
|
||||
@@ -365,7 +366,7 @@ func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
// 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)
|
||||
ip := netutils.ParseIPSloppy(value)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address"))
|
||||
}
|
||||
|
||||
258
vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
generated
vendored
258
vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
generated
vendored
@@ -24,14 +24,16 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
// For any test of the style:
|
||||
// ...
|
||||
// <- time.After(timeout):
|
||||
// t.Errorf("Timed out")
|
||||
//
|
||||
// ...
|
||||
// <- 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.
|
||||
@@ -166,6 +168,9 @@ func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan
|
||||
// of every loop to prevent extra executions of f().
|
||||
select {
|
||||
case <-stopCh:
|
||||
if !t.Stop() {
|
||||
<-t.C()
|
||||
}
|
||||
return
|
||||
case <-t.C():
|
||||
}
|
||||
@@ -205,10 +210,29 @@ var ErrWaitTimeout = errors.New("timed out waiting for the condition")
|
||||
// if the loop should be aborted.
|
||||
type ConditionFunc func() (done bool, err error)
|
||||
|
||||
// ConditionWithContextFunc returns true if the condition is satisfied, or an error
|
||||
// if the loop should be aborted.
|
||||
//
|
||||
// The caller passes along a context that can be used by the condition function.
|
||||
type ConditionWithContextFunc func(context.Context) (done bool, err error)
|
||||
|
||||
// WithContext converts a ConditionFunc into a ConditionWithContextFunc
|
||||
func (cf ConditionFunc) WithContext() ConditionWithContextFunc {
|
||||
return func(context.Context) (done bool, err error) {
|
||||
return cf()
|
||||
}
|
||||
}
|
||||
|
||||
// runConditionWithCrashProtection runs a ConditionFunc with crash protection
|
||||
func runConditionWithCrashProtection(condition ConditionFunc) (bool, error) {
|
||||
return runConditionWithCrashProtectionWithContext(context.TODO(), condition.WithContext())
|
||||
}
|
||||
|
||||
// runConditionWithCrashProtectionWithContext runs a
|
||||
// ConditionWithContextFunc with crash protection.
|
||||
func runConditionWithCrashProtectionWithContext(ctx context.Context, condition ConditionWithContextFunc) (bool, error) {
|
||||
defer runtime.HandleCrash()
|
||||
return condition()
|
||||
return condition(ctx)
|
||||
}
|
||||
|
||||
// Backoff holds parameters applied to a Backoff function.
|
||||
@@ -266,13 +290,13 @@ func (b *Backoff) Step() time.Duration {
|
||||
return duration
|
||||
}
|
||||
|
||||
// contextForChannel derives a child context from a parent channel.
|
||||
// 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) {
|
||||
func ContextForChannel(parentCh <-chan struct{}) (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
@@ -418,13 +442,62 @@ func ExponentialBackoff(backoff Backoff, condition ConditionFunc) error {
|
||||
//
|
||||
// If you want to Poll something forever, see PollInfinite.
|
||||
func Poll(interval, timeout time.Duration, condition ConditionFunc) error {
|
||||
return pollInternal(poller(interval, timeout), condition)
|
||||
return PollWithContext(context.Background(), interval, timeout, condition.WithContext())
|
||||
}
|
||||
|
||||
func pollInternal(wait WaitFunc, condition ConditionFunc) error {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
return WaitFor(wait, condition, done)
|
||||
// PollWithContext tries a condition func until it returns true, an error,
|
||||
// or when the context expires or the timeout is reached, whichever
|
||||
// happens first.
|
||||
//
|
||||
// PollWithContext 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 PollWithContext(ctx context.Context, interval, timeout time.Duration, condition ConditionWithContextFunc) error {
|
||||
return poll(ctx, false, poller(interval, timeout), 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 PollUntilWithContext(ctx, interval, condition.WithContext())
|
||||
}
|
||||
|
||||
// PollUntilWithContext tries a condition func until it returns true,
|
||||
// an error or the specified context is cancelled or expired.
|
||||
//
|
||||
// PollUntilWithContext always waits interval before the first run of 'condition'.
|
||||
// 'condition' will always be invoked at least once.
|
||||
func PollUntilWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
|
||||
return poll(ctx, false, poller(interval, 0), 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 {
|
||||
return PollInfiniteWithContext(context.Background(), interval, condition.WithContext())
|
||||
}
|
||||
|
||||
// PollInfiniteWithContext tries a condition func until it returns true or an error
|
||||
//
|
||||
// PollInfiniteWithContext 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 PollInfiniteWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
|
||||
return poll(ctx, false, poller(interval, 0), condition)
|
||||
}
|
||||
|
||||
// PollImmediate tries a condition func until it returns true, an error, or the timeout
|
||||
@@ -438,30 +511,40 @@ func pollInternal(wait WaitFunc, condition ConditionFunc) error {
|
||||
//
|
||||
// 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)
|
||||
return PollImmediateWithContext(context.Background(), interval, timeout, condition.WithContext())
|
||||
}
|
||||
|
||||
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
|
||||
// PollImmediateWithContext tries a condition func until it returns true, an error,
|
||||
// or the timeout is reached or the specified context expires, whichever happens first.
|
||||
//
|
||||
// PollInfinite always waits the interval before the run of 'condition'.
|
||||
// PollImmediateWithContext 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.
|
||||
func PollInfinite(interval time.Duration, condition ConditionFunc) error {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
return PollUntil(interval, condition, done)
|
||||
//
|
||||
// If you want to immediately Poll something forever, see PollImmediateInfinite.
|
||||
func PollImmediateWithContext(ctx context.Context, interval, timeout time.Duration, condition ConditionWithContextFunc) error {
|
||||
return poll(ctx, true, poller(interval, timeout), condition)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
ctx, cancel := ContextForChannel(stopCh)
|
||||
defer cancel()
|
||||
return PollImmediateUntilWithContext(ctx, interval, condition.WithContext())
|
||||
}
|
||||
|
||||
// PollImmediateUntilWithContext tries a condition func until it returns true,
|
||||
// an error or the specified context is cancelled or expired.
|
||||
//
|
||||
// PollImmediateUntilWithContext runs the 'condition' before waiting for the interval.
|
||||
// 'condition' will always be invoked at least once.
|
||||
func PollImmediateUntilWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
|
||||
return poll(ctx, true, poller(interval, 0), condition)
|
||||
}
|
||||
|
||||
// PollImmediateInfinite tries a condition func until it returns true or an error
|
||||
@@ -471,44 +554,46 @@ func PollInfinite(interval time.Duration, condition ConditionFunc) error {
|
||||
// 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)
|
||||
return PollImmediateInfiniteWithContext(context.Background(), interval, condition.WithContext())
|
||||
}
|
||||
|
||||
// PollUntil tries a condition func until it returns true, an error or stopCh is
|
||||
// closed.
|
||||
// PollImmediateInfiniteWithContext tries a condition func until it returns true
|
||||
// or an error or the specified context gets cancelled or expired.
|
||||
//
|
||||
// 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())
|
||||
// PollImmediateInfiniteWithContext 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 PollImmediateInfiniteWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
|
||||
return poll(ctx, true, poller(interval, 0), condition)
|
||||
}
|
||||
|
||||
// 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
|
||||
// Internally used, each of the public 'Poll*' function defined in this
|
||||
// package should invoke this internal function with appropriate parameters.
|
||||
// ctx: the context specified by the caller, for infinite polling pass
|
||||
// a context that never gets cancelled or expired.
|
||||
// immediate: if true, the 'condition' will be invoked before waiting for the interval,
|
||||
// in this case 'condition' will always be invoked at least once.
|
||||
// wait: user specified WaitFunc function that controls at what interval the condition
|
||||
// function should be invoked periodically and whether it is bound by a timeout.
|
||||
// condition: user specified ConditionWithContextFunc function.
|
||||
func poll(ctx context.Context, immediate bool, wait WaitWithContextFunc, condition ConditionWithContextFunc) error {
|
||||
if immediate {
|
||||
done, err := runConditionWithCrashProtectionWithContext(ctx, condition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-stopCh:
|
||||
case <-ctx.Done():
|
||||
// returning ctx.Err() will break backward compatibility
|
||||
return ErrWaitTimeout
|
||||
default:
|
||||
return PollUntil(interval, condition, stopCh)
|
||||
return WaitForWithContext(ctx, wait, condition)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,9 +601,23 @@ func PollImmediateUntil(interval time.Duration, condition ConditionFunc, stopCh
|
||||
// should be executed and is closed when the last test should be invoked.
|
||||
type WaitFunc func(done <-chan struct{}) <-chan struct{}
|
||||
|
||||
// WithContext converts the WaitFunc to an equivalent WaitWithContextFunc
|
||||
func (w WaitFunc) WithContext() WaitWithContextFunc {
|
||||
return func(ctx context.Context) <-chan struct{} {
|
||||
return w(ctx.Done())
|
||||
}
|
||||
}
|
||||
|
||||
// WaitWithContextFunc creates a channel that receives an item every time a test
|
||||
// should be executed and is closed when the last test should be invoked.
|
||||
//
|
||||
// When the specified context gets cancelled or expires the function
|
||||
// stops sending item and returns immediately.
|
||||
type WaitWithContextFunc func(ctx context.Context) <-chan struct{}
|
||||
|
||||
// WaitFor continually checks 'fn' as driven by 'wait'.
|
||||
//
|
||||
// WaitFor gets a channel from 'wait()'', and then invokes 'fn' once for every value
|
||||
// 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.
|
||||
//
|
||||
@@ -532,13 +631,35 @@ type WaitFunc func(done <-chan struct{}) <-chan struct{}
|
||||
// "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)
|
||||
ctx, cancel := ContextForChannel(done)
|
||||
defer cancel()
|
||||
return WaitForWithContext(ctx, wait.WithContext(), fn.WithContext())
|
||||
}
|
||||
|
||||
// WaitForWithContext continually checks 'fn' as driven by 'wait'.
|
||||
//
|
||||
// WaitForWithContext 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, WaitForWithContext 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.
|
||||
//
|
||||
// context.Canceled will be returned if the ctx.Done() channel is closed
|
||||
// without fn ever returning true.
|
||||
//
|
||||
// When the ctx.Done() channel is closed, because the golang `select` statement is
|
||||
// "uniform pseudo-random", the `fn` might still run one or multiple times,
|
||||
// though eventually `WaitForWithContext` will return.
|
||||
func WaitForWithContext(ctx context.Context, wait WaitWithContextFunc, fn ConditionWithContextFunc) error {
|
||||
waitCtx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
c := wait(waitCtx)
|
||||
for {
|
||||
select {
|
||||
case _, open := <-c:
|
||||
ok, err := runConditionWithCrashProtection(fn)
|
||||
ok, err := runConditionWithCrashProtectionWithContext(ctx, fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -548,7 +669,8 @@ func WaitFor(wait WaitFunc, fn ConditionFunc, done <-chan struct{}) error {
|
||||
if !open {
|
||||
return ErrWaitTimeout
|
||||
}
|
||||
case <-done:
|
||||
case <-ctx.Done():
|
||||
// returning ctx.Err() will break backward compatibility
|
||||
return ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
@@ -564,8 +686,8 @@ func WaitFor(wait WaitFunc, fn ConditionFunc, done <-chan struct{}) error {
|
||||
//
|
||||
// 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{} {
|
||||
func poller(interval, timeout time.Duration) WaitWithContextFunc {
|
||||
return WaitWithContextFunc(func(ctx context.Context) <-chan struct{} {
|
||||
ch := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
@@ -595,7 +717,7 @@ func poller(interval, timeout time.Duration) WaitFunc {
|
||||
}
|
||||
case <-after:
|
||||
return
|
||||
case <-done:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
46
vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go
generated
vendored
46
vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go
generated
vendored
@@ -59,6 +59,34 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalStrict unmarshals the given data
|
||||
// strictly (erroring when there are duplicate fields).
|
||||
func UnmarshalStrict(data []byte, v interface{}) error {
|
||||
preserveIntFloat := func(d *json.Decoder) *json.Decoder {
|
||||
d.UseNumber()
|
||||
return d
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case *map[string]interface{}:
|
||||
if err := yaml.UnmarshalStrict(data, v, preserveIntFloat); err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutil.ConvertMapNumbers(*v, 0)
|
||||
case *[]interface{}:
|
||||
if err := yaml.UnmarshalStrict(data, v, preserveIntFloat); err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutil.ConvertSliceNumbers(*v, 0)
|
||||
case *interface{}:
|
||||
if err := yaml.UnmarshalStrict(data, v, preserveIntFloat); err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutil.ConvertInterfaceNumbers(v, 0)
|
||||
default:
|
||||
return yaml.UnmarshalStrict(data, v)
|
||||
}
|
||||
}
|
||||
|
||||
// ToJSON converts a single YAML document into a JSON document
|
||||
// or returns an error. If the document appears to be JSON the
|
||||
// YAML decoding path is not used (so that error messages are
|
||||
@@ -291,15 +319,19 @@ func (r *YAMLReader) Read() ([]byte, error) {
|
||||
if i := bytes.Index(line, []byte(separator)); i == 0 {
|
||||
// We have a potential document terminator
|
||||
i += sep
|
||||
after := line[i:]
|
||||
if len(strings.TrimRightFunc(string(after), unicode.IsSpace)) == 0 {
|
||||
if buffer.Len() != 0 {
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
if err == io.EOF {
|
||||
return nil, err
|
||||
trimmed := strings.TrimSpace(string(line[i:]))
|
||||
// We only allow comments and spaces following the yaml doc separator, otherwise we'll return an error
|
||||
if len(trimmed) > 0 && string(trimmed[0]) != "#" {
|
||||
return nil, YAMLSyntaxError{
|
||||
err: fmt.Errorf("invalid Yaml document separator: %s", trimmed),
|
||||
}
|
||||
}
|
||||
if buffer.Len() != 0 {
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
if err == io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
if buffer.Len() != 0 {
|
||||
|
||||
Reference in New Issue
Block a user