123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /*
- 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 (
- "context"
- "encoding/json"
- "path"
- "strings"
- "testing"
- "github.com/coreos/pkg/capnslog"
- _ "go.etcd.io/etcd/etcdserver/api/v3rpc" // Force package logger init.
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/kubernetes"
- apitesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
- "k8s.io/kubernetes/test/integration/framework"
- )
- func makeGVR(group, version, resource string) schema.GroupVersionResource {
- return schema.GroupVersionResource{Group: group, Version: version, Resource: resource}
- }
- func makeGVK(group, version, kind string) schema.GroupVersionKind {
- return schema.GroupVersionKind{Group: group, Version: version, Kind: kind}
- }
- func TestMain(m *testing.M) {
- framework.EtcdMain(m.Run)
- }
- func TestScaleSubresources(t *testing.T) {
- clientSet, tearDown := setupWithOptions(t, nil, []string{
- "--runtime-config",
- "api/all=true",
- })
- defer tearDown()
- _, resourceLists, err := clientSet.Discovery().ServerGroupsAndResources()
- if err != nil {
- t.Fatal(err)
- }
- expectedScaleSubresources := map[schema.GroupVersionResource]schema.GroupVersionKind{
- makeGVR("", "v1", "replicationcontrollers/scale"): makeGVK("autoscaling", "v1", "Scale"),
- makeGVR("apps", "v1", "deployments/scale"): makeGVK("autoscaling", "v1", "Scale"),
- makeGVR("apps", "v1", "replicasets/scale"): makeGVK("autoscaling", "v1", "Scale"),
- makeGVR("apps", "v1", "statefulsets/scale"): makeGVK("autoscaling", "v1", "Scale"),
- }
- autoscalingGVK := schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "Scale"}
- discoveredScaleSubresources := map[schema.GroupVersionResource]schema.GroupVersionKind{}
- for _, resourceList := range resourceLists {
- containingGV, err := schema.ParseGroupVersion(resourceList.GroupVersion)
- if err != nil {
- t.Fatalf("error getting group version for %#v: %v", resourceList, err)
- }
- for _, resource := range resourceList.APIResources {
- if !strings.HasSuffix(resource.Name, "/scale") {
- continue
- }
- gvr := containingGV.WithResource(resource.Name)
- if _, exists := discoveredScaleSubresources[gvr]; exists {
- t.Errorf("scale subresource %#v listed multiple times in discovery", gvr)
- continue
- }
- gvk := containingGV.WithKind(resource.Kind)
- if resource.Group != "" {
- gvk.Group = resource.Group
- }
- if resource.Version != "" {
- gvk.Version = resource.Version
- }
- discoveredScaleSubresources[gvr] = gvk
- }
- }
- // Ensure nothing is missing
- for gvr, gvk := range expectedScaleSubresources {
- if _, ok := discoveredScaleSubresources[gvr]; !ok {
- t.Errorf("expected scale subresource %#v of kind %#v was missing from discovery", gvr, gvk)
- }
- }
- // Ensure discovery lists expected types
- for gvr, gvk := range discoveredScaleSubresources {
- if expectedGVK, expected := expectedScaleSubresources[gvr]; !expected {
- if gvk == autoscalingGVK {
- t.Errorf("unexpected scale subresource %#v of kind %#v. new scale subresource should be added to expectedScaleSubresources", gvr, gvk)
- } else {
- t.Errorf("unexpected scale subresource %#v of kind %#v. new scale resources are expected to use Scale from the autoscaling/v1 API group", gvr, gvk)
- }
- continue
- } else if expectedGVK != gvk {
- t.Errorf("scale subresource %#v should be of kind %#v, but %#v was listed in discovery", gvr, expectedGVK, gvk)
- continue
- }
- }
- // Create objects required to exercise scale subresources
- if _, err := clientSet.CoreV1().ReplicationControllers("default").Create(context.TODO(), rcStub, metav1.CreateOptions{}); err != nil {
- t.Fatal(err)
- }
- if _, err := clientSet.AppsV1().ReplicaSets("default").Create(context.TODO(), rsStub, metav1.CreateOptions{}); err != nil {
- t.Fatal(err)
- }
- if _, err := clientSet.AppsV1().Deployments("default").Create(context.TODO(), deploymentStub, metav1.CreateOptions{}); err != nil {
- t.Fatal(err)
- }
- if _, err := clientSet.AppsV1().StatefulSets("default").Create(context.TODO(), ssStub, metav1.CreateOptions{}); err != nil {
- t.Fatal(err)
- }
- // Ensure scale subresources return and accept expected kinds
- for gvr, gvk := range discoveredScaleSubresources {
- prefix := "/apis"
- if gvr.Group == corev1.GroupName {
- prefix = "/api"
- }
- resourceParts := strings.SplitN(gvr.Resource, "/", 2)
- urlPath := path.Join(prefix, gvr.Group, gvr.Version, "namespaces", "default", resourceParts[0], "test", resourceParts[1])
- obj := &unstructured.Unstructured{}
- getData, err := clientSet.CoreV1().RESTClient().Get().AbsPath(urlPath).DoRaw(context.TODO())
- if err != nil {
- t.Errorf("error fetching %s: %v", urlPath, err)
- continue
- }
- if err := json.Unmarshal(getData, obj); err != nil {
- t.Errorf("error decoding %s: %v", urlPath, err)
- t.Log(string(getData))
- continue
- }
- if obj.GetObjectKind().GroupVersionKind() != gvk {
- t.Errorf("expected %#v, got %#v from %s", gvk, obj.GetObjectKind().GroupVersionKind(), urlPath)
- t.Log(string(getData))
- continue
- }
- updateData, err := clientSet.CoreV1().RESTClient().Put().AbsPath(urlPath).Body(getData).DoRaw(context.TODO())
- if err != nil {
- t.Errorf("error putting to %s: %v", urlPath, err)
- t.Log(string(getData))
- t.Log(string(updateData))
- continue
- }
- }
- }
- var (
- replicas = int32(1)
- podStub = corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
- Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "test", Image: "busybox"}}},
- }
- rcStub = &corev1.ReplicationController{
- ObjectMeta: metav1.ObjectMeta{Name: "test"},
- Spec: corev1.ReplicationControllerSpec{Selector: podStub.Labels, Replicas: &replicas, Template: &podStub},
- }
- rsStub = &appsv1.ReplicaSet{
- ObjectMeta: metav1.ObjectMeta{Name: "test"},
- Spec: appsv1.ReplicaSetSpec{Selector: &metav1.LabelSelector{MatchLabels: podStub.Labels}, Replicas: &replicas, Template: podStub},
- }
- deploymentStub = &appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{Name: "test"},
- Spec: appsv1.DeploymentSpec{Selector: &metav1.LabelSelector{MatchLabels: podStub.Labels}, Replicas: &replicas, Template: podStub},
- }
- ssStub = &appsv1.StatefulSet{
- ObjectMeta: metav1.ObjectMeta{Name: "test"},
- Spec: appsv1.StatefulSetSpec{Selector: &metav1.LabelSelector{MatchLabels: podStub.Labels}, Replicas: &replicas, Template: podStub},
- }
- )
- func setupWithOptions(t *testing.T, instanceOptions *apitesting.TestServerInstanceOptions, flags []string) (client kubernetes.Interface, tearDown func()) {
- result := apitesting.StartTestServerOrDie(t, instanceOptions, flags, framework.SharedEtcd())
- // TODO: Disable logging here until we resolve teardown issues which result in
- // massive log spam. Another path forward would be to refactor
- // StartTestServerOrDie to work with the etcd instance already started by the
- // integration test scripts.
- // See https://github.com/kubernetes/kubernetes/issues/49489.
- repo, err := capnslog.GetRepoLogger("go.etcd.io/etcd")
- if err != nil {
- t.Fatalf("couldn't configure logging: %v", err)
- }
- repo.SetLogLevel(map[string]capnslog.LogLevel{
- "etcdserver/api/v3rpc": capnslog.CRITICAL,
- })
- result.ClientConfig.AcceptContentTypes = ""
- result.ClientConfig.ContentType = ""
- result.ClientConfig.NegotiatedSerializer = nil
- clientSet, err := kubernetes.NewForConfig(result.ClientConfig)
- if err != nil {
- t.Fatalf("error creating clientset: %v", err)
- }
- return clientSet, result.TearDownFn
- }
|