Skip to content

Commit

Permalink
use cached discovery client to check scalable
Browse files Browse the repository at this point in the history
  • Loading branch information
yunwang0911 committed May 14, 2024
1 parent 77652cd commit bad38ce
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type ControllerFetcher interface {
type controllerFetcher struct {
scaleNamespacer scale.ScalesGetter
mapper apimeta.RESTMapper
scaleKindResolver scale.ScaleKindResolver
informersMap map[wellKnownController]cache.SharedIndexInformer
scaleSubresourceCacheStorage controllerCacheStorage
}
Expand Down Expand Up @@ -146,6 +147,7 @@ func NewControllerFetcher(config *rest.Config, kubeClient kube_client.Interface,
return &controllerFetcher{
scaleNamespacer: scaleNamespacer,
mapper: mapper,
scaleKindResolver: scale.NewDiscoveryScaleKindResolver(cachedDiscoveryClient),
informersMap: informersMap,
scaleSubresourceCacheStorage: newControllerCacheStorage(betweenRefreshes, lifeTime, jitterFactor),
}
Expand Down Expand Up @@ -206,6 +208,12 @@ func (f *controllerFetcher) getParentOfController(controllerKey ControllerKeyWit
return getParentOfWellKnownController(informer, controllerKey)
}

// check if it's scalable
scalable := f.isScalable(controllerKey.ApiVersion, controllerKey.Kind)
if !scalable {
return nil, nil
}

groupKind, err := controllerKey.groupKind()
if err != nil {
return nil, err
Expand Down Expand Up @@ -261,27 +269,26 @@ func (f *controllerFetcher) isWellKnownOrScalable(key *ControllerKeyWithAPIVersi
return false
}

//if not well known check if it supports scaling
groupKind, err := key.groupKind()
return f.isScalable(key.ApiVersion, key.Kind)
}

// isScalable returns true if the given controller is scalable.
// isScalable checks if the controller is scalable by checking if the resource "<key>/scale" exists in the cached discovery client.
func (f *controllerFetcher) isScalable(apiVersion string, kind string) bool {
gv, err := schema.ParseGroupVersion(apiVersion)
if err != nil {
klog.Errorf("Could not find groupKind for %s/%s: %v", key.Namespace, key.Name, err)
klog.Errorf("Could not parse apiVersion %s: %v", apiVersion, err)
return false
}

mappings, err := f.mapper.RESTMappings(groupKind)
_, err = f.scaleKindResolver.ScaleForResource(schema.GroupVersionResource{
Group: gv.Group,
Version: gv.Version,
Resource: kind,
})
if err != nil {
klog.Errorf("Could not find mappings for %s: %v", groupKind, err)
return false
}

for _, mapping := range mappings {
groupResource := mapping.Resource.GroupResource()
scale, err := f.getScaleForResource(key.Namespace, groupResource, key.Name)
if err == nil && scale != nil {
return true
}
}
return false
return true
}

func (f *controllerFetcher) getOwnerForScaleResource(groupKind schema.GroupKind, namespace, name string) (*ControllerKeyWithAPIVersion, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
cacheddiscovery "k8s.io/client-go/discovery/cached"
"k8s.io/client-go/discovery/fake"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/scale"
scalefake "k8s.io/client-go/scale/fake"
core "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache"
Expand All @@ -56,8 +59,62 @@ func simpleControllerFetcher() *controllerFetcher {
f.informersMap = make(map[wellKnownController]cache.SharedIndexInformer)
f.scaleSubresourceCacheStorage = newControllerCacheStorage(time.Second, time.Minute, 0.1)
versioned := map[string][]metav1.APIResource{
"Foo": {{Kind: "Foo", Name: "bah", Group: "foo"}, {Kind: "Scale", Name: "iCanScale", Group: "foo"}},
"Foo": {{Kind: "Foo", Name: "bah", Group: "foo", SingularName: "foo"}, {Kind: "Scale", Name: "iCanScale", Group: "foo", SingularName: "scale"}},
}
fakeDiscoveryClient := &fake.FakeDiscovery{
Fake: &core.Fake{Resources: []*metav1.APIResourceList{
{
TypeMeta: metav1.TypeMeta{
Kind: "APIResourceList",
APIVersion: "v1",
},
GroupVersion: "Foo/Foo",
APIResources: []metav1.APIResource{
{
Name: "foos",
Namespaced: true,
Kind: "Foo",
Group: "Foo",
Version: "Foo",
SingularName: "foo",
},
{
Name: "scales",
Namespaced: true,
Kind: "Scale",
Group: "Foo",
Version: "Foo",
SingularName: "scale",
},
{
Name: "scales/scale",
Namespaced: true,
Kind: "Scale",
Group: "Foo",
Version: "Foo",
SingularName: "scale",
},
},
},
{
TypeMeta: metav1.TypeMeta{
Kind: "APIResourceList",
APIVersion: "v1",
},
GroupVersion: "v1",
APIResources: []metav1.APIResource{
{
Name: "deployments",
SingularName: "deployment",
Namespaced: true,
Kind: "Deployment",
Group: "",
Version: "v1",
},
},
}}},
}
f.scaleKindResolver = scale.NewDiscoveryScaleKindResolver(cacheddiscovery.NewMemCacheClient(fakeDiscoveryClient))
fakeMapper := []*restmapper.APIGroupResources{
{
Group: metav1.APIGroup{
Expand All @@ -73,7 +130,7 @@ func simpleControllerFetcher() *controllerFetcher {
scaleNamespacer := &scalefake.FakeScaleClient{}
f.scaleNamespacer = scaleNamespacer

// return not found if if tries to find the scale subresource on bah
// return not found if it tries to find the scale subresource on bah
scaleNamespacer.AddReactor("get", "bah", func(action core.Action) (handled bool, ret runtime.Object, err error) {
groupResource := schema.GroupResource{}
error := apierrors.NewNotFound(groupResource, "Foo")
Expand Down Expand Up @@ -386,8 +443,9 @@ func TestControllerFetcher(t *testing.T) {
},
},
}},
expectedKey: nil,
expectedError: fmt.Errorf("Unhandled targetRef v1 / Node / node, last error node is not a valid owner"),
expectedKey: &ControllerKeyWithAPIVersion{ControllerKey: ControllerKey{
Name: testDeployment, Kind: "Deployment", Namespace: testNamespace}}, // Node does not support scale subresource so should return itself"
expectedError: nil,
},
{
name: "custom resource with no scale subresource",
Expand Down

0 comments on commit bad38ce

Please sign in to comment.