3
vendor/k8s.io/apiserver/pkg/storage/OWNERS
generated
vendored
3
vendor/k8s.io/apiserver/pkg/storage/OWNERS
generated
vendored
@@ -19,14 +19,11 @@ reviewers:
|
||||
- timothysc
|
||||
- hongchaodeng
|
||||
- krousey
|
||||
- fgrzadkowski
|
||||
- xiang90
|
||||
- mml
|
||||
- ingvagabund
|
||||
- resouer
|
||||
- mbohlool
|
||||
- lixiaobing10051267
|
||||
- mqliang
|
||||
- feihujiang
|
||||
- rrati
|
||||
- enj
|
||||
|
||||
127
vendor/k8s.io/apiserver/pkg/storage/cacher/cacher.go
generated
vendored
127
vendor/k8s.io/apiserver/pkg/storage/cacher/cacher.go
generated
vendored
@@ -301,8 +301,6 @@ type Cacher struct {
|
||||
watchersToStop []*cacheWatcher
|
||||
// Maintain a timeout queue to send the bookmark event before the watcher times out.
|
||||
bookmarkWatchers *watcherBookmarkTimeBuckets
|
||||
// watchBookmark feature-gate
|
||||
watchBookmarkEnabled bool
|
||||
}
|
||||
|
||||
// NewCacherFromConfig creates a new Cacher responsible for servicing WATCH and LIST requests from
|
||||
@@ -355,11 +353,10 @@ func NewCacherFromConfig(config Config) (*Cacher, error) {
|
||||
// - reflector.ListAndWatch
|
||||
// and there are no guarantees on the order that they will stop.
|
||||
// So we will be simply closing the channel, and synchronizing on the WaitGroup.
|
||||
stopCh: stopCh,
|
||||
clock: clock,
|
||||
timer: time.NewTimer(time.Duration(0)),
|
||||
bookmarkWatchers: newTimeBucketWatchers(clock),
|
||||
watchBookmarkEnabled: utilfeature.DefaultFeatureGate.Enabled(features.WatchBookmark),
|
||||
stopCh: stopCh,
|
||||
clock: clock,
|
||||
timer: time.NewTimer(time.Duration(0)),
|
||||
bookmarkWatchers: newTimeBucketWatchers(clock),
|
||||
}
|
||||
|
||||
// Ensure that timer is stopped.
|
||||
@@ -516,8 +513,8 @@ func (c *Cacher) Watch(ctx context.Context, key string, resourceVersion string,
|
||||
watcher.forget = forgetWatcher(c, c.watcherIdx, triggerValue, triggerSupported)
|
||||
c.watchers.addWatcher(watcher, c.watcherIdx, triggerValue, triggerSupported)
|
||||
|
||||
// Add it to the queue only when server and client support watch bookmarks.
|
||||
if c.watchBookmarkEnabled && watcher.allowWatchBookmarks {
|
||||
// Add it to the queue only when the client support watch bookmarks.
|
||||
if watcher.allowWatchBookmarks {
|
||||
c.bookmarkWatchers.addWatcher(watcher)
|
||||
}
|
||||
c.watcherIdx++
|
||||
@@ -624,7 +621,10 @@ func (c *Cacher) GetToList(ctx context.Context, key string, resourceVersion stri
|
||||
return err
|
||||
}
|
||||
listVal, err := conversion.EnforcePtr(listPtr)
|
||||
if err != nil || listVal.Kind() != reflect.Slice {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if listVal.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind())
|
||||
}
|
||||
filter := filterWithAttrsFunction(key, pred)
|
||||
@@ -693,7 +693,10 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, p
|
||||
return err
|
||||
}
|
||||
listVal, err := conversion.EnforcePtr(listPtr)
|
||||
if err != nil || listVal.Kind() != reflect.Slice {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if listVal.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind())
|
||||
}
|
||||
filter := filterWithAttrsFunction(key, pred)
|
||||
@@ -748,17 +751,25 @@ func (c *Cacher) Count(pathPrefix string) (int64, error) {
|
||||
return c.storage.Count(pathPrefix)
|
||||
}
|
||||
|
||||
func (c *Cacher) triggerValues(event *watchCacheEvent) ([]string, bool) {
|
||||
// baseObjectThreadUnsafe omits locking for cachingObject.
|
||||
func baseObjectThreadUnsafe(object runtime.Object) runtime.Object {
|
||||
if co, ok := object.(*cachingObject); ok {
|
||||
return co.object
|
||||
}
|
||||
return object
|
||||
}
|
||||
|
||||
func (c *Cacher) triggerValuesThreadUnsafe(event *watchCacheEvent) ([]string, bool) {
|
||||
if c.indexedTrigger == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
result := make([]string, 0, 2)
|
||||
result = append(result, c.indexedTrigger.indexerFunc(event.Object))
|
||||
result = append(result, c.indexedTrigger.indexerFunc(baseObjectThreadUnsafe(event.Object)))
|
||||
if event.PrevObject == nil {
|
||||
return result, true
|
||||
}
|
||||
prevTriggerValue := c.indexedTrigger.indexerFunc(event.PrevObject)
|
||||
prevTriggerValue := c.indexedTrigger.indexerFunc(baseObjectThreadUnsafe(event.PrevObject))
|
||||
if result[0] != prevTriggerValue {
|
||||
result = append(result, prevTriggerValue)
|
||||
}
|
||||
@@ -776,10 +787,6 @@ func (c *Cacher) processEvent(event *watchCacheEvent) {
|
||||
func (c *Cacher) dispatchEvents() {
|
||||
// Jitter to help level out any aggregate load.
|
||||
bookmarkTimer := c.clock.NewTimer(wait.Jitter(time.Second, 0.25))
|
||||
// Stop the timer when watchBookmarkFeatureGate is not enabled.
|
||||
if !c.watchBookmarkEnabled && !bookmarkTimer.Stop() {
|
||||
<-bookmarkTimer.C()
|
||||
}
|
||||
defer bookmarkTimer.Stop()
|
||||
|
||||
lastProcessedResourceVersion := uint64(0)
|
||||
@@ -816,6 +823,37 @@ func (c *Cacher) dispatchEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
func setCachingObjects(event *watchCacheEvent, versioner storage.Versioner) {
|
||||
switch event.Type {
|
||||
case watch.Added, watch.Modified:
|
||||
if object, err := newCachingObject(event.Object); err == nil {
|
||||
event.Object = object
|
||||
} else {
|
||||
klog.Errorf("couldn't create cachingObject from: %#v", event.Object)
|
||||
}
|
||||
// Don't wrap PrevObject for update event (for create events it is nil).
|
||||
// We only encode those to deliver DELETE watch events, so if
|
||||
// event.Object is not nil it can be used only for watchers for which
|
||||
// selector was satisfied for its previous version and is no longer
|
||||
// satisfied for the current version.
|
||||
// This is rare enough that it doesn't justify making deep-copy of the
|
||||
// object (done by newCachingObject) every time.
|
||||
case watch.Deleted:
|
||||
// Don't wrap Object for delete events - these are not to deliver any
|
||||
// events. Only wrap PrevObject.
|
||||
if object, err := newCachingObject(event.PrevObject); err == nil {
|
||||
// Update resource version of the underlying object.
|
||||
// event.PrevObject is used to deliver DELETE watch events and
|
||||
// for them, we set resourceVersion to <current> instead of
|
||||
// the resourceVersion of the last modification of the object.
|
||||
updateResourceVersionIfNeeded(object.object, versioner, event.ResourceVersion)
|
||||
event.PrevObject = object
|
||||
} else {
|
||||
klog.Errorf("couldn't create cachingObject from: %#v", event.Object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cacher) dispatchEvent(event *watchCacheEvent) {
|
||||
c.startDispatching(event)
|
||||
defer c.finishDispatching()
|
||||
@@ -829,6 +867,23 @@ func (c *Cacher) dispatchEvent(event *watchCacheEvent) {
|
||||
watcher.nonblockingAdd(event)
|
||||
}
|
||||
} else {
|
||||
// Set up caching of object serializations only for dispatching this event.
|
||||
//
|
||||
// Storing serializations in memory would result in increased memory usage,
|
||||
// but it would help for caching encodings for watches started from old
|
||||
// versions. However, we still don't have a convincing data that the gain
|
||||
// from it justifies increased memory usage, so for now we drop the cached
|
||||
// serializations after dispatching this event.
|
||||
//
|
||||
// Given the deep-copies that are done to create cachingObjects,
|
||||
// we try to cache serializations only if there are at least 3 watchers.
|
||||
if len(c.watchersBuffer) >= 3 {
|
||||
// Make a shallow copy to allow overwriting Object and PrevObject.
|
||||
wcEvent := *event
|
||||
setCachingObjects(&wcEvent, c.versioner)
|
||||
event = &wcEvent
|
||||
}
|
||||
|
||||
c.blockedWatchers = c.blockedWatchers[:0]
|
||||
for _, watcher := range c.watchersBuffer {
|
||||
if !watcher.nonblockingAdd(event) {
|
||||
@@ -886,7 +941,10 @@ func (c *Cacher) startDispatchingBookmarkEvents() {
|
||||
// startDispatching chooses watchers potentially interested in a given event
|
||||
// a marks dispatching as true.
|
||||
func (c *Cacher) startDispatching(event *watchCacheEvent) {
|
||||
triggerValues, supported := c.triggerValues(event)
|
||||
// It is safe to call triggerValuesThreadUnsafe here, because at this
|
||||
// point only this thread can access this event (we create a separate
|
||||
// watchCacheEvent for every dispatch).
|
||||
triggerValues, supported := c.triggerValuesThreadUnsafe(event)
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
@@ -1159,7 +1217,7 @@ func (c *cacheWatcher) add(event *watchCacheEvent, timer *time.Timer) bool {
|
||||
// This means that we couldn't send event to that watcher.
|
||||
// Since we don't want to block on it infinitely,
|
||||
// we simply terminate it.
|
||||
klog.V(1).Infof("Forcing watcher close due to unresponsiveness: %v", reflect.TypeOf(event.Object).String())
|
||||
klog.V(1).Infof("Forcing watcher close due to unresponsiveness: %v", c.objectType.String())
|
||||
c.forget()
|
||||
}
|
||||
|
||||
@@ -1187,6 +1245,25 @@ func (c *cacheWatcher) nextBookmarkTime(now time.Time) (time.Time, bool) {
|
||||
return c.deadline.Add(-2 * time.Second), true
|
||||
}
|
||||
|
||||
func getEventObject(object runtime.Object) runtime.Object {
|
||||
if _, ok := object.(runtime.CacheableObject); ok {
|
||||
// It is safe to return without deep-copy, because the underlying
|
||||
// object was already deep-copied during construction.
|
||||
return object
|
||||
}
|
||||
return object.DeepCopyObject()
|
||||
}
|
||||
|
||||
func updateResourceVersionIfNeeded(object runtime.Object, versioner storage.Versioner, resourceVersion uint64) {
|
||||
if _, ok := object.(*cachingObject); ok {
|
||||
// We assume that for cachingObject resourceVersion was already propagated before.
|
||||
return
|
||||
}
|
||||
if err := versioner.UpdateObject(object, resourceVersion); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("failure to version api object (%d) %#v: %v", resourceVersion, object, err))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cacheWatcher) convertToWatchEvent(event *watchCacheEvent) *watch.Event {
|
||||
if event.Type == watch.Bookmark {
|
||||
return &watch.Event{Type: watch.Bookmark, Object: event.Object.DeepCopyObject()}
|
||||
@@ -1204,15 +1281,13 @@ func (c *cacheWatcher) convertToWatchEvent(event *watchCacheEvent) *watch.Event
|
||||
|
||||
switch {
|
||||
case curObjPasses && !oldObjPasses:
|
||||
return &watch.Event{Type: watch.Added, Object: event.Object.DeepCopyObject()}
|
||||
return &watch.Event{Type: watch.Added, Object: getEventObject(event.Object)}
|
||||
case curObjPasses && oldObjPasses:
|
||||
return &watch.Event{Type: watch.Modified, Object: event.Object.DeepCopyObject()}
|
||||
return &watch.Event{Type: watch.Modified, Object: getEventObject(event.Object)}
|
||||
case !curObjPasses && oldObjPasses:
|
||||
// return a delete event with the previous object content, but with the event's resource version
|
||||
oldObj := event.PrevObject.DeepCopyObject()
|
||||
if err := c.versioner.UpdateObject(oldObj, event.ResourceVersion); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("failure to version api object (%d) %#v: %v", event.ResourceVersion, oldObj, err))
|
||||
}
|
||||
oldObj := getEventObject(event.PrevObject)
|
||||
updateResourceVersionIfNeeded(oldObj, c.versioner, event.ResourceVersion)
|
||||
return &watch.Event{Type: watch.Deleted, Object: oldObj}
|
||||
}
|
||||
|
||||
|
||||
397
vendor/k8s.io/apiserver/pkg/storage/cacher/caching_object.go
generated
vendored
Normal file
397
vendor/k8s.io/apiserver/pkg/storage/cacher/caching_object.go
generated
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
Copyright 2019 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 cacher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
var _ runtime.CacheableObject = &cachingObject{}
|
||||
|
||||
// metaRuntimeInterface implements runtime.Object and
|
||||
// metav1.Object interfaces.
|
||||
type metaRuntimeInterface interface {
|
||||
runtime.Object
|
||||
metav1.Object
|
||||
}
|
||||
|
||||
// serializationResult captures a result of serialization.
|
||||
type serializationResult struct {
|
||||
// once should be used to ensure serialization is computed once.
|
||||
once sync.Once
|
||||
|
||||
// raw is serialized object.
|
||||
raw []byte
|
||||
// err is error from serialization.
|
||||
err error
|
||||
}
|
||||
|
||||
// serializationsCache is a type for caching serialization results.
|
||||
type serializationsCache map[runtime.Identifier]*serializationResult
|
||||
|
||||
// cachingObject is an object that is able to cache its serializations
|
||||
// so that each of those is computed exactly once.
|
||||
//
|
||||
// cachingObject implements the metav1.Object interface (accessors for
|
||||
// all metadata fields). However, setters for all fields except from
|
||||
// SelfLink (which is set lately in the path) are ignored.
|
||||
type cachingObject struct {
|
||||
lock sync.RWMutex
|
||||
|
||||
// Object for which serializations are cached.
|
||||
object metaRuntimeInterface
|
||||
|
||||
// serializations is a cache containing object`s serializations.
|
||||
// The value stored in atomic.Value is of type serializationsCache.
|
||||
// The atomic.Value type is used to allow fast-path.
|
||||
serializations atomic.Value
|
||||
}
|
||||
|
||||
// newCachingObject performs a deep copy of the given object and wraps it
|
||||
// into a cachingObject.
|
||||
// An error is returned if it's not possible to cast the object to
|
||||
// metav1.Object type.
|
||||
func newCachingObject(object runtime.Object) (*cachingObject, error) {
|
||||
if obj, ok := object.(metaRuntimeInterface); ok {
|
||||
result := &cachingObject{object: obj.DeepCopyObject().(metaRuntimeInterface)}
|
||||
result.serializations.Store(make(serializationsCache))
|
||||
return result, nil
|
||||
}
|
||||
return nil, fmt.Errorf("can't cast object to metav1.Object: %#v", object)
|
||||
}
|
||||
|
||||
func (o *cachingObject) getSerializationResult(id runtime.Identifier) *serializationResult {
|
||||
// Fast-path for getting from cache.
|
||||
serializations := o.serializations.Load().(serializationsCache)
|
||||
if result, exists := serializations[id]; exists {
|
||||
return result
|
||||
}
|
||||
|
||||
// Slow-path (that may require insert).
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
serializations = o.serializations.Load().(serializationsCache)
|
||||
// Check if in the meantime it wasn't inserted.
|
||||
if result, exists := serializations[id]; exists {
|
||||
return result
|
||||
}
|
||||
|
||||
// Insert an entry for <id>. This requires copy of existing map.
|
||||
newSerializations := make(serializationsCache)
|
||||
for k, v := range serializations {
|
||||
newSerializations[k] = v
|
||||
}
|
||||
result := &serializationResult{}
|
||||
newSerializations[id] = result
|
||||
o.serializations.Store(newSerializations)
|
||||
return result
|
||||
}
|
||||
|
||||
// CacheEncode implements runtime.CacheableObject interface.
|
||||
// It serializes the object and writes the result to given io.Writer trying
|
||||
// to first use the already cached result and falls back to a given encode
|
||||
// function in case of cache miss.
|
||||
// It assumes that for a given identifier, the encode function always encodes
|
||||
// each input object into the same output format.
|
||||
func (o *cachingObject) CacheEncode(id runtime.Identifier, encode func(runtime.Object, io.Writer) error, w io.Writer) error {
|
||||
result := o.getSerializationResult(id)
|
||||
result.once.Do(func() {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
result.err = encode(o.GetObject(), buffer)
|
||||
result.raw = buffer.Bytes()
|
||||
})
|
||||
// Once invoked, fields of serialization will not change.
|
||||
if result.err != nil {
|
||||
return result.err
|
||||
}
|
||||
_, err := w.Write(result.raw)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetObject implements runtime.CacheableObject interface.
|
||||
// It returns deep-copy of the wrapped object to return ownership of it
|
||||
// to the called according to the contract of the interface.
|
||||
func (o *cachingObject) GetObject() runtime.Object {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.DeepCopyObject().(metaRuntimeInterface)
|
||||
}
|
||||
|
||||
// GetObjectKind implements runtime.Object interface.
|
||||
func (o *cachingObject) GetObjectKind() schema.ObjectKind {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetObjectKind()
|
||||
}
|
||||
|
||||
// DeepCopyObject implements runtime.Object interface.
|
||||
func (o *cachingObject) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyObject on cachingObject is not expected to be called anywhere.
|
||||
// However, to be on the safe-side, we implement it, though given the
|
||||
// cache is only an optimization we ignore copying it.
|
||||
result := &cachingObject{}
|
||||
result.serializations.Store(make(serializationsCache))
|
||||
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
result.object = o.object.DeepCopyObject().(metaRuntimeInterface)
|
||||
return result
|
||||
}
|
||||
|
||||
var (
|
||||
invalidationCacheTimestampLock sync.Mutex
|
||||
invalidationCacheTimestamp time.Time
|
||||
)
|
||||
|
||||
// shouldLogCacheInvalidation allows for logging cache-invalidation
|
||||
// at most once per second (to avoid spamming logs in case of issues).
|
||||
func shouldLogCacheInvalidation(now time.Time) bool {
|
||||
invalidationCacheTimestampLock.Lock()
|
||||
defer invalidationCacheTimestampLock.Unlock()
|
||||
if invalidationCacheTimestamp.Add(time.Second).Before(now) {
|
||||
invalidationCacheTimestamp = now
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *cachingObject) invalidateCacheLocked() {
|
||||
if cache, ok := o.serializations.Load().(serializationsCache); ok && len(cache) == 0 {
|
||||
return
|
||||
}
|
||||
// We don't expect cache invalidation to happen - so we want
|
||||
// to log the stacktrace to allow debugging if that will happen.
|
||||
// OTOH, we don't want to spam logs with it.
|
||||
// So we try to log it at most once per second.
|
||||
if shouldLogCacheInvalidation(time.Now()) {
|
||||
klog.Warningf("Unexpected cache invalidation for %#v\n%s", o.object, string(debug.Stack()))
|
||||
}
|
||||
o.serializations.Store(make(serializationsCache))
|
||||
}
|
||||
|
||||
// The following functions implement metav1.Object interface:
|
||||
// - getters simply delegate for the underlying object
|
||||
// - setters check if operations isn't noop and if so,
|
||||
// invalidate the cache and delegate for the underlying object
|
||||
|
||||
func (o *cachingObject) conditionalSet(isNoop func() bool, set func()) {
|
||||
if fastPath := func() bool {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return isNoop()
|
||||
}(); fastPath {
|
||||
return
|
||||
}
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
if isNoop() {
|
||||
return
|
||||
}
|
||||
o.invalidateCacheLocked()
|
||||
set()
|
||||
}
|
||||
|
||||
func (o *cachingObject) GetNamespace() string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetNamespace()
|
||||
}
|
||||
func (o *cachingObject) SetNamespace(namespace string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetNamespace() == namespace },
|
||||
func() { o.object.SetNamespace(namespace) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetName() string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetName()
|
||||
}
|
||||
func (o *cachingObject) SetName(name string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetName() == name },
|
||||
func() { o.object.SetName(name) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetGenerateName() string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetGenerateName()
|
||||
}
|
||||
func (o *cachingObject) SetGenerateName(name string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetGenerateName() == name },
|
||||
func() { o.object.SetGenerateName(name) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetUID() types.UID {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetUID()
|
||||
}
|
||||
func (o *cachingObject) SetUID(uid types.UID) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetUID() == uid },
|
||||
func() { o.object.SetUID(uid) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetResourceVersion() string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetResourceVersion()
|
||||
}
|
||||
func (o *cachingObject) SetResourceVersion(version string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetResourceVersion() == version },
|
||||
func() { o.object.SetResourceVersion(version) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetGeneration() int64 {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetGeneration()
|
||||
}
|
||||
func (o *cachingObject) SetGeneration(generation int64) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetGeneration() == generation },
|
||||
func() { o.object.SetGeneration(generation) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetSelfLink() string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetSelfLink()
|
||||
}
|
||||
func (o *cachingObject) SetSelfLink(selfLink string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetSelfLink() == selfLink },
|
||||
func() { o.object.SetSelfLink(selfLink) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetCreationTimestamp() metav1.Time {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetCreationTimestamp()
|
||||
}
|
||||
func (o *cachingObject) SetCreationTimestamp(timestamp metav1.Time) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetCreationTimestamp() == timestamp },
|
||||
func() { o.object.SetCreationTimestamp(timestamp) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetDeletionTimestamp() *metav1.Time {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetDeletionTimestamp()
|
||||
}
|
||||
func (o *cachingObject) SetDeletionTimestamp(timestamp *metav1.Time) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetDeletionTimestamp() == timestamp },
|
||||
func() { o.object.SetDeletionTimestamp(timestamp) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetDeletionGracePeriodSeconds() *int64 {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetDeletionGracePeriodSeconds()
|
||||
}
|
||||
func (o *cachingObject) SetDeletionGracePeriodSeconds(gracePeriodSeconds *int64) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetDeletionGracePeriodSeconds() == gracePeriodSeconds },
|
||||
func() { o.object.SetDeletionGracePeriodSeconds(gracePeriodSeconds) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetLabels() map[string]string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetLabels()
|
||||
}
|
||||
func (o *cachingObject) SetLabels(labels map[string]string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return reflect.DeepEqual(o.object.GetLabels(), labels) },
|
||||
func() { o.object.SetLabels(labels) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetAnnotations() map[string]string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetAnnotations()
|
||||
}
|
||||
func (o *cachingObject) SetAnnotations(annotations map[string]string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return reflect.DeepEqual(o.object.GetAnnotations(), annotations) },
|
||||
func() { o.object.SetAnnotations(annotations) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetFinalizers() []string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetFinalizers()
|
||||
}
|
||||
func (o *cachingObject) SetFinalizers(finalizers []string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return reflect.DeepEqual(o.object.GetFinalizers(), finalizers) },
|
||||
func() { o.object.SetFinalizers(finalizers) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetOwnerReferences() []metav1.OwnerReference {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetOwnerReferences()
|
||||
}
|
||||
func (o *cachingObject) SetOwnerReferences(references []metav1.OwnerReference) {
|
||||
o.conditionalSet(
|
||||
func() bool { return reflect.DeepEqual(o.object.GetOwnerReferences(), references) },
|
||||
func() { o.object.SetOwnerReferences(references) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetClusterName() string {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetClusterName()
|
||||
}
|
||||
func (o *cachingObject) SetClusterName(clusterName string) {
|
||||
o.conditionalSet(
|
||||
func() bool { return o.object.GetClusterName() == clusterName },
|
||||
func() { o.object.SetClusterName(clusterName) },
|
||||
)
|
||||
}
|
||||
func (o *cachingObject) GetManagedFields() []metav1.ManagedFieldsEntry {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
return o.object.GetManagedFields()
|
||||
}
|
||||
func (o *cachingObject) SetManagedFields(managedFields []metav1.ManagedFieldsEntry) {
|
||||
o.conditionalSet(
|
||||
func() bool { return reflect.DeepEqual(o.object.GetManagedFields(), managedFields) },
|
||||
func() { o.object.SetManagedFields(managedFields) },
|
||||
)
|
||||
}
|
||||
22
vendor/k8s.io/apiserver/pkg/storage/cacher/watch_cache.go
generated
vendored
22
vendor/k8s.io/apiserver/pkg/storage/cacher/watch_cache.go
generated
vendored
@@ -40,6 +40,10 @@ const (
|
||||
// before terminating request and returning Timeout error with retry
|
||||
// after suggestion.
|
||||
blockTimeout = 3 * time.Second
|
||||
|
||||
// resourceVersionTooHighRetrySeconds is the seconds before a operation should be retried by the client
|
||||
// after receiving a 'too high resource version' error.
|
||||
resourceVersionTooHighRetrySeconds = 1
|
||||
)
|
||||
|
||||
// watchCacheEvent is a single "watch event" that is send to users of
|
||||
@@ -219,7 +223,7 @@ func (w *watchCache) processEvent(event watch.Event, resourceVersion uint64, upd
|
||||
return err
|
||||
}
|
||||
|
||||
watchCacheEvent := &watchCacheEvent{
|
||||
wcEvent := &watchCacheEvent{
|
||||
Type: event.Type,
|
||||
Object: elem.Object,
|
||||
ObjLabels: elem.Labels,
|
||||
@@ -242,12 +246,12 @@ func (w *watchCache) processEvent(event watch.Event, resourceVersion uint64, upd
|
||||
}
|
||||
if exists {
|
||||
previousElem := previous.(*storeElement)
|
||||
watchCacheEvent.PrevObject = previousElem.Object
|
||||
watchCacheEvent.PrevObjLabels = previousElem.Labels
|
||||
watchCacheEvent.PrevObjFields = previousElem.Fields
|
||||
wcEvent.PrevObject = previousElem.Object
|
||||
wcEvent.PrevObjLabels = previousElem.Labels
|
||||
wcEvent.PrevObjFields = previousElem.Fields
|
||||
}
|
||||
|
||||
w.updateCache(watchCacheEvent)
|
||||
w.updateCache(wcEvent)
|
||||
w.resourceVersion = resourceVersion
|
||||
defer w.cond.Broadcast()
|
||||
|
||||
@@ -260,7 +264,7 @@ func (w *watchCache) processEvent(event watch.Event, resourceVersion uint64, upd
|
||||
// This is safe as long as there is at most one call to processEvent in flight
|
||||
// at any point in time.
|
||||
if w.eventHandler != nil {
|
||||
w.eventHandler(watchCacheEvent)
|
||||
w.eventHandler(wcEvent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -303,8 +307,8 @@ func (w *watchCache) waitUntilFreshAndBlock(resourceVersion uint64, trace *utilt
|
||||
}
|
||||
for w.resourceVersion < resourceVersion {
|
||||
if w.clock.Since(startTime) >= blockTimeout {
|
||||
// Timeout with retry after 1 second.
|
||||
return errors.NewTimeoutError(fmt.Sprintf("Too large resource version: %v, current: %v", resourceVersion, w.resourceVersion), 1)
|
||||
// Request that the client retry after 'resourceVersionTooHighRetrySeconds' seconds.
|
||||
return storage.NewTooLargeResourceVersionError(resourceVersion, w.resourceVersion, resourceVersionTooHighRetrySeconds)
|
||||
}
|
||||
w.cond.Wait()
|
||||
}
|
||||
@@ -464,7 +468,7 @@ func (w *watchCache) GetAllEventsSinceThreadUnsafe(resourceVersion uint64) ([]*w
|
||||
return result, nil
|
||||
}
|
||||
if resourceVersion < oldest-1 {
|
||||
return nil, errors.NewGone(fmt.Sprintf("too old resource version: %d (%d)", resourceVersion, oldest-1))
|
||||
return nil, errors.NewResourceExpired(fmt.Sprintf("too old resource version: %d (%d)", resourceVersion, oldest-1))
|
||||
}
|
||||
|
||||
// Binary search the smallest index at which resourceVersion is greater than the given one.
|
||||
|
||||
30
vendor/k8s.io/apiserver/pkg/storage/errors.go
generated
vendored
30
vendor/k8s.io/apiserver/pkg/storage/errors.go
generated
vendored
@@ -19,6 +19,8 @@ package storage
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
@@ -168,3 +170,31 @@ func NewInternalError(reason string) InternalError {
|
||||
func NewInternalErrorf(format string, a ...interface{}) InternalError {
|
||||
return InternalError{fmt.Sprintf(format, a...)}
|
||||
}
|
||||
|
||||
var tooLargeResourceVersionCauseMsg = "Too large resource version"
|
||||
|
||||
// NewTooLargeResourceVersionError returns a timeout error with the given retrySeconds for a request for
|
||||
// a minimum resource version that is larger than the largest currently available resource version for a requested resource.
|
||||
func NewTooLargeResourceVersionError(minimumResourceVersion, currentRevision uint64, retrySeconds int) error {
|
||||
err := errors.NewTimeoutError(fmt.Sprintf("Too large resource version: %d, current: %d", minimumResourceVersion, currentRevision), retrySeconds)
|
||||
err.ErrStatus.Details.Causes = []metav1.StatusCause{{Message: tooLargeResourceVersionCauseMsg}}
|
||||
return err
|
||||
}
|
||||
|
||||
// IsTooLargeResourceVersion returns true if the error is a TooLargeResourceVersion error.
|
||||
func IsTooLargeResourceVersion(err error) bool {
|
||||
if !errors.IsTimeout(err) {
|
||||
return false
|
||||
}
|
||||
switch t := err.(type) {
|
||||
case errors.APIStatus:
|
||||
if d := t.Status().Details; d != nil {
|
||||
for _, cause := range d.Causes {
|
||||
if cause.Message == tooLargeResourceVersionCauseMsg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/compact.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/compact.go
generated
vendored
@@ -22,7 +22,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/errors.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/errors.go
generated
vendored
@@ -19,7 +19,7 @@ package etcd3
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
etcdrpc "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
|
||||
etcdrpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
|
||||
4
vendor/k8s.io/apiserver/pkg/storage/etcd3/event.go
generated
vendored
4
vendor/k8s.io/apiserver/pkg/storage/etcd3/event.go
generated
vendored
@@ -18,8 +18,8 @@ package etcd3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/mvcc/mvccpb"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"go.etcd.io/etcd/mvcc/mvccpb"
|
||||
)
|
||||
|
||||
type event struct {
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/lease_manager.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/lease_manager.go
generated
vendored
@@ -21,7 +21,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
)
|
||||
|
||||
// leaseManager is used to manage leases requested from etcd. If a new write
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/logger.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/logger.go
generated
vendored
@@ -19,7 +19,7 @@ package etcd3
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
|
||||
7
vendor/k8s.io/apiserver/pkg/storage/etcd3/metrics/metrics.go
generated
vendored
7
vendor/k8s.io/apiserver/pkg/storage/etcd3/metrics/metrics.go
generated
vendored
@@ -52,9 +52,10 @@ var (
|
||||
|
||||
deprecatedEtcdRequestLatenciesSummary = compbasemetrics.NewSummaryVec(
|
||||
&compbasemetrics.SummaryOpts{
|
||||
Name: "etcd_request_latencies_summary",
|
||||
Help: "(Deprecated) Etcd request latency summary in microseconds for each operation and object type.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
Name: "etcd_request_latencies_summary",
|
||||
Help: "Etcd request latency summary in microseconds for each operation and object type.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
DeprecatedVersion: "1.14.0",
|
||||
},
|
||||
[]string{"operation", "type"},
|
||||
)
|
||||
|
||||
42
vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go
generated
vendored
42
vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go
generated
vendored
@@ -28,8 +28,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"k8s.io/klog"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
@@ -41,6 +40,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/storage/etcd3/metrics"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/klog"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
@@ -119,6 +119,9 @@ func (s *store) Get(ctx context.Context, key string, resourceVersion string, out
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = s.ensureMinimumResourceVersion(resourceVersion, uint64(getResp.Header.Revision)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(getResp.Kvs) == 0 {
|
||||
if ignoreNotFound {
|
||||
@@ -398,6 +401,9 @@ func (s *store) GetToList(ctx context.Context, key string, resourceVersion strin
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = s.ensureMinimumResourceVersion(resourceVersion, uint64(getResp.Header.Revision)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(getResp.Kvs) > 0 {
|
||||
data, _, err := s.transformer.TransformFromStorage(getResp.Kvs[0].Value, authenticatedDataString(key))
|
||||
@@ -559,17 +565,6 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
|
||||
options = append(options, clientv3.WithRange(rangeEnd))
|
||||
|
||||
default:
|
||||
if len(resourceVersion) > 0 {
|
||||
fromRV, err := s.versioner.ParseResourceVersion(resourceVersion)
|
||||
if err != nil {
|
||||
return apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %v", err))
|
||||
}
|
||||
if fromRV > 0 {
|
||||
options = append(options, clientv3.WithRev(int64(fromRV)))
|
||||
}
|
||||
returnedRV = int64(fromRV)
|
||||
}
|
||||
|
||||
options = append(options, clientv3.WithPrefix())
|
||||
}
|
||||
|
||||
@@ -584,6 +579,9 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
|
||||
if err != nil {
|
||||
return interpretListError(err, len(pred.Continue) > 0, continueKey, keyPrefix)
|
||||
}
|
||||
if err = s.ensureMinimumResourceVersion(resourceVersion, uint64(getResp.Header.Revision)); err != nil {
|
||||
return err
|
||||
}
|
||||
hasMore = getResp.More
|
||||
|
||||
if len(getResp.Kvs) == 0 && getResp.More {
|
||||
@@ -798,6 +796,24 @@ func (s *store) ttlOpts(ctx context.Context, ttl int64) ([]clientv3.OpOption, er
|
||||
return []clientv3.OpOption{clientv3.WithLease(id)}, nil
|
||||
}
|
||||
|
||||
// ensureMinimumResourceVersion returns a 'too large resource' version error when the provided minimumResourceVersion is
|
||||
// greater than the most recent actualRevision available from storage.
|
||||
func (s *store) ensureMinimumResourceVersion(minimumResourceVersion string, actualRevision uint64) error {
|
||||
if minimumResourceVersion == "" {
|
||||
return nil
|
||||
}
|
||||
minimumRV, err := s.versioner.ParseResourceVersion(minimumResourceVersion)
|
||||
if err != nil {
|
||||
return apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %v", err))
|
||||
}
|
||||
// Enforce the storage.Interface guarantee that the resource version of the returned data
|
||||
// "will be at least 'resourceVersion'".
|
||||
if minimumRV > actualRevision {
|
||||
return storage.NewTooLargeResourceVersionError(minimumRV, actualRevision, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// decode decodes value of bytes into object. It will also set the object resource version to rev.
|
||||
// On success, objPtr would be set to the object.
|
||||
func decode(codec runtime.Codec, versioner storage.Versioner, value []byte, objPtr runtime.Object, rev int64) error {
|
||||
|
||||
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/watcher.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/watcher.go
generated
vendored
@@ -31,7 +31,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
|
||||
6
vendor/k8s.io/apiserver/pkg/storage/storagebackend/config.go
generated
vendored
6
vendor/k8s.io/apiserver/pkg/storage/storagebackend/config.go
generated
vendored
@@ -36,9 +36,9 @@ type TransportConfig struct {
|
||||
// ServerList is the list of storage servers to connect with.
|
||||
ServerList []string
|
||||
// TLS credentials
|
||||
KeyFile string
|
||||
CertFile string
|
||||
CAFile string
|
||||
KeyFile string
|
||||
CertFile string
|
||||
TrustedCAFile string
|
||||
// function to determine the egress dialer. (i.e. konnectivity server dialer)
|
||||
EgressLookup egressselector.Lookup
|
||||
}
|
||||
|
||||
16
vendor/k8s.io/apiserver/pkg/storage/storagebackend/factory/etcd3.go
generated
vendored
16
vendor/k8s.io/apiserver/pkg/storage/storagebackend/factory/etcd3.go
generated
vendored
@@ -26,9 +26,9 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/pkg/transport"
|
||||
grpcprom "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"go.etcd.io/etcd/pkg/transport"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
@@ -86,8 +86,8 @@ func newETCD3HealthCheck(c storagebackend.Config) (func() error, error) {
|
||||
client := clientValue.Load().(*clientv3.Client)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
// See https://github.com/etcd-io/etcd/blob/master/etcdctl/ctlv3/command/ep_command.go#L118
|
||||
_, err := client.Get(ctx, path.Join(c.Prefix, "health"))
|
||||
// See https://github.com/etcd-io/etcd/blob/c57f8b3af865d1b531b979889c602ba14377420e/etcdctl/ctlv3/command/ep_command.go#L118
|
||||
_, err := client.Get(ctx, path.Join("/", c.Prefix, "health"))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -97,9 +97,9 @@ func newETCD3HealthCheck(c storagebackend.Config) (func() error, error) {
|
||||
|
||||
func newETCD3Client(c storagebackend.TransportConfig) (*clientv3.Client, error) {
|
||||
tlsInfo := transport.TLSInfo{
|
||||
CertFile: c.CertFile,
|
||||
KeyFile: c.KeyFile,
|
||||
CAFile: c.CAFile,
|
||||
CertFile: c.CertFile,
|
||||
KeyFile: c.KeyFile,
|
||||
TrustedCAFile: c.TrustedCAFile,
|
||||
}
|
||||
tlsConfig, err := tlsInfo.ClientConfig()
|
||||
if err != nil {
|
||||
@@ -107,7 +107,7 @@ func newETCD3Client(c storagebackend.TransportConfig) (*clientv3.Client, error)
|
||||
}
|
||||
// NOTE: Client relies on nil tlsConfig
|
||||
// for non-secure connections, update the implicit variable
|
||||
if len(c.CertFile) == 0 && len(c.KeyFile) == 0 && len(c.CAFile) == 0 {
|
||||
if len(c.CertFile) == 0 && len(c.KeyFile) == 0 && len(c.TrustedCAFile) == 0 {
|
||||
tlsConfig = nil
|
||||
}
|
||||
networkContext := egressselector.Etcd.AsNetworkContext()
|
||||
|
||||
9
vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/envelope.go
generated
vendored
9
vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/envelope.go
generated
vendored
@@ -94,13 +94,17 @@ func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Co
|
||||
value.RecordCacheMiss()
|
||||
key, err := t.envelopeService.Decrypt(encKey)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error while decrypting key: %q", err)
|
||||
// Do NOT wrap this err using fmt.Errorf() or similar functions
|
||||
// because this gRPC status error has useful error code when
|
||||
// record the metric.
|
||||
return nil, false, err
|
||||
}
|
||||
transformer, err = t.addTransformer(encKey, key)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return transformer.TransformFromStorage(encData, context)
|
||||
}
|
||||
|
||||
@@ -113,6 +117,9 @@ func (t *envelopeTransformer) TransformToStorage(data []byte, context value.Cont
|
||||
|
||||
encKey, err := t.envelopeService.Encrypt(newKey)
|
||||
if err != nil {
|
||||
// Do NOT wrap this err using fmt.Errorf() or similar functions
|
||||
// because this gRPC status error has useful error code when
|
||||
// record the metric.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
62
vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go
generated
vendored
62
vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/grpc_service.go
generated
vendored
@@ -61,28 +61,31 @@ func NewGRPCService(endpoint string, callTimeout time.Duration) (Service, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
connection, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.FailFast(false)), grpc.WithDialer(
|
||||
func(string, time.Duration) (net.Conn, error) {
|
||||
// Ignoring addr and timeout arguments:
|
||||
// addr - comes from the closure
|
||||
// timeout - is ignored since we are connecting in a non-blocking configuration
|
||||
c, err := net.DialTimeout(unixProtocol, addr, 0)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to create connection to unix socket: %s, error: %v", addr, err)
|
||||
}
|
||||
return c, err
|
||||
}))
|
||||
s := &gRPCService{callTimeout: callTimeout}
|
||||
s.connection, err = grpc.Dial(
|
||||
addr,
|
||||
grpc.WithInsecure(),
|
||||
grpc.WithUnaryInterceptor(s.interceptor),
|
||||
grpc.WithDefaultCallOptions(grpc.WaitForReady(true)),
|
||||
grpc.WithContextDialer(
|
||||
func(context.Context, string) (net.Conn, error) {
|
||||
// Ignoring addr and timeout arguments:
|
||||
// addr - comes from the closure
|
||||
c, err := net.DialUnix(unixProtocol, nil, &net.UnixAddr{Name: addr})
|
||||
if err != nil {
|
||||
klog.Errorf("failed to create connection to unix socket: %s, error: %v", addr, err)
|
||||
} else {
|
||||
klog.V(4).Infof("Successfully dialed Unix socket %v", addr)
|
||||
}
|
||||
return c, err
|
||||
}))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create connection to %s, error: %v", endpoint, err)
|
||||
}
|
||||
|
||||
kmsClient := kmsapi.NewKeyManagementServiceClient(connection)
|
||||
return &gRPCService{
|
||||
kmsClient: kmsClient,
|
||||
connection: connection,
|
||||
callTimeout: callTimeout,
|
||||
}, nil
|
||||
s.kmsClient = kmsapi.NewKeyManagementServiceClient(s.connection)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Parse the endpoint to extract schema, host or path.
|
||||
@@ -138,10 +141,6 @@ func (g *gRPCService) Decrypt(cipher []byte) ([]byte, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), g.callTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := g.checkAPIVersion(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request := &kmsapi.DecryptRequest{Cipher: cipher, Version: kmsapiVersion}
|
||||
response, err := g.kmsClient.Decrypt(ctx, request)
|
||||
if err != nil {
|
||||
@@ -154,9 +153,6 @@ func (g *gRPCService) Decrypt(cipher []byte) ([]byte, error) {
|
||||
func (g *gRPCService) Encrypt(plain []byte) ([]byte, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), g.callTimeout)
|
||||
defer cancel()
|
||||
if err := g.checkAPIVersion(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request := &kmsapi.EncryptRequest{Plain: plain, Version: kmsapiVersion}
|
||||
response, err := g.kmsClient.Encrypt(ctx, request)
|
||||
@@ -165,3 +161,21 @@ func (g *gRPCService) Encrypt(plain []byte) ([]byte, error) {
|
||||
}
|
||||
return response.Cipher, nil
|
||||
}
|
||||
|
||||
func (g *gRPCService) interceptor(
|
||||
ctx context.Context,
|
||||
method string,
|
||||
req interface{},
|
||||
reply interface{},
|
||||
cc *grpc.ClientConn,
|
||||
invoker grpc.UnaryInvoker,
|
||||
opts ...grpc.CallOption,
|
||||
) error {
|
||||
if !kmsapi.IsVersionCheckMethod(method) {
|
||||
if err := g.checkAPIVersion(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return invoker(ctx, method, req, reply, cc, opts...)
|
||||
}
|
||||
|
||||
23
vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/v1beta1.go
generated
vendored
Normal file
23
vendor/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/v1beta1/v1beta1.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2019 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 v1beta1 contains definition of kms-plugin's gRPC service.
|
||||
package v1beta1
|
||||
|
||||
// IsVersionCheckMethod determines whether the supplied method is a version check against kms-plugin.
|
||||
func IsVersionCheckMethod(method string) bool {
|
||||
return method == "/v1beta1.KeyManagementService/Version"
|
||||
}
|
||||
36
vendor/k8s.io/apiserver/pkg/storage/value/metrics.go
generated
vendored
36
vendor/k8s.io/apiserver/pkg/storage/value/metrics.go
generated
vendored
@@ -20,7 +20,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"k8s.io/component-base/metrics"
|
||||
@@ -49,7 +48,7 @@ var (
|
||||
Help: "Latencies in seconds of value transformation operations.",
|
||||
// In-process transformations (ex. AES CBC) complete on the order of 20 microseconds. However, when
|
||||
// external KMS is involved latencies may climb into milliseconds.
|
||||
Buckets: prometheus.ExponentialBuckets(5e-6, 2, 14),
|
||||
Buckets: metrics.ExponentialBuckets(5e-6, 2, 14),
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"transformation_type"},
|
||||
@@ -59,11 +58,12 @@ var (
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "transformation_latencies_microseconds",
|
||||
Help: "(Deprecated) Latencies in microseconds of value transformation operations.",
|
||||
Help: "Latencies in microseconds of value transformation operations.",
|
||||
// In-process transformations (ex. AES CBC) complete on the order of 20 microseconds. However, when
|
||||
// external KMS is involved latencies may climb into milliseconds.
|
||||
Buckets: prometheus.ExponentialBuckets(5, 2, 14),
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
Buckets: metrics.ExponentialBuckets(5, 2, 14),
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
DeprecatedVersion: "1.14.0",
|
||||
},
|
||||
[]string{"transformation_type"},
|
||||
)
|
||||
@@ -81,11 +81,12 @@ var (
|
||||
|
||||
deprecatedTransformerFailuresTotal = metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "transformation_failures_total",
|
||||
Help: "(Deprecated) Total number of failed transformation operations.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "transformation_failures_total",
|
||||
Help: "Total number of failed transformation operations.",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
DeprecatedVersion: "1.15.0",
|
||||
},
|
||||
[]string{"transformation_type"},
|
||||
)
|
||||
@@ -106,18 +107,19 @@ var (
|
||||
Subsystem: subsystem,
|
||||
Name: "data_key_generation_duration_seconds",
|
||||
Help: "Latencies in seconds of data encryption key(DEK) generation operations.",
|
||||
Buckets: prometheus.ExponentialBuckets(5e-6, 2, 14),
|
||||
Buckets: metrics.ExponentialBuckets(5e-6, 2, 14),
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
)
|
||||
deprecatedDataKeyGenerationLatencies = metrics.NewHistogram(
|
||||
&metrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "data_key_generation_latencies_microseconds",
|
||||
Help: "(Deprecated) Latencies in microseconds of data encryption key(DEK) generation operations.",
|
||||
Buckets: prometheus.ExponentialBuckets(5, 2, 14),
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "data_key_generation_latencies_microseconds",
|
||||
Help: "Latencies in microseconds of data encryption key(DEK) generation operations.",
|
||||
Buckets: metrics.ExponentialBuckets(5, 2, 14),
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
DeprecatedVersion: "1.14.0",
|
||||
},
|
||||
)
|
||||
dataKeyGenerationFailuresTotal = metrics.NewCounter(
|
||||
|
||||
Reference in New Issue
Block a user