123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906 |
- /*
- Copyright 2015 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 master
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "os"
- "path"
- "strconv"
- "strings"
- "sync"
- "testing"
- "time"
- "sigs.k8s.io/yaml"
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/apiserver/pkg/authentication/group"
- "k8s.io/apiserver/pkg/authentication/request/bearertoken"
- "k8s.io/apiserver/pkg/authentication/user"
- "k8s.io/apiserver/pkg/authorization/authorizer"
- "k8s.io/apiserver/pkg/authorization/authorizerfactory"
- "k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest"
- clientset "k8s.io/client-go/kubernetes"
- clienttypedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
- restclient "k8s.io/client-go/rest"
- "k8s.io/kubernetes/pkg/master"
- "k8s.io/kubernetes/test/integration"
- "k8s.io/kubernetes/test/integration/framework"
- )
- const (
- AliceToken string = "abc123" // username: alice. Present in token file.
- BobToken string = "xyz987" // username: bob. Present in token file.
- )
- type allowAliceAuthorizer struct{}
- func (allowAliceAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
- if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
- return authorizer.DecisionAllow, "", nil
- }
- return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
- }
- func testPrefix(t *testing.T, prefix string) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- resp, err := http.Get(s.URL + prefix)
- if err != nil {
- t.Fatalf("unexpected error getting %s prefix: %v", prefix, err)
- }
- if resp.StatusCode != http.StatusOK {
- t.Fatalf("got status %v instead of 200 OK", resp.StatusCode)
- }
- }
- func TestAutoscalingPrefix(t *testing.T) {
- testPrefix(t, "/apis/autoscaling/")
- }
- func TestBatchPrefix(t *testing.T) {
- testPrefix(t, "/apis/batch/")
- }
- func TestAppsPrefix(t *testing.T) {
- testPrefix(t, "/apis/apps/")
- }
- func TestExtensionsPrefix(t *testing.T) {
- testPrefix(t, "/apis/extensions/")
- }
- func TestKubernetesService(t *testing.T) {
- config := framework.NewMasterConfig()
- _, _, closeFn := framework.RunAMaster(config)
- defer closeFn()
- coreClient := clientset.NewForConfigOrDie(config.GenericConfig.LoopbackClientConfig)
- err := wait.PollImmediate(time.Millisecond*100, wait.ForeverTestTimeout, func() (bool, error) {
- if _, err := coreClient.CoreV1().Services(metav1.NamespaceDefault).Get("kubernetes", metav1.GetOptions{}); err != nil && errors.IsNotFound(err) {
- return false, nil
- } else if err != nil {
- return false, err
- }
- return true, nil
- })
- if err != nil {
- t.Fatalf("Expected kubernetes service to exist, got: %v", err)
- }
- }
- func TestEmptyList(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- u := s.URL + "/api/v1/namespaces/default/pods"
- resp, err := http.Get(u)
- if err != nil {
- t.Fatalf("unexpected error getting %s: %v", u, err)
- }
- if resp.StatusCode != http.StatusOK {
- t.Fatalf("got status %v instead of 200 OK", resp.StatusCode)
- }
- defer resp.Body.Close()
- data, _ := ioutil.ReadAll(resp.Body)
- decodedData := map[string]interface{}{}
- if err := json.Unmarshal(data, &decodedData); err != nil {
- t.Logf("body: %s", string(data))
- t.Fatalf("got error decoding data: %v", err)
- }
- if items, ok := decodedData["items"]; !ok {
- t.Logf("body: %s", string(data))
- t.Fatalf("missing items field in empty list (all lists should return an items field)")
- } else if items == nil {
- t.Logf("body: %s", string(data))
- t.Fatalf("nil items field from empty list (all lists should return non-nil empty items lists)")
- }
- }
- func initStatusForbiddenMasterCongfig() *master.Config {
- masterConfig := framework.NewIntegrationTestMasterConfig()
- masterConfig.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysDenyAuthorizer()
- return masterConfig
- }
- func initUnauthorizedMasterCongfig() *master.Config {
- masterConfig := framework.NewIntegrationTestMasterConfig()
- tokenAuthenticator := tokentest.New()
- tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"}
- tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"}
- masterConfig.GenericConfig.Authentication.Authenticator = group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated})
- masterConfig.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
- return masterConfig
- }
- func TestStatus(t *testing.T) {
- testCases := []struct {
- name string
- masterConfig *master.Config
- statusCode int
- reqPath string
- reason string
- message string
- }{
- {
- name: "404",
- masterConfig: nil,
- statusCode: http.StatusNotFound,
- reqPath: "/apis/batch/v1/namespaces/default/jobs/foo",
- reason: "NotFound",
- message: `jobs.batch "foo" not found`,
- },
- {
- name: "403",
- masterConfig: initStatusForbiddenMasterCongfig(),
- statusCode: http.StatusForbidden,
- reqPath: "/apis",
- reason: "Forbidden",
- message: `forbidden: User "" cannot get path "/apis": Everything is forbidden.`,
- },
- {
- name: "401",
- masterConfig: initUnauthorizedMasterCongfig(),
- statusCode: http.StatusUnauthorized,
- reqPath: "/apis",
- reason: "Unauthorized",
- message: `Unauthorized`,
- },
- }
- for _, tc := range testCases {
- _, s, closeFn := framework.RunAMaster(tc.masterConfig)
- defer closeFn()
- u := s.URL + tc.reqPath
- resp, err := http.Get(u)
- if err != nil {
- t.Fatalf("unexpected error getting %s: %v", u, err)
- }
- if resp.StatusCode != tc.statusCode {
- t.Fatalf("got status %v instead of %s", resp.StatusCode, tc.name)
- }
- defer resp.Body.Close()
- data, _ := ioutil.ReadAll(resp.Body)
- decodedData := map[string]interface{}{}
- if err := json.Unmarshal(data, &decodedData); err != nil {
- t.Logf("body: %s", string(data))
- t.Fatalf("got error decoding data: %v", err)
- }
- t.Logf("body: %s", string(data))
- if got, expected := decodedData["apiVersion"], "v1"; got != expected {
- t.Errorf("unexpected apiVersion %q, expected %q", got, expected)
- }
- if got, expected := decodedData["kind"], "Status"; got != expected {
- t.Errorf("unexpected kind %q, expected %q", got, expected)
- }
- if got, expected := decodedData["status"], "Failure"; got != expected {
- t.Errorf("unexpected status %q, expected %q", got, expected)
- }
- if got, expected := decodedData["code"], float64(tc.statusCode); got != expected {
- t.Errorf("unexpected code %v, expected %v", got, expected)
- }
- if got, expected := decodedData["reason"], tc.reason; got != expected {
- t.Errorf("unexpected reason %v, expected %v", got, expected)
- }
- if got, expected := decodedData["message"], tc.message; got != expected {
- t.Errorf("unexpected message %v, expected %v", got, expected)
- }
- }
- }
- func constructBody(val string, size int, field string, t *testing.T) *appsv1.Deployment {
- var replicas int32 = 1
- deploymentObject := &appsv1.Deployment{
- TypeMeta: metav1.TypeMeta{
- Kind: "Deployment",
- APIVersion: "apps/v1",
- },
- ObjectMeta: metav1.ObjectMeta{
- Namespace: "default",
- Name: "test",
- },
- Spec: appsv1.DeploymentSpec{
- Replicas: &replicas,
- Selector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "foo": "bar",
- },
- },
- Strategy: appsv1.DeploymentStrategy{
- Type: appsv1.RollingUpdateDeploymentStrategyType,
- },
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{"foo": "bar"},
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: "foo",
- Image: "foo",
- },
- },
- },
- },
- },
- }
- switch field {
- case "labels":
- labelsMap := map[string]string{}
- for i := 0; i < size; i++ {
- key := val + strconv.Itoa(i)
- labelsMap[key] = val
- }
- deploymentObject.ObjectMeta.Labels = labelsMap
- case "annotations":
- annotationsMap := map[string]string{}
- for i := 0; i < size; i++ {
- key := val + strconv.Itoa(i)
- annotationsMap[key] = val
- }
- deploymentObject.ObjectMeta.Annotations = annotationsMap
- case "finalizers":
- finalizerString := []string{}
- for i := 0; i < size; i++ {
- finalizerString = append(finalizerString, val)
- }
- deploymentObject.ObjectMeta.Finalizers = finalizerString
- default:
- t.Fatalf("Unexpected field: %s used for making large deployment object value", field)
- }
- return deploymentObject
- }
- func TestObjectSizeResponses(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL})
- const DeploymentMegabyteSize = 100000
- const DeploymentTwoMegabyteSize = 1000000
- expectedMsgFor1MB := `etcdserver: request is too large`
- expectedMsgFor2MB := `rpc error: code = ResourceExhausted desc = trying to send message larger than max`
- expectedMsgForLargeAnnotation := `metadata.annotations: Too long: must have at most 262144 characters`
- deployment1 := constructBody("a", DeploymentMegabyteSize, "labels", t) // >1 MB file
- deployment2 := constructBody("a", DeploymentTwoMegabyteSize, "labels", t) // >2 MB file
- deployment3 := constructBody("a", DeploymentMegabyteSize, "annotations", t)
- deployment4 := constructBody("sample/sample", DeploymentMegabyteSize, "finalizers", t) // >1 MB file
- deployment5 := constructBody("sample/sample", DeploymentTwoMegabyteSize, "finalizers", t) // >2 MB file
- requests := []struct {
- size string
- deploymentObject *appsv1.Deployment
- expectedMessage string
- }{
- {"1 MB", deployment1, expectedMsgFor1MB},
- {"2 MB", deployment2, expectedMsgFor2MB},
- {"1 MB", deployment3, expectedMsgForLargeAnnotation},
- {"1 MB", deployment4, expectedMsgFor1MB},
- {"2 MB", deployment5, expectedMsgFor2MB},
- }
- for _, r := range requests {
- t.Run(r.size, func(t *testing.T) {
- _, err := client.AppsV1().Deployments(metav1.NamespaceDefault).Create(r.deploymentObject)
- if err != nil {
- if !strings.Contains(err.Error(), r.expectedMessage) {
- t.Errorf("got: %s;want: %s", err.Error(), r.expectedMessage)
- }
- }
- })
- }
- }
- func TestWatchSucceedsWithoutArgs(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- resp, err := http.Get(s.URL + "/api/v1/namespaces?watch=1")
- if err != nil {
- t.Fatalf("unexpected error getting experimental prefix: %v", err)
- }
- if resp.StatusCode != http.StatusOK {
- t.Fatalf("got status %v instead of 200 OK", resp.StatusCode)
- }
- resp.Body.Close()
- }
- var hpaV1 = `
- {
- "apiVersion": "autoscaling/v1",
- "kind": "HorizontalPodAutoscaler",
- "metadata": {
- "name": "test-hpa",
- "namespace": "default"
- },
- "spec": {
- "scaleTargetRef": {
- "kind": "ReplicationController",
- "name": "test-hpa",
- "namespace": "default"
- },
- "minReplicas": 1,
- "maxReplicas": 10,
- "targetCPUUtilizationPercentage": 50
- }
- }
- `
- var deploymentExtensions = `
- {
- "apiVersion": "extensions/v1beta1",
- "kind": "Deployment",
- "metadata": {
- "name": "test-deployment1",
- "namespace": "default"
- },
- "spec": {
- "replicas": 1,
- "template": {
- "metadata": {
- "labels": {
- "app": "nginx0"
- }
- },
- "spec": {
- "containers": [{
- "name": "nginx",
- "image": "k8s.gcr.io/nginx:1.7.9"
- }]
- }
- }
- }
- }
- `
- var deploymentApps = `
- {
- "apiVersion": "apps/v1",
- "kind": "Deployment",
- "metadata": {
- "name": "test-deployment2",
- "namespace": "default"
- },
- "spec": {
- "replicas": 1,
- "selector": {
- "matchLabels": {
- "app": "nginx0"
- }
- },
- "template": {
- "metadata": {
- "labels": {
- "app": "nginx0"
- }
- },
- "spec": {
- "containers": [{
- "name": "nginx",
- "image": "k8s.gcr.io/nginx:1.7.9"
- }]
- }
- }
- }
- }
- `
- func autoscalingPath(resource, namespace, name string) string {
- if namespace != "" {
- namespace = path.Join("namespaces", namespace)
- }
- return path.Join("/apis/autoscaling/v1", namespace, resource, name)
- }
- func batchPath(resource, namespace, name string) string {
- if namespace != "" {
- namespace = path.Join("namespaces", namespace)
- }
- return path.Join("/apis/batch/v1", namespace, resource, name)
- }
- func extensionsPath(resource, namespace, name string) string {
- if namespace != "" {
- namespace = path.Join("namespaces", namespace)
- }
- return path.Join("/apis/extensions/v1beta1", namespace, resource, name)
- }
- func appsPath(resource, namespace, name string) string {
- if namespace != "" {
- namespace = path.Join("namespaces", namespace)
- }
- return path.Join("/apis/apps/v1", namespace, resource, name)
- }
- func TestAutoscalingGroupBackwardCompatibility(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- transport := http.DefaultTransport
- requests := []struct {
- verb string
- URL string
- body string
- expectedStatusCodes map[int]bool
- expectedVersion string
- }{
- {"POST", autoscalingPath("horizontalpodautoscalers", metav1.NamespaceDefault, ""), hpaV1, integration.Code201, ""},
- {"GET", autoscalingPath("horizontalpodautoscalers", metav1.NamespaceDefault, ""), "", integration.Code200, "autoscaling/v1"},
- }
- for _, r := range requests {
- bodyBytes := bytes.NewReader([]byte(r.body))
- req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
- if err != nil {
- t.Logf("case %v", r)
- t.Fatalf("unexpected error: %v", err)
- }
- func() {
- resp, err := transport.RoundTrip(req)
- defer resp.Body.Close()
- if err != nil {
- t.Logf("case %v", r)
- t.Fatalf("unexpected error: %v", err)
- }
- b, _ := ioutil.ReadAll(resp.Body)
- body := string(b)
- if _, ok := r.expectedStatusCodes[resp.StatusCode]; !ok {
- t.Logf("case %v", r)
- t.Errorf("Expected status one of %v, but got %v", r.expectedStatusCodes, resp.StatusCode)
- t.Errorf("Body: %v", body)
- }
- if !strings.Contains(body, "\"apiVersion\":\""+r.expectedVersion) {
- t.Logf("case %v", r)
- t.Errorf("Expected version %v, got body %v", r.expectedVersion, body)
- }
- }()
- }
- }
- func TestAppsGroupBackwardCompatibility(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- transport := http.DefaultTransport
- requests := []struct {
- verb string
- URL string
- body string
- expectedStatusCodes map[int]bool
- expectedVersion string
- }{
- // Post to extensions endpoint and get back from both: extensions and apps
- {"POST", extensionsPath("deployments", metav1.NamespaceDefault, ""), deploymentExtensions, integration.Code201, ""},
- {"GET", extensionsPath("deployments", metav1.NamespaceDefault, "test-deployment1"), "", integration.Code200, "extensions/v1beta1"},
- {"GET", appsPath("deployments", metav1.NamespaceDefault, "test-deployment1"), "", integration.Code200, "apps/v1"},
- {"DELETE", extensionsPath("deployments", metav1.NamespaceDefault, "test-deployment1"), "", integration.Code200, "extensions/v1beta1"},
- // Post to apps endpoint and get back from both: apps and extensions
- {"POST", appsPath("deployments", metav1.NamespaceDefault, ""), deploymentApps, integration.Code201, ""},
- {"GET", appsPath("deployments", metav1.NamespaceDefault, "test-deployment2"), "", integration.Code200, "apps/v1"},
- {"GET", extensionsPath("deployments", metav1.NamespaceDefault, "test-deployment2"), "", integration.Code200, "extensions/v1beta1"},
- // set propagationPolicy=Orphan to force the object to be returned so we can check the apiVersion (otherwise, we just get a status object back)
- {"DELETE", appsPath("deployments", metav1.NamespaceDefault, "test-deployment2") + "?propagationPolicy=Orphan", "", integration.Code200, "apps/v1"},
- }
- for _, r := range requests {
- bodyBytes := bytes.NewReader([]byte(r.body))
- req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
- if err != nil {
- t.Logf("case %v", r)
- t.Fatalf("unexpected error: %v", err)
- }
- func() {
- resp, err := transport.RoundTrip(req)
- defer resp.Body.Close()
- if err != nil {
- t.Logf("case %v", r)
- t.Fatalf("unexpected error: %v", err)
- }
- b, _ := ioutil.ReadAll(resp.Body)
- body := string(b)
- if _, ok := r.expectedStatusCodes[resp.StatusCode]; !ok {
- t.Logf("case %v", r)
- t.Errorf("Expected status one of %v, but got %v", r.expectedStatusCodes, resp.StatusCode)
- t.Errorf("Body: %v", body)
- }
- if !strings.Contains(body, "\"apiVersion\":\""+r.expectedVersion) {
- t.Logf("case %v", r)
- t.Errorf("Expected version %v, got body %v", r.expectedVersion, body)
- }
- }()
- }
- }
- func TestAccept(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(nil)
- defer closeFn()
- resp, err := http.Get(s.URL + "/api/")
- if err != nil {
- t.Fatalf("unexpected error getting api: %v", err)
- }
- if resp.StatusCode != http.StatusOK {
- t.Fatalf("got status %v instead of 200 OK", resp.StatusCode)
- }
- body, _ := ioutil.ReadAll(resp.Body)
- if resp.Header.Get("Content-Type") != "application/json" {
- t.Errorf("unexpected content: %s", body)
- }
- if err := json.Unmarshal(body, &map[string]interface{}{}); err != nil {
- t.Fatal(err)
- }
- req, err := http.NewRequest("GET", s.URL+"/api/", nil)
- if err != nil {
- t.Fatal(err)
- }
- req.Header.Set("Accept", "application/yaml")
- resp, err = http.DefaultClient.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- body, _ = ioutil.ReadAll(resp.Body)
- if resp.Header.Get("Content-Type") != "application/yaml" {
- t.Errorf("unexpected content: %s", body)
- }
- t.Logf("body: %s", body)
- if err := yaml.Unmarshal(body, &map[string]interface{}{}); err != nil {
- t.Fatal(err)
- }
- req, err = http.NewRequest("GET", s.URL+"/api/", nil)
- if err != nil {
- t.Fatal(err)
- }
- req.Header.Set("Accept", "application/json, application/yaml")
- resp, err = http.DefaultClient.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- body, _ = ioutil.ReadAll(resp.Body)
- if resp.Header.Get("Content-Type") != "application/json" {
- t.Errorf("unexpected content: %s", body)
- }
- t.Logf("body: %s", body)
- if err := yaml.Unmarshal(body, &map[string]interface{}{}); err != nil {
- t.Fatal(err)
- }
- req, err = http.NewRequest("GET", s.URL+"/api/", nil)
- if err != nil {
- t.Fatal(err)
- }
- req.Header.Set("Accept", "application") // not a valid media type
- resp, err = http.DefaultClient.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- if resp.StatusCode != http.StatusNotAcceptable {
- t.Errorf("unexpected error from the server")
- }
- }
- func countEndpoints(eps *corev1.Endpoints) int {
- count := 0
- for i := range eps.Subsets {
- count += len(eps.Subsets[i].Addresses) * len(eps.Subsets[i].Ports)
- }
- return count
- }
- func TestMasterService(t *testing.T) {
- _, s, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig())
- defer closeFn()
- client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL})
- err := wait.Poll(time.Second, time.Minute, func() (bool, error) {
- svcList, err := client.CoreV1().Services(metav1.NamespaceDefault).List(metav1.ListOptions{})
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- return false, nil
- }
- found := false
- for i := range svcList.Items {
- if svcList.Items[i].Name == "kubernetes" {
- found = true
- break
- }
- }
- if found {
- ep, err := client.CoreV1().Endpoints(metav1.NamespaceDefault).Get("kubernetes", metav1.GetOptions{})
- if err != nil {
- return false, nil
- }
- if countEndpoints(ep) == 0 {
- return false, fmt.Errorf("no endpoints for kubernetes service: %v", ep)
- }
- return true, nil
- }
- return false, nil
- })
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- }
- func TestServiceAlloc(t *testing.T) {
- cfg := framework.NewIntegrationTestMasterConfig()
- _, cidr, err := net.ParseCIDR("192.168.0.0/29")
- if err != nil {
- t.Fatalf("bad cidr: %v", err)
- }
- cfg.ExtraConfig.ServiceIPRange = *cidr
- _, s, closeFn := framework.RunAMaster(cfg)
- defer closeFn()
- client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL})
- svc := func(i int) *corev1.Service {
- return &corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("svc-%v", i),
- },
- Spec: corev1.ServiceSpec{
- Type: corev1.ServiceTypeClusterIP,
- Ports: []corev1.ServicePort{
- {Port: 80},
- },
- },
- }
- }
- // Wait until the default "kubernetes" service is created.
- if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
- _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get("kubernetes", metav1.GetOptions{})
- if err != nil && !errors.IsNotFound(err) {
- return false, err
- }
- return !errors.IsNotFound(err), nil
- }); err != nil {
- t.Fatalf("creating kubernetes service timed out")
- }
- // make 5 more services to take up all IPs
- for i := 0; i < 5; i++ {
- if _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(svc(i)); err != nil {
- t.Error(err)
- }
- }
- // Make another service. It will fail because we're out of cluster IPs
- if _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(svc(8)); err != nil {
- if !strings.Contains(err.Error(), "range is full") {
- t.Errorf("unexpected error text: %v", err)
- }
- } else {
- svcs, err := client.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{})
- if err != nil {
- t.Fatalf("unexpected success, and error getting the services: %v", err)
- }
- allIPs := []string{}
- for _, s := range svcs.Items {
- allIPs = append(allIPs, s.Spec.ClusterIP)
- }
- t.Fatalf("unexpected creation success. The following IPs exist: %#v. It should only be possible to allocate 2 IP addresses in this cluster.\n\n%#v", allIPs, svcs)
- }
- // Delete the first service.
- if err := client.CoreV1().Services(metav1.NamespaceDefault).Delete(svc(1).ObjectMeta.Name, nil); err != nil {
- t.Fatalf("got unexpected error: %v", err)
- }
- // This time creating the second service should work.
- if _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(svc(8)); err != nil {
- t.Fatalf("got unexpected error: %v", err)
- }
- }
- // TestUpdateNodeObjects represents a simple version of the behavior of node checkins at steady
- // state. This test allows for easy profiling of a realistic master scenario for baseline CPU
- // in very large clusters. It is disabled by default - start a kube-apiserver and pass
- // UPDATE_NODE_APISERVER as the host value.
- func TestUpdateNodeObjects(t *testing.T) {
- server := os.Getenv("UPDATE_NODE_APISERVER")
- if len(server) == 0 {
- t.Skip("UPDATE_NODE_APISERVER is not set")
- }
- c := clienttypedv1.NewForConfigOrDie(&restclient.Config{
- QPS: 10000,
- Host: server,
- ContentConfig: restclient.ContentConfig{
- AcceptContentTypes: "application/vnd.kubernetes.protobuf",
- ContentType: "application/vnd.kubernetes.protobuf",
- },
- })
- nodes := 400
- listers := 5
- watchers := 50
- iterations := 10000
- for i := 0; i < nodes*6; i++ {
- c.Nodes().Delete(fmt.Sprintf("node-%d", i), nil)
- _, err := c.Nodes().Create(&corev1.Node{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("node-%d", i),
- },
- })
- if err != nil {
- t.Fatal(err)
- }
- }
- for k := 0; k < listers; k++ {
- go func(lister int) {
- for i := 0; i < iterations; i++ {
- _, err := c.Nodes().List(metav1.ListOptions{})
- if err != nil {
- fmt.Printf("[list:%d] error after %d: %v\n", lister, i, err)
- break
- }
- time.Sleep(time.Duration(lister)*10*time.Millisecond + 1500*time.Millisecond)
- }
- }(k)
- }
- for k := 0; k < watchers; k++ {
- go func(lister int) {
- w, err := c.Nodes().Watch(metav1.ListOptions{})
- if err != nil {
- fmt.Printf("[watch:%d] error: %v", lister, err)
- return
- }
- i := 0
- for r := range w.ResultChan() {
- i++
- if _, ok := r.Object.(*corev1.Node); !ok {
- fmt.Printf("[watch:%d] unexpected object after %d: %#v\n", lister, i, r)
- }
- if i%100 == 0 {
- fmt.Printf("[watch:%d] iteration %d ...\n", lister, i)
- }
- }
- fmt.Printf("[watch:%d] done\n", lister)
- }(k)
- }
- var wg sync.WaitGroup
- wg.Add(nodes - listers)
- for j := 0; j < nodes; j++ {
- go func(node int) {
- var lastCount int
- for i := 0; i < iterations; i++ {
- if i%100 == 0 {
- fmt.Printf("[%d] iteration %d ...\n", node, i)
- }
- if i%20 == 0 {
- _, err := c.Nodes().List(metav1.ListOptions{})
- if err != nil {
- fmt.Printf("[%d] error after %d: %v\n", node, i, err)
- break
- }
- }
- r, err := c.Nodes().List(metav1.ListOptions{
- FieldSelector: fmt.Sprintf("metadata.name=node-%d", node),
- ResourceVersion: "0",
- })
- if err != nil {
- fmt.Printf("[%d] error after %d: %v\n", node, i, err)
- break
- }
- if len(r.Items) != 1 {
- fmt.Printf("[%d] error after %d: unexpected list count\n", node, i)
- break
- }
- n, err := c.Nodes().Get(fmt.Sprintf("node-%d", node), metav1.GetOptions{})
- if err != nil {
- fmt.Printf("[%d] error after %d: %v\n", node, i, err)
- break
- }
- if len(n.Status.Conditions) != lastCount {
- fmt.Printf("[%d] worker set %d, read %d conditions\n", node, lastCount, len(n.Status.Conditions))
- break
- }
- previousCount := lastCount
- switch {
- case i%4 == 0:
- lastCount = 1
- n.Status.Conditions = []corev1.NodeCondition{
- {
- Type: corev1.NodeReady,
- Status: corev1.ConditionTrue,
- Reason: "foo",
- },
- }
- case i%4 == 1:
- lastCount = 2
- n.Status.Conditions = []corev1.NodeCondition{
- {
- Type: corev1.NodeReady,
- Status: corev1.ConditionFalse,
- Reason: "foo",
- },
- {
- Type: corev1.NodeDiskPressure,
- Status: corev1.ConditionTrue,
- Reason: "bar",
- },
- }
- case i%4 == 2:
- lastCount = 0
- n.Status.Conditions = nil
- }
- if _, err := c.Nodes().UpdateStatus(n); err != nil {
- if !errors.IsConflict(err) {
- fmt.Printf("[%d] error after %d: %v\n", node, i, err)
- break
- }
- lastCount = previousCount
- }
- }
- wg.Done()
- fmt.Printf("[%d] done\n", node)
- }(j)
- }
- wg.Wait()
- }
|