karmada/pkg/search/proxy/store/cluster_cache.go

105 lines
2.9 KiB
Go

package store
import (
"sync"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/klog/v2"
)
// clusterCache caches resources for single member cluster
type clusterCache struct {
lock sync.RWMutex
cache map[schema.GroupVersionResource]*resourceCache
clusterName string
restMapper meta.RESTMapper
// newClientFunc returns a dynamic client for member cluster apiserver
newClientFunc func() (dynamic.Interface, error)
}
func newClusterCache(clusterName string, newClientFunc func() (dynamic.Interface, error), restMapper meta.RESTMapper) *clusterCache {
return &clusterCache{
clusterName: clusterName,
newClientFunc: newClientFunc,
restMapper: restMapper,
cache: map[schema.GroupVersionResource]*resourceCache{},
}
}
func (c *clusterCache) updateCache(resources map[schema.GroupVersionResource]*MultiNamespace) error {
c.lock.Lock()
defer c.lock.Unlock()
// remove non-exist resources
for resource, cache := range c.cache {
if multiNS, exist := resources[resource]; !exist || !multiNS.Equal(cache.multiNS) {
klog.Infof("Remove cache for %s %s", c.clusterName, resource.String())
c.cache[resource].stop()
delete(c.cache, resource)
}
}
// add resource cache
for resource, multiNS := range resources {
_, exist := c.cache[resource]
if !exist {
kind, err := c.restMapper.KindFor(resource)
if err != nil {
return err
}
mapping, err := c.restMapper.RESTMapping(kind.GroupKind(), kind.Version)
if err != nil {
return err
}
namespaced := mapping.Scope.Name() == meta.RESTScopeNameNamespace
if !namespaced && !multiNS.allNamespaces {
klog.Warningf("Namespace is invalid for %v, skip it.", kind.String())
multiNS.Add(metav1.NamespaceAll)
}
singularName, err := c.restMapper.ResourceSingularizer(resource.Resource)
if err != nil {
klog.Warningf("Failed to get singular name for resource: %s", resource.String())
return err
}
klog.Infof("Add cache for %s %s", c.clusterName, resource.String())
cache, err := newResourceCache(c.clusterName, resource, kind, singularName, namespaced, multiNS, c.clientForResourceFunc(resource))
if err != nil {
return err
}
c.cache[resource] = cache
}
}
return nil
}
func (c *clusterCache) stop() {
c.lock.RLock()
defer c.lock.RUnlock()
for _, cache := range c.cache {
cache.stop()
}
}
func (c *clusterCache) clientForResourceFunc(resource schema.GroupVersionResource) func() (dynamic.NamespaceableResourceInterface, error) {
return func() (dynamic.NamespaceableResourceInterface, error) {
client, err := c.newClientFunc()
if err != nil {
return nil, err
}
return client.Resource(resource), nil
}
}
func (c *clusterCache) cacheForResource(gvr schema.GroupVersionResource) *resourceCache {
c.lock.RLock()
defer c.lock.RUnlock()
return c.cache[gvr]
}