Merge pull request #53743 from DirectXMan12/feature/polymorphic-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 #29698
Unblocks #38756
Unblocks #49504 
Fixes #38810
This commit is contained in:
Kubernetes Submit Queue 2017-10-23 13:39:07 -07:00 committed by GitHub
commit ca8d97d673
89 changed files with 2551 additions and 438 deletions

View File

@ -124,6 +124,7 @@ go_library(
"//vendor/k8s.io/client-go/kubernetes:go_default_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/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/rest: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/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/leaderelection:go_default_library", "//vendor/k8s.io/client-go/tools/leaderelection:go_default_library",
"//vendor/k8s.io/client-go/tools/leaderelection/resourcelock:go_default_library", "//vendor/k8s.io/client-go/tools/leaderelection/resourcelock:go_default_library",

View File

@ -21,7 +21,12 @@ limitations under the License.
package app package app
import ( import (
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema" "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"
"k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics"
resourceclient "k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1beta1" resourceclient "k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1beta1"
@ -63,16 +68,33 @@ func startHPAControllerWithLegacyClient(ctx ControllerContext) (bool, error) {
} }
func startHPAControllerWithMetricsClient(ctx ControllerContext, metricsClient metrics.MetricsClient) (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") 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( replicaCalc := podautoscaler.NewReplicaCalculator(
metricsClient, metricsClient,
hpaClient.Core(), hpaClient.Core(),
ctx.Options.HorizontalPodAutoscalerTolerance, ctx.Options.HorizontalPodAutoscalerTolerance,
) )
go podautoscaler.NewHorizontalController( go podautoscaler.NewHorizontalController(
ctx.ClientBuilder.ClientGoClientOrDie("horizontal-pod-autoscaler").Core(), hpaClientGoClient.Core(),
hpaClient.Extensions(), scaleClient,
hpaClient.Autoscaling(), hpaClient.Autoscaling(),
restMapper,
replicaCalc, replicaCalc,
ctx.InformerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), ctx.InformerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
ctx.Options.HorizontalPodAutoscalerSyncPeriod.Duration, ctx.Options.HorizontalPodAutoscalerSyncPeriod.Duration,

View File

@ -1184,7 +1184,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.TmpDir = tmpDirPath tf.TmpDir = tmpDirPath
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -231,7 +231,7 @@ func testJoinFederationFactory(clusterName, secretName, server string, isRBACAPI
codec := testapi.Federation.Codec() codec := testapi.Federation.Codec()
ns := dynamic.ContentConfig().NegotiatedSerializer ns := dynamic.ContentConfig().NegotiatedSerializer
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -365,7 +365,7 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token, dns
ns := dynamic.ContentConfig().NegotiatedSerializer ns := dynamic.ContentConfig().NegotiatedSerializer
tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -526,7 +526,7 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa
tf.TmpDir = tmpDirPath tf.TmpDir = tmpDirPath
tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, r := req.URL.Path, req.Method, isRBACAPIAvailable; { switch p, m, r := req.URL.Path, req.Method, isRBACAPIAvailable; {

View File

@ -185,9 +185,8 @@ func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory {
tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
ns := serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: runtime.NewCodec(f.JSONEncoder(), legacyscheme.Codecs.UniversalDecoder(fedv1beta1.SchemeGroupVersion))}) ns := serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: runtime.NewCodec(f.JSONEncoder(), legacyscheme.Codecs.UniversalDecoder(fedv1beta1.SchemeGroupVersion))})
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie("federation").GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
GroupName: "federation",
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
case strings.HasPrefix(p, urlPrefix): case strings.HasPrefix(p, urlPrefix):
@ -242,7 +241,7 @@ func fakeUnjoinHostFactory(clusterName string) cmdutil.Factory {
ns := dynamic.ContentConfig().NegotiatedSerializer ns := dynamic.ContentConfig().NegotiatedSerializer
tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -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/plugin/pkg/client/auth/oidc
staging/src/k8s.io/client-go/rest staging/src/k8s.io/client-go/rest
staging/src/k8s.io/client-go/rest/fake 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/testing
staging/src/k8s.io/client-go/tools/cache staging/src/k8s.io/client-go/tools/cache
staging/src/k8s.io/client-go/tools/cache/testing staging/src/k8s.io/client-go/tools/cache/testing

View File

@ -289,7 +289,7 @@ runTests() {
${KUBE_RACE} ${KUBE_TIMEOUT} "${@}" \ ${KUBE_RACE} ${KUBE_TIMEOUT} "${@}" \
"${testargs[@]:+${testargs[@]}}" \ "${testargs[@]:+${testargs[@]}}" \
| tee ${junit_filename_prefix:+"${junit_filename_prefix}.stdout"} \ | 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}" produceJUnitXMLReport "${junit_filename_prefix}"
return ${rc} return ${rc}
fi fi

View File

@ -104,6 +104,15 @@ func TestSetControllerConversion(t *testing.T) {
fuzzInternalObject(t, extGroup.InternalGroupVersion(), rs, rand.Int63()) 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") t.Logf("rs._internal.extensions -> rs.v1beta1.extensions")
data, err := runtime.Encode(extGroup.Codec(), rs) data, err := runtime.Encode(extGroup.Codec(), rs)
if err != nil { if err != nil {

View File

@ -12,7 +12,6 @@ go_library(
deps = [ deps = [
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//vendor/github.com/google/gofuzz: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/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
], ],

View File

@ -21,7 +21,6 @@ import (
fuzz "github.com/google/gofuzz" fuzz "github.com/google/gofuzz"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
@ -83,25 +82,6 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
} }
psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))] 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) { func(j *extensions.DaemonSetSpec, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again c.FuzzNoCustom(j) // fuzz self without calling this function again
rhl := int32(c.Rand.Int31()) rhl := int32(c.Rand.Int31())

View File

@ -24,9 +24,9 @@ go_library(
"//vendor/k8s.io/api/autoscaling/v1:go_default_library", "//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1: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/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/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors: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/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/labels:go_default_library",
@ -39,8 +39,8 @@ go_library(
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_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/autoscaling/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/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/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/cache:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library", "//vendor/k8s.io/client-go/tools/record:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library", "//vendor/k8s.io/client-go/util/workqueue:go_default_library",
@ -58,6 +58,7 @@ go_test(
importpath = "k8s.io/kubernetes/pkg/controller/podautoscaler", importpath = "k8s.io/kubernetes/pkg/controller/podautoscaler",
library = ":go_default_library", library = ":go_default_library",
deps = [ deps = [
"//pkg/api/install:go_default_library",
"//pkg/api/legacyscheme:go_default_library", "//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/autoscaling:go_default_library", "//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/autoscaling/install:go_default_library", "//pkg/apis/autoscaling/install:go_default_library",
@ -69,15 +70,16 @@ go_test(
"//vendor/k8s.io/api/autoscaling/v1:go_default_library", "//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1: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/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/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema: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/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/informers: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/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/rest: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/client-go/testing:go_default_library",
"//vendor/k8s.io/heapster/metrics/api/v1/types: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", "//vendor/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library",

View File

@ -25,9 +25,9 @@ import (
autoscalingv1 "k8s.io/api/autoscaling/v1" autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2beta1" autoscalingv2 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
apiequality "k8s.io/apimachinery/pkg/api/equality" apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
@ -39,8 +39,8 @@ import (
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
autoscalingclient "k8s.io/client-go/kubernetes/typed/autoscaling/v1" autoscalingclient "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
v1core "k8s.io/client-go/kubernetes/typed/core/v1" v1core "k8s.io/client-go/kubernetes/typed/core/v1"
extensionsclient "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
autoscalinglisters "k8s.io/client-go/listers/autoscaling/v1" autoscalinglisters "k8s.io/client-go/listers/autoscaling/v1"
scaleclient "k8s.io/client-go/scale"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
@ -57,8 +57,9 @@ var (
// in the system with the actual deployments/replication controllers they // in the system with the actual deployments/replication controllers they
// control. // control.
type HorizontalController struct { type HorizontalController struct {
scaleNamespacer extensionsclient.ScalesGetter scaleNamespacer scaleclient.ScalesGetter
hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter
mapper apimeta.RESTMapper
replicaCalc *ReplicaCalculator replicaCalc *ReplicaCalculator
eventRecorder record.EventRecorder eventRecorder record.EventRecorder
@ -78,8 +79,9 @@ type HorizontalController struct {
// NewHorizontalController creates a new HorizontalController. // NewHorizontalController creates a new HorizontalController.
func NewHorizontalController( func NewHorizontalController(
evtNamespacer v1core.EventsGetter, evtNamespacer v1core.EventsGetter,
scaleNamespacer extensionsclient.ScalesGetter, scaleNamespacer scaleclient.ScalesGetter,
hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter, hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter,
mapper apimeta.RESTMapper,
replicaCalc *ReplicaCalculator, replicaCalc *ReplicaCalculator,
hpaInformer autoscalinginformers.HorizontalPodAutoscalerInformer, hpaInformer autoscalinginformers.HorizontalPodAutoscalerInformer,
resyncPeriod time.Duration, resyncPeriod time.Duration,
@ -100,7 +102,8 @@ func NewHorizontalController(
hpaNamespacer: hpaNamespacer, hpaNamespacer: hpaNamespacer,
upscaleForbiddenWindow: upscaleForbiddenWindow, upscaleForbiddenWindow: upscaleForbiddenWindow,
downscaleForbiddenWindow: downscaleForbiddenWindow, downscaleForbiddenWindow: downscaleForbiddenWindow,
queue: workqueue.NewNamedRateLimitingQueue(NewDefaultHPARateLimiter(resyncPeriod), "horizontalpodautoscaler"), queue: workqueue.NewNamedRateLimitingQueue(NewDefaultHPARateLimiter(resyncPeriod), "horizontalpodautoscaler"),
mapper: mapper,
} }
hpaInformer.Informer().AddEventHandlerWithResyncPeriod( hpaInformer.Informer().AddEventHandlerWithResyncPeriod(
@ -190,7 +193,7 @@ func (a *HorizontalController) processNextWorkItem() bool {
// Computes the desired number of replicas for the metric specifications listed in the HPA, returning the maximum // Computes the desired number of replicas for the metric specifications listed in the HPA, returning the maximum
// of the computed replica counts, a description of the associated metric, and the statuses of all metrics // of the computed replica counts, a description of the associated metric, and the statuses of all metrics
// computed. // computed.
func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, scale *extensions.Scale, func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, scale *autoscalingv1.Scale,
metricSpecs []autoscalingv2.MetricSpec) (replicas int32, metric string, statuses []autoscalingv2.MetricStatus, timestamp time.Time, err error) { metricSpecs []autoscalingv2.MetricSpec) (replicas int32, metric string, statuses []autoscalingv2.MetricStatus, timestamp time.Time, err error) {
currentReplicas := scale.Status.Replicas currentReplicas := scale.Status.Replicas
@ -198,21 +201,14 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori
statuses = make([]autoscalingv2.MetricStatus, len(metricSpecs)) statuses = make([]autoscalingv2.MetricStatus, len(metricSpecs))
for i, metricSpec := range metricSpecs { for i, metricSpec := range metricSpecs {
if len(scale.Status.Selector) == 0 && len(scale.Status.TargetSelector) == 0 { if scale.Status.Selector == "" {
errMsg := "selector is required" errMsg := "selector is required"
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "SelectorRequired", errMsg) a.eventRecorder.Event(hpa, v1.EventTypeWarning, "SelectorRequired", errMsg)
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "InvalidSelector", "the HPA target's scale is missing a selector") setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "InvalidSelector", "the HPA target's scale is missing a selector")
return 0, "", nil, time.Time{}, fmt.Errorf(errMsg) return 0, "", nil, time.Time{}, fmt.Errorf(errMsg)
} }
var selector labels.Selector selector, err := labels.Parse(scale.Status.Selector)
var err error
if len(scale.Status.Selector) > 0 {
selector = labels.SelectorFromSet(labels.Set(scale.Status.Selector))
err = nil
} else {
selector, err = labels.Parse(scale.Status.TargetSelector)
}
if err != nil { if err != nil {
errMsg := fmt.Sprintf("couldn't convert selector into a corresponding internal selector object: %v", err) errMsg := fmt.Sprintf("couldn't convert selector into a corresponding internal selector object: %v", err)
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "InvalidSelector", errMsg) a.eventRecorder.Event(hpa, v1.EventTypeWarning, "InvalidSelector", errMsg)
@ -350,7 +346,28 @@ func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.Ho
reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleTargetRef.Kind, hpa.Namespace, hpa.Spec.ScaleTargetRef.Name) reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleTargetRef.Kind, hpa.Namespace, hpa.Spec.ScaleTargetRef.Name)
scale, err := a.scaleNamespacer.Scales(hpa.Namespace).Get(hpa.Spec.ScaleTargetRef.Kind, hpa.Spec.ScaleTargetRef.Name) targetGV, err := schema.ParseGroupVersion(hpa.Spec.ScaleTargetRef.APIVersion)
if err != nil {
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error())
setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err)
a.updateStatusIfNeeded(hpaStatusOriginal, hpa)
return fmt.Errorf("invalid API version in scale target reference: %v", err)
}
targetGK := schema.GroupKind{
Group: targetGV.Group,
Kind: hpa.Spec.ScaleTargetRef.Kind,
}
mappings, err := a.mapper.RESTMappings(targetGK)
if err != nil {
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error())
setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err)
a.updateStatusIfNeeded(hpaStatusOriginal, hpa)
return fmt.Errorf("unable to determine resource for scale target reference: %v", err)
}
scale, targetGR, err := a.scaleForResourceMappings(hpa.Namespace, hpa.Spec.ScaleTargetRef.Name, mappings)
if err != nil { if err != nil {
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error()) a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error())
setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err)
@ -480,7 +497,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.Ho
if rescale { if rescale {
scale.Spec.Replicas = desiredReplicas scale.Spec.Replicas = desiredReplicas
_, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(hpa.Spec.ScaleTargetRef.Kind, scale) _, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(targetGR, scale)
if err != nil { if err != nil {
a.eventRecorder.Eventf(hpa, v1.EventTypeWarning, "FailedRescale", "New size: %d; reason: %s; error: %v", desiredReplicas, rescaleReason, err.Error()) a.eventRecorder.Eventf(hpa, v1.EventTypeWarning, "FailedRescale", "New size: %d; reason: %s; error: %v", desiredReplicas, rescaleReason, err.Error())
setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedUpdateScale", "the HPA controller was unable to update the target scale: %v", err) setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedUpdateScale", "the HPA controller was unable to update the target scale: %v", err)
@ -527,6 +544,35 @@ func (a *HorizontalController) shouldScale(hpa *autoscalingv2.HorizontalPodAutos
return false return false
} }
// scaleForResourceMappings attempts to fetch the scale for the
// resource with the given name and namespace, trying each RESTMapping
// in turn until a working one is found. If none work, the first error
// is returned. It returns both the scale, as well as the group-resource from
// the working mapping.
func (a *HorizontalController) scaleForResourceMappings(namespace, name string, mappings []*apimeta.RESTMapping) (*autoscalingv1.Scale, schema.GroupResource, error) {
var firstErr error
for i, mapping := range mappings {
targetGR := mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource).GroupResource()
scale, err := a.scaleNamespacer.Scales(namespace).Get(targetGR, name)
if err == nil {
return scale, targetGR, nil
}
// if this is the first error, remember it,
// then go on and try other mappings until we find a good one
if i == 0 {
firstErr = err
}
}
// make sure we handle an empty set of mappings
if firstErr == nil {
firstErr = fmt.Errorf("unrecognized resource")
}
return nil, schema.GroupResource{}, firstErr
}
// setCurrentReplicasInStatus sets the current replica count in the status of the HPA. // setCurrentReplicasInStatus sets the current replica count in the status of the HPA.
func (a *HorizontalController) setCurrentReplicasInStatus(hpa *autoscalingv2.HorizontalPodAutoscaler, currentReplicas int32) { func (a *HorizontalController) setCurrentReplicasInStatus(hpa *autoscalingv2.HorizontalPodAutoscaler, currentReplicas int32) {
a.setStatus(hpa, currentReplicas, hpa.Status.DesiredReplicas, hpa.Status.CurrentMetrics, false) a.setStatus(hpa, currentReplicas, hpa.Status.DesiredReplicas, hpa.Status.CurrentMetrics, false)

View File

@ -27,15 +27,16 @@ import (
autoscalingv1 "k8s.io/api/autoscaling/v1" autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2beta1" autoscalingv2 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
clientfake "k8s.io/client-go/kubernetes/fake" clientfake "k8s.io/client-go/kubernetes/fake"
scalefake "k8s.io/client-go/scale/fake"
core "k8s.io/client-go/testing" core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling"
@ -121,6 +122,7 @@ type testCase struct {
testClient *fake.Clientset testClient *fake.Clientset
testMetricsClient *metricsfake.Clientset testMetricsClient *metricsfake.Clientset
testCMClient *cmfake.FakeCustomMetricsClient testCMClient *cmfake.FakeCustomMetricsClient
testScaleClient *scalefake.FakeScaleClient
} }
// Needs to be called under a lock. // Needs to be called under a lock.
@ -144,12 +146,12 @@ func init() {
scaleUpLimitFactor = 8 scaleUpLimitFactor = 8
} }
func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfake.Clientset, *cmfake.FakeCustomMetricsClient) { func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfake.Clientset, *cmfake.FakeCustomMetricsClient, *scalefake.FakeScaleClient) {
namespace := "test-namespace" namespace := "test-namespace"
hpaName := "test-hpa" hpaName := "test-hpa"
podNamePrefix := "test-pod" podNamePrefix := "test-pod"
// TODO: also test with TargetSelector labelSet := map[string]string{"name": podNamePrefix}
selector := map[string]string{"name": podNamePrefix} selector := labels.SelectorFromSet(labelSet).String()
tc.Lock() tc.Lock()
@ -161,13 +163,11 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
tc.computeCPUCurrent() tc.computeCPUCurrent()
} }
// TODO(madhusudancs): HPA only supports resources in extensions/v1beta1 right now. Add
// tests for "v1" replicationcontrollers when HPA adds support for cross-group scale.
if tc.resource == nil { if tc.resource == nil {
tc.resource = &fakeResource{ tc.resource = &fakeResource{
name: "test-rc", name: "test-rc",
apiVersion: "extensions/v1beta1", apiVersion: "v1",
kind: "replicationcontrollers", kind: "ReplicationController",
} }
} }
tc.Unlock() tc.Unlock()
@ -239,66 +239,6 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
return true, objv1, nil return true, objv1, nil
}) })
fakeClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &extensions.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: extensions.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: extensions.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &extensions.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: extensions.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: extensions.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &extensions.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: extensions.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: extensions.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock() tc.Lock()
defer tc.Unlock() defer tc.Unlock()
@ -344,39 +284,6 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
return true, obj, nil return true, obj, nil
}) })
fakeClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*extensions.Scale)
replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*extensions.Scale)
replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*extensions.Scale)
replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) { fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock() tc.Lock()
defer tc.Unlock() defer tc.Unlock()
@ -386,8 +293,9 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected") assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected")
assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected") assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected")
if tc.verifyCPUCurrent { if tc.verifyCPUCurrent {
assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") {
assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected") assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected")
}
} }
var actualConditions []autoscalingv1.HorizontalPodAutoscalerCondition var actualConditions []autoscalingv1.HorizontalPodAutoscalerCondition
if err := json.Unmarshal([]byte(obj.ObjectMeta.Annotations[autoscaling.HorizontalPodAutoscalerConditionsAnnotation]), &actualConditions); err != nil { if err := json.Unmarshal([]byte(obj.ObjectMeta.Annotations[autoscaling.HorizontalPodAutoscalerConditionsAnnotation]), &actualConditions); err != nil {
@ -411,6 +319,100 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
return true, obj, nil return true, obj, nil
}) })
fakeScaleClient := &scalefake.FakeScaleClient{}
fakeScaleClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeScaleClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeScaleClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeScaleClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale)
replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeScaleClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale)
replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeScaleClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale)
replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeWatch := watch.NewFake() fakeWatch := watch.NewFake()
fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil)) fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil))
@ -427,7 +429,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%d", podNamePrefix, i), Name: fmt.Sprintf("%s-%d", podNamePrefix, i),
Namespace: namespace, Namespace: namespace,
Labels: selector, Labels: labelSet,
}, },
Timestamp: metav1.Time{Time: time.Now()}, Timestamp: metav1.Time{Time: time.Now()},
Containers: []metricsapi.ContainerMetrics{ Containers: []metricsapi.ContainerMetrics{
@ -522,7 +524,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
return true, metrics, nil return true, metrics, nil
}) })
return fakeClient, fakeMetricsClient, fakeCMClient return fakeClient, fakeMetricsClient, fakeCMClient, fakeScaleClient
} }
func (tc *testCase) verifyResults(t *testing.T) { func (tc *testCase) verifyResults(t *testing.T) {
@ -537,7 +539,7 @@ func (tc *testCase) verifyResults(t *testing.T) {
} }
func (tc *testCase) setupController(t *testing.T) (*HorizontalController, informers.SharedInformerFactory) { func (tc *testCase) setupController(t *testing.T) (*HorizontalController, informers.SharedInformerFactory) {
testClient, testMetricsClient, testCMClient := tc.prepareTestClient(t) testClient, testMetricsClient, testCMClient, testScaleClient := tc.prepareTestClient(t)
if tc.testClient != nil { if tc.testClient != nil {
testClient = tc.testClient testClient = tc.testClient
} }
@ -547,6 +549,9 @@ func (tc *testCase) setupController(t *testing.T) (*HorizontalController, inform
if tc.testCMClient != nil { if tc.testCMClient != nil {
testCMClient = tc.testCMClient testCMClient = tc.testCMClient
} }
if tc.testScaleClient != nil {
testScaleClient = tc.testScaleClient
}
metricsClient := metrics.NewRESTMetricsClient( metricsClient := metrics.NewRESTMetricsClient(
testMetricsClient.MetricsV1beta1(), testMetricsClient.MetricsV1beta1(),
testCMClient, testCMClient,
@ -587,8 +592,9 @@ func (tc *testCase) setupController(t *testing.T) (*HorizontalController, inform
hpaController := NewHorizontalController( hpaController := NewHorizontalController(
eventClient.Core(), eventClient.Core(),
testClient.Extensions(), testScaleClient,
testClient.Autoscaling(), testClient.Autoscaling(),
legacyscheme.Registry.RESTMapper(),
replicaCalc, replicaCalc,
informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
controller.NoResyncPeriodFunc(), controller.NoResyncPeriodFunc(),
@ -692,7 +698,7 @@ func TestScaleUpDeployment(t *testing.T) {
resource: &fakeResource{ resource: &fakeResource{
name: "test-dep", name: "test-dep",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
kind: "deployments", kind: "Deployment",
}, },
} }
tc.runTest(t) tc.runTest(t)
@ -712,7 +718,7 @@ func TestScaleUpReplicaSet(t *testing.T) {
resource: &fakeResource{ resource: &fakeResource{
name: "test-replicaset", name: "test-replicaset",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
kind: "replicasets", kind: "ReplicaSet",
}, },
} }
tc.runTest(t) tc.runTest(t)
@ -1267,18 +1273,18 @@ func TestConditionInvalidSelectorMissing(t *testing.T) {
}, },
} }
testClient, _, _ := tc.prepareTestClient(t) _, _, _, testScaleClient := tc.prepareTestClient(t)
tc.testClient = testClient tc.testScaleClient = testScaleClient
testClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { testScaleClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
obj := &extensions.Scale{ obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name, Name: tc.resource.name,
}, },
Spec: extensions.ScaleSpec{ Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas, Replicas: tc.initialReplicas,
}, },
Status: extensions.ScaleStatus{ Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas, Replicas: tc.initialReplicas,
}, },
} }
@ -1312,20 +1318,20 @@ func TestConditionInvalidSelectorUnparsable(t *testing.T) {
}, },
} }
testClient, _, _ := tc.prepareTestClient(t) _, _, _, testScaleClient := tc.prepareTestClient(t)
tc.testClient = testClient tc.testScaleClient = testScaleClient
testClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { testScaleClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
obj := &extensions.Scale{ obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name, Name: tc.resource.name,
}, },
Spec: extensions.ScaleSpec{ Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas, Replicas: tc.initialReplicas,
}, },
Status: extensions.ScaleStatus{ Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas, Replicas: tc.initialReplicas,
TargetSelector: "cheddar cheese", Selector: "cheddar cheese",
}, },
} }
return true, obj, nil return true, obj, nil
@ -1373,7 +1379,7 @@ func TestConditionFailedGetMetrics(t *testing.T) {
reportedCPURequests: []resource.Quantity{resource.MustParse("0.1"), resource.MustParse("0.1"), resource.MustParse("0.1")}, reportedCPURequests: []resource.Quantity{resource.MustParse("0.1"), resource.MustParse("0.1"), resource.MustParse("0.1")},
useMetricsAPI: true, useMetricsAPI: true,
} }
_, testMetricsClient, testCMClient := tc.prepareTestClient(t) _, testMetricsClient, testCMClient, _ := tc.prepareTestClient(t)
tc.testMetricsClient = testMetricsClient tc.testMetricsClient = testMetricsClient
tc.testCMClient = testCMClient tc.testCMClient = testCMClient
@ -1446,11 +1452,11 @@ func TestConditionFailedGetScale(t *testing.T) {
}, },
} }
testClient, _, _ := tc.prepareTestClient(t) _, _, _, testScaleClient := tc.prepareTestClient(t)
tc.testClient = testClient tc.testScaleClient = testScaleClient
testClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { testScaleClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
return true, &extensions.Scale{}, fmt.Errorf("something went wrong") return true, &autoscalingv1.Scale{}, fmt.Errorf("something went wrong")
}) })
tc.runTest(t) tc.runTest(t)
@ -1473,11 +1479,11 @@ func TestConditionFailedUpdateScale(t *testing.T) {
}), }),
} }
testClient, _, _ := tc.prepareTestClient(t) _, _, _, testScaleClient := tc.prepareTestClient(t)
tc.testClient = testClient tc.testScaleClient = testScaleClient
testClient.PrependReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { testScaleClient.PrependReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
return true, &extensions.Scale{}, fmt.Errorf("something went wrong") return true, &autoscalingv1.Scale{}, fmt.Errorf("something went wrong")
}) })
tc.runTest(t) tc.runTest(t)
@ -1659,7 +1665,7 @@ func TestAvoidUncessaryUpdates(t *testing.T) {
reportedPodReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse}, reportedPodReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse},
useMetricsAPI: true, useMetricsAPI: true,
} }
testClient, _, _ := tc.prepareTestClient(t) testClient, _, _, _ := tc.prepareTestClient(t)
tc.testClient = testClient tc.testClient = testClient
var savedHPA *autoscalingv1.HorizontalPodAutoscaler var savedHPA *autoscalingv1.HorizontalPodAutoscaler
testClient.PrependReactor("list", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) { testClient.PrependReactor("list", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {

View File

@ -30,16 +30,18 @@ import (
autoscalingv1 "k8s.io/api/autoscaling/v1" autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2beta1" autoscalingv2 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
clientfake "k8s.io/client-go/kubernetes/fake" clientfake "k8s.io/client-go/kubernetes/fake"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
scalefake "k8s.io/client-go/scale/fake"
core "k8s.io/client-go/testing" core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics"
@ -48,6 +50,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
_ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install" _ "k8s.io/kubernetes/pkg/apis/extensions/install"
) )
@ -114,12 +117,12 @@ func (tc *legacyTestCase) computeCPUCurrent() {
tc.CPUCurrent = int32(100 * reported / requested) tc.CPUCurrent = int32(100 * reported / requested)
} }
func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { func (tc *legacyTestCase) prepareTestClient(t *testing.T) (*fake.Clientset, *scalefake.FakeScaleClient) {
namespace := "test-namespace" namespace := "test-namespace"
hpaName := "test-hpa" hpaName := "test-hpa"
podNamePrefix := "test-pod" podNamePrefix := "test-pod"
// TODO: also test with TargetSelector labelSet := map[string]string{"name": podNamePrefix}
selector := map[string]string{"name": podNamePrefix} selector := labels.SelectorFromSet(labelSet).String()
tc.Lock() tc.Lock()
@ -131,13 +134,11 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset {
tc.computeCPUCurrent() tc.computeCPUCurrent()
} }
// TODO(madhusudancs): HPA only supports resources in extensions/v1beta1 right now. Add
// tests for "v1" replicationcontrollers when HPA adds support for cross-group scale.
if tc.resource == nil { if tc.resource == nil {
tc.resource = &fakeResource{ tc.resource = &fakeResource{
name: "test-rc", name: "test-rc",
apiVersion: "extensions/v1beta1", apiVersion: "v1",
kind: "replicationcontrollers", kind: "ReplicationController",
} }
} }
tc.Unlock() tc.Unlock()
@ -208,66 +209,6 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset {
return true, objv1, nil return true, objv1, nil
}) })
fakeClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &extensions.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: extensions.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: extensions.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &extensions.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: extensions.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: extensions.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &extensions.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: extensions.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: extensions.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock() tc.Lock()
defer tc.Unlock() defer tc.Unlock()
@ -386,39 +327,6 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset {
return true, newFakeResponseWrapper(heapsterRawMemResponse), nil return true, newFakeResponseWrapper(heapsterRawMemResponse), nil
}) })
fakeClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*extensions.Scale)
replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*extensions.Scale)
replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*extensions.Scale)
replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) { fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock() tc.Lock()
defer tc.Unlock() defer tc.Unlock()
@ -428,8 +336,9 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset {
assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected") assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected")
assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected") assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected")
if tc.verifyCPUCurrent { if tc.verifyCPUCurrent {
assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") {
assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected") assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected")
}
} }
tc.statusUpdated = true tc.statusUpdated = true
// Every time we reconcile HPA object we are updating status. // Every time we reconcile HPA object we are updating status.
@ -437,10 +346,104 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset {
return true, obj, nil return true, obj, nil
}) })
fakeScaleClient := &scalefake.FakeScaleClient{}
fakeScaleClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeScaleClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeScaleClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := &autoscalingv1.Scale{
ObjectMeta: metav1.ObjectMeta{
Name: tc.resource.name,
Namespace: namespace,
},
Spec: autoscalingv1.ScaleSpec{
Replicas: tc.initialReplicas,
},
Status: autoscalingv1.ScaleStatus{
Replicas: tc.initialReplicas,
Selector: selector,
},
}
return true, obj, nil
})
fakeScaleClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale)
replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeScaleClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale)
replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeScaleClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
tc.Lock()
defer tc.Unlock()
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale)
replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas
assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected")
tc.scaleUpdated = true
return true, obj, nil
})
fakeWatch := watch.NewFake() fakeWatch := watch.NewFake()
fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil)) fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil))
return fakeClient return fakeClient, fakeScaleClient
} }
func (tc *legacyTestCase) verifyResults(t *testing.T) { func (tc *legacyTestCase) verifyResults(t *testing.T) {
@ -455,7 +458,7 @@ func (tc *legacyTestCase) verifyResults(t *testing.T) {
} }
func (tc *legacyTestCase) runTest(t *testing.T) { func (tc *legacyTestCase) runTest(t *testing.T) {
testClient := tc.prepareTestClient(t) testClient, testScaleClient := tc.prepareTestClient(t)
metricsClient := metrics.NewHeapsterMetricsClient(testClient, metrics.DefaultHeapsterNamespace, metrics.DefaultHeapsterScheme, metrics.DefaultHeapsterService, metrics.DefaultHeapsterPort) metricsClient := metrics.NewHeapsterMetricsClient(testClient, metrics.DefaultHeapsterNamespace, metrics.DefaultHeapsterScheme, metrics.DefaultHeapsterService, metrics.DefaultHeapsterPort)
eventClient := &clientfake.Clientset{} eventClient := &clientfake.Clientset{}
@ -493,8 +496,9 @@ func (tc *legacyTestCase) runTest(t *testing.T) {
hpaController := NewHorizontalController( hpaController := NewHorizontalController(
eventClient.Core(), eventClient.Core(),
testClient.Extensions(), testScaleClient,
testClient.Autoscaling(), testClient.Autoscaling(),
legacyscheme.Registry.RESTMapper(),
replicaCalc, replicaCalc,
informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
controller.NoResyncPeriodFunc(), controller.NoResyncPeriodFunc(),
@ -584,7 +588,7 @@ func LegacyTestScaleUpDeployment(t *testing.T) {
resource: &fakeResource{ resource: &fakeResource{
name: "test-dep", name: "test-dep",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
kind: "deployments", kind: "Deployment",
}, },
} }
tc.runTest(t) tc.runTest(t)
@ -604,7 +608,7 @@ func LegacyTestScaleUpReplicaSet(t *testing.T) {
resource: &fakeResource{ resource: &fakeResource{
name: "test-replicaset", name: "test-replicaset",
apiVersion: "extensions/v1beta1", apiVersion: "extensions/v1beta1",
kind: "replicasets", kind: "ReplicaSet",
}, },
} }
tc.runTest(t) tc.runTest(t)

View File

@ -452,7 +452,7 @@ func TestAnnotateObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method { switch req.Method {
@ -503,7 +503,7 @@ func TestAnnotateObjectFromFile(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method { switch req.Method {
@ -552,7 +552,7 @@ func TestAnnotateObjectFromFile(t *testing.T) {
func TestAnnotateLocal(t *testing.T) { func TestAnnotateLocal(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
@ -585,7 +585,7 @@ func TestAnnotateMultipleObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method { switch req.Method {

View File

@ -302,7 +302,7 @@ func TestRunApplyViewLastApplied(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -358,7 +358,7 @@ func TestApplyObjectWithoutAnnotation(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -403,7 +403,7 @@ func TestApplyObject(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -460,7 +460,7 @@ func TestApplyObjectOutput(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &printers.YAMLPrinter{} tf.Printer = &printers.YAMLPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -505,7 +505,7 @@ func TestApplyRetry(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -559,7 +559,7 @@ func TestApplyNonExistObject(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -610,7 +610,7 @@ func testApplyMultipleObjects(t *testing.T, asList bool) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -688,7 +688,7 @@ func TestApplyNULLPreservation(t *testing.T) {
f, tf, _, _ := cmdtesting.NewTestFactory() f, tf, _, _ := cmdtesting.NewTestFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -757,7 +757,7 @@ func TestUnstructuredApply(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -821,7 +821,7 @@ func TestUnstructuredIdempotentApply(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -946,7 +946,7 @@ func TestRunApplySetLastApplied(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -1035,7 +1035,7 @@ func TestForceApply(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -140,7 +140,7 @@ func TestPodAndContainerAttach(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if test.obj != nil { if test.obj != nil {
@ -217,7 +217,7 @@ func TestAttach(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -304,7 +304,7 @@ func TestAttachWarnings(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -122,7 +122,7 @@ func TestRunAccessCheck(t *testing.T) {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews" expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews"

View File

@ -163,7 +163,7 @@ func Example_printReplicationControllerWithNamespace() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -216,7 +216,7 @@ func Example_printMultiContainersReplicationControllerWithWide() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -270,7 +270,7 @@ func Example_printReplicationController() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -325,7 +325,7 @@ func Example_printPodWithWideFormat() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -368,7 +368,7 @@ func Example_printPodWithShowLabels() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -505,7 +505,7 @@ func Example_printPodHideTerminated() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -541,7 +541,7 @@ func Example_printPodShowAll() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }
@ -570,7 +570,7 @@ func Example_printServiceWithNamespacesAndLabels() {
printersinternal.AddHandlers(p) printersinternal.AddHandlers(p)
tf.Printer = p tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: nil, Client: nil,
} }

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
) )
@ -77,7 +78,7 @@ func TestCreateClusterRoleBinding(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &ClusterRoleBindingRESTClient{ tf.Client = &ClusterRoleBindingRESTClient{
RESTClient: &fake.RESTClient{ RESTClient: &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -33,7 +33,7 @@ func TestCreateConfigMap(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -26,6 +26,7 @@ import (
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
@ -76,7 +77,7 @@ func TestCreateDeployment(t *testing.T) {
depName := "jonny-dep" depName := "jonny-dep"
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
return &http.Response{ return &http.Response{
@ -105,7 +106,7 @@ func TestCreateDeploymentNoImage(t *testing.T) {
depName := "jonny-dep" depName := "jonny-dep"
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
return &http.Response{ return &http.Response{

View File

@ -33,7 +33,7 @@ func TestCreateNamespace(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -24,6 +24,7 @@ import (
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
) )
@ -32,7 +33,7 @@ func TestCreatePdb(t *testing.T) {
pdbName := "my-pdb" pdbName := "my-pdb"
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
return &http.Response{ return &http.Response{

View File

@ -33,7 +33,7 @@ func TestCreateQuota(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -29,6 +29,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
@ -75,7 +76,7 @@ func TestCreateRoleBinding(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &RoleBindingRESTClient{ tf.Client = &RoleBindingRESTClient{
RESTClient: &fake.RESTClient{ RESTClient: &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -38,7 +38,7 @@ func TestCreateSecretGeneric(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -69,7 +69,7 @@ func TestCreateSecretDockerRegistry(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -33,7 +33,7 @@ func TestCreateService(t *testing.T) {
f, tf, codec, negSer := cmdtesting.NewAPIFactory() f, tf, codec, negSer := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: negSer, NegotiatedSerializer: negSer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -63,7 +63,7 @@ func TestCreateServiceNodePort(t *testing.T) {
f, tf, codec, negSer := cmdtesting.NewAPIFactory() f, tf, codec, negSer := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: negSer, NegotiatedSerializer: negSer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -93,7 +93,7 @@ func TestCreateServiceExternalName(t *testing.T) {
f, tf, codec, negSer := cmdtesting.NewAPIFactory() f, tf, codec, negSer := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: negSer, NegotiatedSerializer: negSer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -33,7 +33,7 @@ func TestCreateServiceAccount(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -22,6 +22,7 @@ import (
"testing" "testing"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
) )
@ -46,7 +47,7 @@ func TestCreateObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -80,7 +81,7 @@ func TestCreateMultipleObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -118,7 +119,7 @@ func TestCreateDirectory(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -58,7 +58,7 @@ func TestDeleteObjectByTuple(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -123,7 +123,7 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
var expectedOrphanDependents *bool var expectedOrphanDependents *bool
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, b := req.URL.Path, req.Method, req.Body; { switch p, m, b := req.URL.Path, req.Method, req.Body; {
@ -172,7 +172,7 @@ func TestDeleteNamedObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -223,7 +223,7 @@ func TestDeleteObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -282,7 +282,7 @@ func TestDeleteObjectGraceZero(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Logf("got request %s %s", req.Method, req.URL.Path) t.Logf("got request %s %s", req.Method, req.URL.Path)
@ -332,7 +332,7 @@ func TestDeleteObjectNotFound(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -370,7 +370,7 @@ func TestDeleteObjectIgnoreNotFound(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -408,7 +408,7 @@ func TestDeleteAllNotFound(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -458,7 +458,7 @@ func TestDeleteAllIgnoreNotFound(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -495,7 +495,7 @@ func TestDeleteMultipleObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -531,7 +531,7 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -576,7 +576,7 @@ func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -615,7 +615,7 @@ func TestDeleteDirectory(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -648,7 +648,7 @@ func TestDeleteMultipleSelector(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -23,6 +23,7 @@ import (
"testing" "testing"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
) )
@ -33,7 +34,7 @@ func TestDescribeUnknownSchemaObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewTestFactory() f, tf, codec, _ := cmdtesting.NewTestFactory()
tf.Describer = d tf.Describer = d
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
} }
@ -58,7 +59,7 @@ func TestDescribeUnknownNamespacedSchemaObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewTestFactory() f, tf, codec, _ := cmdtesting.NewTestFactory()
tf.Describer = d tf.Describer = d
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalNamespacedType("", "", "foo", "non-default"))}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalNamespacedType("", "", "foo", "non-default"))},
} }
@ -83,7 +84,7 @@ func TestDescribeObject(t *testing.T) {
d := &testDescriber{Output: "test output"} d := &testDescriber{Output: "test output"}
tf.Describer = d tf.Describer = d
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -117,7 +118,7 @@ func TestDescribeListObjects(t *testing.T) {
d := &testDescriber{Output: "test output"} d := &testDescriber{Output: "test output"}
tf.Describer = d tf.Describer = d
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
} }
@ -138,7 +139,7 @@ func TestDescribeObjectShowEvents(t *testing.T) {
d := &testDescriber{Output: "test output"} d := &testDescriber{Output: "test output"}
tf.Describer = d tf.Describer = d
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
} }
@ -160,7 +161,7 @@ func TestDescribeObjectSkipEvents(t *testing.T) {
d := &testDescriber{Output: "test output"} d := &testDescriber{Output: "test output"}
tf.Describer = d tf.Describer = d
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
} }

View File

@ -154,7 +154,7 @@ func TestCordon(t *testing.T) {
new_node := &v1.Node{} new_node := &v1.Node{}
updated := false updated := false
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
m := &MyReq{req} m := &MyReq{req}
@ -597,7 +597,7 @@ func TestDrain(t *testing.T) {
evicted := false evicted := false
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
m := &MyReq{req} m := &MyReq{req}

View File

@ -36,6 +36,7 @@ import (
"k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -217,7 +218,7 @@ func TestEdit(t *testing.T) {
versionedAPIPath = "/apis/" + mapping.GroupVersionKind.Group + "/" + mapping.GroupVersionKind.Version versionedAPIPath = "/apis/" + mapping.GroupVersionKind.Group + "/" + mapping.GroupVersionKind.Version
} }
return &fake.RESTClient{ return &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
VersionedAPIPath: versionedAPIPath, VersionedAPIPath: versionedAPIPath,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(reqResp), Client: fake.CreateHTTPClient(reqResp),

View File

@ -131,7 +131,7 @@ func TestPodAndContainer(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }), Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }),
} }
@ -186,7 +186,7 @@ func TestExec(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -463,7 +463,7 @@ func TestRunExposeService(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &printers.JSONPrinter{} tf.Printer = &printers.JSONPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -126,7 +126,7 @@ func TestGetUnknownSchemaObject(t *testing.T) {
_, _, codec, _ := cmdtesting.NewTestFactory() _, _, codec, _ := cmdtesting.NewTestFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
} }
@ -171,7 +171,7 @@ func TestGetSchemaObject(t *testing.T) {
codec := testapi.Default.Codec() codec := testapi.Default.Codec()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})},
} }
@ -197,7 +197,7 @@ func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) {
// for Pod type. // for Pod type.
tf.OpenAPISchemaFunc = testOpenAPISchemaData tf.OpenAPISchemaFunc = testOpenAPISchemaData
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
} }
@ -251,7 +251,7 @@ func TestGetObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
} }
@ -303,7 +303,7 @@ func TestGetObjectsFiltered(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{GenericPrinter: test.genericPrinter} tf.Printer = &testPrinter{GenericPrinter: test.genericPrinter}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.resp)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.resp)},
} }
@ -344,7 +344,7 @@ func TestGetObjectIgnoreNotFound(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{GenericPrinter: true} tf.Printer = &testPrinter{GenericPrinter: true}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -397,7 +397,7 @@ func TestGetSortedObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
} }
@ -456,7 +456,7 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{GenericPrinter: true} tf.Printer = &testPrinter{GenericPrinter: true}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
} }
@ -483,7 +483,7 @@ func TestGetListObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
} }
@ -524,7 +524,7 @@ func TestGetAllListObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
} }
@ -554,7 +554,7 @@ func TestGetListComponentStatus(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, statuses)}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, statuses)},
} }
@ -596,7 +596,7 @@ func TestGetMixedGenericObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{GenericPrinter: true} tf.Printer = &testPrinter{GenericPrinter: true}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -660,7 +660,7 @@ func TestGetMultipleTypeObjects(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -699,7 +699,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{GenericPrinter: true} tf.Printer = &testPrinter{GenericPrinter: true}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -764,7 +764,7 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if req.URL.Query().Get(metav1.LabelSelectorQueryParam(legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" { if req.URL.Query().Get(metav1.LabelSelectorQueryParam(legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" {
@ -816,7 +816,7 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -853,7 +853,7 @@ func TestGetByFormatForcesFlag(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{GenericPrinter: true} tf.Printer = &testPrinter{GenericPrinter: true}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
} }
@ -954,7 +954,7 @@ func TestWatchSelector(t *testing.T) {
}, },
} }
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if req.URL.Query().Get(metav1.LabelSelectorQueryParam(legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" { if req.URL.Query().Get(metav1.LabelSelectorQueryParam(legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" {
@ -998,7 +998,7 @@ func TestWatchResource(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -1040,7 +1040,7 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -1083,7 +1083,7 @@ func TestWatchOnlyResource(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {
@ -1131,7 +1131,7 @@ func TestWatchOnlyList(t *testing.T) {
}, },
} }
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.URL.Path { switch req.URL.Path {

View File

@ -358,7 +358,7 @@ func TestLabelForResourceFromFile(t *testing.T) {
pods, _, _ := testData() pods, _, _ := testData()
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method { switch req.Method {
@ -409,7 +409,7 @@ func TestLabelForResourceFromFile(t *testing.T) {
func TestLabelLocal(t *testing.T) { func TestLabelLocal(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
@ -443,7 +443,7 @@ func TestLabelMultipleObjects(t *testing.T) {
pods, _, _ := testData() pods, _, _ := testData()
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch req.Method { switch req.Method {

View File

@ -52,7 +52,7 @@ func TestLog(t *testing.T) {
logContent := "test log content" logContent := "test log content"
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -23,6 +23,7 @@ import (
"testing" "testing"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/printers"
@ -33,7 +34,7 @@ func TestPatchObject(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -72,7 +73,7 @@ func TestPatchObjectFromFile(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -107,7 +108,7 @@ func TestPatchNoop(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -153,7 +154,7 @@ func TestPatchObjectFromFileOutput(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &printers.YAMLPrinter{} tf.Printer = &printers.YAMLPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -70,7 +70,7 @@ func testPortForward(t *testing.T, flags map[string]string, args []string) {
var err error var err error
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -35,7 +35,7 @@ func TestReplaceObject(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
deleted := false deleted := false
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -92,7 +92,7 @@ func TestReplaceMultipleObject(t *testing.T) {
redisMasterDeleted := false redisMasterDeleted := false
frontendDeleted := false frontendDeleted := false
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -161,7 +161,7 @@ func TestReplaceDirectory(t *testing.T) {
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
created := map[string]bool{} created := map[string]bool{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -217,7 +217,7 @@ func TestForceReplaceObjectNotFound(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {

View File

@ -164,7 +164,7 @@ func TestRunArgsFollowDashRules(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if req.URL.Path == "/namespaces/test/replicationcontrollers" { if req.URL.Path == "/namespaces/test/replicationcontrollers" {
@ -288,7 +288,7 @@ func TestGenerateService(t *testing.T) {
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}}
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -429,7 +429,7 @@ func TestRunValidations(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewTestFactory() f, tf, codec, ns := cmdtesting.NewTestFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", ""))}, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", ""))},
} }

View File

@ -74,6 +74,7 @@ go_test(
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime: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/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library", "//vendor/k8s.io/client-go/rest/fake:go_default_library",
], ],

View File

@ -36,7 +36,7 @@ import (
func TestSetEnvLocal(t *testing.T) { func TestSetEnvLocal(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)

View File

@ -35,7 +35,7 @@ import (
func TestImageLocal(t *testing.T) { func TestImageLocal(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)

View File

@ -35,7 +35,7 @@ import (
func TestResourcesLocal(t *testing.T) { func TestResourcesLocal(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)

View File

@ -318,7 +318,7 @@ func TestGetResourcesAndSelector(t *testing.T) {
func TestSelectorTest(t *testing.T) { func TestSelectorTest(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)

View File

@ -29,6 +29,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
@ -65,7 +66,7 @@ func TestServiceAccountLocal(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
return nil, nil return nil, nil
@ -155,7 +156,7 @@ func TestServiceAccountRemote(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.CategoryExpander = resource.LegacyCategoryExpander tf.CategoryExpander = resource.LegacyCategoryExpander
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(input.apiGroup).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1]) resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1])
@ -179,7 +180,6 @@ func TestServiceAccountRemote(t *testing.T) {
} }
}), }),
VersionedAPIPath: path.Join(input.apiPrefix, groupVersion.String()), VersionedAPIPath: path.Join(input.apiPrefix, groupVersion.String()),
GroupName: input.apiGroup,
} }
out := new(bytes.Buffer) out := new(bytes.Buffer)
cmd := NewCmdServiceAccount(f, out, out) cmd := NewCmdServiceAccount(f, out, out)
@ -207,7 +207,7 @@ func TestServiceAccountValidation(t *testing.T) {
for _, input := range inputs { for _, input := range inputs {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: schema.GroupVersion{Version: "v1"},
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
return nil, nil return nil, nil

View File

@ -29,6 +29,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -242,7 +243,7 @@ func TestTaint(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
m := &MyReq{req} m := &MyReq{req}

View File

@ -46,7 +46,7 @@ func TestTopNodeAllMetrics(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -92,7 +92,7 @@ func TestTopNodeAllMetricsCustomDefaults(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -148,7 +148,7 @@ func TestTopNodeWithNameMetrics(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -208,7 +208,7 @@ func TestTopNodeWithLabelSelectorMetrics(t *testing.T) {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; { switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; {

View File

@ -29,6 +29,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
metricsapi "k8s.io/metrics/pkg/apis/metrics/v1alpha1" metricsapi "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
@ -118,7 +119,7 @@ func TestTopPod(t *testing.T) {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; { switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; {
@ -254,7 +255,7 @@ func TestTopPodCustomDefaults(t *testing.T) {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; { switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; {

View File

@ -72,7 +72,7 @@ func fakeClient() ClientMapper {
func fakeClientWith(testName string, t *testing.T, data map[string]string) ClientMapper { func fakeClientWith(testName string, t *testing.T, data map[string]string) ClientMapper {
return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) { return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) {
return &fake.RESTClient{ return &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p := req.URL.Path p := req.URL.Path

View File

@ -104,7 +104,7 @@ func TestHelperDelete(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
client := &fake.RESTClient{ client := &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Resp: test.Resp, Resp: test.Resp,
Err: test.HttpErr, Err: test.HttpErr,
@ -195,7 +195,7 @@ func TestHelperCreate(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
client := &fake.RESTClient{ client := &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Resp: test.Resp, Resp: test.Resp,
Err: test.HttpErr, Err: test.HttpErr,
@ -276,7 +276,7 @@ func TestHelperGet(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
client := &fake.RESTClient{ client := &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Resp: test.Resp, Resp: test.Resp,
Err: test.HttpErr, Err: test.HttpErr,
@ -350,7 +350,7 @@ func TestHelperList(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
client := &fake.RESTClient{ client := &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Resp: test.Resp, Resp: test.Resp,
Err: test.HttpErr, Err: test.HttpErr,
@ -484,7 +484,7 @@ func TestHelperReplace(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
client := &fake.RESTClient{ client := &fake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: test.HTTPClient, Client: test.HTTPClient,
Resp: test.Resp, Resp: test.Resp,

View File

@ -1469,7 +1469,7 @@ func TestUpdateRcWithRetries(t *testing.T) {
{StatusCode: 200, Header: header, Body: objBody(codec, rc)}, {StatusCode: 200, Header: header, Body: objBody(codec, rc)},
} }
fakeClient := &manualfake.RESTClient{ fakeClient := &manualfake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
@ -1562,7 +1562,7 @@ func TestAddDeploymentHash(t *testing.T) {
seen := sets.String{} seen := sets.String{}
updatedRc := false updatedRc := false
fakeClient := &manualfake.RESTClient{ fakeClient := &manualfake.RESTClient{
APIRegistry: legacyscheme.Registry, GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
header := http.Header{} header := http.Header{}

View File

@ -167,6 +167,7 @@ filegroup(
"//staging/src/k8s.io/client-go/plugin/pkg/auth/authenticator/token/oidc/testing:all-srcs", "//staging/src/k8s.io/client-go/plugin/pkg/auth/authenticator/token/oidc/testing:all-srcs",
"//staging/src/k8s.io/client-go/plugin/pkg/client/auth:all-srcs", "//staging/src/k8s.io/client-go/plugin/pkg/client/auth:all-srcs",
"//staging/src/k8s.io/client-go/rest:all-srcs", "//staging/src/k8s.io/client-go/rest:all-srcs",
"//staging/src/k8s.io/client-go/scale:all-srcs",
"//staging/src/k8s.io/client-go/testing:all-srcs", "//staging/src/k8s.io/client-go/testing:all-srcs",
"//staging/src/k8s.io/client-go/third_party/forked/golang/template:all-srcs", "//staging/src/k8s.io/client-go/third_party/forked/golang/template:all-srcs",
"//staging/src/k8s.io/client-go/tools/auth:all-srcs", "//staging/src/k8s.io/client-go/tools/auth:all-srcs",

View File

@ -18,7 +18,10 @@ package fuzzer
import ( import (
"fmt" "fmt"
"math/rand"
"sort"
"strconv" "strconv"
"strings"
"github.com/google/gofuzz" "github.com/google/gofuzz"
@ -96,7 +99,80 @@ func genericFuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
} }
} }
// taken from gofuzz internals for RandString
type charRange struct {
first, last rune
}
func (c *charRange) choose(r *rand.Rand) rune {
count := int64(c.last - c.first + 1)
ch := c.first + rune(r.Int63n(count))
return ch
}
// randomLabelPart produces a valid random label value or name-part
// of a label key.
func randomLabelPart(c fuzz.Continue, canBeEmpty bool) string {
validStartEnd := []charRange{{'0', '9'}, {'a', 'z'}, {'A', 'Z'}}
validMiddle := []charRange{{'0', '9'}, {'a', 'z'}, {'A', 'Z'},
{'.', '.'}, {'-', '-'}, {'_', '_'}}
partLen := c.Rand.Intn(64) // len is [0, 63]
if !canBeEmpty {
partLen = c.Rand.Intn(63) + 1 // len is [1, 63]
}
runes := make([]rune, partLen)
if partLen == 0 {
return string(runes)
}
runes[0] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
for i := range runes[1:] {
runes[i+1] = validMiddle[c.Rand.Intn(len(validMiddle))].choose(c.Rand)
}
runes[len(runes)-1] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
return string(runes)
}
func randomDNSLabel(c fuzz.Continue) string {
validStartEnd := []charRange{{'0', '9'}, {'a', 'z'}}
validMiddle := []charRange{{'0', '9'}, {'a', 'z'}, {'-', '-'}}
partLen := c.Rand.Intn(63) + 1 // len is [1, 63]
runes := make([]rune, partLen)
runes[0] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
for i := range runes[1:] {
runes[i+1] = validMiddle[c.Rand.Intn(len(validMiddle))].choose(c.Rand)
}
runes[len(runes)-1] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
return string(runes)
}
func randomLabelKey(c fuzz.Continue) string {
namePart := randomLabelPart(c, false)
prefixPart := ""
usePrefix := c.RandBool()
if usePrefix {
// we can fit, with dots, at most 3 labels in the 253 allotted characters
prefixPartsLen := c.Rand.Intn(2) + 1
prefixParts := make([]string, prefixPartsLen)
for i := range prefixParts {
prefixParts[i] = randomDNSLabel(c)
}
prefixPart = strings.Join(prefixParts, ".") + "/"
}
return prefixPart + namePart
}
func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} { func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
return []interface{}{ return []interface{}{
func(j *metav1.TypeMeta, c fuzz.Continue) { func(j *metav1.TypeMeta, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their // We have to customize the randomization of TypeMetas because their
@ -120,6 +196,57 @@ func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10) j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
j.SelfLink = c.RandString() j.SelfLink = c.RandString()
}, },
func(j *metav1.LabelSelector, c fuzz.Continue) {
c.FuzzNoCustom(j)
// we can't have an entirely empty selector, so force
// use of MatchExpression if necessary
if len(j.MatchLabels) == 0 && len(j.MatchExpressions) == 0 {
j.MatchExpressions = make([]metav1.LabelSelectorRequirement, c.Rand.Intn(2)+1)
}
if j.MatchLabels != nil {
fuzzedMatchLabels := make(map[string]string, len(j.MatchLabels))
for i := 0; i < len(j.MatchLabels); i++ {
fuzzedMatchLabels[randomLabelKey(c)] = randomLabelPart(c, true)
}
j.MatchLabels = fuzzedMatchLabels
}
validOperators := []metav1.LabelSelectorOperator{
metav1.LabelSelectorOpIn,
metav1.LabelSelectorOpNotIn,
metav1.LabelSelectorOpExists,
metav1.LabelSelectorOpDoesNotExist,
}
if j.MatchExpressions != nil {
// NB: the label selector parser code sorts match expressions by key, and sorts the values,
// so we need to make sure ours are sorted as well here to preserve round-trip comparision.
// In practice, not sorting doesn't hurt anything...
for i := range j.MatchExpressions {
req := metav1.LabelSelectorRequirement{}
c.Fuzz(&req)
req.Key = randomLabelKey(c)
req.Operator = validOperators[c.Rand.Intn(len(validOperators))]
if req.Operator == metav1.LabelSelectorOpIn || req.Operator == metav1.LabelSelectorOpNotIn {
if len(req.Values) == 0 {
// we must have some values here, so randomly choose a short length
req.Values = make([]string, c.Rand.Intn(2)+1)
}
for i := range req.Values {
req.Values[i] = randomLabelPart(c, true)
}
sort.Strings(req.Values)
} else {
req.Values = nil
}
j.MatchExpressions[i] = req
}
sort.Slice(j.MatchExpressions, func(a, b int) bool { return j.MatchExpressions[a].Key < j.MatchExpressions[b].Key })
}
},
} }
} }

View File

@ -490,14 +490,34 @@
"ImportPath": "k8s.io/apimachinery/pkg/api/resource", "ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}, },
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery", "ImportPath": "k8s.io/apimachinery/pkg/apimachinery",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}, },
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}, },
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

View File

@ -68,7 +68,44 @@ func (c *FakeDiscovery) ServerPreferredNamespacedResources() ([]*metav1.APIResou
} }
func (c *FakeDiscovery) ServerGroups() (*metav1.APIGroupList, error) { func (c *FakeDiscovery) ServerGroups() (*metav1.APIGroupList, error) {
return nil, nil action := testing.ActionImpl{
Verb: "get",
Resource: schema.GroupVersionResource{Resource: "group"},
}
c.Invokes(action, nil)
groups := map[string]*metav1.APIGroup{}
for _, res := range c.Resources {
gv, err := schema.ParseGroupVersion(res.GroupVersion)
if err != nil {
return nil, err
}
group := groups[gv.Group]
if group == nil {
group = &metav1.APIGroup{
Name: gv.Group,
PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: res.GroupVersion,
Version: gv.Version,
},
}
groups[gv.Group] = group
}
group.Versions = append(group.Versions, metav1.GroupVersionForDiscovery{
GroupVersion: res.GroupVersion,
Version: gv.Version,
})
}
list := &metav1.APIGroupList{}
for _, apiGroup := range groups {
list.Groups = append(list.Groups, *apiGroup)
}
return list, nil
} }
func (c *FakeDiscovery) ServerVersion() (*version.Info, error) { func (c *FakeDiscovery) ServerVersion() (*version.Info, error) {

View File

@ -10,7 +10,6 @@ go_library(
srcs = ["fake.go"], srcs = ["fake.go"],
importpath = "k8s.io/client-go/rest/fake", importpath = "k8s.io/client-go/rest/fake",
deps = [ deps = [
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime: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/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",

View File

@ -22,7 +22,6 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@ -46,8 +45,7 @@ func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
type RESTClient struct { type RESTClient struct {
Client *http.Client Client *http.Client
NegotiatedSerializer runtime.NegotiatedSerializer NegotiatedSerializer runtime.NegotiatedSerializer
GroupName string GroupVersion schema.GroupVersion
APIRegistry *registered.APIRegistrationManager
VersionedAPIPath string VersionedAPIPath string
Req *http.Request Req *http.Request
@ -80,7 +78,7 @@ func (c *RESTClient) Verb(verb string) *restclient.Request {
} }
func (c *RESTClient) APIVersion() schema.GroupVersion { func (c *RESTClient) APIVersion() schema.GroupVersion {
return c.APIRegistry.GroupOrDie("").GroupVersion return c.GroupVersion
} }
func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter { func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
@ -89,22 +87,20 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
func (c *RESTClient) request(verb string) *restclient.Request { func (c *RESTClient) request(verb string) *restclient.Request {
config := restclient.ContentConfig{ config := restclient.ContentConfig{
ContentType: runtime.ContentTypeJSON, ContentType: runtime.ContentTypeJSON,
// TODO this was hardcoded before, but it doesn't look right GroupVersion: &c.GroupVersion,
GroupVersion: &c.APIRegistry.GroupOrDie("").GroupVersion,
NegotiatedSerializer: c.NegotiatedSerializer, NegotiatedSerializer: c.NegotiatedSerializer,
} }
ns := c.NegotiatedSerializer ns := c.NegotiatedSerializer
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON) info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
internalVersion := schema.GroupVersion{ internalVersion := schema.GroupVersion{
Group: c.APIRegistry.GroupOrDie(c.GroupName).GroupVersion.Group, Group: c.GroupVersion.Group,
Version: runtime.APIVersionInternal, Version: runtime.APIVersionInternal,
} }
internalVersion.Version = runtime.APIVersionInternal
serializers := restclient.Serializers{ serializers := restclient.Serializers{
// TODO this was hardcoded before, but it doesn't look right // TODO this was hardcoded before, but it doesn't look right
Encoder: ns.EncoderForVersion(info.Serializer, c.APIRegistry.GroupOrDie("").GroupVersion), Encoder: ns.EncoderForVersion(info.Serializer, c.GroupVersion),
Decoder: ns.DecoderToVersion(info.Serializer, internalVersion), Decoder: ns.DecoderToVersion(info.Serializer, internalVersion),
} }
if info.StreamSerializer != nil { if info.StreamSerializer != nil {

View File

@ -56,6 +56,14 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de
// hostURL.Path should be blank. // hostURL.Path should be blank.
// //
// versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base // versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base
versionedAPIPath := DefaultVersionedAPIPath(apiPath, groupVersion)
return hostURL, versionedAPIPath, nil
}
// DefaultVersionedAPIPathFor constructs the default path for the given group version, assuming the given
// API path, following the standard conventions of the Kubernetes API.
func DefaultVersionedAPIPath(apiPath string, groupVersion schema.GroupVersion) string {
versionedAPIPath := path.Join("/", apiPath) versionedAPIPath := path.Join("/", apiPath)
// Add the version to the end of the path // Add the version to the end of the path
@ -64,10 +72,9 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de
} else { } else {
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version) versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version)
} }
return hostURL, versionedAPIPath, nil return versionedAPIPath
} }
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It // defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It

View File

@ -0,0 +1,73 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"client.go",
"doc.go",
"interfaces.go",
"util.go",
],
importpath = "k8s.io/client-go/scale",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta: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/runtime/serializer:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/scale/scheme:go_default_library",
"//vendor/k8s.io/client-go/scale/scheme/autoscalingv1:go_default_library",
"//vendor/k8s.io/client-go/scale/scheme/extensionsint:go_default_library",
"//vendor/k8s.io/client-go/scale/scheme/extensionsv1beta1:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"client_test.go",
"roundtrip_test.go",
],
importpath = "k8s.io/client-go/scale",
library = ":go_default_library",
deps = [
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/apps/v1beta2:go_default_library",
"//vendor/k8s.io/api/autoscaling/v1: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/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/runtime/serializer:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/discovery/fake:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/client-go/scale/fake:all-srcs",
"//staging/src/k8s.io/client-go/scale/scheme:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,197 @@
/*
Copyright 2017 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 scale
import (
"fmt"
autoscaling "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/dynamic"
restclient "k8s.io/client-go/rest"
)
var scaleConverter = NewScaleConverter()
var codecs = serializer.NewCodecFactory(scaleConverter.Scheme())
// restInterfaceProvider turns a restclient.Config into a restclient.Interface.
// It's overridable for the purposes of testing.
type restInterfaceProvider func(*restclient.Config) (restclient.Interface, error)
// scaleClient is an implementation of ScalesGetter
// which makes use of a RESTMapper and a generic REST
// client to support an discoverable resource.
// It behaves somewhat similarly to the dynamic ClientPool,
// but is more specifically scoped to Scale.
type scaleClient struct {
mapper meta.RESTMapper
apiPathResolverFunc dynamic.APIPathResolverFunc
scaleKindResolver ScaleKindResolver
clientBase restclient.Interface
}
// NewForConfig creates a new ScalesGetter which resolves kinds
// to resources using the given RESTMapper, and API paths using
// the given dynamic.APIPathResolverFunc.
func NewForConfig(cfg *restclient.Config, mapper meta.RESTMapper, resolver dynamic.APIPathResolverFunc, scaleKindResolver ScaleKindResolver) (ScalesGetter, error) {
// so that the RESTClientFor doesn't complain
cfg.GroupVersion = &schema.GroupVersion{}
cfg.NegotiatedSerializer = serializer.DirectCodecFactory{
CodecFactory: codecs,
}
if len(cfg.UserAgent) == 0 {
cfg.UserAgent = restclient.DefaultKubernetesUserAgent()
}
client, err := restclient.RESTClientFor(cfg)
if err != nil {
return nil, err
}
return New(client, mapper, resolver, scaleKindResolver), nil
}
// New creates a new ScalesGetter using the given client to make requests.
// The GroupVersion on the client is ignored.
func New(baseClient restclient.Interface, mapper meta.RESTMapper, resolver dynamic.APIPathResolverFunc, scaleKindResolver ScaleKindResolver) ScalesGetter {
return &scaleClient{
mapper: mapper,
apiPathResolverFunc: resolver,
scaleKindResolver: scaleKindResolver,
clientBase: baseClient,
}
}
// pathAndVersionFor returns the appropriate base path and the associated full GroupVersionResource
// for the given GroupResource
func (c *scaleClient) pathAndVersionFor(resource schema.GroupResource) (string, schema.GroupVersionResource, error) {
gvr, err := c.mapper.ResourceFor(resource.WithVersion(""))
if err != nil {
return "", gvr, fmt.Errorf("unable to get full preferred group-version-resource for %s: %v", resource.String(), err)
}
groupVer := gvr.GroupVersion()
// we need to set the API path based on GroupVersion (defaulting to the legacy path if none is set)
// TODO: we "cheat" here since the API path really only depends on group ATM, but this should
// *probably* take GroupVersionResource and not GroupVersionKind.
apiPath := c.apiPathResolverFunc(groupVer.WithKind(""))
if apiPath == "" {
apiPath = "/api"
}
path := restclient.DefaultVersionedAPIPath(apiPath, groupVer)
return path, gvr, nil
}
// namespacedScaleClient is an ScaleInterface for fetching
// Scales in a given namespace.
type namespacedScaleClient struct {
client *scaleClient
namespace string
}
func (c *scaleClient) Scales(namespace string) ScaleInterface {
return &namespacedScaleClient{
client: c,
namespace: namespace,
}
}
func (c *namespacedScaleClient) Get(resource schema.GroupResource, name string) (*autoscaling.Scale, error) {
// Currently, a /scale endpoint can return different scale types.
// Until we have support for the alternative API representations proposal,
// we need to deal with accepting different API versions.
// In practice, this is autoscaling/v1.Scale and extensions/v1beta1.Scale
path, gvr, err := c.client.pathAndVersionFor(resource)
if err != nil {
return nil, fmt.Errorf("unable to get client for %s: %v", resource.String(), err)
}
rawObj, err := c.client.clientBase.Get().
AbsPath(path).
Namespace(c.namespace).
Resource(gvr.Resource).
Name(name).
SubResource("scale").
Do().
Get()
if err != nil {
return nil, err
}
// convert whatever this is to autoscaling/v1.Scale
scaleObj, err := scaleConverter.ConvertToVersion(rawObj, autoscaling.SchemeGroupVersion)
if err != nil {
return nil, fmt.Errorf("received an object from a /scale endpoint which was not convertible to autoscaling Scale: %v", err)
}
return scaleObj.(*autoscaling.Scale), nil
}
func (c *namespacedScaleClient) Update(resource schema.GroupResource, scale *autoscaling.Scale) (*autoscaling.Scale, error) {
path, gvr, err := c.client.pathAndVersionFor(resource)
if err != nil {
return nil, fmt.Errorf("unable to get client for %s: %v", resource.String(), err)
}
// Currently, a /scale endpoint can receive and return different scale types.
// Until we hvae support for the alternative API representations proposal,
// we need to deal with sending and accepting differnet API versions.
// figure out what scale we actually need here
desiredGVK, err := c.client.scaleKindResolver.ScaleForResource(gvr)
if err != nil {
return nil, fmt.Errorf("could not find proper group-version for scale subresource of %s: %v", gvr.String(), err)
}
// convert this to whatever this endpoint wants
scaleUpdate, err := scaleConverter.ConvertToVersion(scale, desiredGVK.GroupVersion())
if err != nil {
return nil, fmt.Errorf("could not convert scale update to internal Scale: %v", err)
}
rawObj, err := c.client.clientBase.Put().
AbsPath(path).
Namespace(c.namespace).
Resource(gvr.Resource).
Name(scale.Name).
SubResource("scale").
Body(scaleUpdate).
Do().
Get()
if err != nil {
return nil, fmt.Errorf("could not fetch the scale for %s %s: %v", resource.String(), scale.Name, err)
}
// convert whatever this is back to autoscaling/v1.Scale
scaleObj, err := scaleConverter.ConvertToVersion(rawObj, autoscaling.SchemeGroupVersion)
if err != nil {
return nil, fmt.Errorf("received an object from a /scale endpoint which was not convertible to autoscaling Scale: %v", err)
}
return scaleObj.(*autoscaling.Scale), err
}

View File

@ -0,0 +1,246 @@
/*
Copyright 2017 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 scale
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/discovery"
fakedisco "k8s.io/client-go/discovery/fake"
"k8s.io/client-go/dynamic"
fakerest "k8s.io/client-go/rest/fake"
"github.com/stretchr/testify/assert"
appsv1beta2 "k8s.io/api/apps/v1beta2"
autoscalingv1 "k8s.io/api/autoscaling/v1"
corev1 "k8s.io/api/core/v1"
extv1beta1 "k8s.io/api/extensions/v1beta1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
coretesting "k8s.io/client-go/testing"
)
func bytesBody(bodyBytes []byte) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader(bodyBytes))
}
func defaultHeaders() http.Header {
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return header
}
func fakeScaleClient(t *testing.T) (ScalesGetter, []schema.GroupResource) {
fakeDiscoveryClient := &fakedisco.FakeDiscovery{Fake: &coretesting.Fake{}}
fakeDiscoveryClient.Resources = []*metav1.APIResourceList{
{
GroupVersion: corev1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "pods", Namespaced: true, Kind: "Pod"},
{Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController"},
{Name: "replicationcontrollers/scale", Namespaced: true, Kind: "Scale", Group: "autoscaling", Version: "v1"},
},
},
{
GroupVersion: extv1beta1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "replicasets", Namespaced: true, Kind: "ReplicaSet"},
{Name: "replicasets/scale", Namespaced: true, Kind: "Scale"},
},
},
{
GroupVersion: appsv1beta2.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
{Name: "deployments/scale", Namespaced: true, Kind: "Scale", Group: "autoscaling", Version: "v1"},
},
},
// test a resource that doesn't exist anywere to make sure we're not accidentally depending
// on a static RESTMapper anywhere.
{
GroupVersion: "cheese.testing.k8s.io/v27alpha15",
APIResources: []metav1.APIResource{
{Name: "cheddars", Namespaced: true, Kind: "Cheddar"},
{Name: "cheddars/scale", Namespaced: true, Kind: "Scale", Group: "extensions", Version: "v1beta1"},
},
},
}
restMapperRes, err := discovery.GetAPIGroupResources(fakeDiscoveryClient)
if err != nil {
t.Fatalf("unexpected error while constructing resource list from fake discovery client: %v")
}
restMapper := discovery.NewRESTMapper(restMapperRes, apimeta.InterfacesForUnstructured)
autoscalingScale := &autoscalingv1.Scale{
TypeMeta: metav1.TypeMeta{
Kind: "Scale",
APIVersion: autoscalingv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: autoscalingv1.ScaleSpec{Replicas: 10},
Status: autoscalingv1.ScaleStatus{
Replicas: 10,
Selector: "foo=bar",
},
}
extScale := &extv1beta1.Scale{
TypeMeta: metav1.TypeMeta{
Kind: "Scale",
APIVersion: extv1beta1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: extv1beta1.ScaleSpec{Replicas: 10},
Status: extv1beta1.ScaleStatus{
Replicas: 10,
TargetSelector: "foo=bar",
},
}
resourcePaths := map[string]runtime.Object{
"/api/v1/namespaces/default/replicationcontrollers/foo/scale": autoscalingScale,
"/apis/extensions/v1beta1/namespaces/default/replicasets/foo/scale": extScale,
"/apis/apps/v1beta2/namespaces/default/deployments/foo/scale": autoscalingScale,
"/apis/cheese.testing.k8s.io/v27alpha15/namespaces/default/cheddars/foo/scale": extScale,
}
fakeReqHandler := func(req *http.Request) (*http.Response, error) {
scale, isScalePath := resourcePaths[req.URL.Path]
if !isScalePath {
return nil, fmt.Errorf("unexpected request for URL %q with method %q", req.URL.String(), req.Method)
}
switch req.Method {
case "GET":
res, err := json.Marshal(scale)
if err != nil {
return nil, err
}
return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil
case "PUT":
decoder := codecs.UniversalDeserializer()
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
newScale, newScaleGVK, err := decoder.Decode(body, nil, nil)
if err != nil {
return nil, fmt.Errorf("unexpected request body: %v", err)
}
if *newScaleGVK != scale.GetObjectKind().GroupVersionKind() {
return nil, fmt.Errorf("unexpected scale API version %s (expected %s)", newScaleGVK.String(), scale.GetObjectKind().GroupVersionKind().String())
}
res, err := json.Marshal(newScale)
if err != nil {
return nil, err
}
return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil
default:
return nil, fmt.Errorf("unexpected request for URL %q with method %q", req.URL.String(), req.Method)
}
}
fakeClient := &fakerest.RESTClient{
Client: fakerest.CreateHTTPClient(fakeReqHandler),
NegotiatedSerializer: serializer.DirectCodecFactory{
CodecFactory: codecs,
},
GroupVersion: schema.GroupVersion{},
VersionedAPIPath: "/not/a/real/path",
}
resolver := NewDiscoveryScaleKindResolver(fakeDiscoveryClient)
client := New(fakeClient, restMapper, dynamic.LegacyAPIPathResolverFunc, resolver)
groupResources := []schema.GroupResource{
{Group: corev1.GroupName, Resource: "replicationcontroller"},
{Group: extv1beta1.GroupName, Resource: "replicaset"},
{Group: appsv1beta2.GroupName, Resource: "deployment"},
{Group: "cheese.testing.k8s.io", Resource: "cheddar"},
}
return client, groupResources
}
func TestGetScale(t *testing.T) {
scaleClient, groupResources := fakeScaleClient(t)
expectedScale := &autoscalingv1.Scale{
TypeMeta: metav1.TypeMeta{
Kind: "Scale",
APIVersion: autoscalingv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: autoscalingv1.ScaleSpec{Replicas: 10},
Status: autoscalingv1.ScaleStatus{
Replicas: 10,
Selector: "foo=bar",
},
}
for _, groupResource := range groupResources {
scale, err := scaleClient.Scales("default").Get(groupResource, "foo")
if !assert.NoError(t, err, "should have been able to fetch a scale for %s", groupResource.String()) {
continue
}
assert.NotNil(t, scale, "should have returned a non-nil scale for %s", groupResource.String())
assert.Equal(t, expectedScale, scale, "should have returned the expected scale for %s", groupResource.String())
}
}
func TestUpdateScale(t *testing.T) {
scaleClient, groupResources := fakeScaleClient(t)
expectedScale := &autoscalingv1.Scale{
TypeMeta: metav1.TypeMeta{
Kind: "Scale",
APIVersion: autoscalingv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: autoscalingv1.ScaleSpec{Replicas: 10},
Status: autoscalingv1.ScaleStatus{
Replicas: 10,
Selector: "foo=bar",
},
}
for _, groupResource := range groupResources {
scale, err := scaleClient.Scales("default").Update(groupResource, expectedScale)
if !assert.NoError(t, err, "should have been able to fetch a scale for %s", groupResource.String()) {
continue
}
assert.NotNil(t, scale, "should have returned a non-nil scale for %s", groupResource.String())
assert.Equal(t, expectedScale, scale, "should have returned the expected scale for %s", groupResource.String())
}
}

View File

@ -0,0 +1,21 @@
/*
Copyright 2017 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 scale provides a polymorphic scale client capable of fetching
// and updating Scale for any resource which implements the `scale` subresource,
// as long as that subresource operates on a version of scale convertable to
// autoscaling.Scale.
package scale

View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "k8s.io/client-go/scale/fake",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,67 @@
/*
Copyright 2017 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 fake provides a fake client interface to arbitrary Kubernetes
// APIs that exposes common high level operations and exposes common
// metadata.
package fake
import (
autoscalingapi "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/scale"
"k8s.io/client-go/testing"
)
// FakeScaleClient provides a fake implementation of scale.ScalesGetter.
type FakeScaleClient struct {
testing.Fake
}
func (f *FakeScaleClient) Scales(namespace string) scale.ScaleInterface {
return &fakeNamespacedScaleClient{
namespace: namespace,
fake: &f.Fake,
}
}
type fakeNamespacedScaleClient struct {
namespace string
fake *testing.Fake
}
func (f *fakeNamespacedScaleClient) Get(resource schema.GroupResource, name string) (*autoscalingapi.Scale, error) {
obj, err := f.fake.
Invokes(testing.NewGetSubresourceAction(resource.WithVersion(""), f.namespace, "scale", name), &autoscalingapi.Scale{})
if err != nil {
return nil, err
}
return obj.(*autoscalingapi.Scale), err
}
func (f *fakeNamespacedScaleClient) Update(resource schema.GroupResource, scale *autoscalingapi.Scale) (*autoscalingapi.Scale, error) {
obj, err := f.fake.
Invokes(testing.NewUpdateSubresourceAction(resource.WithVersion(""), f.namespace, "scale", scale), &autoscalingapi.Scale{})
if err != nil {
return nil, err
}
return obj.(*autoscalingapi.Scale), err
}

View File

@ -0,0 +1,39 @@
/*
Copyright 2017 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 scale
import (
autoscalingapi "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// ScalesGetter can produce a ScaleInterface
// for a particular namespace.
type ScalesGetter interface {
Scales(namespace string) ScaleInterface
}
// ScaleInterface can fetch and update scales for
// resources in a particular namespace which implement
// the scale subresource.
type ScaleInterface interface {
// Get fetches the scale of the given scalable resource.
Get(resource schema.GroupResource, name string) (*autoscalingapi.Scale, error)
// Update updates the scale of the the given scalable resource.
Update(resource schema.GroupResource, scale *autoscalingapi.Scale) (*autoscalingapi.Scale, error)
}

View File

@ -0,0 +1,34 @@
/*
Copyright 2017 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 scale
import (
"testing"
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
)
// NB: this can't be in the scheme package, because importing'
// scheme/autoscalingv1 from scheme causes a depedency loop from
// conversions
func TestRoundTrip(t *testing.T) {
scheme := NewScaleConverter().Scheme()
// we don't actually need any custom fuzzer funcs ATM -- the defaults
// will do just fine
roundtrip.RoundTripTestForScheme(t, scheme, nil)
}

View File

@ -0,0 +1,39 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"register.go",
"types.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/client-go/scale/scheme",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/client-go/scale/scheme/autoscalingv1:all-srcs",
"//staging/src/k8s.io/client-go/scale/scheme/extensionsint:all-srcs",
"//staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,35 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"conversion.go",
"doc.go",
"register.go",
"zz_generated.conversion.go",
],
importpath = "k8s.io/client-go/scale/scheme/autoscalingv1",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion: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/client-go/scale/scheme:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,69 @@
/*
Copyright 2017 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 autoscalingv1
import (
"fmt"
v1 "k8s.io/api/autoscaling/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
scheme "k8s.io/client-go/scale/scheme"
)
// addConversions registers conversions between the internal version
// of Scale and supported external versions of Scale.
func addConversionFuncs(scheme *runtime.Scheme) error {
err := scheme.AddConversionFuncs(
Convert_scheme_ScaleStatus_To_v1_ScaleStatus,
Convert_v1_ScaleStatus_To_scheme_ScaleStatus,
)
if err != nil {
return err
}
return nil
}
func Convert_scheme_ScaleStatus_To_v1_ScaleStatus(in *scheme.ScaleStatus, out *v1.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
out.Selector = ""
if in.Selector != nil {
selector, err := metav1.LabelSelectorAsSelector(in.Selector)
if err != nil {
return fmt.Errorf("invalid label selector: %v", err)
}
out.Selector = selector.String()
}
return nil
}
func Convert_v1_ScaleStatus_To_scheme_ScaleStatus(in *v1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
if in.Selector != "" {
labelSelector, err := metav1.ParseToLabelSelector(in.Selector)
if err != nil {
out.Selector = nil
return fmt.Errorf("failed to parse target selector: %v", err)
}
out.Selector = labelSelector
}
return nil
}

View File

@ -0,0 +1,20 @@
/*
Copyright 2017 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.
*/
// +k8s:conversion-gen=k8s.io/kubernetes/vendor/k8s.io/client-go/scale/scheme
// +k8s:conversion-gen-external-types=../../../../../k8s.io/api/autoscaling/v1
package autoscalingv1 // import "k8s.io/client-go/scale/scheme/autoscalingv1"

View File

@ -0,0 +1,45 @@
/*
Copyright 2017 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 autoscalingv1
import (
autoscalingapiv1 "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = autoscalingapiv1.GroupName
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
localSchemeBuilder = &autoscalingapiv1.SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addConversionFuncs)
}

View File

@ -0,0 +1,109 @@
// +build !ignore_autogenerated
/*
Copyright 2017 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.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package autoscalingv1
import (
v1 "k8s.io/api/autoscaling/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
scheme "k8s.io/client-go/scale/scheme"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1_Scale_To_scheme_Scale,
Convert_scheme_Scale_To_v1_Scale,
Convert_v1_ScaleSpec_To_scheme_ScaleSpec,
Convert_scheme_ScaleSpec_To_v1_ScaleSpec,
Convert_v1_ScaleStatus_To_scheme_ScaleStatus,
Convert_scheme_ScaleStatus_To_v1_ScaleStatus,
)
}
func autoConvert_v1_Scale_To_scheme_Scale(in *v1.Scale, out *scheme.Scale, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1_ScaleSpec_To_scheme_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1_ScaleStatus_To_scheme_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_v1_Scale_To_scheme_Scale is an autogenerated conversion function.
func Convert_v1_Scale_To_scheme_Scale(in *v1.Scale, out *scheme.Scale, s conversion.Scope) error {
return autoConvert_v1_Scale_To_scheme_Scale(in, out, s)
}
func autoConvert_scheme_Scale_To_v1_Scale(in *scheme.Scale, out *v1.Scale, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_scheme_ScaleSpec_To_v1_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_scheme_ScaleStatus_To_v1_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_scheme_Scale_To_v1_Scale is an autogenerated conversion function.
func Convert_scheme_Scale_To_v1_Scale(in *scheme.Scale, out *v1.Scale, s conversion.Scope) error {
return autoConvert_scheme_Scale_To_v1_Scale(in, out, s)
}
func autoConvert_v1_ScaleSpec_To_scheme_ScaleSpec(in *v1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error {
out.Replicas = in.Replicas
return nil
}
// Convert_v1_ScaleSpec_To_scheme_ScaleSpec is an autogenerated conversion function.
func Convert_v1_ScaleSpec_To_scheme_ScaleSpec(in *v1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error {
return autoConvert_v1_ScaleSpec_To_scheme_ScaleSpec(in, out, s)
}
func autoConvert_scheme_ScaleSpec_To_v1_ScaleSpec(in *scheme.ScaleSpec, out *v1.ScaleSpec, s conversion.Scope) error {
out.Replicas = in.Replicas
return nil
}
// Convert_scheme_ScaleSpec_To_v1_ScaleSpec is an autogenerated conversion function.
func Convert_scheme_ScaleSpec_To_v1_ScaleSpec(in *scheme.ScaleSpec, out *v1.ScaleSpec, s conversion.Scope) error {
return autoConvert_scheme_ScaleSpec_To_v1_ScaleSpec(in, out, s)
}
func autoConvert_v1_ScaleStatus_To_scheme_ScaleStatus(in *v1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
// WARNING: in.Selector requires manual conversion: inconvertible types (string vs *k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector)
return nil
}
func autoConvert_scheme_ScaleStatus_To_v1_ScaleStatus(in *scheme.ScaleStatus, out *v1.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
// WARNING: in.Selector requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector vs string)
return nil
}

View File

@ -0,0 +1,22 @@
/*
Copyright 2017 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.
*/
// +k8s:deepcopy-gen=package,register
// Package scheme contains a runtime.Scheme to be used for serializing
// and deserializing different versions of Scale, and for converting
// in between them.
package scheme

View File

@ -0,0 +1,31 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"register.go",
],
importpath = "k8s.io/client-go/scale/scheme/extensionsint",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/extensions/v1beta1: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/client-go/scale/scheme:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,22 @@
/*
Copyright 2017 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 extensionsint contains the necessary scaffolding of the
// internal version of extensions as required by conversion logic.
// It doesn't have any of its own types -- it's just necessary to
// get the expected behavoir out of runtime.Scheme.ConvertToVersion
// and associated methods.
package extensionsint

View File

@ -0,0 +1,53 @@
/*
Copyright 2016 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 extensionsint
import (
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
scalescheme "k8s.io/client-go/scale/scheme"
)
// GroupName is the group name use in this package
const GroupName = extensionsv1beta1.GroupName
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&scalescheme.Scale{},
)
return nil
}

View File

@ -0,0 +1,35 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"conversion.go",
"doc.go",
"register.go",
"zz_generated.conversion.go",
],
importpath = "k8s.io/client-go/scale/scheme/extensionsv1beta1",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion: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/client-go/scale/scheme:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,87 @@
/*
Copyright 2017 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 extensionsv1beta1
import (
"fmt"
v1beta1 "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
scheme "k8s.io/client-go/scale/scheme"
)
// addConversions registers conversions between the internal version
// of Scale and supported external versions of Scale.
func addConversionFuncs(scheme *runtime.Scheme) error {
err := scheme.AddConversionFuncs(
Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus,
Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus,
)
if err != nil {
return err
}
return nil
}
func Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus(in *scheme.ScaleStatus, out *v1beta1.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
out.Selector = nil
out.TargetSelector = ""
if in.Selector != nil {
if in.Selector.MatchExpressions == nil || len(in.Selector.MatchExpressions) == 0 {
out.Selector = in.Selector.MatchLabels
}
selector, err := metav1.LabelSelectorAsSelector(in.Selector)
if err != nil {
return fmt.Errorf("invalid label selector: %v", err)
}
out.TargetSelector = selector.String()
}
return nil
}
func Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus(in *v1beta1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
// Normally when 2 fields map to the same internal value we favor the old field, since
// old clients can't be expected to know about new fields but clients that know about the
// new field can be expected to know about the old field (though that's not quite true, due
// to kubectl apply). However, these fields are readonly, so any non-nil value should work.
if in.TargetSelector != "" {
labelSelector, err := metav1.ParseToLabelSelector(in.TargetSelector)
if err != nil {
out.Selector = nil
return fmt.Errorf("failed to parse target selector: %v", err)
}
out.Selector = labelSelector
} else if in.Selector != nil {
out.Selector = new(metav1.LabelSelector)
selector := make(map[string]string)
for key, val := range in.Selector {
selector[key] = val
}
out.Selector.MatchLabels = selector
} else {
out.Selector = nil
}
return nil
}

View File

@ -0,0 +1,20 @@
/*
Copyright 2017 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.
*/
// +k8s:conversion-gen=k8s.io/kubernetes/vendor/k8s.io/client-go/scale/scheme
// +k8s:conversion-gen-external-types=../../../../../k8s.io/api/extensions/v1beta1
package extensionsv1beta1 // import "k8s.io/client-go/scale/scheme/extensionsv1beta1"

View File

@ -0,0 +1,45 @@
/*
Copyright 2017 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 extensionsv1beta1
import (
extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = extensionsapiv1beta1.GroupName
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
localSchemeBuilder = &extensionsapiv1beta1.SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addConversionFuncs)
}

View File

@ -0,0 +1,110 @@
// +build !ignore_autogenerated
/*
Copyright 2017 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.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package extensionsv1beta1
import (
v1beta1 "k8s.io/api/extensions/v1beta1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
scheme "k8s.io/client-go/scale/scheme"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1beta1_Scale_To_scheme_Scale,
Convert_scheme_Scale_To_v1beta1_Scale,
Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec,
Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec,
Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus,
Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus,
)
}
func autoConvert_v1beta1_Scale_To_scheme_Scale(in *v1beta1.Scale, out *scheme.Scale, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_v1beta1_Scale_To_scheme_Scale is an autogenerated conversion function.
func Convert_v1beta1_Scale_To_scheme_Scale(in *v1beta1.Scale, out *scheme.Scale, s conversion.Scope) error {
return autoConvert_v1beta1_Scale_To_scheme_Scale(in, out, s)
}
func autoConvert_scheme_Scale_To_v1beta1_Scale(in *scheme.Scale, out *v1beta1.Scale, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_scheme_Scale_To_v1beta1_Scale is an autogenerated conversion function.
func Convert_scheme_Scale_To_v1beta1_Scale(in *scheme.Scale, out *v1beta1.Scale, s conversion.Scope) error {
return autoConvert_scheme_Scale_To_v1beta1_Scale(in, out, s)
}
func autoConvert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(in *v1beta1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error {
out.Replicas = in.Replicas
return nil
}
// Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec is an autogenerated conversion function.
func Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(in *v1beta1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error {
return autoConvert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(in, out, s)
}
func autoConvert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(in *scheme.ScaleSpec, out *v1beta1.ScaleSpec, s conversion.Scope) error {
out.Replicas = in.Replicas
return nil
}
// Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec is an autogenerated conversion function.
func Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(in *scheme.ScaleSpec, out *v1beta1.ScaleSpec, s conversion.Scope) error {
return autoConvert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(in, out, s)
}
func autoConvert_v1beta1_ScaleStatus_To_scheme_ScaleStatus(in *v1beta1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
// WARNING: in.Selector requires manual conversion: inconvertible types (map[string]string vs *k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector)
// WARNING: in.TargetSelector requires manual conversion: does not exist in peer-type
return nil
}
func autoConvert_scheme_ScaleStatus_To_v1beta1_ScaleStatus(in *scheme.ScaleStatus, out *v1beta1.ScaleStatus, s conversion.Scope) error {
out.Replicas = in.Replicas
// WARNING: in.Selector requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector vs map[string]string)
return nil
}

View File

@ -0,0 +1,52 @@
/*
Copyright 2016 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 scheme
import (
autoscalingv1 "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = autoscalingv1.GroupName
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Scale{},
)
return nil
}

View File

@ -0,0 +1,60 @@
/*
Copyright 2017 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 scheme
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// This file contains our own "internal" version of scale that we use for conversions,
// since we can't use the main Kubernetes internal versions.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Scale represents a scaling request for a resource.
type Scale struct {
metav1.TypeMeta
// Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata.
// +optional
metav1.ObjectMeta
// defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status.
// +optional
Spec ScaleSpec
// current status of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. Read-only.
// +optional
Status ScaleStatus
}
// ScaleSpec describes the attributes of a scale subresource.
type ScaleSpec struct {
// desired number of instances for the scaled object.
// +optional
Replicas int32
}
// ScaleStatus represents the current status of a scale subresource.
type ScaleStatus struct {
// actual number of observed instances of the scaled object.
Replicas int32
// label query over pods that should match the replicas count.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
// +optional
Selector *metav1.LabelSelector
}

View File

@ -0,0 +1,123 @@
// +build !ignore_autogenerated
/*
Copyright 2017 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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package scheme
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
reflect "reflect"
)
func init() {
SchemeBuilder.Register(RegisterDeepCopies)
}
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
// to allow building arbitrary schemes.
//
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*Scale).DeepCopyInto(out.(*Scale))
return nil
}, InType: reflect.TypeOf(&Scale{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*ScaleSpec).DeepCopyInto(out.(*ScaleSpec))
return nil
}, InType: reflect.TypeOf(&ScaleSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*ScaleStatus).DeepCopyInto(out.(*ScaleStatus))
return nil
}, InType: reflect.TypeOf(&ScaleStatus{})},
)
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Scale) DeepCopyInto(out *Scale) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scale.
func (in *Scale) DeepCopy() *Scale {
if in == nil {
return nil
}
out := new(Scale)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Scale) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ScaleSpec) DeepCopyInto(out *ScaleSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleSpec.
func (in *ScaleSpec) DeepCopy() *ScaleSpec {
if in == nil {
return nil
}
out := new(ScaleSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ScaleStatus) DeepCopyInto(out *ScaleStatus) {
*out = *in
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
if *in == nil {
*out = nil
} else {
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleStatus.
func (in *ScaleStatus) DeepCopy() *ScaleStatus {
if in == nil {
return nil
}
out := new(ScaleStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,159 @@
/*
Copyright 2017 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 scale
import (
"fmt"
"strings"
"sync"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
scalescheme "k8s.io/client-go/scale/scheme"
scaleautoscaling "k8s.io/client-go/scale/scheme/autoscalingv1"
scaleextint "k8s.io/client-go/scale/scheme/extensionsint"
scaleext "k8s.io/client-go/scale/scheme/extensionsv1beta1"
)
// ScaleKindResolver knows about the relationship between
// resources and the GroupVersionKind of their scale subresources.
type ScaleKindResolver interface {
// ScaleForResource returns the GroupVersionKind of the
// scale subresource for the given GroupVersionResource.
ScaleForResource(resource schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error)
}
// discoveryScaleResolver is a ScaleKindResolver that uses
// a DiscoveryInterface to associate resources with their
// scale-kinds
type discoveryScaleResolver struct {
discoveryClient discovery.ServerResourcesInterface
}
func (r *discoveryScaleResolver) ScaleForResource(inputRes schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error) {
groupVerResources, err := r.discoveryClient.ServerResourcesForGroupVersion(inputRes.GroupVersion().String())
if err != nil {
return schema.GroupVersionKind{}, fmt.Errorf("unable to fetch discovery information for %s: %v", inputRes.String(), err)
}
for _, resource := range groupVerResources.APIResources {
resourceParts := strings.SplitN(resource.Name, "/", 2)
if len(resourceParts) != 2 || resourceParts[0] != inputRes.Resource || resourceParts[1] != "scale" {
// skip non-scale resources, or scales for resources that we're not looking for
continue
}
scaleGV := inputRes.GroupVersion()
if resource.Group != "" && resource.Version != "" {
scaleGV = schema.GroupVersion{
Group: resource.Group,
Version: resource.Version,
}
}
return scaleGV.WithKind(resource.Kind), nil
}
return schema.GroupVersionKind{}, fmt.Errorf("could not find scale subresource for %s in discovery information", inputRes.String())
}
// cachedScaleKindResolver is a ScaleKindResolver that caches results
// from another ScaleKindResolver, re-fetching on cache misses.
type cachedScaleKindResolver struct {
base ScaleKindResolver
cache map[schema.GroupVersionResource]schema.GroupVersionKind
mu sync.RWMutex
}
func (r *cachedScaleKindResolver) ScaleForResource(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
r.mu.RLock()
gvk, isCached := r.cache[resource]
r.mu.RUnlock()
if isCached {
return gvk, nil
}
// we could have multiple fetches of the same resources, but that's probably
// better than limiting to only one reader at once (mu.Mutex),
// or blocking checks for other resources while we fetch
// (mu.Lock before fetch).
gvk, err := r.base.ScaleForResource(resource)
if err != nil {
return schema.GroupVersionKind{}, err
}
r.mu.Lock()
defer r.mu.Unlock()
r.cache[resource] = gvk
return gvk, nil
}
// NewDiscoveryScaleKindResolver creates a new ScaleKindResolver which uses information from the given
// disovery client to resolve the correct Scale GroupVersionKind for different resources.
func NewDiscoveryScaleKindResolver(client discovery.ServerResourcesInterface) ScaleKindResolver {
base := &discoveryScaleResolver{
discoveryClient: client,
}
return &cachedScaleKindResolver{
base: base,
cache: make(map[schema.GroupVersionResource]schema.GroupVersionKind),
}
}
// ScaleConverter knows how to convert between external scale versions.
type ScaleConverter struct {
scheme *runtime.Scheme
internalVersioner runtime.GroupVersioner
}
// NewScaleConverter creates a new ScaleConverter for converting between
// Scales in autoscaling/v1 and extensions/v1beta1.
func NewScaleConverter() *ScaleConverter {
scheme := runtime.NewScheme()
scaleautoscaling.AddToScheme(scheme)
scalescheme.AddToScheme(scheme)
scaleext.AddToScheme(scheme)
scaleextint.AddToScheme(scheme)
return &ScaleConverter{
scheme: scheme,
internalVersioner: runtime.NewMultiGroupVersioner(
scalescheme.SchemeGroupVersion,
schema.GroupKind{Group: scaleext.GroupName, Kind: "Scale"},
schema.GroupKind{Group: scaleautoscaling.GroupName, Kind: "Scale"},
),
}
}
// Scheme returns the scheme used by this scale converter.
func (c *ScaleConverter) Scheme() *runtime.Scheme {
return c.scheme
}
// ConvertToVersion converts the given *external* input object to the given output *external* output group-version.
func (c *ScaleConverter) ConvertToVersion(in runtime.Object, outVersion schema.GroupVersion) (runtime.Object, error) {
scaleInt, err := c.scheme.ConvertToVersion(in, c.internalVersioner)
if err != nil {
return nil, err
}
return c.scheme.ConvertToVersion(scaleInt, outVersion)
}