Skip to content

Commit

Permalink
Merge pull request kubernetes#53743 from DirectXMan12/feature/polymor…
Browse files Browse the repository at this point in the history
…phic-scale-client

Automatic merge from submit-queue (batch tested with PRs 53743, 53564). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Polymorphic Scale Client

This PR introduces a polymorphic scale client based on discovery information that's able to scale scalable resources in arbitrary group-versions, as long as they present the scale subresource in their discovery information.

Currently, it supports `extensions/v1beta1.Scale` and `autoscaling/v1.Scale`, but supporting other versions of scale if/when we produce them should be fairly trivial.

It also updates the HPA to use this client, meaning the HPA will now work on any scalable resource, not just things in the `extensions/v1beta1` API group.

**Release note**:
```release-note
Introduces a polymorphic scale client, allowing HorizontalPodAutoscalers to properly function on scalable resources in any API group.
```

Unblocks kubernetes#29698
Unblocks kubernetes#38756
Unblocks kubernetes#49504 
Fixes kubernetes#38810
  • Loading branch information
Kubernetes Submit Queue authored Oct 23, 2017
2 parents 067f2db + f22bfcd commit ca8d97d
Show file tree
Hide file tree
Showing 89 changed files with 2,541 additions and 428 deletions.
1 change: 1 addition & 0 deletions cmd/kube-controller-manager/app/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ go_library(
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/leaderelection:go_default_library",
"//vendor/k8s.io/client-go/tools/leaderelection/resourcelock:go_default_library",
Expand Down
26 changes: 24 additions & 2 deletions cmd/kube-controller-manager/app/autoscaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ limitations under the License.
package app

import (
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
discocache "k8s.io/client-go/discovery/cached" // Saturday Night Fever
"k8s.io/client-go/dynamic"
"k8s.io/client-go/scale"
"k8s.io/kubernetes/pkg/controller/podautoscaler"
"k8s.io/kubernetes/pkg/controller/podautoscaler/metrics"
resourceclient "k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1beta1"
Expand Down Expand Up @@ -63,16 +68,33 @@ func startHPAControllerWithLegacyClient(ctx ControllerContext) (bool, error) {
}

func startHPAControllerWithMetricsClient(ctx ControllerContext, metricsClient metrics.MetricsClient) (bool, error) {
hpaClientGoClient := ctx.ClientBuilder.ClientGoClientOrDie("horizontal-pod-autoscaler")
hpaClient := ctx.ClientBuilder.ClientOrDie("horizontal-pod-autoscaler")
hpaClientConfig := ctx.ClientBuilder.ConfigOrDie("horizontal-pod-autoscaler")

// TODO: we need something like deferred discovery REST mapper that calls invalidate
// on cache misses.
cachedDiscovery := discocache.NewMemCacheClient(hpaClientGoClient.Discovery())
restMapper := discovery.NewDeferredDiscoveryRESTMapper(cachedDiscovery, apimeta.InterfacesForUnstructured)
restMapper.Reset()
// we don't use cached discovery because DiscoveryScaleKindResolver does its own caching,
// so we want to re-fetch every time when we actually ask for it
scaleKindResolver := scale.NewDiscoveryScaleKindResolver(hpaClientGoClient.Discovery())
scaleClient, err := scale.NewForConfig(hpaClientConfig, restMapper, dynamic.LegacyAPIPathResolverFunc, scaleKindResolver)
if err != nil {
return false, err
}

replicaCalc := podautoscaler.NewReplicaCalculator(
metricsClient,
hpaClient.Core(),
ctx.Options.HorizontalPodAutoscalerTolerance,
)
go podautoscaler.NewHorizontalController(
ctx.ClientBuilder.ClientGoClientOrDie("horizontal-pod-autoscaler").Core(),
hpaClient.Extensions(),
hpaClientGoClient.Core(),
scaleClient,
hpaClient.Autoscaling(),
restMapper,
replicaCalc,
ctx.InformerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
ctx.Options.HorizontalPodAutoscalerSyncPeriod.Duration,
Expand Down
2 changes: 1 addition & 1 deletion federation/pkg/kubefed/init/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.TmpDir = tmpDirPath
tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry,
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
Expand Down
6 changes: 3 additions & 3 deletions federation/pkg/kubefed/join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func testJoinFederationFactory(clusterName, secretName, server string, isRBACAPI
codec := testapi.Federation.Codec()
ns := dynamic.ContentConfig().NegotiatedSerializer
tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry,
GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
Expand Down Expand Up @@ -365,7 +365,7 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token, dns
ns := dynamic.ContentConfig().NegotiatedSerializer
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry,
GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
Expand Down Expand Up @@ -526,7 +526,7 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa
tf.TmpDir = tmpDirPath
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry,
GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, r := req.URL.Path, req.Method, isRBACAPIAvailable; {
Expand Down
5 changes: 2 additions & 3 deletions federation/pkg/kubefed/unjoin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,8 @@ func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory {
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
ns := serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: runtime.NewCodec(f.JSONEncoder(), legacyscheme.Codecs.UniversalDecoder(fedv1beta1.SchemeGroupVersion))})
tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry,
GroupVersion: legacyscheme.Registry.GroupOrDie("federation").GroupVersion,
NegotiatedSerializer: ns,
GroupName: "federation",
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case strings.HasPrefix(p, urlPrefix):
Expand Down Expand Up @@ -242,7 +241,7 @@ func fakeUnjoinHostFactory(clusterName string) cmdutil.Factory {
ns := dynamic.ContentConfig().NegotiatedSerializer
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry,
GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
Expand Down
6 changes: 6 additions & 0 deletions hack/.golint_failures
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,12 @@ staging/src/k8s.io/client-go/plugin/pkg/auth/authenticator/token/oidc/testing
staging/src/k8s.io/client-go/plugin/pkg/client/auth/oidc
staging/src/k8s.io/client-go/rest
staging/src/k8s.io/client-go/rest/fake
staging/src/k8s.io/client-go/scale
staging/src/k8s.io/client-go/scale/fake
staging/src/k8s.io/client-go/scale/scheme
staging/src/k8s.io/client-go/scale/scheme/autoscalingv1
staging/src/k8s.io/client-go/scale/scheme/extensionsint
staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1
staging/src/k8s.io/client-go/testing
staging/src/k8s.io/client-go/tools/cache
staging/src/k8s.io/client-go/tools/cache/testing
Expand Down
2 changes: 1 addition & 1 deletion hack/make-rules/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ runTests() {
${KUBE_RACE} ${KUBE_TIMEOUT} "${@}" \
"${testargs[@]:+${testargs[@]}}" \
| tee ${junit_filename_prefix:+"${junit_filename_prefix}.stdout"} \
| grep "${go_test_grep_pattern}" && rc=$? || rc=$?
| grep --binary-files=text "${go_test_grep_pattern}" && rc=$? || rc=$?
produceJUnitXMLReport "${junit_filename_prefix}"
return ${rc}
fi
Expand Down
9 changes: 9 additions & 0 deletions pkg/api/testing/serialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ func TestSetControllerConversion(t *testing.T) {

fuzzInternalObject(t, extGroup.InternalGroupVersion(), rs, rand.Int63())

// explicitly set the selector to something that is convertible to old-style selectors
// (since normally we'll fuzz the selectors with things that aren't convertible)
rs.Spec.Selector = &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
"baz": "quux",
},
}

t.Logf("rs._internal.extensions -> rs.v1beta1.extensions")
data, err := runtime.Encode(extGroup.Codec(), rs)
if err != nil {
Expand Down
1 change: 0 additions & 1 deletion pkg/apis/extensions/fuzzer/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ go_library(
deps = [
"//pkg/apis/extensions:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
],
Expand Down
20 changes: 0 additions & 20 deletions pkg/apis/extensions/fuzzer/fuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

fuzz "github.com/google/gofuzz"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubernetes/pkg/apis/extensions"
Expand Down Expand Up @@ -83,25 +82,6 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
}
psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))]
},
func(s *extensions.Scale, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again
// TODO: Implement a fuzzer to generate valid keys, values and operators for
// selector requirements.
if s.Status.Selector != nil {
s.Status.Selector = &metav1.LabelSelector{
MatchLabels: map[string]string{
"testlabelkey": "testlabelval",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "testkey",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"val1", "val2", "val3"},
},
},
}
}
},
func(j *extensions.DaemonSetSpec, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again
rhl := int32(c.Rand.Int31())
Expand Down
8 changes: 5 additions & 3 deletions pkg/controller/podautoscaler/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ go_library(
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
Expand All @@ -39,8 +39,8 @@ go_library(
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/client-go/listers/autoscaling/v1:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
Expand All @@ -58,6 +58,7 @@ go_test(
importpath = "k8s.io/kubernetes/pkg/controller/podautoscaler",
library = ":go_default_library",
deps = [
"//pkg/api/install:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/autoscaling/install:go_default_library",
Expand All @@ -69,15 +70,16 @@ go_test(
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/scale/fake:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
"//vendor/k8s.io/heapster/metrics/api/v1/types:go_default_library",
"//vendor/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library",
Expand Down
Loading

0 comments on commit ca8d97d

Please sign in to comment.