* add resource getter & reader Signed-off-by: Wenhao Zhou <wenhaozhou@yunify.com> * add resource v1beta1 handler * delete gvrToGvk map instead of using the dynamicRESTMapper for getting gvk, and rename the ResourceLister to ResourceGetter * add unregisteredMiddleware filter Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> * add secret contains benchmark & add fieldSelector to resourcev1beta1 Signed-off-by: Wenhao Zhou <wenhaozhou@yunify.com> * delete crds models Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> * delete parameterExtractor and instead of requestInfo Signed-off-by: Wenhao Zhou <wenhaozhou@yunify.com> * add benchmark test * move fieldSelector to DefaultObjectMetaFilter Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> * move fieldSelector to DefaultObjectMetaFilter * change registeredGv type to set Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> * update filter chains Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> * fix fieldSelector cannot work Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> * fix: list known type do not need served label Signed-off-by: wenhaozhou <wenhaozhou@yunify.com> --------- Signed-off-by: Wenhao Zhou <wenhaozhou@yunify.com> Signed-off-by: wenhaozhou <wenhaozhou@yunify.com>
151 lines
3.4 KiB
Go
151 lines
3.4 KiB
Go
package v1beta1
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
|
|
|
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
|
|
|
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
var ErrResourceNotSupported = errors.New("resource is not supported")
|
|
var ErrResourceNotServed = errors.New("resource is not served")
|
|
|
|
const labelResourceServed = "kubesphere.io/resource-served"
|
|
|
|
// TODO If delete the crd at the cluster when ks is running, the client.cache doesn`t return err but empty result
|
|
func New(client client.Client, cache cache.Cache) ResourceGetter {
|
|
return &resourceGetter{
|
|
client: client,
|
|
cache: NewResourceCache(cache),
|
|
serveCRD: make(map[string]bool, 0),
|
|
}
|
|
}
|
|
|
|
type resourceGetter struct {
|
|
client client.Client
|
|
cache Interface
|
|
serveCRD map[string]bool
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (h *resourceGetter) GetResource(gvr schema.GroupVersionResource, name, namespace string) (client.Object, error) {
|
|
var obj client.Object
|
|
gvk, err := h.getGVK(gvr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if h.client.Scheme().Recognizes(gvk) {
|
|
gvkObject, err := h.client.Scheme().New(gvk)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
obj = gvkObject.(client.Object)
|
|
} else {
|
|
serviced, err := h.isServed(gvr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !serviced {
|
|
return nil, ErrResourceNotServed
|
|
}
|
|
|
|
u := &unstructured.Unstructured{}
|
|
u.SetGroupVersionKind(gvk)
|
|
obj = u
|
|
}
|
|
|
|
if err := h.cache.Get(name, namespace, obj); err != nil {
|
|
return nil, err
|
|
}
|
|
return obj, nil
|
|
}
|
|
|
|
func (h *resourceGetter) ListResources(gvr schema.GroupVersionResource, namespace string, query *query.Query) (client.ObjectList, error) {
|
|
var obj client.ObjectList
|
|
|
|
gvk, err := h.getGVK(gvr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
gvk = convertGVKToList(gvk)
|
|
|
|
if h.client.Scheme().Recognizes(gvk) {
|
|
gvkObject, err := h.client.Scheme().New(gvk)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
obj = gvkObject.(client.ObjectList)
|
|
} else {
|
|
serviced, err := h.isServed(gvr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !serviced {
|
|
return nil, ErrResourceNotServed
|
|
}
|
|
u := &unstructured.UnstructuredList{}
|
|
u.SetGroupVersionKind(gvk)
|
|
obj = u
|
|
}
|
|
|
|
if err := h.cache.List(namespace, query, obj); err != nil {
|
|
return nil, err
|
|
}
|
|
return obj, nil
|
|
}
|
|
|
|
func convertGVKToList(gvk schema.GroupVersionKind) schema.GroupVersionKind {
|
|
if strings.HasSuffix(gvk.Kind, "List") {
|
|
return gvk
|
|
}
|
|
gvk.Kind = gvk.Kind + "List"
|
|
return gvk
|
|
}
|
|
|
|
func (h *resourceGetter) getGVK(gvr schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
|
var (
|
|
gvk schema.GroupVersionKind
|
|
err error
|
|
)
|
|
gvk, err = h.client.RESTMapper().KindFor(gvr)
|
|
if err != nil {
|
|
return gvk, err
|
|
}
|
|
|
|
return gvk, nil
|
|
}
|
|
|
|
func (h *resourceGetter) isServed(gvr schema.GroupVersionResource) (bool, error) {
|
|
resourceName := gvr.Resource + "." + gvr.Group
|
|
h.RWMutex.RLock()
|
|
isServed := h.serveCRD[resourceName]
|
|
h.RWMutex.RUnlock()
|
|
if isServed {
|
|
return true, nil
|
|
}
|
|
|
|
crd := &extv1.CustomResourceDefinition{}
|
|
err := h.client.Get(context.Background(), client.ObjectKey{Name: resourceName}, crd)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if crd.Labels[labelResourceServed] == "true" {
|
|
h.RWMutex.Lock()
|
|
h.serveCRD[resourceName] = true
|
|
h.RWMutex.Unlock()
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|