mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
Migrate from snapClient.VolumesnapshotV1alpha1Client to
snapClient.SnapshotV1alpha1Client and also update kube dependency Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
committed by
mergify[bot]
parent
3bc6771df8
commit
22ff5c0911
272
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/cache_based_manager.go
generated
vendored
Normal file
272
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/cache_based_manager.go
generated
vendored
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
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 manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
storageetcd "k8s.io/apiserver/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// GetObjectTTLFunc defines a function to get value of TTL.
|
||||
type GetObjectTTLFunc func() (time.Duration, bool)
|
||||
|
||||
// GetObjectFunc defines a function to get object with a given namespace and name.
|
||||
type GetObjectFunc func(string, string, metav1.GetOptions) (runtime.Object, error)
|
||||
|
||||
type objectKey struct {
|
||||
namespace string
|
||||
name string
|
||||
}
|
||||
|
||||
// objectStoreItems is a single item stored in objectStore.
|
||||
type objectStoreItem struct {
|
||||
refCount int
|
||||
data *objectData
|
||||
}
|
||||
|
||||
type objectData struct {
|
||||
sync.Mutex
|
||||
|
||||
object runtime.Object
|
||||
err error
|
||||
lastUpdateTime time.Time
|
||||
}
|
||||
|
||||
// objectStore is a local cache of objects.
|
||||
type objectStore struct {
|
||||
getObject GetObjectFunc
|
||||
clock clock.Clock
|
||||
|
||||
lock sync.Mutex
|
||||
items map[objectKey]*objectStoreItem
|
||||
|
||||
defaultTTL time.Duration
|
||||
getTTL GetObjectTTLFunc
|
||||
}
|
||||
|
||||
// NewObjectStore returns a new ttl-based instance of Store interface.
|
||||
func NewObjectStore(getObject GetObjectFunc, clock clock.Clock, getTTL GetObjectTTLFunc, ttl time.Duration) Store {
|
||||
return &objectStore{
|
||||
getObject: getObject,
|
||||
clock: clock,
|
||||
items: make(map[objectKey]*objectStoreItem),
|
||||
defaultTTL: ttl,
|
||||
getTTL: getTTL,
|
||||
}
|
||||
}
|
||||
|
||||
func isObjectOlder(newObject, oldObject runtime.Object) bool {
|
||||
if newObject == nil || oldObject == nil {
|
||||
return false
|
||||
}
|
||||
newVersion, _ := storageetcd.Versioner.ObjectResourceVersion(newObject)
|
||||
oldVersion, _ := storageetcd.Versioner.ObjectResourceVersion(oldObject)
|
||||
return newVersion < oldVersion
|
||||
}
|
||||
|
||||
func (s *objectStore) AddReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
// AddReference is called from RegisterPod, thus it needs to be efficient.
|
||||
// Thus Add() is only increasing refCount and generation of a given object.
|
||||
// Then Get() is responsible for fetching if needed.
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
item, exists := s.items[key]
|
||||
if !exists {
|
||||
item = &objectStoreItem{
|
||||
refCount: 0,
|
||||
data: &objectData{},
|
||||
}
|
||||
s.items[key] = item
|
||||
}
|
||||
|
||||
item.refCount++
|
||||
// This will trigger fetch on the next Get() operation.
|
||||
item.data = nil
|
||||
}
|
||||
|
||||
func (s *objectStore) DeleteReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
if item, ok := s.items[key]; ok {
|
||||
item.refCount--
|
||||
if item.refCount == 0 {
|
||||
delete(s.items, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetObjectTTLFromNodeFunc returns a function that returns TTL value
|
||||
// from a given Node object.
|
||||
func GetObjectTTLFromNodeFunc(getNode func() (*v1.Node, error)) GetObjectTTLFunc {
|
||||
return func() (time.Duration, bool) {
|
||||
node, err := getNode()
|
||||
if err != nil {
|
||||
return time.Duration(0), false
|
||||
}
|
||||
if node != nil && node.Annotations != nil {
|
||||
if value, ok := node.Annotations[v1.ObjectTTLAnnotationKey]; ok {
|
||||
if intValue, err := strconv.Atoi(value); err == nil {
|
||||
return time.Duration(intValue) * time.Second, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return time.Duration(0), false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *objectStore) isObjectFresh(data *objectData) bool {
|
||||
objectTTL := s.defaultTTL
|
||||
if ttl, ok := s.getTTL(); ok {
|
||||
objectTTL = ttl
|
||||
}
|
||||
return s.clock.Now().Before(data.lastUpdateTime.Add(objectTTL))
|
||||
}
|
||||
|
||||
func (s *objectStore) Get(namespace, name string) (runtime.Object, error) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
data := func() *objectData {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
item, exists := s.items[key]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if item.data == nil {
|
||||
item.data = &objectData{}
|
||||
}
|
||||
return item.data
|
||||
}()
|
||||
if data == nil {
|
||||
return nil, fmt.Errorf("object %q/%q not registered", namespace, name)
|
||||
}
|
||||
|
||||
// After updating data in objectStore, lock the data, fetch object if
|
||||
// needed and return data.
|
||||
data.Lock()
|
||||
defer data.Unlock()
|
||||
if data.err != nil || !s.isObjectFresh(data) {
|
||||
opts := metav1.GetOptions{}
|
||||
if data.object != nil && data.err == nil {
|
||||
// This is just a periodic refresh of an object we successfully fetched previously.
|
||||
// In this case, server data from apiserver cache to reduce the load on both
|
||||
// etcd and apiserver (the cache is eventually consistent).
|
||||
util.FromApiserverCache(&opts)
|
||||
}
|
||||
|
||||
object, err := s.getObject(namespace, name, opts)
|
||||
if err != nil && !apierrors.IsNotFound(err) && data.object == nil && data.err == nil {
|
||||
// Couldn't fetch the latest object, but there is no cached data to return.
|
||||
// Return the fetch result instead.
|
||||
return object, err
|
||||
}
|
||||
if (err == nil && !isObjectOlder(object, data.object)) || apierrors.IsNotFound(err) {
|
||||
// If the fetch succeeded with a newer version of the object, or if the
|
||||
// object could not be found in the apiserver, update the cached data to
|
||||
// reflect the current status.
|
||||
data.object = object
|
||||
data.err = err
|
||||
data.lastUpdateTime = s.clock.Now()
|
||||
}
|
||||
}
|
||||
return data.object, data.err
|
||||
}
|
||||
|
||||
// cacheBasedManager keeps a store with objects necessary
|
||||
// for registered pods. Different implementations of the store
|
||||
// may result in different semantics for freshness of objects
|
||||
// (e.g. ttl-based implementation vs watch-based implementation).
|
||||
type cacheBasedManager struct {
|
||||
objectStore Store
|
||||
getReferencedObjects func(*v1.Pod) sets.String
|
||||
|
||||
lock sync.Mutex
|
||||
registeredPods map[objectKey]*v1.Pod
|
||||
}
|
||||
|
||||
func (c *cacheBasedManager) GetObject(namespace, name string) (runtime.Object, error) {
|
||||
return c.objectStore.Get(namespace, name)
|
||||
}
|
||||
|
||||
func (c *cacheBasedManager) RegisterPod(pod *v1.Pod) {
|
||||
names := c.getReferencedObjects(pod)
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
for name := range names {
|
||||
c.objectStore.AddReference(pod.Namespace, name)
|
||||
}
|
||||
var prev *v1.Pod
|
||||
key := objectKey{namespace: pod.Namespace, name: pod.Name}
|
||||
prev = c.registeredPods[key]
|
||||
c.registeredPods[key] = pod
|
||||
if prev != nil {
|
||||
for name := range c.getReferencedObjects(prev) {
|
||||
// On an update, the .Add() call above will have re-incremented the
|
||||
// ref count of any existing object, so any objects that are in both
|
||||
// names and prev need to have their ref counts decremented. Any that
|
||||
// are only in prev need to be completely removed. This unconditional
|
||||
// call takes care of both cases.
|
||||
c.objectStore.DeleteReference(prev.Namespace, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cacheBasedManager) UnregisterPod(pod *v1.Pod) {
|
||||
var prev *v1.Pod
|
||||
key := objectKey{namespace: pod.Namespace, name: pod.Name}
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
prev = c.registeredPods[key]
|
||||
delete(c.registeredPods, key)
|
||||
if prev != nil {
|
||||
for name := range c.getReferencedObjects(prev) {
|
||||
c.objectStore.DeleteReference(prev.Namespace, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewCacheBasedManager creates a manager that keeps a cache of all objects
|
||||
// necessary for registered pods.
|
||||
// It implements the following logic:
|
||||
// - whenever a pod is created or updated, the cached versions of all objects
|
||||
// is referencing are invalidated
|
||||
// - every GetObject() call tries to fetch the value from local cache; if it is
|
||||
// not there, invalidated or too old, we fetch it from apiserver and refresh the
|
||||
// value in cache; otherwise it is just fetched from cache
|
||||
func NewCacheBasedManager(objectStore Store, getReferencedObjects func(*v1.Pod) sets.String) Manager {
|
||||
return &cacheBasedManager{
|
||||
objectStore: objectStore,
|
||||
getReferencedObjects: getReferencedObjects,
|
||||
registeredPods: make(map[objectKey]*v1.Pod),
|
||||
}
|
||||
}
|
60
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/manager.go
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/manager.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
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 manager
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Manager is the interface for registering and unregistering
|
||||
// objects referenced by pods in the underlying cache and
|
||||
// extracting those from that cache if needed.
|
||||
type Manager interface {
|
||||
// Get object by its namespace and name.
|
||||
GetObject(namespace, name string) (runtime.Object, error)
|
||||
|
||||
// WARNING: Register/UnregisterPod functions should be efficient,
|
||||
// i.e. should not block on network operations.
|
||||
|
||||
// RegisterPod registers all objects referenced from a given pod.
|
||||
//
|
||||
// NOTE: All implementations of RegisterPod should be idempotent.
|
||||
RegisterPod(pod *v1.Pod)
|
||||
|
||||
// UnregisterPod unregisters objects referenced from a given pod that are not
|
||||
// used by any other registered pod.
|
||||
//
|
||||
// NOTE: All implementations of UnregisterPod should be idempotent.
|
||||
UnregisterPod(pod *v1.Pod)
|
||||
}
|
||||
|
||||
// Store is the interface for a object cache that
|
||||
// can be used by cacheBasedManager.
|
||||
type Store interface {
|
||||
// AddReference adds a reference to the object to the store.
|
||||
// Note that multiple additions to the store has to be allowed
|
||||
// in the implementations and effectively treated as refcounted.
|
||||
AddReference(namespace, name string)
|
||||
// DeleteReference deletes reference to the object from the store.
|
||||
// Note that object should be deleted only when there was a
|
||||
// corresponding Delete call for each of Add calls (effectively
|
||||
// when refcount was reduced to zero).
|
||||
DeleteReference(namespace, name string)
|
||||
// Get an object from a store.
|
||||
Get(namespace, name string) (runtime.Object, error)
|
||||
}
|
194
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/watch_based_manager.go
generated
vendored
Normal file
194
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/watch_based_manager.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// TODO: We did some scalability tests and using watchBasedManager
|
||||
// seems to help with apiserver performance at scale visibly.
|
||||
// No issues we also observed at the scale of ~200k watchers with a
|
||||
// single apiserver.
|
||||
// However, we need to perform more extensive testing before we
|
||||
// enable this in production setups.
|
||||
|
||||
package manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
type listObjectFunc func(string, metav1.ListOptions) (runtime.Object, error)
|
||||
type watchObjectFunc func(string, metav1.ListOptions) (watch.Interface, error)
|
||||
type newObjectFunc func() runtime.Object
|
||||
|
||||
// objectCacheItem is a single item stored in objectCache.
|
||||
type objectCacheItem struct {
|
||||
refCount int
|
||||
store cache.Store
|
||||
hasSynced func() (bool, error)
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
// objectCache is a local cache of objects propagated via
|
||||
// individual watches.
|
||||
type objectCache struct {
|
||||
listObject listObjectFunc
|
||||
watchObject watchObjectFunc
|
||||
newObject newObjectFunc
|
||||
groupResource schema.GroupResource
|
||||
|
||||
lock sync.Mutex
|
||||
items map[objectKey]*objectCacheItem
|
||||
}
|
||||
|
||||
// NewObjectCache returns a new watch-based instance of Store interface.
|
||||
func NewObjectCache(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource) Store {
|
||||
return &objectCache{
|
||||
listObject: listObject,
|
||||
watchObject: watchObject,
|
||||
newObject: newObject,
|
||||
groupResource: groupResource,
|
||||
items: make(map[objectKey]*objectCacheItem),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *objectCache) newStore() cache.Store {
|
||||
// TODO: We may consider created a dedicated store keeping just a single
|
||||
// item, instead of using a generic store implementation for this purpose.
|
||||
// However, simple benchmarks show that memory overhead in that case is
|
||||
// decrease from ~600B to ~300B per object. So we are not optimizing it
|
||||
// until we will see a good reason for that.
|
||||
return cache.NewStore(cache.MetaNamespaceKeyFunc)
|
||||
}
|
||||
|
||||
func (c *objectCache) newReflector(namespace, name string) *objectCacheItem {
|
||||
fieldSelector := fields.Set{"metadata.name": name}.AsSelector().String()
|
||||
listFunc := func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
options.FieldSelector = fieldSelector
|
||||
return c.listObject(namespace, options)
|
||||
}
|
||||
watchFunc := func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
options.FieldSelector = fieldSelector
|
||||
return c.watchObject(namespace, options)
|
||||
}
|
||||
store := c.newStore()
|
||||
reflector := cache.NewNamedReflector(
|
||||
fmt.Sprintf("object-%q/%q", namespace, name),
|
||||
&cache.ListWatch{ListFunc: listFunc, WatchFunc: watchFunc},
|
||||
c.newObject(),
|
||||
store,
|
||||
0,
|
||||
)
|
||||
stopCh := make(chan struct{})
|
||||
go reflector.Run(stopCh)
|
||||
return &objectCacheItem{
|
||||
refCount: 0,
|
||||
store: store,
|
||||
hasSynced: func() (bool, error) { return reflector.LastSyncResourceVersion() != "", nil },
|
||||
stopCh: stopCh,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *objectCache) AddReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
// AddReference is called from RegisterPod thus it needs to be efficient.
|
||||
// Thus, it is only increaisng refCount and in case of first registration
|
||||
// of a given object it starts corresponding reflector.
|
||||
// It's responsibility of the first Get operation to wait until the
|
||||
// reflector propagated the store.
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
item, exists := c.items[key]
|
||||
if !exists {
|
||||
item = c.newReflector(namespace, name)
|
||||
c.items[key] = item
|
||||
}
|
||||
item.refCount++
|
||||
}
|
||||
|
||||
func (c *objectCache) DeleteReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if item, ok := c.items[key]; ok {
|
||||
item.refCount--
|
||||
if item.refCount == 0 {
|
||||
// Stop the underlying reflector.
|
||||
close(item.stopCh)
|
||||
delete(c.items, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// key returns key of an object with a given name and namespace.
|
||||
// This has to be in-sync with cache.MetaNamespaceKeyFunc.
|
||||
func (c *objectCache) key(namespace, name string) string {
|
||||
if len(namespace) > 0 {
|
||||
return namespace + "/" + name
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (c *objectCache) Get(namespace, name string) (runtime.Object, error) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
c.lock.Lock()
|
||||
item, exists := c.items[key]
|
||||
c.lock.Unlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("object %q/%q not registered", namespace, name)
|
||||
}
|
||||
if err := wait.PollImmediate(10*time.Millisecond, time.Second, item.hasSynced); err != nil {
|
||||
return nil, fmt.Errorf("couldn't propagate object cache: %v", err)
|
||||
}
|
||||
|
||||
obj, exists, err := item.store.GetByKey(c.key(namespace, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, apierrors.NewNotFound(c.groupResource, name)
|
||||
}
|
||||
if object, ok := obj.(runtime.Object); ok {
|
||||
return object, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected object type: %v", obj)
|
||||
}
|
||||
|
||||
// NewWatchBasedManager creates a manager that keeps a cache of all objects
|
||||
// necessary for registered pods.
|
||||
// It implements the following logic:
|
||||
// - whenever a pod is created or updated, we start individual watches for all
|
||||
// referenced objects that aren't referenced from other registered pods
|
||||
// - every GetObject() returns a value from local cache propagated via watches
|
||||
func NewWatchBasedManager(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource, getReferencedObjects func(*v1.Pod) sets.String) Manager {
|
||||
objectStore := NewObjectCache(listObject, watchObject, newObject, groupResource)
|
||||
return NewCacheBasedManager(objectStore, getReferencedObjects)
|
||||
}
|
Reference in New Issue
Block a user