// TestSecrets tests apiserver-side behavior of creation of secret objects and their use by pods. func TestSecrets(t *testing.T) { helper, err := framework.NewHelper() if err != nil { t.Fatalf("unexpected error: %v", err) } var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) framework.DeleteAllEtcdKeys() client := client.NewOrDie(&client.Config{Host: s.URL, Version: testapi.Version()}) DoTestSecrets(t, client, testapi.Version()) }
// TestUnknownUserIsUnauthorized tests that a user who is unknown // to the authentication system get status code "Unauthorized". // An authorization module is installed in this scenario for integration // test purposes, but requests aren't expected to reach it. func TestUnknownUserIsUnauthorized(t *testing.T) { framework.DeleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := framework.NewHelper() if err != nil { t.Fatalf("unexpected error: %v", err) } var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", // enable v1beta3 if we are testing that api version. EnableV1Beta3: testapi.Version() == "v1beta3", Authenticator: getTestTokenAuth(), Authorizer: allowAliceAuthorizer{}, AdmissionControl: admit.NewAlwaysAdmit(), }) transport := http.DefaultTransport for _, r := range getTestRequests() { token := UnknownToken bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } // Expect all of unauthenticated user's request to be "Unauthorized" if resp.StatusCode != http.StatusUnauthorized { t.Logf("case %v", r) t.Errorf("Expected status %v, but got %v", http.StatusUnauthorized, resp.StatusCode) b, _ := ioutil.ReadAll(resp.Body) t.Errorf("Body: %v", string(b)) } }() } }
// TestBobIsForbidden tests that a user who is known to // the authentication system but not authorized to do any actions // should receive "Forbidden". func TestBobIsForbidden(t *testing.T) { framework.DeleteAllEtcdKeys() // This file has alice and bob in it. etcdStorage, err := framework.NewEtcdStorage() if err != nil { t.Fatalf("unexpected error: %v", err) } var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ DatabaseStorage: etcdStorage, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", Authenticator: getTestTokenAuth(), Authorizer: allowAliceAuthorizer{}, AdmissionControl: admit.NewAlwaysAdmit(), }) transport := http.DefaultTransport for _, r := range getTestRequests() { token := BobToken bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } // Expect all of bob's actions to return Forbidden if resp.StatusCode != http.StatusForbidden { t.Logf("case %v", r) t.Errorf("Expected not status Forbidden, but got %s", resp.Status) } }() } }
func TestAuthModeAlwaysDeny(t *testing.T) { framework.DeleteAllEtcdKeys() // Set up a master helper, err := framework.NewHelper() if err != nil { t.Fatalf("unexpected error: %v", err) } var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", // enable v1beta3 if we are testing that api version. EnableV1Beta3: testapi.Version() == "v1beta3", Authorizer: apiserver.NewAlwaysDenyAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) transport := http.DefaultTransport for _, r := range getTestRequests() { 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) } if resp.StatusCode != http.StatusForbidden { t.Logf("case %v", r) t.Errorf("Expected status Forbidden but got status %v", resp.Status) } }() } }
func init() { q := flag.Int("bench-quiet", 3, "Quietness, don't glog severities <= given level during the benchmark.") pods := flag.Int("bench-pods", -1, "Number of pods for the benchmark. If unspecified, uses b.N.") workers := flag.Int("bench-workers", -1, "Number workers for the benchmark. If unspecified, uses tasks.") tasks := flag.Int("bench-tasks", -1, "Number of tasks for the benchmark. These tasks are sharded across the workers. If unspecified, uses b.N.") flag.Parse() // Unfortunately this v level goes in the opposite direction as stderrthreshold. flag.Set("v", fmt.Sprintf("%d", *q)) // We need quiet logs to parse benchmark results, which includes Errorf. flag.Set("logtostderr", "false") flag.Set("stderrthreshold", fmt.Sprintf("%d", Glog_fatalf-*q)) Pods = *pods Workers = *workers Tasks = *tasks framework.DeleteAllEtcdKeys() }
func TestUnschedulableNodes(t *testing.T) { helper, err := framework.NewHelper() if err != nil { t.Fatalf("Couldn't create etcd helper: %v", err) } framework.DeleteAllEtcdKeys() var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", // Enable v1beta3 if we are testing that version. EnableV1Beta3: testapi.Version() == "v1beta3", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) restClient := client.NewOrDie(&client.Config{Host: s.URL, Version: testapi.Version()}) schedulerConfigFactory := factory.NewConfigFactory(restClient) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { t.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}) eventBroadcaster.StartRecordingToSink(restClient.Events("")) scheduler.New(schedulerConfig).Run() defer close(schedulerConfig.StopEverything) DoTestUnschedulableNodes(t, restClient, schedulerConfigFactory.NodeLister.Store) }
// TestKindAuthorization tests that authorization can be controlled // by namespace. func TestKindAuthorization(t *testing.T) { framework.DeleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := framework.NewHelper() if err != nil { t.Fatalf("unexpected error: %v", err) } a := newAuthorizerWithContents(t, `{"resource": "services"} `) var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", // enable v1beta3 if we are testing that api version. EnableV1Beta3: testapi.Version() == "v1beta3", Authenticator: getTestTokenAuth(), Authorizer: a, AdmissionControl: admit.NewAlwaysAdmit(), }) previousResourceVersion := make(map[string]float64) transport := http.DefaultTransport requests := []struct { verb string URL string body string statusCodes map[int]bool // allowed status codes. }{ {"POST", timeoutPath("services", api.NamespaceDefault, ""), aService, code201}, {"GET", path("services", api.NamespaceDefault, ""), "", code200}, {"GET", path("services", api.NamespaceDefault, "a"), "", code200}, {"DELETE", timeoutPath("services", api.NamespaceDefault, "a"), "", code200}, {"POST", timeoutPath("pods", api.NamespaceDefault, ""), aPod, code403}, {"GET", path("pods", "", ""), "", code403}, {"GET", path("pods", api.NamespaceDefault, "a"), "", code403}, {"DELETE", timeoutPath("pods", api.NamespaceDefault, "a"), "", code403}, } for _, r := range requests { token := BobToken var bodyStr string if r.body != "" { bodyStr = fmt.Sprintf(r.body, "") if r.verb == "PUT" && r.body != "" { // For update operations, insert previous resource version if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 { resourceVersionJson := fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion) bodyStr = fmt.Sprintf(r.body, resourceVersionJson) } } } r.body = bodyStr bodyBytes := bytes.NewReader([]byte(bodyStr)) 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) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) { 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) if _, ok := r.statusCodes[resp.StatusCode]; !ok { t.Logf("case %v", r) t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode) t.Errorf("Body: %v", string(b)) } else { if r.verb == "POST" { // For successful create operations, extract resourceVersion id, currentResourceVersion, err := parseResourceVersion(b) if err == nil { key := getPreviousResourceVersionKey(r.URL, id) previousResourceVersion[key] = currentResourceVersion } } } } } }
// TestAliceNotForbiddenOrUnauthorized tests a user who is known to // the authentication system and authorized to do any actions. func TestAliceNotForbiddenOrUnauthorized(t *testing.T) { framework.DeleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := framework.NewHelper() if err != nil { t.Fatalf("unexpected error: %v", err) } var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", // enable v1beta3 if we are testing that api version. EnableV1Beta3: testapi.Version() == "v1beta3", Authenticator: getTestTokenAuth(), Authorizer: allowAliceAuthorizer{}, AdmissionControl: admit.NewAlwaysAdmit(), }) previousResourceVersion := make(map[string]float64) transport := http.DefaultTransport for _, r := range getTestRequests() { token := AliceToken var bodyStr string if r.body != "" { sub := "" if r.verb == "PUT" { // For update operations, insert previous resource version if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 { sub += fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion) } namespace := "default" sub += fmt.Sprintf(",\r\n\"namespace\": %q", namespace) } bodyStr = fmt.Sprintf(r.body, sub) } r.body = bodyStr bodyBytes := bytes.NewReader([]byte(bodyStr)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) if r.verb == "PATCH" { req.Header.Set("Content-Type", "application/merge-patch+json") } 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) if _, ok := r.statusCodes[resp.StatusCode]; !ok { t.Logf("case %v", r) t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode) t.Errorf("Body: %v", string(b)) } else { if r.verb == "POST" { // For successful create operations, extract resourceVersion id, currentResourceVersion, err := parseResourceVersion(b) if err == nil { key := getPreviousResourceVersionKey(r.URL, id) previousResourceVersion[key] = currentResourceVersion } } } }() } }
// TestReadOnlyAuthorization tests that authorization can be controlled // by namespace. func TestReadOnlyAuthorization(t *testing.T) { framework.DeleteAllEtcdKeys() // This file has alice and bob in it. // Set up a master helper, err := framework.NewHelper() if err != nil { t.Fatalf("unexpected error: %v", err) } a := newAuthorizerWithContents(t, `{"readonly": true}`) var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) defer s.Close() m = master.New(&master.Config{ EtcdHelper: helper, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", // enable v1beta3 if we are testing that api version. EnableV1Beta3: testapi.Version() == "v1beta3", Authenticator: getTestTokenAuth(), Authorizer: a, AdmissionControl: admit.NewAlwaysAdmit(), }) transport := http.DefaultTransport requests := []struct { verb string URL string body string statusCodes map[int]bool // allowed status codes. }{ {"POST", path("pods", "", ""), aPod, code403}, {"GET", path("pods", "", ""), "", code200}, {"GET", path("pods", api.NamespaceDefault, "a"), "", code404}, } for _, r := range requests { token := BobToken bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } if _, ok := r.statusCodes[resp.StatusCode]; !ok { t.Logf("case %v", r) t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode) b, _ := ioutil.ReadAll(resp.Body) t.Errorf("Body: %v", string(b)) } }() } }
func TestClient(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() ns := api.NamespaceDefault framework.DeleteAllEtcdKeys() client := client.NewOrDie(&client.Config{Host: s.URL, Version: testapi.Version()}) info, err := client.ServerVersion() if err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := version.Get(), *info; !reflect.DeepEqual(e, a) { t.Errorf("expected %#v, got %#v", e, a) } pods, err := client.Pods(ns).List(labels.Everything(), fields.Everything()) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(pods.Items) != 0 { t.Errorf("expected no pods, got %#v", pods) } // get a validation error pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ GenerateName: "test", }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "test", }, }, }, } got, err := client.Pods(ns).Create(pod) if err == nil { t.Fatalf("unexpected non-error: %v", got) } // get a created pod pod.Spec.Containers[0].Image = "an-image" got, err = client.Pods(ns).Create(pod) if err != nil { t.Fatalf("unexpected error: %v", err) } if got.Name == "" { t.Errorf("unexpected empty pod Name %v", got) } // pod is shown, but not scheduled pods, err = client.Pods(ns).List(labels.Everything(), fields.Everything()) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(pods.Items) != 1 { t.Errorf("expected one pod, got %#v", pods) } actual := pods.Items[0] if actual.Name != got.Name { t.Errorf("expected pod %#v, got %#v", got, actual) } if actual.Spec.NodeName != "" { t.Errorf("expected pod to be unscheduled, got %#v", actual) } }
func TestMultiWatch(t *testing.T) { // Disable this test as long as it demonstrates a problem. // TODO: Reenable this test when we get #6059 resolved. return const watcherCount = 50 runtime.GOMAXPROCS(watcherCount) framework.DeleteAllEtcdKeys() defer framework.DeleteAllEtcdKeys() _, s := framework.RunAMaster(t) defer s.Close() ns := api.NamespaceDefault client := client.NewOrDie(&client.Config{Host: s.URL, Version: testapi.Version()}) dummyEvent := func(i int) *api.Event { name := fmt.Sprintf("unrelated-%v", i) return &api.Event{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%v.%x", name, time.Now().UnixNano()), Namespace: ns, }, InvolvedObject: api.ObjectReference{ Name: name, Namespace: ns, }, Reason: fmt.Sprintf("unrelated change %v", i), } } type timePair struct { t time.Time name string } receivedTimes := make(chan timePair, watcherCount*2) watchesStarted := sync.WaitGroup{} // make a bunch of pods and watch them for i := 0; i < watcherCount; i++ { watchesStarted.Add(1) name := fmt.Sprintf("multi-watch-%v", i) got, err := client.Pods(ns).Create(&api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels.Set{"watchlabel": name}, }, Spec: api.PodSpec{ Containers: []api.Container{{ Name: "nothing", Image: "kubernetes/pause", }}, }, }) if err != nil { t.Fatalf("Couldn't make %v: %v", name, err) } go func(name, rv string) { w, err := client.Pods(ns).Watch( labels.Set{"watchlabel": name}.AsSelector(), fields.Everything(), rv, ) if err != nil { panic(fmt.Sprintf("watch error for %v: %v", name, err)) } defer w.Stop() watchesStarted.Done() e, ok := <-w.ResultChan() // should get the update (that we'll do below) if !ok { panic(fmt.Sprintf("%v ended early?", name)) } if e.Type != watch.Modified { panic(fmt.Sprintf("Got unexpected watch notification:\n%v: %+v %+v", name, e, e.Object)) } receivedTimes <- timePair{time.Now(), name} }(name, got.ObjectMeta.ResourceVersion) } log.Printf("%v: %v pods made and watchers started", time.Now(), watcherCount) // wait for watches to start before we start spamming the system with // objects below, otherwise we'll hit the watch window restriction. watchesStarted.Wait() const ( useEventsAsUnrelatedType = false usePodsAsUnrelatedType = true ) // make a bunch of unrelated changes in parallel if useEventsAsUnrelatedType { const unrelatedCount = 3000 var wg sync.WaitGroup defer wg.Wait() changeToMake := make(chan int, unrelatedCount*2) changeMade := make(chan int, unrelatedCount*2) go func() { for i := 0; i < unrelatedCount; i++ { changeToMake <- i } close(changeToMake) }() for i := 0; i < 50; i++ { wg.Add(1) go func() { defer wg.Done() for { i, ok := <-changeToMake if !ok { return } if _, err := client.Events(ns).Create(dummyEvent(i)); err != nil { panic(fmt.Sprintf("couldn't make an event: %v", err)) } changeMade <- i } }() } for i := 0; i < 2000; i++ { <-changeMade if (i+1)%50 == 0 { log.Printf("%v: %v unrelated changes made", time.Now(), i+1) } } } if usePodsAsUnrelatedType { const unrelatedCount = 3000 var wg sync.WaitGroup defer wg.Wait() changeToMake := make(chan int, unrelatedCount*2) changeMade := make(chan int, unrelatedCount*2) go func() { for i := 0; i < unrelatedCount; i++ { changeToMake <- i } close(changeToMake) }() for i := 0; i < 50; i++ { wg.Add(1) go func() { defer wg.Done() for { i, ok := <-changeToMake if !ok { return } name := fmt.Sprintf("unrelated-%v", i) _, err := client.Pods(ns).Create(&api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.PodSpec{ Containers: []api.Container{{ Name: "nothing", Image: "kubernetes/pause", }}, }, }) if err != nil { panic(fmt.Sprintf("couldn't make unrelated pod: %v", err)) } changeMade <- i } }() } for i := 0; i < 2000; i++ { <-changeMade if (i+1)%50 == 0 { log.Printf("%v: %v unrelated changes made", time.Now(), i+1) } } } // Now we still have changes being made in parallel, but at least 1000 have been made. // Make some updates to send down the watches. sentTimes := make(chan timePair, watcherCount*2) for i := 0; i < watcherCount; i++ { go func(i int) { name := fmt.Sprintf("multi-watch-%v", i) pod, err := client.Pods(ns).Get(name) if err != nil { panic(fmt.Sprintf("Couldn't get %v: %v", name, err)) } pod.Spec.Containers[0].Image = "kubernetes/pause:1" sentTimes <- timePair{time.Now(), name} if _, err := client.Pods(ns).Update(pod); err != nil { panic(fmt.Sprintf("Couldn't make %v: %v", name, err)) } }(i) } sent := map[string]time.Time{} for i := 0; i < watcherCount; i++ { tp := <-sentTimes sent[tp.name] = tp.t } log.Printf("all changes made") dur := map[string]time.Duration{} for i := 0; i < watcherCount; i++ { tp := <-receivedTimes delta := tp.t.Sub(sent[tp.name]) dur[tp.name] = delta log.Printf("%v: %v", tp.name, delta) } log.Printf("all watches ended") t.Errorf("durations: %v", dur) }