mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
rebase: update kubernetes to 1.30
updating kubernetes to 1.30 release Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
committed by
mergify[bot]
parent
62ddcf715b
commit
e727bd351e
104
vendor/k8s.io/apiserver/pkg/storage/cacher/cacher.go
generated
vendored
104
vendor/k8s.io/apiserver/pkg/storage/cacher/cacher.go
generated
vendored
@ -45,9 +45,9 @@ import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/component-base/tracing"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/utils/clock"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -422,7 +422,7 @@ func NewCacherFromConfig(config Config) (*Cacher, error) {
|
||||
reflector.MaxInternalErrorRetryDuration = time.Second * 30
|
||||
// since the watch-list is provided by the watch cache instruct
|
||||
// the reflector to issue a regular LIST against the store
|
||||
reflector.UseWatchList = false
|
||||
reflector.UseWatchList = ptr.To(false)
|
||||
|
||||
cacher.watchCache = watchCache
|
||||
cacher.reflector = reflector
|
||||
@ -522,7 +522,8 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.WatchList) && opts.SendInitialEvents != nil {
|
||||
opts.SendInitialEvents = nil
|
||||
}
|
||||
if opts.SendInitialEvents == nil && opts.ResourceVersion == "" {
|
||||
// TODO: we should eventually get rid of this legacy case
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.WatchFromStorageWithoutResourceVersion) && opts.SendInitialEvents == nil && opts.ResourceVersion == "" {
|
||||
return c.storage.Watch(ctx, key, opts)
|
||||
}
|
||||
requestedWatchRV, err := c.versioner.ParseResourceVersion(opts.ResourceVersion)
|
||||
@ -554,6 +555,7 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
|
||||
if field == c.indexedTrigger.indexName {
|
||||
if value, ok := pred.Field.RequiresExactMatch(field); ok {
|
||||
triggerValue, triggerSupported = value, true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -566,14 +568,14 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
|
||||
// watchers on our watcher having a processing hiccup
|
||||
chanSize := c.watchCache.suggestedWatchChannelSize(c.indexedTrigger != nil, triggerSupported)
|
||||
|
||||
// Determine a function that computes the bookmarkAfterResourceVersion
|
||||
bookmarkAfterResourceVersionFn, err := c.getBookmarkAfterResourceVersionLockedFunc(ctx, requestedWatchRV, opts)
|
||||
// Determine the ResourceVersion to which the watch cache must be synchronized
|
||||
requiredResourceVersion, err := c.getWatchCacheResourceVersion(ctx, requestedWatchRV, opts)
|
||||
if err != nil {
|
||||
return newErrWatcher(err), nil
|
||||
}
|
||||
|
||||
// Determine a function that computes the watchRV we should start from
|
||||
startWatchResourceVersionFn, err := c.getStartResourceVersionForWatchLockedFunc(ctx, requestedWatchRV, opts)
|
||||
// Determine a function that computes the bookmarkAfterResourceVersion
|
||||
bookmarkAfterResourceVersionFn, err := c.getBookmarkAfterResourceVersionLockedFunc(requestedWatchRV, requiredResourceVersion, opts)
|
||||
if err != nil {
|
||||
return newErrWatcher(err), nil
|
||||
}
|
||||
@ -605,7 +607,7 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
|
||||
// moreover even though the c.waitUntilWatchCacheFreshAndForceAllEvents acquires a lock
|
||||
// it is safe to release the lock after the method finishes because we don't require
|
||||
// any atomicity between the call to the method and further calls that actually get the events.
|
||||
forceAllEvents, err := c.waitUntilWatchCacheFreshAndForceAllEvents(ctx, requestedWatchRV, opts)
|
||||
err = c.waitUntilWatchCacheFreshAndForceAllEvents(ctx, requiredResourceVersion, opts)
|
||||
if err != nil {
|
||||
return newErrWatcher(err), nil
|
||||
}
|
||||
@ -618,13 +620,8 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
|
||||
c.watchCache.RLock()
|
||||
defer c.watchCache.RUnlock()
|
||||
|
||||
startWatchRV := startWatchResourceVersionFn()
|
||||
var cacheInterval *watchCacheInterval
|
||||
if forceAllEvents {
|
||||
cacheInterval, err = c.watchCache.getIntervalFromStoreLocked()
|
||||
} else {
|
||||
cacheInterval, err = c.watchCache.getAllEventsSinceLocked(startWatchRV)
|
||||
}
|
||||
cacheInterval, err = c.watchCache.getAllEventsSinceLocked(requiredResourceVersion, opts)
|
||||
if err != nil {
|
||||
// To match the uncached watch implementation, once we have passed authn/authz/admission,
|
||||
// and successfully parsed a resource version, other errors must fail with a watch event of type ERROR,
|
||||
@ -666,7 +663,7 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
|
||||
return newImmediateCloseWatcher(), nil
|
||||
}
|
||||
|
||||
go watcher.processInterval(ctx, cacheInterval, startWatchRV)
|
||||
go watcher.processInterval(ctx, cacheInterval, requiredResourceVersion)
|
||||
return watcher, nil
|
||||
}
|
||||
|
||||
@ -755,7 +752,7 @@ func (c *Cacher) listItems(ctx context.Context, listRV uint64, key string, pred
|
||||
}
|
||||
return nil, readResourceVersion, "", nil
|
||||
}
|
||||
return c.watchCache.WaitUntilFreshAndList(ctx, listRV, pred.MatcherIndex())
|
||||
return c.watchCache.WaitUntilFreshAndList(ctx, listRV, pred.MatcherIndex(ctx))
|
||||
}
|
||||
|
||||
// GetList implements storage.Interface
|
||||
@ -776,7 +773,7 @@ func (c *Cacher) GetList(ctx context.Context, key string, opts storage.ListOptio
|
||||
// minimal resource version, simply forward the request to storage.
|
||||
return c.storage.GetList(ctx, key, opts, listObj)
|
||||
}
|
||||
if listRV == 0 && utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
|
||||
if resourceVersion == "" && utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
|
||||
listRV, err = storage.GetCurrentResourceVersionFromStorage(ctx, c.storage, c.newListFunc, c.resourcePrefix, c.objectType.String())
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1258,59 +1255,62 @@ func (c *Cacher) LastSyncResourceVersion() (uint64, error) {
|
||||
// spits a ResourceVersion after which the bookmark event will be delivered.
|
||||
//
|
||||
// The returned function must be called under the watchCache lock.
|
||||
func (c *Cacher) getBookmarkAfterResourceVersionLockedFunc(ctx context.Context, parsedResourceVersion uint64, opts storage.ListOptions) (func() uint64, error) {
|
||||
func (c *Cacher) getBookmarkAfterResourceVersionLockedFunc(parsedResourceVersion, requiredResourceVersion uint64, opts storage.ListOptions) (func() uint64, error) {
|
||||
if opts.SendInitialEvents == nil || !*opts.SendInitialEvents || !opts.Predicate.AllowWatchBookmarks {
|
||||
return func() uint64 { return 0 }, nil
|
||||
}
|
||||
return c.getCommonResourceVersionLockedFunc(ctx, parsedResourceVersion, opts)
|
||||
}
|
||||
|
||||
// getStartResourceVersionForWatchLockedFunc returns a function that
|
||||
// spits a ResourceVersion the watch will be started from.
|
||||
// Depending on the input parameters the semantics of the returned ResourceVersion are:
|
||||
// - start at Exact (return parsedWatchResourceVersion)
|
||||
// - start at Most Recent (return an RV from etcd)
|
||||
// - start at Any (return the current watchCache's RV)
|
||||
//
|
||||
// The returned function must be called under the watchCache lock.
|
||||
func (c *Cacher) getStartResourceVersionForWatchLockedFunc(ctx context.Context, parsedWatchResourceVersion uint64, opts storage.ListOptions) (func() uint64, error) {
|
||||
if opts.SendInitialEvents == nil || *opts.SendInitialEvents {
|
||||
return func() uint64 { return parsedWatchResourceVersion }, nil
|
||||
}
|
||||
return c.getCommonResourceVersionLockedFunc(ctx, parsedWatchResourceVersion, opts)
|
||||
}
|
||||
|
||||
// getCommonResourceVersionLockedFunc a helper that simply computes a ResourceVersion
|
||||
// based on the input parameters. Please examine callers of this method to get more context.
|
||||
//
|
||||
// The returned function must be called under the watchCache lock.
|
||||
func (c *Cacher) getCommonResourceVersionLockedFunc(ctx context.Context, parsedWatchResourceVersion uint64, opts storage.ListOptions) (func() uint64, error) {
|
||||
switch {
|
||||
case len(opts.ResourceVersion) == 0:
|
||||
rv, err := storage.GetCurrentResourceVersionFromStorage(ctx, c.storage, c.newListFunc, c.resourcePrefix, c.objectType.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func() uint64 { return rv }, nil
|
||||
case parsedWatchResourceVersion == 0:
|
||||
return func() uint64 { return requiredResourceVersion }, nil
|
||||
case parsedResourceVersion == 0:
|
||||
// here we assume that watchCache locked is already held
|
||||
return func() uint64 { return c.watchCache.resourceVersion }, nil
|
||||
default:
|
||||
return func() uint64 { return parsedWatchResourceVersion }, nil
|
||||
return func() uint64 { return parsedResourceVersion }, nil
|
||||
}
|
||||
}
|
||||
|
||||
// getWatchCacheResourceVersion returns a ResourceVersion to which the watch cache must be synchronized to
|
||||
//
|
||||
// Depending on the input parameters, the semantics of the returned ResourceVersion are:
|
||||
// - must be at Exact RV (when parsedWatchResourceVersion > 0)
|
||||
// - can be at Any RV (when parsedWatchResourceVersion = 0)
|
||||
// - must be at Most Recent RV (return an RV from etcd)
|
||||
//
|
||||
// note that the above semantic is enforced by the API validation (defined elsewhere):
|
||||
//
|
||||
// if SendInitiaEvents != nil => ResourceVersionMatch = NotOlderThan
|
||||
// if ResourceVersionmatch != nil => ResourceVersionMatch = NotOlderThan & SendInitialEvents != nil
|
||||
func (c *Cacher) getWatchCacheResourceVersion(ctx context.Context, parsedWatchResourceVersion uint64, opts storage.ListOptions) (uint64, error) {
|
||||
if len(opts.ResourceVersion) != 0 {
|
||||
return parsedWatchResourceVersion, nil
|
||||
}
|
||||
// legacy case
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.WatchFromStorageWithoutResourceVersion) && opts.SendInitialEvents == nil && opts.ResourceVersion == "" {
|
||||
return 0, nil
|
||||
}
|
||||
rv, err := storage.GetCurrentResourceVersionFromStorage(ctx, c.storage, c.newListFunc, c.resourcePrefix, c.objectType.String())
|
||||
return rv, err
|
||||
}
|
||||
|
||||
// waitUntilWatchCacheFreshAndForceAllEvents waits until cache is at least
|
||||
// as fresh as given requestedWatchRV if sendInitialEvents was requested.
|
||||
// Additionally, it instructs the caller whether it should ask for
|
||||
// all events from the cache (full state) or not.
|
||||
func (c *Cacher) waitUntilWatchCacheFreshAndForceAllEvents(ctx context.Context, requestedWatchRV uint64, opts storage.ListOptions) (bool, error) {
|
||||
// otherwise, we allow for establishing the connection because the clients
|
||||
// can wait for events without unnecessary blocking.
|
||||
func (c *Cacher) waitUntilWatchCacheFreshAndForceAllEvents(ctx context.Context, requestedWatchRV uint64, opts storage.ListOptions) error {
|
||||
if opts.SendInitialEvents != nil && *opts.SendInitialEvents {
|
||||
// TODO(p0lyn0mial): adapt the following logic once
|
||||
// https://github.com/kubernetes/kubernetes/pull/123264 merges
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && c.watchCache.notFresh(requestedWatchRV) {
|
||||
c.watchCache.waitingUntilFresh.Add()
|
||||
defer c.watchCache.waitingUntilFresh.Remove()
|
||||
}
|
||||
err := c.watchCache.waitUntilFreshAndBlock(ctx, requestedWatchRV)
|
||||
defer c.watchCache.RUnlock()
|
||||
return err == nil, err
|
||||
return err
|
||||
}
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// errWatcher implements watch.Interface to return a single error
|
||||
|
11
vendor/k8s.io/apiserver/pkg/storage/cacher/metrics/metrics.go
generated
vendored
11
vendor/k8s.io/apiserver/pkg/storage/cacher/metrics/metrics.go
generated
vendored
@ -146,6 +146,16 @@ var (
|
||||
},
|
||||
[]string{"resource"},
|
||||
)
|
||||
|
||||
WatchCacheReadWait = compbasemetrics.NewHistogramVec(
|
||||
&compbasemetrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "read_wait_seconds",
|
||||
Help: "Histogram of time spent waiting for a watch cache to become fresh.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
Buckets: []float64{0.005, 0.025, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.25, 1.5, 2, 3},
|
||||
}, []string{"resource"})
|
||||
)
|
||||
|
||||
var registerMetrics sync.Once
|
||||
@ -165,6 +175,7 @@ func Register() {
|
||||
legacyregistry.MustRegister(watchCacheCapacityDecreaseTotal)
|
||||
legacyregistry.MustRegister(WatchCacheCapacity)
|
||||
legacyregistry.MustRegister(WatchCacheInitializations)
|
||||
legacyregistry.MustRegister(WatchCacheReadWait)
|
||||
})
|
||||
}
|
||||
|
||||
|
14
vendor/k8s.io/apiserver/pkg/storage/cacher/util.go
generated
vendored
14
vendor/k8s.io/apiserver/pkg/storage/cacher/util.go
generated
vendored
@ -44,17 +44,3 @@ func hasPathPrefix(s, pathPrefix string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
50
vendor/k8s.io/apiserver/pkg/storage/cacher/watch_cache.go
generated
vendored
50
vendor/k8s.io/apiserver/pkg/storage/cacher/watch_cache.go
generated
vendored
@ -440,6 +440,11 @@ func (w *watchCache) List() []interface{} {
|
||||
// You HAVE TO explicitly call w.RUnlock() after this function.
|
||||
func (w *watchCache) waitUntilFreshAndBlock(ctx context.Context, resourceVersion uint64) error {
|
||||
startTime := w.clock.Now()
|
||||
defer func() {
|
||||
if resourceVersion > 0 {
|
||||
metrics.WatchCacheReadWait.WithContext(ctx).WithLabelValues(w.groupResource.String()).Observe(w.clock.Since(startTime).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
// In case resourceVersion is 0, we accept arbitrarily stale result.
|
||||
// As a result, the condition in the below for loop will never be
|
||||
@ -492,8 +497,7 @@ func (s sortableStoreElements) Swap(i, j int) {
|
||||
|
||||
// WaitUntilFreshAndList returns list of pointers to `storeElement` objects along
|
||||
// with their ResourceVersion and the name of the index, if any, that was used.
|
||||
func (w *watchCache) WaitUntilFreshAndList(ctx context.Context, resourceVersion uint64, matchValues []storage.MatchValue) ([]interface{}, uint64, string, error) {
|
||||
var err error
|
||||
func (w *watchCache) WaitUntilFreshAndList(ctx context.Context, resourceVersion uint64, matchValues []storage.MatchValue) (result []interface{}, rv uint64, index string, err error) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && w.notFresh(resourceVersion) {
|
||||
w.waitingUntilFresh.Add()
|
||||
err = w.waitUntilFreshAndBlock(ctx, resourceVersion)
|
||||
@ -501,12 +505,14 @@ func (w *watchCache) WaitUntilFreshAndList(ctx context.Context, resourceVersion
|
||||
} else {
|
||||
err = w.waitUntilFreshAndBlock(ctx, resourceVersion)
|
||||
}
|
||||
|
||||
defer func() { sort.Sort(sortableStoreElements(result)) }()
|
||||
defer w.RUnlock()
|
||||
if err != nil {
|
||||
return nil, 0, "", err
|
||||
return result, rv, index, err
|
||||
}
|
||||
|
||||
result, rv, index, err := func() ([]interface{}, uint64, string, error) {
|
||||
result, rv, index, err = func() ([]interface{}, uint64, string, error) {
|
||||
// This isn't the place where we do "final filtering" - only some "prefiltering" is happening here. So the only
|
||||
// requirement here is to NOT miss anything that should be returned. We can return as many non-matching items as we
|
||||
// want - they will be filtered out later. The fact that we return less things is only further performance improvement.
|
||||
@ -519,7 +525,6 @@ func (w *watchCache) WaitUntilFreshAndList(ctx context.Context, resourceVersion
|
||||
return w.store.List(), w.resourceVersion, "", nil
|
||||
}()
|
||||
|
||||
sort.Sort(sortableStoreElements(result))
|
||||
return result, rv, index, err
|
||||
}
|
||||
|
||||
@ -531,7 +536,14 @@ func (w *watchCache) notFresh(resourceVersion uint64) bool {
|
||||
|
||||
// WaitUntilFreshAndGet returns a pointers to <storeElement> object.
|
||||
func (w *watchCache) WaitUntilFreshAndGet(ctx context.Context, resourceVersion uint64, key string) (interface{}, bool, uint64, error) {
|
||||
err := w.waitUntilFreshAndBlock(ctx, resourceVersion)
|
||||
var err error
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && w.notFresh(resourceVersion) {
|
||||
w.waitingUntilFresh.Add()
|
||||
err = w.waitUntilFreshAndBlock(ctx, resourceVersion)
|
||||
w.waitingUntilFresh.Remove()
|
||||
} else {
|
||||
err = w.waitUntilFreshAndBlock(ctx, resourceVersion)
|
||||
}
|
||||
defer w.RUnlock()
|
||||
if err != nil {
|
||||
return nil, false, 0, err
|
||||
@ -691,7 +703,11 @@ func (w *watchCache) isIndexValidLocked(index int) bool {
|
||||
// getAllEventsSinceLocked returns a watchCacheInterval that can be used to
|
||||
// retrieve events since a certain resourceVersion. This function assumes to
|
||||
// be called under the watchCache lock.
|
||||
func (w *watchCache) getAllEventsSinceLocked(resourceVersion uint64) (*watchCacheInterval, error) {
|
||||
func (w *watchCache) getAllEventsSinceLocked(resourceVersion uint64, opts storage.ListOptions) (*watchCacheInterval, error) {
|
||||
if opts.SendInitialEvents != nil && *opts.SendInitialEvents {
|
||||
return w.getIntervalFromStoreLocked()
|
||||
}
|
||||
|
||||
size := w.endIndex - w.startIndex
|
||||
var oldest uint64
|
||||
switch {
|
||||
@ -711,13 +727,19 @@ func (w *watchCache) getAllEventsSinceLocked(resourceVersion uint64) (*watchCach
|
||||
}
|
||||
|
||||
if resourceVersion == 0 {
|
||||
// resourceVersion = 0 means that we don't require any specific starting point
|
||||
// and we would like to start watching from ~now.
|
||||
// However, to keep backward compatibility, we additionally need to return the
|
||||
// current state and only then start watching from that point.
|
||||
//
|
||||
// TODO: In v2 api, we should stop returning the current state - #13969.
|
||||
return w.getIntervalFromStoreLocked()
|
||||
if opts.SendInitialEvents == nil {
|
||||
// resourceVersion = 0 means that we don't require any specific starting point
|
||||
// and we would like to start watching from ~now.
|
||||
// However, to keep backward compatibility, we additionally need to return the
|
||||
// current state and only then start watching from that point.
|
||||
//
|
||||
// TODO: In v2 api, we should stop returning the current state - #13969.
|
||||
return w.getIntervalFromStoreLocked()
|
||||
}
|
||||
// SendInitialEvents = false and resourceVersion = 0
|
||||
// means that the request would like to start watching
|
||||
// from Any resourceVersion
|
||||
resourceVersion = w.resourceVersion
|
||||
}
|
||||
if resourceVersion < oldest-1 {
|
||||
return nil, errors.NewResourceExpired(fmt.Sprintf("too old resource version: %d (%d)", resourceVersion, oldest-1))
|
||||
|
17
vendor/k8s.io/apiserver/pkg/storage/cacher/watch_cache_interval.go
generated
vendored
17
vendor/k8s.io/apiserver/pkg/storage/cacher/watch_cache_interval.go
generated
vendored
@ -18,6 +18,7 @@ package cacher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
@ -114,9 +115,24 @@ func newCacheInterval(startIndex, endIndex int, indexer indexerFunc, indexValida
|
||||
}
|
||||
}
|
||||
|
||||
type sortableWatchCacheEvents []*watchCacheEvent
|
||||
|
||||
func (s sortableWatchCacheEvents) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s sortableWatchCacheEvents) Less(i, j int) bool {
|
||||
return s[i].Key < s[j].Key
|
||||
}
|
||||
|
||||
func (s sortableWatchCacheEvents) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// newCacheIntervalFromStore is meant to handle the case of rv=0, such that the events
|
||||
// returned by Next() need to be events from a List() done on the underlying store of
|
||||
// the watch cache.
|
||||
// The items returned in the interval will be sorted by Key.
|
||||
func newCacheIntervalFromStore(resourceVersion uint64, store cache.Indexer, getAttrsFunc attrFunc) (*watchCacheInterval, error) {
|
||||
buffer := &watchCacheIntervalBuffer{}
|
||||
allItems := store.List()
|
||||
@ -140,6 +156,7 @@ func newCacheIntervalFromStore(resourceVersion uint64, store cache.Indexer, getA
|
||||
}
|
||||
buffer.endIndex++
|
||||
}
|
||||
sort.Sort(sortableWatchCacheEvents(buffer.buffer))
|
||||
ci := &watchCacheInterval{
|
||||
startIndex: 0,
|
||||
// Simulate that we already have all the events we're looking for.
|
||||
|
15
vendor/k8s.io/apiserver/pkg/storage/errors.go
generated
vendored
15
vendor/k8s.io/apiserver/pkg/storage/errors.go
generated
vendored
@ -33,6 +33,7 @@ const (
|
||||
ErrCodeResourceVersionConflicts
|
||||
ErrCodeInvalidObj
|
||||
ErrCodeUnreachable
|
||||
ErrCodeTimeout
|
||||
)
|
||||
|
||||
var errCodeToMessage = map[int]string{
|
||||
@ -41,6 +42,7 @@ var errCodeToMessage = map[int]string{
|
||||
ErrCodeResourceVersionConflicts: "resource version conflicts",
|
||||
ErrCodeInvalidObj: "invalid object",
|
||||
ErrCodeUnreachable: "server unreachable",
|
||||
ErrCodeTimeout: "request timeout",
|
||||
}
|
||||
|
||||
func NewKeyNotFoundError(key string, rv int64) *StorageError {
|
||||
@ -75,6 +77,14 @@ func NewUnreachableError(key string, rv int64) *StorageError {
|
||||
}
|
||||
}
|
||||
|
||||
func NewTimeoutError(key, msg string) *StorageError {
|
||||
return &StorageError{
|
||||
Code: ErrCodeTimeout,
|
||||
Key: key,
|
||||
AdditionalErrorMsg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInvalidObjError(key, msg string) *StorageError {
|
||||
return &StorageError{
|
||||
Code: ErrCodeInvalidObj,
|
||||
@ -115,6 +125,11 @@ func IsConflict(err error) bool {
|
||||
return isErrCode(err, ErrCodeResourceVersionConflicts)
|
||||
}
|
||||
|
||||
// IsRequestTimeout returns true if and only if err indicates that the request has timed out.
|
||||
func IsRequestTimeout(err error) bool {
|
||||
return isErrCode(err, ErrCodeTimeout)
|
||||
}
|
||||
|
||||
// IsInvalidObj returns true if and only if err is invalid error
|
||||
func IsInvalidObj(err error) bool {
|
||||
return isErrCode(err, ErrCodeInvalidObj)
|
||||
|
2
vendor/k8s.io/apiserver/pkg/storage/errors/storage.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/errors/storage.go
generated
vendored
@ -28,7 +28,7 @@ func InterpretListError(err error, qualifiedResource schema.GroupResource) error
|
||||
switch {
|
||||
case storage.IsNotFound(err):
|
||||
return errors.NewNotFound(qualifiedResource, "")
|
||||
case storage.IsUnreachable(err):
|
||||
case storage.IsUnreachable(err), storage.IsRequestTimeout(err):
|
||||
return errors.NewServerTimeout(qualifiedResource, "list", 2) // TODO: make configurable or handled at a higher level
|
||||
case storage.IsInternalError(err):
|
||||
return errors.NewInternalError(err)
|
||||
|
13
vendor/k8s.io/apiserver/pkg/storage/etcd3/metrics/metrics.go
generated
vendored
13
vendor/k8s.io/apiserver/pkg/storage/etcd3/metrics/metrics.go
generated
vendored
@ -84,7 +84,7 @@ var (
|
||||
},
|
||||
[]string{"endpoint"},
|
||||
)
|
||||
storageSizeDescription = compbasemetrics.NewDesc("apiserver_storage_size_bytes", "Size of the storage database file physically allocated in bytes.", []string{"cluster"}, nil, compbasemetrics.ALPHA, "")
|
||||
storageSizeDescription = compbasemetrics.NewDesc("apiserver_storage_size_bytes", "Size of the storage database file physically allocated in bytes.", []string{"storage_cluster_id"}, nil, compbasemetrics.STABLE, "")
|
||||
storageMonitor = &monitorCollector{monitorGetter: func() ([]Monitor, error) { return nil, nil }}
|
||||
etcdEventsReceivedCounts = compbasemetrics.NewCounterVec(
|
||||
&compbasemetrics.CounterOpts{
|
||||
@ -167,6 +167,7 @@ func Register() {
|
||||
legacyregistry.MustRegister(objectCounts)
|
||||
legacyregistry.MustRegister(dbTotalSize)
|
||||
legacyregistry.CustomMustRegister(storageMonitor)
|
||||
legacyregistry.MustRegister(etcdEventsReceivedCounts)
|
||||
legacyregistry.MustRegister(etcdBookmarkCounts)
|
||||
legacyregistry.MustRegister(etcdLeaseObjectCounts)
|
||||
legacyregistry.MustRegister(listStorageCount)
|
||||
@ -287,21 +288,21 @@ func (c *monitorCollector) CollectWithStability(ch chan<- compbasemetrics.Metric
|
||||
}
|
||||
|
||||
for i, m := range monitors {
|
||||
cluster := fmt.Sprintf("etcd-%d", i)
|
||||
storageClusterID := fmt.Sprintf("etcd-%d", i)
|
||||
|
||||
klog.V(4).InfoS("Start collecting storage metrics", "cluster", cluster)
|
||||
klog.V(4).InfoS("Start collecting storage metrics", "storage_cluster_id", storageClusterID)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
metrics, err := m.Monitor(ctx)
|
||||
cancel()
|
||||
m.Close()
|
||||
if err != nil {
|
||||
klog.InfoS("Failed to get storage metrics", "cluster", cluster, "err", err)
|
||||
klog.InfoS("Failed to get storage metrics", "storage_cluster_id", storageClusterID, "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
metric, err := compbasemetrics.NewConstMetric(storageSizeDescription, compbasemetrics.GaugeValue, float64(metrics.Size), cluster)
|
||||
metric, err := compbasemetrics.NewConstMetric(storageSizeDescription, compbasemetrics.GaugeValue, float64(metrics.Size), storageClusterID)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Failed to create metric", "cluster", cluster)
|
||||
klog.ErrorS(err, "Failed to create metric", "storage_cluster_id", storageClusterID)
|
||||
}
|
||||
ch <- metric
|
||||
}
|
||||
|
112
vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go
generated
vendored
112
vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go
generated
vendored
@ -38,6 +38,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/audit"
|
||||
endpointsrequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/etcd3/metrics"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
@ -584,6 +585,47 @@ func (s *store) Count(key string) (int64, error) {
|
||||
return getResp.Count, nil
|
||||
}
|
||||
|
||||
// resolveGetListRev is used by GetList to resolve the rev to use in the client.KV.Get request.
|
||||
func (s *store) resolveGetListRev(continueKey string, continueRV int64, opts storage.ListOptions) (int64, error) {
|
||||
var withRev int64
|
||||
// Uses continueRV if this is a continuation request.
|
||||
if len(continueKey) > 0 {
|
||||
if len(opts.ResourceVersion) > 0 && opts.ResourceVersion != "0" {
|
||||
return withRev, apierrors.NewBadRequest("specifying resource version is not allowed when using continue")
|
||||
}
|
||||
// If continueRV > 0, the LIST request needs a specific resource version.
|
||||
// continueRV==0 is invalid.
|
||||
// If continueRV < 0, the request is for the latest resource version.
|
||||
if continueRV > 0 {
|
||||
withRev = continueRV
|
||||
}
|
||||
return withRev, nil
|
||||
}
|
||||
// Returns 0 if ResourceVersion is not specified.
|
||||
if len(opts.ResourceVersion) == 0 {
|
||||
return withRev, nil
|
||||
}
|
||||
parsedRV, err := s.versioner.ParseResourceVersion(opts.ResourceVersion)
|
||||
if err != nil {
|
||||
return withRev, apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %v", err))
|
||||
}
|
||||
|
||||
switch opts.ResourceVersionMatch {
|
||||
case metav1.ResourceVersionMatchNotOlderThan:
|
||||
// The not older than constraint is checked after we get a response from etcd,
|
||||
// and returnedRV is then set to the revision we get from the etcd response.
|
||||
case metav1.ResourceVersionMatchExact:
|
||||
withRev = int64(parsedRV)
|
||||
case "": // legacy case
|
||||
if opts.Recursive && opts.Predicate.Limit > 0 && parsedRV > 0 {
|
||||
withRev = int64(parsedRV)
|
||||
}
|
||||
default:
|
||||
return withRev, fmt.Errorf("unknown ResourceVersionMatch value: %v", opts.ResourceVersionMatch)
|
||||
}
|
||||
return withRev, nil
|
||||
}
|
||||
|
||||
// GetList implements storage.Interface.
|
||||
func (s *store) GetList(ctx context.Context, key string, opts storage.ListOptions, listObj runtime.Object) error {
|
||||
preparedKey, err := s.prepareKey(key)
|
||||
@ -636,41 +678,15 @@ func (s *store) GetList(ctx context.Context, key string, opts storage.ListOption
|
||||
|
||||
var continueRV, withRev int64
|
||||
var continueKey string
|
||||
switch {
|
||||
case opts.Recursive && len(opts.Predicate.Continue) > 0:
|
||||
if opts.Recursive && len(opts.Predicate.Continue) > 0 {
|
||||
continueKey, continueRV, err = storage.DecodeContinue(opts.Predicate.Continue, keyPrefix)
|
||||
if err != nil {
|
||||
return apierrors.NewBadRequest(fmt.Sprintf("invalid continue token: %v", err))
|
||||
}
|
||||
|
||||
if len(opts.ResourceVersion) > 0 && opts.ResourceVersion != "0" {
|
||||
return apierrors.NewBadRequest("specifying resource version is not allowed when using continue")
|
||||
}
|
||||
preparedKey = continueKey
|
||||
// If continueRV > 0, the LIST request needs a specific resource version.
|
||||
// continueRV==0 is invalid.
|
||||
// If continueRV < 0, the request is for the latest resource version.
|
||||
if continueRV > 0 {
|
||||
withRev = continueRV
|
||||
}
|
||||
case len(opts.ResourceVersion) > 0:
|
||||
parsedRV, err := s.versioner.ParseResourceVersion(opts.ResourceVersion)
|
||||
if err != nil {
|
||||
return apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %v", err))
|
||||
}
|
||||
switch opts.ResourceVersionMatch {
|
||||
case metav1.ResourceVersionMatchNotOlderThan:
|
||||
// The not older than constraint is checked after we get a response from etcd,
|
||||
// and returnedRV is then set to the revision we get from the etcd response.
|
||||
case metav1.ResourceVersionMatchExact:
|
||||
withRev = int64(parsedRV)
|
||||
case "": // legacy case
|
||||
if opts.Recursive && opts.Predicate.Limit > 0 && parsedRV > 0 {
|
||||
withRev = int64(parsedRV)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown ResourceVersionMatch value: %v", opts.ResourceVersionMatch)
|
||||
}
|
||||
}
|
||||
if withRev, err = s.resolveGetListRev(continueKey, continueRV, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if withRev != 0 {
|
||||
@ -738,10 +754,25 @@ func (s *store) GetList(ctx context.Context, key string, opts storage.ListOption
|
||||
return storage.NewInternalErrorf("unable to transform key %q: %v", kv.Key, err)
|
||||
}
|
||||
|
||||
if err := appendListItem(v, data, uint64(kv.ModRevision), opts.Predicate, s.codec, s.versioner, newItemFunc); err != nil {
|
||||
// Check if the request has already timed out before decode object
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// parent context is canceled or timed out, no point in continuing
|
||||
return storage.NewTimeoutError(string(kv.Key), "request did not complete within requested timeout")
|
||||
default:
|
||||
}
|
||||
|
||||
obj, err := decodeListItem(ctx, data, uint64(kv.ModRevision), s.codec, s.versioner, newItemFunc)
|
||||
if err != nil {
|
||||
recordDecodeError(s.groupResourceString, string(kv.Key))
|
||||
return err
|
||||
}
|
||||
|
||||
// being unable to set the version does not prevent the object from being extracted
|
||||
if matched, err := opts.Predicate.Matches(obj); err == nil && matched {
|
||||
v.Set(reflect.Append(v, reflect.ValueOf(obj).Elem()))
|
||||
}
|
||||
|
||||
numEvald++
|
||||
|
||||
// free kv early. Long lists can take O(seconds) to decode.
|
||||
@ -1015,20 +1046,23 @@ func decode(codec runtime.Codec, versioner storage.Versioner, value []byte, objP
|
||||
return nil
|
||||
}
|
||||
|
||||
// appendListItem decodes and appends the object (if it passes filter) to v, which must be a slice.
|
||||
func appendListItem(v reflect.Value, data []byte, rev uint64, pred storage.SelectionPredicate, codec runtime.Codec, versioner storage.Versioner, newItemFunc func() runtime.Object) error {
|
||||
// decodeListItem decodes bytes value in array into object.
|
||||
func decodeListItem(ctx context.Context, data []byte, rev uint64, codec runtime.Codec, versioner storage.Versioner, newItemFunc func() runtime.Object) (runtime.Object, error) {
|
||||
startedAt := time.Now()
|
||||
defer func() {
|
||||
endpointsrequest.TrackDecodeLatency(ctx, time.Since(startedAt))
|
||||
}()
|
||||
|
||||
obj, _, err := codec.Decode(data, nil, newItemFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
// being unable to set the version does not prevent the object from being extracted
|
||||
|
||||
if err := versioner.UpdateObject(obj, rev); err != nil {
|
||||
klog.Errorf("failed to update object version: %v", err)
|
||||
}
|
||||
if matched, err := pred.Matches(obj); err == nil && matched {
|
||||
v.Set(reflect.Append(v, reflect.ValueOf(obj).Elem()))
|
||||
}
|
||||
return nil
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// recordDecodeError record decode error split by object type.
|
||||
|
18
vendor/k8s.io/apiserver/pkg/storage/selection_predicate.go
generated
vendored
18
vendor/k8s.io/apiserver/pkg/storage/selection_predicate.go
generated
vendored
@ -17,10 +17,13 @@ limitations under the License.
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
// AttrFunc returns label and field sets and the uninitialized flag for List or Watch to match.
|
||||
@ -145,11 +148,16 @@ func (s *SelectionPredicate) Empty() bool {
|
||||
// For any index defined by IndexFields, if a matcher can match only (a subset)
|
||||
// of objects that return <value> for a given index, a pair (<index name>, <value>)
|
||||
// wil be returned.
|
||||
func (s *SelectionPredicate) MatcherIndex() []MatchValue {
|
||||
func (s *SelectionPredicate) MatcherIndex(ctx context.Context) []MatchValue {
|
||||
var result []MatchValue
|
||||
for _, field := range s.IndexFields {
|
||||
if value, ok := s.Field.RequiresExactMatch(field); ok {
|
||||
result = append(result, MatchValue{IndexName: FieldIndex(field), Value: value})
|
||||
} else if field == "metadata.namespace" {
|
||||
// list pods in the namespace. i.e. /api/v1/namespaces/default/pods
|
||||
if namespace, isNamespaceScope := isNamespaceScopedRequest(ctx); isNamespaceScope {
|
||||
result = append(result, MatchValue{IndexName: FieldIndex(field), Value: namespace})
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, label := range s.IndexLabels {
|
||||
@ -160,6 +168,14 @@ func (s *SelectionPredicate) MatcherIndex() []MatchValue {
|
||||
return result
|
||||
}
|
||||
|
||||
func isNamespaceScopedRequest(ctx context.Context) (string, bool) {
|
||||
re, _ := request.RequestInfoFrom(ctx)
|
||||
if re == nil || len(re.Namespace) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return re.Namespace, true
|
||||
}
|
||||
|
||||
// LabelIndex add prefix for label index.
|
||||
func LabelIndex(label string) string {
|
||||
return "l:" + label
|
||||
|
Reference in New Issue
Block a user